/* ─────────────────────────────────────────────────────────────────────────────
   BASE
   Design tokens, reset, typography and the page scaffold.

   Part 1 of 11, cut from the 5,142-line app.css. THE ORDER OF THESE
   FILES IS LOAD-BEARING — they are one cascade, split for navigation only, and
   index.php links them in this sequence. Moving one changes which rule wins.
   ───────────────────────────────────────────────────────────────────────────── */
/* =========================================
   STUDIO MANAGER | PRO - MASTER STYLESHEET
   ========================================= */

/* Executive — the document typeface (quotes, invoices, receipts, PDF generation).
   ../../ AND NOT ../ — a url() resolves against the STYLESHEET, not the page. These
   rules were written in css/app.css, where ../assets reached the repository root;
   the split moved them a directory deeper into css/app/, where the same string points
   at css/assets, which does not exist. All six faces 404ed and every document fell
   back to the system sans. css/auth.css still says ../assets and is still correct —
   it never moved. The same mechanism repointed six requires when api.php was split;
   tests/test_structure.php now resolves every url() in css/ against the filesystem. */
@font-face {
    font-family: 'Executive';
    src: url('../../assets/fonts/Executive-Regular.otf') format('opentype');
    font-weight: 400;
    font-style: normal;
}
@font-face {
    font-family: 'Executive';
    src: url('../../assets/fonts/Executive-RegularIta.otf') format('opentype');
    font-weight: 400;
    font-style: italic;
}
@font-face {
    font-family: 'Executive';
    src: url('../../assets/fonts/Executive-Medium.otf') format('opentype');
    font-weight: 500;
    font-style: normal;
}
@font-face {
    font-family: 'Executive';
    src: url('../../assets/fonts/Executive-MediumIta.otf') format('opentype');
    font-weight: 500;
    font-style: italic;
}
@font-face {
    font-family: 'Executive';
    src: url('../../assets/fonts/Executive-Bold.otf') format('opentype');
    font-weight: 700;
    font-style: normal;
}
@font-face {
    font-family: 'Executive';
    src: url('../../assets/fonts/Executive-BoldIta.otf') format('opentype');
    font-weight: 700;
    font-style: italic;
}

