Only transmittal had any @media (max-width) rules; the other seven
tools silently break below ~900px. Adds a baseline shared rule that
every tool inherits — desktop-first stays the same, but a tablet in
landscape or a window split next to a document remains usable.
@media (max-width: 800px):
- tighter header padding + gaps
- .app-header__title drops 18px → 16px
- .build-timestamp inside .header-title-group hidden (it's
traceability info, not a primary affordance — still reachable
via help panel)
- header text buttons get a smaller padding so they fit
@media (max-width: 480px) phone-width:
- .app-header switches to column layout
- .header-left and .header-right each span full width with
justify-content: space-between
prefers-reduced-motion was already covered for the page-load stagger.
Each tool can still override in its own css/layout.css; this is the
shared floor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
730 lines
20 KiB
CSS
730 lines
20 KiB
CSS
/* ==========================================================================
|
|
ZDDC Shared Base — single source of truth for tokens and primitives
|
|
Included first by every tool's build.sh via ../shared/base.css
|
|
========================================================================== */
|
|
|
|
/* ── CSS custom properties ────────────────────────────────────────────────── */
|
|
:root {
|
|
/* Brand / accent (matches zddc.varasys.io website --accent) */
|
|
--primary: #2a5a8a;
|
|
--primary-hover: #1d4060;
|
|
--primary-active: #163352;
|
|
--primary-light: #e8f0f7;
|
|
|
|
/* Semantic colours */
|
|
--success: #28a745;
|
|
--warning: #d97706;
|
|
--danger: #dc3545;
|
|
--info: #17a2b8;
|
|
|
|
/* Backgrounds */
|
|
--bg: #ffffff;
|
|
--bg-secondary: #f8f9fa;
|
|
--bg-hover: #f0f4f8;
|
|
--bg-selected: var(--primary-light);
|
|
|
|
/* Text */
|
|
--text: #212529;
|
|
--text-muted: #6c757d;
|
|
--text-light: #ffffff;
|
|
|
|
/* Borders */
|
|
--border: #dee2e6;
|
|
--border-dark: #adb5bd;
|
|
|
|
/* Shape */
|
|
--radius: 4px;
|
|
|
|
/* Typography. --font-display covers headings (Source Serif 4 — a refined
|
|
transitional serif that reads as "engineering / document / serious"
|
|
without being academic). --font is body UI text (IBM Plex Sans —
|
|
distinctive engineering sans, with proper figures and tabular nums).
|
|
Both are base64-inlined via shared/fonts.css; system fallbacks kick in
|
|
when fonts.css isn't loaded (e.g. unbuilt component preview). --font-mono
|
|
stays as a system stack; engineering tools rarely benefit from a custom
|
|
mono and platform mono fonts are already excellent. */
|
|
--font-display: 'Source Serif 4', ui-serif, Charter, 'Iowan Old Style', Georgia, serif;
|
|
--font: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
--font-mono: 'SF Mono', 'Fira Code', 'Consolas', 'Courier New', monospace;
|
|
}
|
|
|
|
/* ── Dark mode tokens ─────────────────────────────────────────────────────── */
|
|
/* Applied via: OS preference (auto) or [data-theme="dark"] on <html> */
|
|
/* The [data-theme="light"] selector locks light mode regardless of OS pref. */
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) {
|
|
--primary: #5fa8e0;
|
|
--primary-hover: #74b6e6;
|
|
--primary-active: #88c4ec;
|
|
--primary-light: #1a3550;
|
|
|
|
--bg: #1e1e1e;
|
|
--bg-secondary: #252526;
|
|
--bg-hover: #2d2d30;
|
|
--bg-selected: #1a3550;
|
|
|
|
--text: #d4d4d4;
|
|
--text-muted: #9d9d9d;
|
|
--text-light: #ffffff;
|
|
|
|
--border: #3e3e42;
|
|
--border-dark: #6e6e72;
|
|
}
|
|
}
|
|
|
|
/* Manual dark override — wins over media query */
|
|
[data-theme="dark"] {
|
|
--primary: #5fa8e0;
|
|
--primary-hover: #74b6e6;
|
|
--primary-active: #88c4ec;
|
|
--primary-light: #1a3550;
|
|
|
|
--bg: #1e1e1e;
|
|
--bg-secondary: #252526;
|
|
--bg-hover: #2d2d30;
|
|
--bg-selected: #1a3550;
|
|
|
|
--text: #d4d4d4;
|
|
--text-muted: #9d9d9d;
|
|
--text-light: #ffffff;
|
|
|
|
--border: #3e3e42;
|
|
--border-dark: #6e6e72;
|
|
}
|
|
|
|
/* ── Reset ────────────────────────────────────────────────────────────────── */
|
|
*, *::before, *::after {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
/* ── Base document ────────────────────────────────────────────────────────── */
|
|
html, body {
|
|
height: 100%;
|
|
font-family: var(--font);
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
color: var(--text);
|
|
background-color: var(--bg-secondary);
|
|
}
|
|
|
|
/* ── Typography ───────────────────────────────────────────────────────────── */
|
|
h1, h2, h3, h4, h5, h6 {
|
|
font-family: var(--font-display);
|
|
font-weight: 600;
|
|
line-height: 1.2;
|
|
/* Source Serif 4 has subtle optical sizing; let the browser opt in
|
|
where supported (modern Chromium/Firefox). */
|
|
font-optical-sizing: auto;
|
|
}
|
|
|
|
/* Tracking numbers and other engineering identifiers should align in
|
|
columns when stacked vertically. Apply tabular figures wherever we
|
|
render structured numeric data. */
|
|
table, .tabular-nums, code {
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
a {
|
|
color: var(--primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* ── Utility ──────────────────────────────────────────────────────────────── */
|
|
.hidden {
|
|
display: none !important;
|
|
}
|
|
|
|
.truncate {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* ── Scrollbars (webkit) ──────────────────────────────────────────────────── */
|
|
::-webkit-scrollbar {
|
|
width: 7px;
|
|
height: 7px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: var(--bg-secondary);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: #c1c1c1;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #a0a0a0;
|
|
}
|
|
|
|
/* ── Button primitive ─────────────────────────────────────────────────────── */
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
padding: 0.4rem 0.85rem;
|
|
font-family: var(--font);
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
line-height: 1.4;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
vertical-align: middle;
|
|
cursor: pointer;
|
|
border: 1px solid transparent;
|
|
border-radius: var(--radius);
|
|
transition: background 0.15s, box-shadow 0.15s, border-color 0.15s, color 0.15s;
|
|
background: var(--bg-secondary);
|
|
color: var(--text);
|
|
}
|
|
|
|
.btn:disabled,
|
|
.btn[disabled] {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.btn:not(:disabled):hover {
|
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
|
|
}
|
|
|
|
.btn:not(:disabled):active {
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* Variants */
|
|
.btn-primary {
|
|
background: var(--primary);
|
|
color: var(--text-light);
|
|
border-color: var(--primary);
|
|
}
|
|
|
|
.btn-primary:not(:disabled):hover {
|
|
background: var(--primary-hover);
|
|
border-color: var(--primary-hover);
|
|
color: var(--text-light);
|
|
}
|
|
|
|
.btn-primary:not(:disabled):active {
|
|
background: var(--primary-active);
|
|
border-color: var(--primary-active);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
border-color: var(--border);
|
|
}
|
|
|
|
.btn-secondary:not(:disabled):hover {
|
|
background: var(--bg-secondary);
|
|
}
|
|
|
|
/* Subdued / de-emphasized variant.
|
|
Used on the "Add Local Directory" button when a tool is operating
|
|
in server (online) mode — the local-dir affordance is still
|
|
available but visually quieter, since the typical user already
|
|
has the directory loaded from the server. */
|
|
.btn.btn--subtle {
|
|
background: transparent;
|
|
color: var(--text-muted);
|
|
border-color: var(--border);
|
|
box-shadow: none;
|
|
font-weight: normal;
|
|
}
|
|
|
|
.btn.btn--subtle:not(:disabled):hover {
|
|
color: var(--text);
|
|
background: var(--bg-secondary);
|
|
}
|
|
|
|
.btn-success {
|
|
background: var(--success);
|
|
color: var(--text-light);
|
|
border-color: var(--success);
|
|
}
|
|
|
|
.btn-danger {
|
|
background: var(--danger);
|
|
color: var(--text-light);
|
|
border-color: var(--danger);
|
|
}
|
|
|
|
/* Sizes */
|
|
.btn-sm {
|
|
padding: 0.25rem 0.5rem;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.btn-lg {
|
|
padding: 0.6rem 1.4rem;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.btn-link {
|
|
background: transparent;
|
|
border-color: transparent;
|
|
color: var(--primary);
|
|
padding-left: 0;
|
|
padding-right: 0;
|
|
}
|
|
|
|
.btn-link:not(:disabled):hover {
|
|
text-decoration: underline;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* ── App header chrome ────────────────────────────────────────────────────── */
|
|
.app-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.35rem 1rem;
|
|
background: var(--bg-secondary);
|
|
border-bottom: 1px solid var(--border);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Left and right groups inside .app-header. Both flex-row so their
|
|
children (logo, title, action button, theme icon, etc.) lay out
|
|
horizontally rather than stacking. Left side gets a slightly
|
|
larger gap because it carries the title group and an action
|
|
button; right side is just icon buttons. */
|
|
.header-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.header-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
/* Tool name inside the header. Renders in the display serif so the
|
|
tool's identity reads as a document title, not a UI label. */
|
|
.app-header__title {
|
|
font-family: var(--font-display);
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
letter-spacing: 0;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Brand logo — sits left of the title in every tool's app-header.
|
|
Self-contained: the SVG provides its own dark blue rounded background,
|
|
so no extra wrapper styling is needed. */
|
|
.app-header__logo {
|
|
width: 26px;
|
|
height: 26px;
|
|
flex-shrink: 0;
|
|
display: block;
|
|
}
|
|
|
|
/* Page-load reveal. The header is the first thing a user sees — a
|
|
short staggered fade-in over ~360ms turns "instant pop-in" into a
|
|
subtle "the tool is composing itself for you" beat. Pure CSS, no
|
|
JS; respects prefers-reduced-motion. The stagger order (logo →
|
|
title → action buttons → right-side icons) mirrors the reading
|
|
order of the chrome itself. */
|
|
@keyframes zddc-header-rise {
|
|
from { opacity: 0; transform: translateY(-4px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.app-header__logo,
|
|
.header-title-group,
|
|
.header-left > .btn,
|
|
.header-right > * {
|
|
animation: zddc-header-rise 360ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
|
|
}
|
|
|
|
.app-header__logo { animation-delay: 0ms; }
|
|
.header-title-group { animation-delay: 60ms; }
|
|
.header-left > .btn { animation-delay: 120ms; }
|
|
.header-right > *:nth-child(1) { animation-delay: 180ms; }
|
|
.header-right > *:nth-child(2) { animation-delay: 220ms; }
|
|
.header-right > *:nth-child(3) { animation-delay: 260ms; }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.app-header__logo,
|
|
.header-title-group,
|
|
.header-left > .btn,
|
|
.header-right > * {
|
|
animation: none;
|
|
}
|
|
}
|
|
|
|
/* ── Build timestamp ──────────────────────────────────────────────────────── */
|
|
.build-timestamp {
|
|
font-size: 0.55rem;
|
|
color: var(--text-muted);
|
|
opacity: 0.7;
|
|
font-weight: 300;
|
|
white-space: nowrap;
|
|
padding-top: 0.15rem;
|
|
}
|
|
|
|
/* Title + timestamp stacked vertically on the left side of the header */
|
|
.header-title-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0;
|
|
line-height: 1;
|
|
}
|
|
|
|
/* ── Icon buttons (help, theme, refresh) ─────────────────────────────────── */
|
|
/* Square, centered — overrides the asymmetric text-button padding/line-height */
|
|
#help-btn,
|
|
#theme-btn,
|
|
#refreshHeaderBtn {
|
|
width: 2rem;
|
|
height: 2rem;
|
|
padding: 0;
|
|
line-height: 1;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
/* The refresh ⟳ glyph renders slightly smaller than ◐ / ? — bump to match. */
|
|
#refreshHeaderBtn {
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
/* Toast CSS lives in shared/toast.css; loaded by every tool's build. */
|
|
|
|
/* ── Empty state ──────────────────────────────────────────────────────────── */
|
|
/* The "nothing's loaded yet" screen. By default, centers its inner
|
|
content in whatever space the parent gives it (works inside a flex
|
|
column). Tools that need to overlay an existing layout (archive,
|
|
classifier) add .empty-state--overlay; the screen pins below the
|
|
app header and on top of whatever underlying layout already exists.
|
|
Inner content uses BEM-ish .empty-state__inner with two variants:
|
|
plain (left-aligned, doc-style) and --centered (centered card). */
|
|
|
|
.empty-state {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 2rem;
|
|
background: var(--bg);
|
|
}
|
|
|
|
.empty-state--overlay {
|
|
position: absolute;
|
|
top: 50px; /* clear the app-header */
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 10;
|
|
flex: none;
|
|
}
|
|
|
|
.empty-state__inner {
|
|
max-width: 640px;
|
|
color: var(--text-muted);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.empty-state__inner h2 {
|
|
color: var(--text);
|
|
margin: 0 0 1rem;
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.empty-state__inner p {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.empty-state__inner ul,
|
|
.empty-state__inner ol {
|
|
margin: 1rem 0;
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
.empty-state__inner li {
|
|
margin: 0.4rem 0;
|
|
}
|
|
|
|
.empty-state__inner .note {
|
|
font-size: 0.85rem;
|
|
font-style: italic;
|
|
}
|
|
|
|
/* Centered variant: tighter max-width + centered text. Used by tools
|
|
whose empty-state reads as a "welcome card" (archive, classifier)
|
|
rather than a doc-style page (browse). */
|
|
.empty-state__inner--centered {
|
|
max-width: 500px;
|
|
text-align: center;
|
|
padding: 2rem;
|
|
}
|
|
|
|
/* Bullet list inside an empty-state — keep the bullets left-aligned
|
|
even when the surrounding card is centered. */
|
|
.welcome-list {
|
|
text-align: left;
|
|
margin: 0.5rem auto;
|
|
max-width: 400px;
|
|
}
|
|
|
|
/* ── Theme and help icon buttons ─────────────────────────────────────────── */
|
|
#theme-btn,
|
|
#help-btn {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
/* ── Help panel (shared slide-out drawer) ─────────────────────────────────── */
|
|
/* Used by all four tools. Toggle open/close via shared/help.js. */
|
|
|
|
.help-panel {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
width: min(420px, 85vw);
|
|
height: 100vh;
|
|
z-index: 1000;
|
|
background: var(--bg);
|
|
border-left: 1px solid var(--border);
|
|
box-shadow: -2px 0 12px rgba(0, 0, 0, 0.08);
|
|
display: flex;
|
|
flex-direction: column;
|
|
transform: translateX(100%);
|
|
transition: transform 0.25s ease;
|
|
}
|
|
|
|
.help-panel:not([hidden]) {
|
|
transform: translateX(0);
|
|
}
|
|
|
|
.help-panel[hidden] {
|
|
display: flex;
|
|
transform: translateX(100%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.help-panel__header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.75rem 1rem;
|
|
border-bottom: 1px solid var(--border);
|
|
flex-shrink: 0;
|
|
background: var(--bg);
|
|
}
|
|
|
|
.help-panel__title {
|
|
font-size: 1rem;
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
margin: 0;
|
|
}
|
|
|
|
.help-panel__close {
|
|
background: none;
|
|
border: none;
|
|
color: var(--text-muted);
|
|
font-size: 1.35rem;
|
|
cursor: pointer;
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: var(--radius);
|
|
line-height: 1;
|
|
transition: background 0.15s, color 0.15s;
|
|
}
|
|
|
|
.help-panel__close:hover {
|
|
color: var(--text);
|
|
background: var(--bg-secondary);
|
|
}
|
|
|
|
.help-panel__body {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 1rem 1rem 2rem;
|
|
font-size: 0.85rem;
|
|
line-height: 1.6;
|
|
color: var(--text);
|
|
}
|
|
|
|
.help-panel__body h3 {
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
margin: 1.25rem 0 0.35rem;
|
|
color: var(--text);
|
|
border-bottom: 1px solid var(--border);
|
|
padding-bottom: 0.15rem;
|
|
}
|
|
|
|
.help-panel__body h3:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.help-panel__body h4 {
|
|
font-size: 0.7rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
margin: 1.25rem 0 0.3rem;
|
|
padding-left: 0.5rem;
|
|
border-left: 3px solid var(--border-dark);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.help-panel__body p {
|
|
margin: 0 0 0.5rem;
|
|
}
|
|
|
|
.help-panel__body ol,
|
|
.help-panel__body ul {
|
|
padding-left: 1.5rem;
|
|
margin: 0.3rem 0 0.5rem;
|
|
}
|
|
|
|
.help-panel__body li {
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.help-panel__body dl {
|
|
margin: 0.3rem 0;
|
|
}
|
|
|
|
.help-panel__body dt {
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
|
|
.help-panel__body dd {
|
|
margin: 0 0 0.5rem 1rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.help-panel__body code {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8em;
|
|
background: var(--bg-secondary);
|
|
padding: 0.1em 0.3em;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.help-badge {
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
padding: 0.1rem 0.35rem;
|
|
border-radius: var(--radius);
|
|
vertical-align: middle;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
.help-badge--draft {
|
|
color: #2563eb;
|
|
background: #eff6ff;
|
|
}
|
|
|
|
.help-badge--published {
|
|
color: #7c3aed;
|
|
background: #f5f3ff;
|
|
}
|
|
|
|
/* Shrink main content when help panel is open */
|
|
body.help-open .app-header {
|
|
margin-right: min(420px, 85vw);
|
|
}
|
|
|
|
/* ── Column filter inputs (shared across archive, classifier, transmittal) ─── */
|
|
.column-filter {
|
|
display: block;
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
margin-top: 0.25rem;
|
|
padding: 0.2rem 0.4rem;
|
|
font-size: 0.8rem;
|
|
font-family: var(--font);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
transition: border-color 0.15s;
|
|
}
|
|
|
|
.column-filter:focus {
|
|
border-color: var(--primary);
|
|
outline: none;
|
|
box-shadow: 0 0 0 1px rgba(42, 90, 138, 0.35);
|
|
}
|
|
|
|
.column-filter::placeholder {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* ── Narrow-viewport behavior ─────────────────────────────────────────────────
|
|
ZDDC tools are desktop-first (engineering workstations, large monitors),
|
|
but a baseline narrow rule keeps them usable on a tablet in landscape or
|
|
a window split next to a document. Three principled moves:
|
|
|
|
1. Smaller header padding so the chrome doesn't dominate the viewport.
|
|
2. The build-timestamp inside .header-title-group is hidden — it's a
|
|
traceability artifact, never an immediate-action element. (The full
|
|
label remains visible via the help panel and the "About" surface.)
|
|
3. .header-right gap tightens; the action button next to the title
|
|
drops to a 32x32 icon-only square via the .btn-square pattern (tools
|
|
that haven't adopted .btn-square just keep the text button — graceful).
|
|
|
|
Each tool is welcome to add its own narrow-mode rules in css/layout.css;
|
|
this block is the shared baseline. */
|
|
@media (max-width: 800px) {
|
|
.app-header {
|
|
padding: 0.3rem 0.6rem;
|
|
}
|
|
.app-header__title {
|
|
font-size: 16px;
|
|
}
|
|
.header-left {
|
|
gap: 0.5rem;
|
|
}
|
|
.header-right {
|
|
gap: 0.25rem;
|
|
}
|
|
/* Hide the build-timestamp on narrow viewports — it's reference info,
|
|
not a primary affordance, and steals horizontal space from the title.
|
|
Still reachable via the help panel and DOM. */
|
|
.header-title-group .build-timestamp {
|
|
display: none;
|
|
}
|
|
/* Action buttons that have an emoji-only or symbol-only label keep
|
|
their full width; text-labeled action buttons in the header shrink
|
|
to a more compact pad to fit. */
|
|
.header-left > .btn {
|
|
padding: 0.3rem 0.6rem;
|
|
font-size: 0.85rem;
|
|
}
|
|
}
|
|
|
|
/* Very narrow (phone-width). Stack the header-left children vertically so
|
|
the title and action button each get their own line; tools can override
|
|
this in their own CSS if they have a dedicated mobile layout. */
|
|
@media (max-width: 480px) {
|
|
.app-header {
|
|
align-items: flex-start;
|
|
flex-direction: column;
|
|
gap: 0.4rem;
|
|
}
|
|
.header-left,
|
|
.header-right {
|
|
width: 100%;
|
|
justify-content: space-between;
|
|
}
|
|
}
|