:root {
    /* Background gradient — DARK theme · "Poolside" (vivid Hockney pool palette):
       yellow · pool cyan · hot pink · cobalt · yellow · jade green over deep navy.
       This is the liquid-glass ARTWORK and is meant to be saturated and colourful —
       the black-and-white rule applies only to the UI accent (buttons / nav), not
       to this refracted field. */
    --liquid-color-1: #FFF100; /* sun yellow */
    --liquid-color-2: #00C2D6; /* pool cyan */
    --liquid-color-3: #FF4FA3; /* hot pink */
    --liquid-color-4: #1E5BFF; /* cobalt */
    --liquid-color-5: #FFF100; /* sun echo */
    --liquid-color-6: #19B85C; /* jade green */
    --liquid-base: #111111;    /* deep pool navy */

    /* Monochrome accent — white in dark mode, black in light mode. */
    --theme-color: #FFFFFF;
    --theme-color-hover: #E5E5E5;
    --theme-text: #FFFFFF;
    --active-theme-bg: rgba(255, 255, 255, 0.15);
    /* Semantics — Interactive Brokers gain/loss: clean ticker-green up, strong
       red down (IBKR brand red is #FF0000). Amber reserved for pending/warning. */
    /* ONE green / ONE red / ONE yellow site-wide. neon-* alias the semantic
       tokens so there is a single source per hue; yellow = logo.svg brand #fff100. */
    --success-green: #01eb72;
    --danger-red: #ff0f0f;
    --neon-green: var(--success-green);
    --neon-red: var(--danger-red);
    /* calm glow — restrained halo (zen), hue stays vivid */
    --neon-green-glow: rgba(1, 235, 114, 0.30);
    --neon-red-glow: rgba(255, 15, 15, 0.30);
    --warning-yellow: #fff100;   /* brand yellow — from assets/logo.svg */
    /* NEON PINK — the "critical / overdue" alarm hue for invoice & A/R elements
       (pending-AR figure, the overdue aging segment, the Action-Required cards). */
    --neon-pink: #ff6afa;   /* pending-A/R · critical/overdue tag */
    --neon-pink-glow: rgba(255, 106, 250, 0.34);
    /* ----------------------------------------------------------------
       CHART / DATA-VIZ PALETTE — SINGLE SOURCE OF TRUTH.
       Edit a colour here and every donut/chart follows (js/theme.js
       reads these). Comma-separated; the first slice of each family is
       the semantic token so e.g. changing --success-green also moves
       the income charts. Accents are theme-agnostic (one definition).
       ---------------------------------------------------------------- */
    --chart-income:  var(--success-green), #00e5ff, #19ffc8, #9dff00, #00b4ff, #08fa55;
    --chart-expense: var(--danger-red), #ff6a00, #ff2bae, #ff4d7d, #ff003c, #ffb300;
    --chart-pending: var(--warning-yellow), #ffd400, #ffc000, #ffe600, #ffaa00;
    --chart-default: #0883fd, #b14dff, #0095e5, #926eff, #2d1fee;
    /* CATEGORY IDENTITY — VIVID NEON cool tones for neutral categories (project types),
       spanning aqua→cyan→blue→violet→purple→magenta. Bright + saturated to match the house
       neon palette, but still avoids the income-green / expense-red-orange / pending-yellow
       semantic hues so a category never reads as a status. */
    --chart-category: #00f5d4, #00c8ff, #3c6bff, #8a4dff, #d24dff, #ff2eb8, #6b5bff;
    --chart-blue: #0883fd;
    --chart-cyan: #00fbff;   /* quote accent — all quote DOTS/chips/glows use this bright cyan */
    --ultra-cyan: #00fbff;   /* Action-Required quote tag (kept as an alias of the quote cyan) */
    --quote-ink: #0a8f9e;    /* readable quote TEXT (dark teal) — same reading tone as the invoicing gold #b8860b */
    --bg-main: #000000;
    --bg-card: #18181B;
    --bg-input: #000000;
    --bg-hover: #000000;
    --bg-glass: rgba(23, 23, 24, 0.82);
    --bg-glass-panel: rgba(16, 16, 19, 0.92);
    --text-main: #FFFFFF;
    --text-muted: #A1A1AA;
    --divider: #27272A;
    --divider-strong: #3F3F46;
    /* heavy structural border — gives the layout editorial weight. Near-black "ink"
       on light; a stronger, more-visible grey on dark (black would vanish on dark). */
    --border-ink: #5C5C66;
    /* Host Grotesk (Google Fonts) — the main UI typeface across the whole web app.
       The Studio MARY "Executive" face is reserved for the PDF + on-screen document
       preview only. CJK fallbacks keep trilingual (jp / zh-Hant) text legible since
       the Latin face is Latin-only. */
    --font-sans: "Host Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "PingFang HK", "PingFang TC", "Hiragino Sans", "Microsoft JhengHei", "Noto Sans CJK TC", sans-serif;
}
/* Per-script overrides: Host Grotesk carries no CJK or Thai glyphs, and PingFang HK
   would serve TRADITIONAL glyph variants to a Simplified reader. Each locale puts its
   own face ahead of the shared stack; every other locale is untouched. */
html[lang="zh-Hans"] {
    --font-sans: "Host Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;
}
html[lang="th"] {
    --font-sans: "Host Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Thonburi", "Leelawadee UI", "Noto Sans Thai", "Sarabun", sans-serif;
}
:root {
    /* TYPE SCALE — snapped onto the reference system's ladder (12 · 14 · 18 · 24 ·
       30 · 48). The move is not uniform and that is the point: the UI steps DOWN
       one notch (compact density — 14px body, 12px caption) while display steps
       UP (44 → 48). The widened gap between a compact interface and one large,
       tightly-tracked headline is the style's signature contrast; shrinking the
       body without growing the display would just have made everything smaller. */
    --text-xs: 12px;        /* caption · badges · uppercase micro-labels */
    --text-sm: 13px;        /* small controls that are not yet body */
    --text-base: 14px;      /* BODY — the compact default (was 15px) */
    --text-md: 18px;        /* subheading */
    --text-lg: 24px;        /* heading-sm */
    --text-xl: 30px;        /* heading (was 32px) */
    --text-2xl: 48px;       /* display — hero dashboard figures (was 44px) */
    --font-regular: 400;
    --font-bold: 600;
    /* Weight scale — the reference system works in THREE weights (400 · 500 · 600)
       and has nothing heavier: hierarchy there is carried by size and tracking,
       not by mass. Adopting that retires the 760 display weight, so --fw-semibold
       and --fw-bold now both land on 600 by design rather than by accident. Host
       Grotesk is variable (300–800), so 600 is a deliberate stop, not a ceiling —
       raise --fw-bold alone if the hero figures need to shout again. */
    --fw-light: 400;        /* nothing below 400 at text sizes (legibility) */
    --fw-regular: 400;
    --fw-medium: 500;       /* labels — sit back */
    --fw-semibold: 600;     /* names, data values */
    --fw-bold: 600;         /* display — confident by size and tracking, not weight */
    --leading-none: 1;
    --leading-display: 1.1; /* 48px display — the reference's tightest setting */
    --leading-tight: 1.2;
    --leading-normal: 1.4;
    --leading-relaxed: 1.6;
    /* Tracking — the reference tightens hard at display (-0.05em at 48px,
       -0.025em at 24–30px) to get its "engineered headline" voice. We take that
       direction at HALF magnitude, because those numbers were cut for Geist and
       THE FACE IS THE VARIABLE: Host Grotesk sets on wider sidebearings, so
       Geist's -0.05em closes its counters instead of merely tightening the fit.
       This is the one place the reference is adapted rather than copied. Small
       uppercase stays tracked OUT (the reference does this too, at +0.05em; ours
       is looser still and stays where it is). Body sits at zero. */
    --tracking-display: -0.025em;   /* 48px titles & grand-total figures */
    --tracking-tight: -0.015em;     /* 24–30px card names / medium display */
    --tracking-normal: 0em;
    --tracking-wide: 0.08em;        /* UPPERCASE labels (.text-sm-caps, section heads) — Swiss air */
    --tracking-caps: 0.1em;         /* smaller UPPERCASE micro-labels (9–11px) — most open */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-8: 32px;
    --space-10: 40px;
    /* ── RADIUS · TWO VALUES, AND A DOCUMENT EXCEPTION ────────────────────────
       The reference system enforces exactly two radii — 18px on anything you can
       touch, 24px on anything that holds content — and gets its "radius-based
       hierarchy" from that discipline, not from a wide ladder. We had eight
       values spanning 4→24px, which meant the corner told you almost nothing.
       So: two primitives, and every legacy name below is now an ALIAS onto one
       of them. ~90 call sites follow without being touched.

       18px is a CAPPED pill, and that distinction is the whole trick. On a 36px
       control it renders as a perfect capsule — identical to --radius-pill — but
       on anything taller (a textarea, a tall field, a stacked rail) it stays at
       18px instead of bulging into a lozenge. --radius-pill is kept for the nav
       and segmented rails, where a true capsule at any height IS the affordance.

       --radius-doc survives as the deliberate third role. The reference has no
       document surface to have an opinion about; ours does (the .client-doc
       letterhead modules), and "the corner names the role" is the reference's
       own principle, so a sharp corner that means "this is paper" is in keeping
       with it rather than a leftover from before it. */
    --radius-control: 18px;   /* PRIMITIVE — buttons · inputs · badges · tabs */
    --radius-container: 24px; /* PRIMITIVE — cards · boards · modals · panels */
    --radius-sm: var(--radius-control);     /* buttons, inputs (was 8px) */
    --radius-md: var(--radius-control);     /* dropdowns, tabs, small floating bits (was 12px) */
    --radius-lg: var(--radius-container);   /* modals / large floating overlays (was 16px) */
    --radius-xl: var(--radius-container);   /* (legacy) */
    --radius-board: var(--radius-container);/* content panels · boards · tables (was 18px) */
    --radius-doc: 4px;      /* the flat letterhead modules (.client-doc) — the document exception */
    --radius-pill: 999px;   /* segmented toggles · nav — a true capsule at any height */
    --radius-full: 50%;     /* FAB, avatars */
    --shadow-card: 0 4px 12px rgba(0, 0, 0, 0.2);
    --shadow-modal: 0 0 0 1px var(--divider), 0 24px 48px -12px rgba(0, 0, 0, 0.8);
    /* Flat-design depth — sophisticated layered drop shadow. --shadow-tint is the
       rgb base; the Settings shadow-tint picker writes it, so changing it colour-
       tints every shadow at once. Stacked stops = realistic light falloff. */
    --shadow-tint: 4, 6, 16;
    /* ── ELEVATION · HAIRLINE FIRST, SHADOW SECOND ────────────────────────────
       The reference calls its card "1px hairline + 1px + 2px offset" and the
       result "barely-perceptible elevation". The hairline is doing the work and
       the shadow is only implying a light source — which is why the two have to
       arrive together. Dropping our shadows to a whisper WITHOUT restoring the
       edge would have left cards dissolving into the page.

       That restores an outer frame the app removed site-wide at one point. It is
       a single token: set --hairline to `transparent` and every card is frameless
       again, with no other edit. */
    --hairline: var(--divider);
    --card-border: 1px solid var(--hairline);
    --ring-focus: 0 0 0 1px var(--theme-color);   /* reference: 1px ring, NO offset */
    --shadow-2:
        0 1px 2px rgba(var(--shadow-tint), 0.20),
        0 2px 4px rgba(var(--shadow-tint), 0.16);
    --shadow-3:
        0 2px 6px rgba(var(--shadow-tint), 0.30),
        0 12px 28px rgba(var(--shadow-tint), 0.34);
    --glass-blur: blur(50px) saturate(200%) brightness(1.08);
    --glass-border: 1px solid rgba(255, 255, 255, 0.12);
    /* Neumorphic raised pill — the active nav item (soft, Swiss). Same-tone fill
       lifted by a top highlight + layered drop shadow. */
    --neu-bg: #212127;
    --neu-raised:
        inset 0 1px 0 rgba(255, 255, 255, 0.07),
        0 1px 2px rgba(0, 0, 0, 0.42),
        0 4px 11px rgba(0, 0, 0, 0.34);
}

/* Liquid-glass refraction — append the SVG displacement so every element using
   var(--glass-blur) optically lenses the background at its surface. Guarded by
   @supports so browsers without backdrop url() filters keep the plain blur.
   NOTE: blur is kept equal to the base value — the SVG filter adds refraction
   on top; reducing blur to compensate was counterproductive. */
@supports (backdrop-filter: url('#liquid-glass')) or (-webkit-backdrop-filter: url('#liquid-glass')) {
    :root { --glass-blur: blur(50px) saturate(200%) brightness(1.08) url('#liquid-glass'); }
}

html[data-theme='light'] {
    --theme-color: #000000;
    --theme-color-hover: #333333;
    --theme-text: #000000;
    --active-theme-bg: rgba(0, 0, 0, 0.05);
    /* Background gradient — LIGHT theme · "Poolside" (vivid Hockney pool palette):
       hot pink · yellow · pool cyan · cobalt · hot pink · jade green over pale sky.
       Saturated artwork by design — the black-and-white rule is for the UI accent
       only, not this refracted field. */
    --liquid-color-1: #FF4FA3; /* hot pink */
    --liquid-color-2: #FFF100; /* sun yellow */
    --liquid-color-3: #00C2D6; /* pool cyan */
    --liquid-color-4: #1E5BFF; /* cobalt */
    --liquid-color-5: #FF4FA3; /* hot pink */
    --liquid-color-6: #19B85C; /* jade green */
    --liquid-base: #edf2f4;    /* pale sky */
    /* Semantics deepened for AA contrast on the light surface (IBKR green/red). */
    --success-green: #01eb72;
    --danger-red: #ff0e16;
    /* neon-* alias the semantic tokens — one red / one green on the light surface */
    --neon-green: var(--success-green);
    --neon-red: var(--danger-red);
    --neon-green-glow: rgba(1, 235, 114, 0.22);
    --neon-red-glow: rgba(255, 14, 22, 0.22);
    --warning-yellow: #fff100;   /* brand yellow — from assets/logo.svg */
    --bg-main: #F4F4F5;
    --bg-card: #FFFFFF;
    --bg-input: #F4F4F5;
    --bg-hover: #E4E4E7;
    /* Frosted enough that content behind the chrome/modals isn't legible, while
       the edge still refracts the background (realistic frosted glass). */
    --bg-glass: rgba(255, 255, 255, 0.85);
    --bg-glass-panel: rgba(255, 255, 255, 0.94);
    --text-main: #18181B;
    --text-muted: #71717A;
    --divider: #E4E4E7;
    --divider-strong: #D4D4D8;
    --border-ink: #1F1F23;       /* near-black ink frame — strong weight on white */
    --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.05);
    --shadow-modal: 0 0 0 1px var(--divider), 0 24px 48px -12px rgba(0, 0, 0, 0.15);
    /* realistic layered shadow on the white surface (default tint = cool slate) */
    --shadow-tint: 17, 19, 28;
    /* Hairline-first elevation (see the dark block above). On white the hairline
       carries almost the whole card edge and the shadow is close to nothing —
       which is exactly the reference's "whisper-quiet" reading on paper. */
    --hairline: var(--divider);
    --card-border: 1px solid var(--hairline);
    --ring-focus: 0 0 0 1px var(--theme-color);
    --shadow-2:
        0 1px 2px rgba(var(--shadow-tint), 0.04),
        0 2px 4px rgba(var(--shadow-tint), 0.04);
    --shadow-3:
        0 1px 3px rgba(var(--shadow-tint), 0.05),
        0 10px 24px rgba(var(--shadow-tint), 0.08);
    --glass-blur: blur(50px) saturate(180%) brightness(1.08);
    --glass-border: 1px solid rgba(255, 255, 255, 0.5);
    --neu-bg: #ffffff;
    --neu-raised:
        inset 0 1px 0 rgba(255, 255, 255, 0.95),
        0 1px 2px rgba(17, 19, 28, 0.08),
        0 4px 12px rgba(17, 19, 28, 0.13);
}

@supports (backdrop-filter: url('#liquid-glass')) or (-webkit-backdrop-filter: url('#liquid-glass')) {
    html[data-theme='light'] { --glass-blur: blur(50px) saturate(180%) brightness(1.08) url('#liquid-glass'); }
}

body {
    font-family: var(--font-sans);
    font-weight: var(--fw-regular);
    margin: 0;
    display: flex;
    min-height: 100vh;
    background-color: transparent;
    color: var(--text-main);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
}

/* FLAT design: retire the liquid-glass 3D backdrop so panels sit on a clean,
   neutral surface and the realistic drop shadows read properly. */
#three-bg { display: none !important; }
body { background-color: var(--bg-main); }

#three-bg {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: -1;
    pointer-events: none;
}

/* Maxed film grain over the dashboard background. Sits at z-index -1 — just
   ABOVE the WebGL gradient canvas (also -1, earlier in the DOM) but BELOW all
   content — so the whole background reads grainy while panels/text stay crisp.
   Glass panels naturally soften it through their backdrop blur. */
.bg-grain {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0.7;
    mix-blend-mode: overlay;
    will-change: background-position;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.72' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 240px 240px;
    animation: bgGrainShift 0.6s steps(6) infinite;
}
@keyframes bgGrainShift {
    0%   { background-position: 0 0; }
    17%  { background-position: -62px 38px; }
    33%  { background-position: 44px -56px; }
    50%  { background-position: -34px -44px; }
    67%  { background-position: 58px 46px; }
    83%  { background-position: -50px 14px; }
    100% { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) { .bg-grain { animation: none; } }

* {
    box-sizing: border-box;
}

.view-content {
    max-width: 1200px;
    margin: 0 auto;
    width: 100%;
}

.hidden {
    display: none !important;
}

.text-center {
    text-align: center;
}

.text-right {
    text-align: right;
}

.text-success {
    color: var(--success-green);
}

.text-warning {
    color: var(--warning-yellow);
}

.text-danger {
    color: var(--danger-red);
}

.text-muted {
    color: var(--text-muted);
}

.tabular-nums {
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-bold);
    letter-spacing: var(--tracking-tight);
}

.stacked-metric {
    white-space: pre-wrap;
    line-height: 1.2 !important;
}

.text-sm-caps {
    font-size: var(--text-sm);
    text-transform: uppercase;
    font-weight: var(--fw-medium);
    color: var(--text-muted);
}

@keyframes slideUpFade {
    0% {
        opacity: 0;
        transform: translateY(10px);
    }

    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes scaleIn {
    0% {
        transform: scale(0.95);
        opacity: 0;
    }

    100% {
        transform: scale(1);
        opacity: 1;
    }
}

.animate-item {
    animation: slideUpFade 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.animate-chart {
    animation: scaleIn 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.animate-bar {
    transition: width 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.cms-sidebar {
    width: 320px;
    min-width: 320px;
    background: transparent;
    border-right: 1px solid var(--divider);
    display: flex;
    flex-direction: column;
    padding: var(--space-8) var(--space-6);
    z-index: 100;
    position: relative;
    height: 100vh;
    transition: margin-left 0.4s cubic-bezier(0.16, 1, 0.3, 1), transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.cms-sidebar.collapsed {
    margin-left: -320px;
}

.cms-sidebar.collapsed .sidebar-toggle-btn {
    right: -48px;
}

.sidebar-toggle-btn {
    position: absolute;
    top: 50%;
    right: -24px;
    transform: translateY(-50%);
    width: 48px;
    height: 48px;
    border-radius: 50%;
    /* glass material supplied by the unified .liquid-surface group below */
    display: flex;
    align-items: center;
    justify-content: center;
    color: #FFFFFF;
    cursor: pointer;
    z-index: 101;
    transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.sidebar-toggle-btn:hover {
    background: var(--bg-hover);
    color: var(--theme-color-hover);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    transform: translateY(-50%) scale(1.05);
}

.sidebar-header {
    margin-bottom: var(--space-10);
    padding-left: var(--space-2);
}

#sidebar-logo-container {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
}

#main-logo {
    height: 40px;
    width: auto;
    object-fit: contain;
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    flex: 1;
}

.sidebar-nav a {
    font-size: 32px;
    font-weight: var(--font-bold);
    color: var(--text-main);
    text-decoration: none;
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    opacity: 0.6;
    transition: opacity 0.2s;
    padding-left: var(--space-2);
}

.sidebar-nav a:hover,
.sidebar-nav a.active {
    opacity: 1;
}

.cms-main {
    flex: 1;
    padding: 96px var(--space-10) var(--space-8);   /* clears the slimmer flat bar */
    display: flex;
    flex-direction: column;
    background: transparent;
    width: 100%;
}

.floating-topbar {
    position: fixed;
    top: 22px;
    left: 0;
    right: 0;
    z-index: 1000;
    /* Match the page content box: .view-content is max 1200px and .cms-main adds a
       40px (--space-10) gutter each side → a 1280px centred container. The brand /
       user pills then line up with the content's left / right edges. */
    max-width: calc(1200px + var(--space-10) * 2);
    margin-inline: auto;
    display: grid;
    grid-template-columns: 1fr auto 1fr;   /* brand left · nav centred · user right */
    align-items: center;
    gap: 16px;
    padding-inline: var(--space-10);
    animation: topbarIn 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;   /* settle-in on load */
}
.floating-topbar > .topbar-brand { justify-self: start; }
.floating-topbar > .nav-group    { justify-self: center; }
.floating-topbar > .action-group { justify-self: end; }
@keyframes topbarIn {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .floating-topbar { animation: none; } }

/* ---- Liquid glass pills ----
   Layered like real glass: blur+saturation lensing in the backdrop,
   a bright bevel along the top edge where light enters, a faint
   counter-bevel on the bottom, and a soft drop shadow for depth. */
/* Header pills — layout only; glass material comes from the unified
   .liquid-surface group near the end of this file. */
.topbar-brand,
.nav-group,
.glass-panel.nav-group,
.action-group,
.glass-panel.action-group {
    position: relative;
    display: flex;
    align-items: center;
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-3);          /* floating pills */
}

/* LEFT — flat brand pill with the SVG logo mark. Reactive: matches the other floating
   pills (--bg-card) in both themes — white pill + black mark in light, dark pill +
   white mark in dark. */
.topbar-brand {
    justify-content: center;
    padding: 13px 22px;    /* 13+13+18px logo = 44px — matches nav-group height */
    flex-shrink: 0;
    background: var(--bg-card);
}
.brand-mark {
    height: 18px; width: auto; display: block;
    filter: brightness(0);   /* black mark on the light pill */
}
html:not([data-theme='light']) .brand-mark {
    filter: brightness(0) invert(1);   /* white mark on the dark pill */
}

/* CENTRE — big nav pill, narrow padding (the items carry their own). */
.nav-group { padding: 5px 6px; gap: 4px; }

/* RIGHT — user pin pill. */
.action-group { padding: 6px 7px; gap: 6px; flex-shrink: 0; }

.nav-links {
    display: flex;
    gap: 2px;
    align-items: center;
    position: relative;          /* anchors the sliding .pill-glider */
}

.top-nav-link {
    position: relative;          /* sit above the glider */
    z-index: 1;
    font-size: 13.5px;
    font-weight: var(--fw-semibold);
    color: var(--text-main);
    text-decoration: none;
    opacity: 0.55;
    padding: 8px 15px;
    border-radius: var(--radius-pill);
    white-space: nowrap;
    letter-spacing: 0.025em;          /* tracked selector text (Swiss) */
    transition: opacity 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

.top-nav-link:hover { opacity: 0.92; }
.nav-links:not(.has-glider) .top-nav-link:hover { background: var(--active-theme-bg); }

/* ACTIVE — raised neumorphic pill (soft, Swiss): same-tone fill lifted off the bar.
   When the JS slider is active (.has-glider) the moving .pill-glider carries the
   pill instead, so the item's own fill is dropped (graceful no-JS fallback keeps it). */
.top-nav-link.active {
    opacity: 1;
    background: var(--neu-bg);
    box-shadow: var(--neu-raised);
}
.nav-links.has-glider .top-nav-link.active,
.toggle-group.has-glider .toggle-btn.active {
    background: transparent;
    box-shadow: none;
}
/* modal segments + option rails join the same glider grammar: the capsule
   paints the active pill, the item itself goes transparent with ink text */
.pill-group.has-glider .btn-pill.active,
.qa-acc-pills.has-glider .qa-acc-pill.active {
    background: transparent;
    color: var(--text-main);
    box-shadow: none;
}
