/* ============================================================================
   LIQUID GLASS — ProfitPlus Command Center design system
   Built 2026-08-02 · LANE A of .agents/mission/RUN2_MASTER_PLAN.md
   Vanilla CSS custom properties. No build step, no framework, no preprocessor.

   ---------------------------------------------------------------------------
   NAMESPACE CONTRACT — read this before you use anything below
   ---------------------------------------------------------------------------
   . Every custom property is  --g-*
   . Every class is            .g-*   (glass surfaces are .glass-1 … .glass-4)
   . Nothing here declares a bare element selector at the top level, so this
     file cannot reach into a legacy V1 view by accident. Element selectors
     appear only as descendants of a .g-* class.
   . --g-* does not collide with index.html's inline :root, sops.css, or the
     v2/tokens.css --v2-* set. Verified 2026-08-02 by grep: zero hits.
   . Load order: this file LAST. It only wins where a .g-* class is applied.

   ---------------------------------------------------------------------------
   THE FIVE RULES THAT KEEP IT FAST (breaking these is how a glass app janks)
   ---------------------------------------------------------------------------
   1. MAX 2 BLURRED LAYERS in a stack. Enforced structurally at the bottom of
      §5: any .glass-1/.glass-2 nested inside a .g-menu/.g-popover/.g-modal/
      .g-sheet/.g-drawer has its backdrop-filter switched OFF and its fill
      swapped for an opaque nested fill. You do not have to remember this.
   2. NEVER animate blur radius, and never animate `backdrop-filter`.
      Animate opacity and transform. A blurred layer fades in by animating the
      OPACITY of the whole blurred element — the radius never moves.
   3. Only promote what moves. `will-change` is set on overlay panels while
      they animate and removed by js/glass.js afterwards. Do not sprinkle it.
   4. Glass on long lists is a trap. A 200-row list of .glass-2 cards means 200
      backdrop-filters. Use .g-solid-2 for list rows and keep the glass for the
      container. There is a global escape hatch: html[data-glass="lite"].
   5. Blur cost scales with AREA, not count. Full-bleed .glass-1 chrome should
      stay short (a bar), not a full-height column.

   ---------------------------------------------------------------------------
   iOS TRAPS ALREADY PAID FOR IN BLOOD — the safe patterns are baked in
   ---------------------------------------------------------------------------
   A. iOS WebKit will NOT pin a `position: sticky` element that is ALSO its own
      `overflow-x` scroller. Chrome pins it happily and lies to you.
      FIX (baked in, §11): .g-sticky-bar owns `position: sticky` and has NO
      overflow; its child .g-sticky-scroll owns `overflow-x: auto`. Two
      elements, two jobs. Use the pair, never one div doing both.
   B. iOS renders `var()` used INSIDE a gradient function unreliably — e.g.
      `linear-gradient(var(--a), var(--b))` can paint as nothing. It renders a
      var() that CONTAINS a whole gradient just fine.
      FIX (baked in): every gradient in this file is authored as a complete
      literal value stored in one token (--g-sheen-*, --g-mesh, --g-scrim-*),
      consumed as `background-image: var(--g-sheen-2)`. There is not one
      `var()` inside a gradient anywhere in this file.
      Additionally every sticky/floating bar sets an opaque `background-color`
      (--g-solid-*) UNDER its glass, so if the gradient or the blur fails the
      bar is still a solid, readable ground and never see-through.

   ---------------------------------------------------------------------------
   CONTENTS
   ---------------------------------------------------------------------------
   §1  tokens — light (the default)      §11 nav chrome + the iOS sticky pattern
   §2  tokens — dark                     §12 menus, popovers, tooltips
   §3  capability + preference fallbacks §13 overlays: scrim, modal, sheet, drawer
   §4  the ground (app canvas)           §14 toasts
   §5  the glass ladder (.glass-1..4)    §15 tables
   §6  interactive states                §16 empty / loading / error states
   §7  type + text utilities             §17 utilities
   §8  buttons                           §18 keyframes
   §9  form controls
   §10 chips, badges, avatars
   ============================================================================ */


/* ============================================================================
   §1  TOKENS — LIGHT (the default theme)
   ============================================================================ */
:root {
  /* MUST be `light`, not `light dark`. With `light dark` the UA keeps picking
     its OWN scheme for native widgets, so an explicit data-theme="light" app
     on a dark-OS machine renders black scrollbars, black textarea resize
     grips and black form controls inside a white modal. The dark blocks below
     set `color-scheme: dark` themselves; the @media block is guarded with
     :not([data-theme="light"]) so an explicit light choice always wins. */
  color-scheme: light;

  /* ---- 1.1 type -------------------------------------------------------- */
  --g-font: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', Roboto, sans-serif;
  --g-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
  --g-font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;

  --g-fw-regular: 400;
  --g-fw-medium:  500;
  --g-fw-semi:    590;   /* the workhorse on glass — 500 goes soft over blur */
  --g-fw-bold:    680;
  --g-fw-heavy:   760;   /* hero numerals only */

  /* size / tracking / line-height travel together, per step */
  --g-fs-2xs: 11px; --g-tr-2xs:  0.03em;  --g-lh-2xs: 1.30;
  --g-fs-xs:  12px; --g-tr-xs:   0.01em;  --g-lh-xs:  1.35;
  --g-fs-sm:  13px; --g-tr-sm:  -0.004em; --g-lh-sm:  1.42;
  --g-fs-md:  15px; --g-tr-md:  -0.010em; --g-lh-md:  1.47;
  --g-fs-lg:  17px; --g-tr-lg:  -0.014em; --g-lh-lg:  1.40;
  --g-fs-xl:  20px; --g-tr-xl:  -0.017em; --g-lh-xl:  1.32;
  --g-fs-2xl: 24px; --g-tr-2xl: -0.020em; --g-lh-2xl: 1.24;
  --g-fs-3xl: 30px; --g-tr-3xl: -0.023em; --g-lh-3xl: 1.16;
  --g-fs-4xl: 40px; --g-tr-4xl: -0.026em; --g-lh-4xl: 1.08;
  --g-lh-prose: 1.6;
  --g-font-features: 'cv01' 1, 'cv03' 1, 'ss03' 1, 'case' 1;
  --g-font-num: 'tnum' 1, 'zero' 1;

  /* ---- 1.2 the ground -------------------------------------------------- */
  /* Glass only reads as glass when there is something behind it. --g-mesh is
     the ambient wash that gives the blur something to chew on. Both extremes
     of the mesh are bounded on purpose — that bound is what makes the
     contrast ratios in the header of this file true. Mesh range: #D2DAEE..#FFF */
  --g-canvas: #EDF0F7;
  --g-mesh:
    radial-gradient(1100px 780px at 12% -8%,  rgba(120,150,255,0.30), rgba(120,150,255,0) 62%),
    radial-gradient(900px 700px at 96% 4%,    rgba(255,120,170,0.20), rgba(255,120,170,0) 60%),
    radial-gradient(1000px 900px at 78% 96%,  rgba(80,215,205,0.22),  rgba(80,215,205,0) 62%),
    radial-gradient(760px 620px at 28% 88%,   rgba(180,130,255,0.20), rgba(180,130,255,0) 62%),
    linear-gradient(168deg, #F3F6FD 0%, #E6EBF7 52%, #EDEFF8 100%);

  /* Opaque grounds. Used UNDER glass on anything sticky/floating so iOS can
     never render a see-through bar, and used verbatim by .g-solid-*. */
  --g-solid-1: #F4F6FB;   /* chrome  */
  --g-solid-2: #F7F9FD;   /* card    */
  --g-solid-3: #FAFBFE;   /* sheet   */
  --g-solid-4: #FDFDFF;   /* modal   */
  --g-solid-sunken: #E6EAF3;

  /* ---- 1.3 ink --------------------------------------------------------- */
  --g-text:   #0E1116;   /* AA everywhere. worst glass case 12.36:1          */
  --g-text-2: #454C5C;   /* worst glass case 6.95:1                          */
  --g-text-3: #5C6474;   /* worst glass case 4.68:1 — the AA floor           */
  --g-text-4: #8A91A1;   /* DISABLED ONLY. 2.85:1. never live copy.          */
  --g-text-on-accent: #FFFFFF;
  --g-placeholder: #79808F;

  /* ---- 1.4 the needle --------------------------------------------------- */
  /* --g-accent  = text / icon / hairline.  --g-accent-fill = solid ground
     under white text ONLY. They are never interchangeable — in dark, using
     --g-accent as a fill fails white text. */
  --g-accent:        #C42B22;
  --g-accent-strong: #A81F18;
  --g-accent-fill:   #C42B22;
  --g-accent-press:  #97160F;
  --g-accent-soft:   rgba(196, 43, 34, 0.12);
  --g-accent-softer: rgba(196, 43, 34, 0.055);
  --g-accent-glow:   rgba(196, 43, 34, 0.30);

  /* ---- 1.5 status ------------------------------------------------------- */
  --g-green:  #12703B; --g-green-bg:  #D6F5E0;
  --g-amber:  #8A5300; --g-amber-bg:  #FCEBCF;
  --g-blue:   #1F5FAE; --g-blue-bg:   #DCEEFF;
  --g-violet: #6549AC; --g-violet-bg: #EDE6FF;
  --g-red:    #B32820; --g-red-bg:    #FFE3E0;
  --g-slate:  #4C5768; --g-slate-bg:  #E7ECF5;
  /* ink ON a solid status fill (per-theme overrides live in themes.css) */
  --g-text-on-green: #EDFAF3; --g-text-on-amber: #FAF5ED; --g-text-on-red: #FAEEED;

  /* ---- 1.6 THE GLASS LADDER -------------------------------------------- */
  /* Four rungs. Each rung = fill + blur + sheen + edge + specular + shadow.
     Real Apple glass reads as LIT, not merely blurred: the specular rim and
     the edge hairline are what sell it. Do not drop them to "simplify". */

  /* fills — translucency. Two constraints, both verified numerically:
     (1) every live ink level stays AA over the bounded mesh, and
     (2) the ladder is MONOTONIC — in light, each rung is whiter than the one
         below it, because in a light theme "higher" reads as "brighter".
         (Dark inverts the colour but not the direction: see §2.) */
  --g-fill-1: rgba(255, 255, 255, 0.72);
  --g-fill-2: rgba(255, 255, 255, 0.76);
  --g-fill-3: rgba(255, 255, 255, 0.84);
  --g-fill-4: rgba(255, 255, 255, 0.92);
  --g-fill-nested: rgba(255, 255, 255, 0.62);   /* de-blurred glass inside glass */
  --g-fill-sunken: rgba(14, 17, 22, 0.045);     /* recessed well / input        */
  --g-fill-hover:  rgba(14, 17, 22, 0.045);
  --g-fill-press:  rgba(14, 17, 22, 0.085);
  --g-fill-sel:    rgba(196, 43, 34, 0.10);

  /* blur — radius is CONSTANT per rung and is NEVER animated. */
  --g-blur-1: blur(22px) saturate(180%);
  --g-blur-2: blur(16px) saturate(160%);
  --g-blur-3: blur(30px) saturate(190%);
  --g-blur-4: blur(40px) saturate(200%);
  --g-blur-scrim: blur(8px) saturate(115%);

  /* sheen — a complete literal gradient per rung (see iOS trap B). */
  --g-sheen-1: linear-gradient(177deg, rgba(255,255,255,0.60) 0%, rgba(255,255,255,0.10) 38%, rgba(255,255,255,0) 70%);
  --g-sheen-2: linear-gradient(177deg, rgba(255,255,255,0.58) 0%, rgba(255,255,255,0.10) 34%, rgba(255,255,255,0) 66%);
  --g-sheen-3: linear-gradient(177deg, rgba(255,255,255,0.66) 0%, rgba(255,255,255,0.12) 32%, rgba(255,255,255,0) 64%);
  --g-sheen-4: linear-gradient(177deg, rgba(255,255,255,0.72) 0%, rgba(255,255,255,0.12) 30%, rgba(255,255,255,0) 60%);
  --g-sheen-nested: linear-gradient(177deg, rgba(255,255,255,0.42) 0%, rgba(255,255,255,0) 58%);
  --g-sheen-none: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,0));

  /* edge — the hairline that makes the pane look cut, not painted. */
  --g-edge-1: inset 0 0 0 1px rgba(14, 20, 34, 0.075);
  --g-edge-2: inset 0 0 0 1px rgba(14, 20, 34, 0.070);
  --g-edge-3: inset 0 0 0 1px rgba(14, 20, 34, 0.085);
  --g-edge-4: inset 0 0 0 1px rgba(14, 20, 34, 0.095);
  --g-hairline:        rgba(14, 20, 34, 0.085);
  --g-hairline-strong: rgba(14, 20, 34, 0.15);

  /* specular — top rim catches the light, bottom rim reads as thickness. */
  --g-spec-1: inset 0 1px 0 rgba(255,255,255,0.85), inset 0 -1px 0 rgba(14,20,34,0.045);
  --g-spec-2: inset 0 1px 0 rgba(255,255,255,0.80), inset 0 -1px 0 rgba(14,20,34,0.040);
  --g-spec-3: inset 0 1px 0 rgba(255,255,255,0.92), inset 0 -1px 0 rgba(14,20,34,0.050);
  --g-spec-4: inset 0 1px 0 rgba(255,255,255,0.96), inset 0 -1px 0 rgba(14,20,34,0.055);

  /* shadow — stacked micro-shadows, never one lazy blur. */
  --g-shadow-1: 0 1px 2px rgba(14,20,34,0.05), 0 8px 20px -10px rgba(14,20,34,0.16);
  --g-shadow-2: 0 1px 2px rgba(14,20,34,0.05), 0 10px 26px -12px rgba(14,20,34,0.20);
  --g-shadow-3: 0 2px 6px rgba(14,20,34,0.07), 0 20px 44px -16px rgba(14,20,34,0.28);
  --g-shadow-4: 0 4px 12px rgba(14,20,34,0.09), 0 32px 68px -20px rgba(14,20,34,0.36), 0 60px 120px -40px rgba(14,20,34,0.28);

  /* non-glass elevation, for solid surfaces */
  --g-e0: 0 0 0 0 rgba(0,0,0,0);
  --g-e1: 0 1px 2px rgba(14,20,34,0.06);
  --g-e2: 0 1px 2px rgba(14,20,34,0.05), 0 6px 14px -8px rgba(14,20,34,0.16);
  --g-e3: 0 2px 6px rgba(14,20,34,0.07), 0 18px 34px -14px rgba(14,20,34,0.24);
  --g-e4: 0 4px 12px rgba(14,20,34,0.09), 0 30px 60px -20px rgba(14,20,34,0.32);
  --g-lift: 0 10px 28px -12px rgba(14,20,34,0.30);

  /* scrim behind overlays */
  --g-scrim: rgba(16, 22, 38, 0.34);
  --g-scrim-strong: rgba(16, 22, 38, 0.48);

  /* ---- 1.7 radii — generous, bubbly, "beautifully held" ----------------- */
  --g-r-xs:   8px;
  --g-r-sm:  12px;
  --g-r-md:  16px;
  --g-r-lg:  22px;
  --g-r-xl:  28px;
  --g-r-2xl: 36px;
  --g-r-pill: 999px;
  --g-r-circle: 50%;
  /* semantic aliases — reach for these, not the raw scale */
  --g-r-ctl:    14px;   /* button, input, select, chip-square */
  --g-r-card:   22px;
  --g-r-chrome: 22px;
  --g-r-menu:   18px;
  --g-r-sheet:  28px;
  --g-r-modal:  28px;
  /* nesting: an inner corner should be outer minus its padding, floored at 8 */
  --g-r-inner: max(8px, calc(var(--g-r-card) - var(--g-pad-card)));

  /* ---- 1.8 space — 4px grid -------------------------------------------- */
  --g-s-0:  2px;  --g-s-1:  4px;  --g-s-2:  8px;  --g-s-3: 12px;
  --g-s-4: 16px;  --g-s-5: 20px;  --g-s-6: 24px;  --g-s-7: 32px;
  --g-s-8: 40px;  --g-s-9: 48px;  --g-s-10: 64px; --g-s-11: 80px;

  --g-pad-card: 20px;
  --g-pad-card-tight: 14px;
  --g-pad-sheet: 24px;
  --g-pad-page: 20px;
  --g-gap: 12px;

  /* ---- 1.9 control sizing ---------------------------------------------- */
  --g-ctl-h:    38px;   /* THE control height */
  --g-ctl-h-sm: 30px;
  --g-ctl-h-lg: 46px;
  --g-ctl-h-touch: 44px;
  --g-row-h: 44px;
  --g-icon-sm: 14px; --g-icon-md: 16px; --g-icon-lg: 20px;
  --g-chrome-h: 56px;
  --g-tabbar-h: 60px;
  --g-sidebar-w: 264px;
  --g-modal-w-sm: 400px; --g-modal-w: 560px; --g-modal-w-lg: 760px;
  --g-drawer-w: 440px;
  --g-read: 68ch;

  /* safe-area (resolves to 0px without viewport-fit=cover, which is harmless) */
  --g-sat: env(safe-area-inset-top, 0px);
  --g-sar: env(safe-area-inset-right, 0px);
  --g-sab: env(safe-area-inset-bottom, 0px);
  --g-sal: env(safe-area-inset-left, 0px);

  /* ---- 1.10 motion ------------------------------------------------------ */
  /* ONE easing set. Enter = out-curve, exit = in-curve, same-element state =
     in-out. --g-ease-glass is Apple's long-settle curve: fast off the mark,
     slow to arrive, zero overshoot. It is the default for anything that
     carries a blurred layer, because overshoot on a blurred pane wobbles. */
  --g-t-instant: 90ms;
  --g-t-fast:   140ms;
  --g-t:        200ms;
  --g-t-slow:   280ms;
  --g-t-slower: 420ms;

  --g-ease:        cubic-bezier(0.25, 0.1, 0.25, 1);
  --g-ease-out:    cubic-bezier(0.16, 1, 0.30, 1);
  --g-ease-in:     cubic-bezier(0.55, 0, 1, 0.45);
  --g-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --g-ease-glass:  cubic-bezier(0.32, 0.72, 0, 1);
  --g-ease-pop:    cubic-bezier(0.34, 1.28, 0.52, 1);  /* chips/toasts ONLY   */

  /* ---- 1.11 focus — one ring, keyboard-only, never shifts layout -------- */
  --g-focus-w: 2px;
  --g-focus-color: rgba(196, 43, 34, 0.65);
  --g-focus-halo:  rgba(196, 43, 34, 0.18);
  --g-focus-ring: 0 0 0 var(--g-focus-w) var(--g-focus-color), 0 0 0 6px var(--g-focus-halo);

  /* ---- 1.12 feedback ---------------------------------------------------- */
  --g-skel: rgba(14, 20, 34, 0.07);
  --g-skel-shine: linear-gradient(100deg, rgba(255,255,255,0) 20%, rgba(255,255,255,0.75) 50%, rgba(255,255,255,0) 80%);
  --g-scroll-thumb: rgba(14, 20, 34, 0.20);
  --g-scroll-thumb-hover: rgba(14, 20, 34, 0.34);
  --g-grabber: rgba(60, 60, 67, 0.32);

  /* ---- 1.12b consumer hooks — set these on a PARENT to steer a component.
     Both are read with a fallback, so leaving them alone is always safe.
       --g-sticky-top   how far below the viewport top .g-sticky-bar pins
       --g-origin       transform-origin for .g-menu / .g-popover, so a menu
                        that opens upward grows from its bottom edge
     ---------------------------------------------------------------------- */
  --g-sticky-top: 0px;
  --g-origin: top center;

  /* ---- 1.13 z ladder ---------------------------------------------------- */
  /* Deliberately above the legacy app's ladder (which tops out at 1100) so a
     glass overlay is never trapped under a V1 tooltip. */
  --g-z-base: 1;
  --g-z-sticky: 50;
  --g-z-chrome: 120;
  --g-z-nav: 140;
  --g-z-overlay: 1000;
  --g-z-popover: 1200;
  --g-z-toast: 1400;
  --g-z-tooltip: 1600;

  /* ---- 1.14 STRUCTURE — the themeable geometry (RUN 4 theme system) ------
     Four of the twelve directions differ STRUCTURALLY, not just chromatically:
       Ink   hard 1.5px black borders + a hard 4px offset shadow, radius ~3px
       Pop   2px outlines + a 4px button ledge the press physically sinks into
       Terra deliberately uneven "river-stone" corners, no borders
       Verde an engraved double rule set in from the edge of every pane
     Colour alone cannot express any of that, so these tokens exist and the
     primitives in §19 consume them. EVERY DEFAULT HERE IS A NO-OP: zero-width
     transparent border, zero press travel, transparent rule. Setting them in
     css/themes.css restructures the whole app with no per-theme component CSS,
     and a theme that ignores them renders exactly as it does today.
     (Terra needs nothing new: --g-r-card / --g-r-menu / --g-r-ctl already
     accept a full four-corner `border-radius` value like `34px 14px 28px 18px`.
     A theme that does that must also set --g-r-inner explicitly, because the
     calc() default below cannot subtract a padding from four numbers.) */
  --g-border-w: 0px;                        /* real border on every primitive */
  --g-border-c: transparent;
  --g-btn-primary-shadow:                   /* the ONE shadow §8 hard-coded    */
    inset 0 1px 0 rgba(255,255,255,0.28),
    inset 0 0 0 1px rgba(0,0,0,0.10),
    0 2px 6px -2px var(--g-accent-glow),
    0 10px 24px -12px var(--g-accent-glow);
  --g-btn-primary-shadow-hover:
    inset 0 1px 0 rgba(255,255,255,0.34),
    inset 0 0 0 1px rgba(0,0,0,0.10),
    0 4px 10px -2px var(--g-accent-glow),
    0 16px 34px -14px var(--g-accent-glow);
  --g-btn-primary-shadow-press: var(--g-btn-primary-shadow);
  --g-press-x: 0px;                         /* press travel — Ink moves both  */
  --g-press-y: 0px;                         /* Pop sinks 4px onto its ledge   */
  --g-press-scale: 0.965;                   /* set to 1 when travel does it   */
  --g-rule-inset: 0px;                      /* engraved double rule (Verde)   */
  --g-rule-c: transparent;
  --g-rule-r: 6px;
}


/* ============================================================================
   §2  TOKENS — DARK
   ----------------------------------------------------------------------------
   Dark glass is NOT inverted light glass. It is a DARK translucent ground with
   a BRIGHTER specular rim and LOWER-opacity white fills. Light comes from
   above: in dark the drop shadow barely registers, so the top rim and the
   lightness step are what make a pane read as "above".

   Two identical bodies on purpose:
     html[data-theme="dark"]                  — the explicit switch (wins)
     @media (prefers-color-scheme: dark)      — the OS preference, guarded with
       html:not([data-theme="light"])           so an explicit LIGHT still wins
   Edit them together or not at all.
   ============================================================================ */
html[data-theme="dark"] {
  color-scheme: dark;

  --g-canvas: #06070B;
  --g-mesh:
    radial-gradient(1100px 800px at 10% -10%, rgba(64,102,255,0.30), rgba(64,102,255,0) 62%),
    radial-gradient(900px 720px at 98% 2%,    rgba(226,58,120,0.20), rgba(226,58,120,0) 60%),
    radial-gradient(1000px 920px at 80% 98%,  rgba(24,190,180,0.20), rgba(24,190,180,0) 62%),
    radial-gradient(780px 640px at 26% 90%,   rgba(132,74,240,0.22), rgba(132,74,240,0) 62%),
    linear-gradient(168deg, #0A0C13 0%, #06070B 54%, #080A11 100%);

  --g-solid-1: #14171E;
  --g-solid-2: #181B23;
  --g-solid-3: #1B1F28;
  --g-solid-4: #1E222C;
  --g-solid-sunken: #0C0E14;

  --g-text:   #F3F6FC;
  --g-text-2: #B4BBCB;
  --g-text-3: #9099AC;
  --g-text-4: #6C7484;
  --g-text-on-accent: #FFFFFF;
  --g-placeholder: #78808F;

  --g-accent:        #FF7A6E;
  --g-accent-strong: #FF9C92;
  --g-accent-fill:   #CE3A30;
  --g-accent-press:  #AE2A21;
  --g-accent-soft:   rgba(255, 122, 110, 0.16);
  --g-accent-softer: rgba(255, 122, 110, 0.075);
  --g-accent-glow:   rgba(255, 122, 110, 0.34);

  --g-green:  #79D19A; --g-green-bg:  #12261A;
  --g-amber:  #E3B36B; --g-amber-bg:  #2E220B;
  --g-blue:   #8EBBF2; --g-blue-bg:   #152130;
  --g-violet: #BBA8F7; --g-violet-bg: #211C33;
  --g-red:    #FF8A7E; --g-red-bg:    #2C1512;
  --g-slate:  #A6B2C6; --g-slate-bg:  #171B24;
  --g-text-on-green: #0A1C11; --g-text-on-amber: #1F1508; --g-text-on-red: #1F0A08;

  /* fills: dark translucent ground, LOWER white content, HIGHER base opacity
     than light so a bright photo behind can't wash the text out. */
  --g-fill-1: rgba(20, 23, 30, 0.76);
  --g-fill-2: rgba(24, 27, 35, 0.79);
  --g-fill-3: rgba(27, 31, 40, 0.85);
  --g-fill-4: rgba(30, 34, 44, 0.91);
  --g-fill-nested: rgba(255, 255, 255, 0.055);
  --g-fill-sunken: rgba(0, 0, 0, 0.30);
  --g-fill-hover:  rgba(255, 255, 255, 0.065);
  --g-fill-press:  rgba(255, 255, 255, 0.11);
  --g-fill-sel:    rgba(255, 122, 110, 0.14);

  --g-blur-1: blur(24px) saturate(170%);
  --g-blur-2: blur(18px) saturate(155%);
  --g-blur-3: blur(32px) saturate(180%);
  --g-blur-4: blur(44px) saturate(190%);
  --g-blur-scrim: blur(10px) saturate(110%);

  /* dark sheen is white but restrained. THESE PEAK ALPHAS ARE LOAD-BEARING —
     they are the exact values the published contrast ratios were computed
     against, and every point of extra white here lowers those ratios. The
     "lit" look in dark comes from --g-spec-* (the 1px rim), not from this
     broad wash; the rim is one pixel tall so it can be bright for free. */
  --g-sheen-1: linear-gradient(177deg, rgba(255,255,255,0.070) 0%, rgba(255,255,255,0.022) 34%, rgba(255,255,255,0) 66%);
  --g-sheen-2: linear-gradient(177deg, rgba(255,255,255,0.060) 0%, rgba(255,255,255,0.020) 32%, rgba(255,255,255,0) 62%);
  --g-sheen-3: linear-gradient(177deg, rgba(255,255,255,0.055) 0%, rgba(255,255,255,0.018) 30%, rgba(255,255,255,0) 60%);
  --g-sheen-4: linear-gradient(177deg, rgba(255,255,255,0.050) 0%, rgba(255,255,255,0.016) 28%, rgba(255,255,255,0) 58%);
  --g-sheen-nested: linear-gradient(177deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0) 56%);

  --g-edge-1: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
  --g-edge-2: inset 0 0 0 1px rgba(255, 255, 255, 0.095);
  --g-edge-3: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
  --g-edge-4: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  --g-hairline:        rgba(255, 255, 255, 0.10);
  --g-hairline-strong: rgba(255, 255, 255, 0.20);

  /* the brighter rim — this single line is most of what makes dark glass read
     as machined glass instead of a flat charcoal rectangle. */
  --g-spec-1: inset 0 1px 0 rgba(255,255,255,0.22), inset 0 -1px 0 rgba(0,0,0,0.42);
  --g-spec-2: inset 0 1px 0 rgba(255,255,255,0.20), inset 0 -1px 0 rgba(0,0,0,0.40);
  --g-spec-3: inset 0 1px 0 rgba(255,255,255,0.26), inset 0 -1px 0 rgba(0,0,0,0.46);
  --g-spec-4: inset 0 1px 0 rgba(255,255,255,0.30), inset 0 -1px 0 rgba(0,0,0,0.50);

  --g-shadow-1: 0 1px 2px rgba(0,0,0,0.45), 0 10px 24px -12px rgba(0,0,0,0.65);
  --g-shadow-2: 0 1px 3px rgba(0,0,0,0.45), 0 12px 30px -14px rgba(0,0,0,0.70);
  --g-shadow-3: 0 4px 10px rgba(0,0,0,0.50), 0 24px 50px -18px rgba(0,0,0,0.78);
  --g-shadow-4: 0 8px 18px rgba(0,0,0,0.55), 0 40px 80px -22px rgba(0,0,0,0.85), 0 70px 140px -50px rgba(0,0,0,0.70);

  --g-e0: 0 0 0 0 rgba(0,0,0,0);
  --g-e1: inset 0 1px 0 rgba(255,255,255,0.06), 0 1px 2px rgba(0,0,0,0.45);
  --g-e2: inset 0 1px 0 rgba(255,255,255,0.07), 0 2px 6px rgba(0,0,0,0.48);
  --g-e3: inset 0 1px 0 rgba(255,255,255,0.08), 0 8px 20px -8px rgba(0,0,0,0.65);
  --g-e4: inset 0 1px 0 rgba(255,255,255,0.10), 0 20px 44px -14px rgba(0,0,0,0.78);
  --g-lift: 0 14px 34px -14px rgba(0,0,0,0.75);

  --g-scrim: rgba(0, 0, 0, 0.55);
  --g-scrim-strong: rgba(0, 0, 0, 0.70);

  --g-focus-color: rgba(255, 122, 110, 0.75);
  --g-focus-halo:  rgba(255, 122, 110, 0.22);
  --g-focus-ring: 0 0 0 var(--g-focus-w) var(--g-focus-color), 0 0 0 6px var(--g-focus-halo);

  --g-skel: rgba(255, 255, 255, 0.07);
  --g-skel-shine: linear-gradient(100deg, rgba(255,255,255,0) 20%, rgba(255,255,255,0.10) 50%, rgba(255,255,255,0) 80%);
  --g-scroll-thumb: rgba(255, 255, 255, 0.20);
  --g-scroll-thumb-hover: rgba(255, 255, 255, 0.34);
  --g-grabber: rgba(235, 235, 245, 0.34);
}

@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
    color-scheme: dark;

    --g-canvas: #06070B;
    --g-mesh:
      radial-gradient(1100px 800px at 10% -10%, rgba(64,102,255,0.30), rgba(64,102,255,0) 62%),
      radial-gradient(900px 720px at 98% 2%,    rgba(226,58,120,0.20), rgba(226,58,120,0) 60%),
      radial-gradient(1000px 920px at 80% 98%,  rgba(24,190,180,0.20), rgba(24,190,180,0) 62%),
      radial-gradient(780px 640px at 26% 90%,   rgba(132,74,240,0.22), rgba(132,74,240,0) 62%),
      linear-gradient(168deg, #0A0C13 0%, #06070B 54%, #080A11 100%);

    --g-solid-1: #14171E;
    --g-solid-2: #181B23;
    --g-solid-3: #1B1F28;
    --g-solid-4: #1E222C;
    --g-solid-sunken: #0C0E14;

    --g-text:   #F3F6FC;
    --g-text-2: #B4BBCB;
    --g-text-3: #9099AC;
    --g-text-4: #6C7484;
    --g-text-on-accent: #FFFFFF;
    --g-placeholder: #78808F;

    --g-accent:        #FF7A6E;
    --g-accent-strong: #FF9C92;
    --g-accent-fill:   #CE3A30;
    --g-accent-press:  #AE2A21;
    --g-accent-soft:   rgba(255, 122, 110, 0.16);
    --g-accent-softer: rgba(255, 122, 110, 0.075);
    --g-accent-glow:   rgba(255, 122, 110, 0.34);

    --g-green:  #79D19A; --g-green-bg:  #12261A;
    --g-amber:  #E3B36B; --g-amber-bg:  #2E220B;
    --g-blue:   #8EBBF2; --g-blue-bg:   #152130;
    --g-violet: #BBA8F7; --g-violet-bg: #211C33;
    --g-red:    #FF8A7E; --g-red-bg:    #2C1512;
    --g-slate:  #A6B2C6; --g-slate-bg:  #171B24;
    --g-text-on-green: #0A1C11; --g-text-on-amber: #1F1508; --g-text-on-red: #1F0A08;

    --g-fill-1: rgba(20, 23, 30, 0.76);
    --g-fill-2: rgba(24, 27, 35, 0.79);
    --g-fill-3: rgba(27, 31, 40, 0.85);
    --g-fill-4: rgba(30, 34, 44, 0.91);
    --g-fill-nested: rgba(255, 255, 255, 0.055);
    --g-fill-sunken: rgba(0, 0, 0, 0.30);
    --g-fill-hover:  rgba(255, 255, 255, 0.065);
    --g-fill-press:  rgba(255, 255, 255, 0.11);
    --g-fill-sel:    rgba(255, 122, 110, 0.14);

    --g-blur-1: blur(24px) saturate(170%);
    --g-blur-2: blur(18px) saturate(155%);
    --g-blur-3: blur(32px) saturate(180%);
    --g-blur-4: blur(44px) saturate(190%);
    --g-blur-scrim: blur(10px) saturate(110%);

    --g-sheen-1: linear-gradient(177deg, rgba(255,255,255,0.070) 0%, rgba(255,255,255,0.022) 34%, rgba(255,255,255,0) 66%);
    --g-sheen-2: linear-gradient(177deg, rgba(255,255,255,0.060) 0%, rgba(255,255,255,0.020) 32%, rgba(255,255,255,0) 62%);
    --g-sheen-3: linear-gradient(177deg, rgba(255,255,255,0.055) 0%, rgba(255,255,255,0.018) 30%, rgba(255,255,255,0) 60%);
    --g-sheen-4: linear-gradient(177deg, rgba(255,255,255,0.050) 0%, rgba(255,255,255,0.016) 28%, rgba(255,255,255,0) 58%);
    --g-sheen-nested: linear-gradient(177deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0) 56%);

    --g-edge-1: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
    --g-edge-2: inset 0 0 0 1px rgba(255, 255, 255, 0.095);
    --g-edge-3: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
    --g-edge-4: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
    --g-hairline:        rgba(255, 255, 255, 0.10);
    --g-hairline-strong: rgba(255, 255, 255, 0.20);

    --g-spec-1: inset 0 1px 0 rgba(255,255,255,0.22), inset 0 -1px 0 rgba(0,0,0,0.42);
    --g-spec-2: inset 0 1px 0 rgba(255,255,255,0.20), inset 0 -1px 0 rgba(0,0,0,0.40);
    --g-spec-3: inset 0 1px 0 rgba(255,255,255,0.26), inset 0 -1px 0 rgba(0,0,0,0.46);
    --g-spec-4: inset 0 1px 0 rgba(255,255,255,0.30), inset 0 -1px 0 rgba(0,0,0,0.50);

    --g-shadow-1: 0 1px 2px rgba(0,0,0,0.45), 0 10px 24px -12px rgba(0,0,0,0.65);
    --g-shadow-2: 0 1px 3px rgba(0,0,0,0.45), 0 12px 30px -14px rgba(0,0,0,0.70);
    --g-shadow-3: 0 4px 10px rgba(0,0,0,0.50), 0 24px 50px -18px rgba(0,0,0,0.78);
    --g-shadow-4: 0 8px 18px rgba(0,0,0,0.55), 0 40px 80px -22px rgba(0,0,0,0.85), 0 70px 140px -50px rgba(0,0,0,0.70);

    --g-e0: 0 0 0 0 rgba(0,0,0,0);
    --g-e1: inset 0 1px 0 rgba(255,255,255,0.06), 0 1px 2px rgba(0,0,0,0.45);
    --g-e2: inset 0 1px 0 rgba(255,255,255,0.07), 0 2px 6px rgba(0,0,0,0.48);
    --g-e3: inset 0 1px 0 rgba(255,255,255,0.08), 0 8px 20px -8px rgba(0,0,0,0.65);
    --g-e4: inset 0 1px 0 rgba(255,255,255,0.10), 0 20px 44px -14px rgba(0,0,0,0.78);
    --g-lift: 0 14px 34px -14px rgba(0,0,0,0.75);

    --g-scrim: rgba(0, 0, 0, 0.55);
    --g-scrim-strong: rgba(0, 0, 0, 0.70);

    --g-focus-color: rgba(255, 122, 110, 0.75);
    --g-focus-halo:  rgba(255, 122, 110, 0.22);
    --g-focus-ring: 0 0 0 var(--g-focus-w) var(--g-focus-color), 0 0 0 6px var(--g-focus-halo);

    --g-skel: rgba(255, 255, 255, 0.07);
    --g-skel-shine: linear-gradient(100deg, rgba(255,255,255,0) 20%, rgba(255,255,255,0.10) 50%, rgba(255,255,255,0) 80%);
    --g-scroll-thumb: rgba(255, 255, 255, 0.20);
    --g-scroll-thumb-hover: rgba(255, 255, 255, 0.34);
    --g-grabber: rgba(235, 235, 245, 0.34);
  }
}


/* ============================================================================
   §3  CAPABILITY + PREFERENCE FALLBACKS
   ----------------------------------------------------------------------------
   Three independent switches, all of which produce a fully readable app:
     a) no backdrop-filter support        -> opaque grounds
     b) prefers-reduced-transparency      -> opaque grounds (user asked)
     c) html[data-glass="lite"]           -> opaque grounds (perf escape hatch)
   Each one only rewrites TOKENS, so every component below keeps working
   untouched. Nothing anywhere becomes unreadable.
   ============================================================================ */

/* (a) No backdrop-filter (old WebKit, some Android WebViews, print). The
   double @supports covers browsers that only ship the -webkit- prefix. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root, html[data-theme="dark"] {
    --g-fill-1: var(--g-solid-1);
    --g-fill-2: var(--g-solid-2);
    --g-fill-3: var(--g-solid-3);
    --g-fill-4: var(--g-solid-4);
    --g-blur-1: none; --g-blur-2: none; --g-blur-3: none; --g-blur-4: none;
    --g-blur-scrim: none;
    --g-scrim: rgba(16, 22, 38, 0.52);
  }
  @media (prefers-color-scheme: dark) {
    html:not([data-theme="light"]) {
      --g-fill-1: var(--g-solid-1);
      --g-fill-2: var(--g-solid-2);
      --g-fill-3: var(--g-solid-3);
      --g-fill-4: var(--g-solid-4);
      --g-blur-1: none; --g-blur-2: none; --g-blur-3: none; --g-blur-4: none;
      --g-blur-scrim: none;
      --g-scrim: rgba(0, 0, 0, 0.68);
    }
  }
}

/* (b) The user asked their OS for less transparency. Honour it exactly. */
@media (prefers-reduced-transparency: reduce) {
  :root, html[data-theme="dark"], html:not([data-theme="light"]) {
    --g-fill-1: var(--g-solid-1);
    --g-fill-2: var(--g-solid-2);
    --g-fill-3: var(--g-solid-3);
    --g-fill-4: var(--g-solid-4);
    --g-fill-nested: var(--g-solid-2);
    --g-blur-1: none; --g-blur-2: none; --g-blur-3: none; --g-blur-4: none;
    --g-blur-scrim: none;
  }
}

/* (c) Perf escape hatch. js/glass.js sets html[data-glass="lite"], and it is
   persisted. Turns every blur off app-wide in one attribute — the single most
   effective thing to try if a slow device ever feels sticky. */
html[data-glass="lite"] {
  --g-fill-1: var(--g-solid-1);
  --g-fill-2: var(--g-solid-2);
  --g-fill-3: var(--g-solid-3);
  --g-fill-4: var(--g-solid-4);
  --g-fill-nested: var(--g-solid-2);
  --g-blur-1: none; --g-blur-2: none; --g-blur-3: none; --g-blur-4: none;
  --g-blur-scrim: none;
}

/* Reduced motion: keep every transition, collapse it to a near-instant cross
   fade. Motion still CONFIRMS the change (an overlay that vanishes with zero
   feedback is worse), it just stops travelling. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --g-t-instant: 1ms;
    --g-t-fast:    1ms;
    --g-t:         1ms;
    --g-t-slow:    1ms;
    --g-t-slower:  1ms;
    --g-ease-pop: var(--g-ease);
  }
  .g-overlay, .g-modal, .g-sheet, .g-drawer, .g-menu, .g-popover, .g-toast {
    transition-duration: 120ms !important;
    transition-property: opacity !important;
  }
  .g-modal, .g-sheet, .g-drawer, .g-menu, .g-popover, .g-toast { transform: none !important; }
  .g-skeleton, .g-spinner, .g-pulse { animation: none !important; }
  .g-btn--primary::after { display: none; }
}


/* ============================================================================
   §4  THE GROUND — apply .g-app to the app root (or <body>)
   ============================================================================ */
.g-app {
  background-color: var(--g-canvas);
  background-image: var(--g-mesh);
  background-attachment: fixed;
  background-size: cover;
  color: var(--g-text);
  font-family: var(--g-font);
  font-size: var(--g-fs-md);
  line-height: var(--g-lh-md);
  letter-spacing: var(--g-tr-md);
  font-feature-settings: var(--g-font-features);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  min-height: 100%;
}

/* background-attachment: fixed is a scroll-perf hazard on iOS (it repaints the
   whole layer every frame). On touch, pin the mesh to the viewport instead. */
@media (pointer: coarse) {
  .g-app { background-attachment: scroll; }
}

.g-canvas-plain { background-image: none; background-color: var(--g-canvas); }


/* ============================================================================
   §5  THE GLASS LADDER
   ----------------------------------------------------------------------------
   .glass-1  chrome  — nav, top bar, tab bar, floating pills, sticky headers
   .glass-2  card    — panels, cards, tiles, list containers
   .glass-3  sheet   — popovers, dropdowns, side panels, bottom sheets
   .glass-4  modal   — modal dialogs, the top of the stack

   Semantic aliases are identical, use whichever reads better at the call site:
   .g-chrome  .g-card  .g-sheet-surface  .g-modal-surface
   ============================================================================ */
.glass-1, .glass-2, .glass-3, .glass-4,
.g-chrome, .g-card, .g-sheet-surface, .g-modal-surface {
  color: var(--g-text);
  background-repeat: no-repeat;
  /* isolate so a child's blend/blur cannot escape the pane */
  isolation: isolate;
}

/* iOS-BREAKER FIX (2026-08-03) — `position: relative` here is ONLY a fallback containing
   block for the ::before sheen and the ::after engraved rule (§19.3). It is NOT a layout
   decision, and it must never beat an element that positions itself.
   It did: glass.css loads after index.html's <style>, so this 0-1-0 rule silently outranked
   `.sidebar{position:sticky}`, `@media(max-width:900px){.sidebar{position:fixed}}`,
   `.mainhead{position:sticky}` and `.tabbar{position:fixed}` — all three app-shell elements
   carry .g-chrome. On a phone the off-canvas drawer therefore stayed IN FLOW at
   `width:264px; flex-shrink:0` while translated off-screen, so it ate 264 of 402 points and
   left every module a 138px-wide column; the bottom tab bar fell to the end of the document
   and the header stopped pinning.
   :where() has zero specificity, so any element that declares its own position now wins,
   while a static glass pane still gets its containing block. `fixed`/`sticky`/`absolute` are
   containing blocks too, so the pseudo-layers keep anchoring correctly either way. */
:where(.glass-1, .glass-2, .glass-3, .glass-4,
       .g-chrome, .g-card, .g-sheet-surface, .g-modal-surface) {
  position: relative;
}

.glass-1, .g-chrome {
  background-color: var(--g-fill-1);
  background-image: var(--g-sheen-1);
  -webkit-backdrop-filter: var(--g-blur-1);
  backdrop-filter: var(--g-blur-1);
  box-shadow: var(--g-edge-1), var(--g-spec-1), var(--g-shadow-1);
  border-radius: var(--g-r-chrome);
}

.glass-2, .g-card {
  background-color: var(--g-fill-2);
  background-image: var(--g-sheen-2);
  -webkit-backdrop-filter: var(--g-blur-2);
  backdrop-filter: var(--g-blur-2);
  box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2);
  border-radius: var(--g-r-card);
}

.glass-3, .g-sheet-surface {
  background-color: var(--g-fill-3);
  background-image: var(--g-sheen-3);
  -webkit-backdrop-filter: var(--g-blur-3);
  backdrop-filter: var(--g-blur-3);
  box-shadow: var(--g-edge-3), var(--g-spec-3), var(--g-shadow-3);
  border-radius: var(--g-r-sheet);
}

.glass-4, .g-modal-surface {
  background-color: var(--g-fill-4);
  background-image: var(--g-sheen-4);
  -webkit-backdrop-filter: var(--g-blur-4);
  backdrop-filter: var(--g-blur-4);
  box-shadow: var(--g-edge-4), var(--g-spec-4), var(--g-shadow-4);
  border-radius: var(--g-r-modal);
}

/* Opaque twins. Use these for: list rows, table rows, anything repeated more
   than ~12 times, and any surface sitting on top of a photo or video. They
   look near-identical and cost nothing. */
.g-solid-1 { background-color: var(--g-solid-1); box-shadow: var(--g-edge-1), var(--g-spec-1), var(--g-shadow-1); border-radius: var(--g-r-chrome); color: var(--g-text); }
.g-solid-2 { background-color: var(--g-solid-2); box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2); border-radius: var(--g-r-card);   color: var(--g-text); }
.g-solid-3 { background-color: var(--g-solid-3); box-shadow: var(--g-edge-3), var(--g-spec-3), var(--g-shadow-3); border-radius: var(--g-r-sheet);  color: var(--g-text); }
.g-solid-4 { background-color: var(--g-solid-4); box-shadow: var(--g-edge-4), var(--g-spec-4), var(--g-shadow-4); border-radius: var(--g-r-modal);  color: var(--g-text); }

/* A recessed well — inverted specular (dark rim on top). Inputs, code blocks,
   inline scroll regions, "empty slot" areas. */
.g-sunken {
  background-color: var(--g-fill-sunken);
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.10), inset 0 0 0 1px var(--g-hairline);
  border-radius: var(--g-r-ctl);
}

/* Surface modifiers */
.g-flush   { padding: 0; overflow: hidden; }
.g-pad     { padding: var(--g-pad-card); }
.g-pad-sm  { padding: var(--g-pad-card-tight); }
.g-pad-lg  { padding: var(--g-pad-sheet); }
.g-flat    { box-shadow: var(--g-edge-2); }
.g-noshadow{ box-shadow: none; }
.g-r-sm    { border-radius: var(--g-r-sm); }
.g-r-md    { border-radius: var(--g-r-md); }
.g-r-lg    { border-radius: var(--g-r-lg); }
.g-r-xl    { border-radius: var(--g-r-xl); }
.g-r-pill  { border-radius: var(--g-r-pill); }

/* Kill the blur on one element without losing the look. */
.g-noblur {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  background-color: var(--g-solid-2);
}

/* ---- THE STACKED-BLUR CAP, enforced structurally --------------------------
   Two blurred layers is the budget. A .glass-1/.glass-2 that finds itself
   inside a level-3 or level-4 surface (which is already blurring) silently
   drops its own backdrop-filter and switches to an opaque nested fill. This is
   the rule from the file header made real so no lane has to remember it. */
.g-menu   .glass-1, .g-menu   .glass-2, .g-menu   .g-chrome, .g-menu   .g-card,
.g-popover .glass-1, .g-popover .glass-2, .g-popover .g-chrome, .g-popover .g-card,
.g-modal  .glass-1, .g-modal  .glass-2, .g-modal  .g-chrome, .g-modal  .g-card,
.g-sheet  .glass-1, .g-sheet  .glass-2, .g-sheet  .g-chrome, .g-sheet  .g-card,
.g-drawer .glass-1, .g-drawer .glass-2, .g-drawer .g-chrome, .g-drawer .g-card,
.glass-3  .glass-1, .glass-3  .glass-2, .glass-4 .glass-1, .glass-4 .glass-2 {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background-color: var(--g-fill-nested);
  background-image: var(--g-sheen-nested);
  box-shadow: var(--g-edge-2), var(--g-spec-2);
}


/* ============================================================================
   §6  INTERACTIVE STATES — hover lift, press scale + tint, focus ring
   ----------------------------------------------------------------------------
   .g-interactive is the base contract. Add it to anything clickable that is
   not already a .g-btn / .g-menu-item / .g-row.
   ============================================================================ */
.g-interactive {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    transform  var(--g-t-fast) var(--g-ease-out),
    box-shadow var(--g-t-fast) var(--g-ease-out),
    background-color var(--g-t-fast) var(--g-ease),
    opacity    var(--g-t-fast) var(--g-ease);
}

/* Hover lift only where hovering is real. On touch this would stick after a
   tap and look broken. */
@media (hover: hover) and (pointer: fine) {
  .g-interactive:hover { transform: translate3d(0, -2px, 0); }
  .glass-2.g-interactive:hover,
  .g-card.g-interactive:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }
  .glass-1.g-interactive:hover,
  .g-chrome.g-interactive:hover { box-shadow: var(--g-edge-1), var(--g-spec-1), var(--g-shadow-2); }
}

.g-interactive:active {
  transform: scale(0.978);
  background-color: var(--g-fill-press);
  transition-duration: var(--g-t-instant);
  transition-timing-function: var(--g-ease-in-out);
}

/* THE focus ring. Keyboard-only, drawn with box-shadow so it never reflows.
   :focus-visible has been safe on iOS since 15.4; the plain :focus fallback
   below covers anything older without double-ringing modern browsers. */
.g-interactive:focus-visible,
.g-btn:focus-visible,
.g-input:focus-visible,
.g-select:focus-visible,
.g-textarea:focus-visible,
.g-menu-item:focus-visible,
.g-chip:focus-visible,
.g-tab:focus-visible,
.g-nav-item:focus-visible,
.g-switch:focus-visible,
.g-row:focus-visible,
.g-icon-btn:focus-visible {
  outline: none;
  box-shadow: var(--g-focus-ring);
  z-index: 1;
}
@supports not selector(:focus-visible) {
  .g-interactive:focus, .g-btn:focus, .g-input:focus, .g-select:focus,
  .g-textarea:focus, .g-menu-item:focus, .g-chip:focus, .g-tab:focus,
  .g-nav-item:focus, .g-icon-btn:focus { outline: none; box-shadow: var(--g-focus-ring); }
}

.g-disabled, .g-btn:disabled, .g-input:disabled, .g-select:disabled, .g-textarea:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}


/* ============================================================================
   §7  TYPE + TEXT UTILITIES
   ============================================================================ */
.g-h1 { font-family: var(--g-font-display); font-size: var(--g-fs-3xl); line-height: var(--g-lh-3xl); letter-spacing: var(--g-tr-3xl); font-weight: var(--g-fw-bold);  color: var(--g-text); margin: 0; }
.g-h2 { font-family: var(--g-font-display); font-size: var(--g-fs-2xl); line-height: var(--g-lh-2xl); letter-spacing: var(--g-tr-2xl); font-weight: var(--g-fw-bold);  color: var(--g-text); margin: 0; }
.g-h3 { font-size: var(--g-fs-xl);  line-height: var(--g-lh-xl);  letter-spacing: var(--g-tr-xl);  font-weight: var(--g-fw-semi); color: var(--g-text); margin: 0; }
.g-h4 { font-size: var(--g-fs-lg);  line-height: var(--g-lh-lg);  letter-spacing: var(--g-tr-lg);  font-weight: var(--g-fw-semi); color: var(--g-text); margin: 0; }
.g-body   { font-size: var(--g-fs-md); line-height: var(--g-lh-md); letter-spacing: var(--g-tr-md); color: var(--g-text); }
.g-body-sm{ font-size: var(--g-fs-sm); line-height: var(--g-lh-sm); letter-spacing: var(--g-tr-sm); color: var(--g-text-2); }
.g-caption{ font-size: var(--g-fs-xs); line-height: var(--g-lh-xs); letter-spacing: var(--g-tr-xs); color: var(--g-text-3); }
.g-eyebrow{
  font-size: var(--g-fs-2xs); line-height: var(--g-lh-2xs); letter-spacing: 0.075em;
  font-weight: var(--g-fw-semi); text-transform: uppercase; color: var(--g-text-3); margin: 0;
}
.g-metric {
  font-size: var(--g-fs-3xl); line-height: var(--g-lh-3xl); letter-spacing: var(--g-tr-3xl);
  font-weight: var(--g-fw-heavy); color: var(--g-text);
  font-variant-numeric: tabular-nums; font-feature-settings: var(--g-font-num);
}
.g-mono { font-family: var(--g-font-mono); font-size: var(--g-fs-xs); letter-spacing: 0; }
.g-num  { font-variant-numeric: tabular-nums; font-feature-settings: var(--g-font-num); }
.g-prose { max-width: var(--g-read); line-height: var(--g-lh-prose); color: var(--g-text-2); }

.g-t1 { color: var(--g-text); }
.g-t2 { color: var(--g-text-2); }
.g-t3 { color: var(--g-text-3); }
.g-t-accent { color: var(--g-accent); }
.g-t-green { color: var(--g-green); } .g-t-amber { color: var(--g-amber); }
.g-t-blue  { color: var(--g-blue);  } .g-t-red   { color: var(--g-red);   }
.g-t-violet{ color: var(--g-violet);}

.g-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.g-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.g-clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* Card header block */
.g-card-hd {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--g-s-3); margin-bottom: var(--g-s-4);
}
.g-card-title {
  font-size: var(--g-fs-lg); line-height: var(--g-lh-lg); letter-spacing: var(--g-tr-lg);
  font-weight: var(--g-fw-semi); color: var(--g-text); margin: 0;
}
.g-card-sub { font-size: var(--g-fs-sm); color: var(--g-text-3); margin: 2px 0 0; }
.g-card-body { display: flex; flex-direction: column; gap: var(--g-s-3); }
.g-card-ft {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--g-s-2);
  margin-top: var(--g-s-4); padding-top: var(--g-s-4);
  box-shadow: inset 0 1px 0 var(--g-hairline);
}


/* ============================================================================
   §8  BUTTONS
   ----------------------------------------------------------------------------
   .g-btn                      neutral glass button (the default)
   .g-btn.g-btn--primary       the accent action
   .g-btn.g-btn--ghost         no ground until hover
   .g-btn.g-btn--danger        destructive
   .g-btn.g-btn--sm / --lg     size
   .g-icon-btn                 square/circular icon-only
   ============================================================================ */
.g-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--g-s-2);
  height: var(--g-ctl-h);
  padding: 0 var(--g-s-4);
  border: 0;
  border-radius: var(--g-r-ctl);
  font-family: inherit;
  font-size: var(--g-fs-sm);
  line-height: 1;
  letter-spacing: var(--g-tr-sm);
  font-weight: var(--g-fw-semi);
  color: var(--g-text);
  background-color: var(--g-fill-2);
  background-image: var(--g-sheen-2);
  -webkit-backdrop-filter: var(--g-blur-2);
  backdrop-filter: var(--g-blur-2);
  box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-e1);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  overflow: hidden;
  transition:
    transform var(--g-t-fast) var(--g-ease-out),
    box-shadow var(--g-t-fast) var(--g-ease-out),
    background-color var(--g-t-fast) var(--g-ease),
    color var(--g-t-fast) var(--g-ease);
}

@media (hover: hover) and (pointer: fine) {
  .g-btn:hover:not(:disabled) { transform: translate3d(0, -1px, 0); box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-e2); }
}
.g-btn:active:not(:disabled) {
  /* Travel + scale are both tokenised (§1.14). Defaults are 0px/0px/0.965, so
     this is byte-identical to the old `scale(0.965)` — but Pop can sink the
     button 4px onto its ledge and Ink can shove it 3px into its shadow without
     one line of per-theme component CSS. */
  transform: translate3d(var(--g-press-x), var(--g-press-y), 0) scale(var(--g-press-scale));
  transition-duration: var(--g-t-instant);
  box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-e0);
}

.g-btn--sm { height: var(--g-ctl-h-sm); padding: 0 var(--g-s-3); font-size: var(--g-fs-xs); border-radius: var(--g-r-sm); }
.g-btn--lg { height: var(--g-ctl-h-lg); padding: 0 var(--g-s-6); font-size: var(--g-fs-md); border-radius: var(--g-r-md); }
.g-btn--pill  { border-radius: var(--g-r-pill); }
.g-btn--block { width: 100%; }

/* Primary — a solid accent ground, not glass. A tinted-glass primary reads as
   "maybe disabled" on a busy backdrop; the one loud element stays solid. */
.g-btn--primary {
  color: var(--g-text-on-accent);
  background-color: var(--g-accent-fill);
  background-image: var(--g-sheen-none);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  /* Tokenised (§1.14). The default value of --g-btn-primary-shadow IS the
     literal that used to sit here, so nothing changes for an unthemed app —
     but Ink can swap it for `3px 3px 0 #E0301E` and Pop for `0 4px 0 #272030`. */
  box-shadow: var(--g-btn-primary-shadow);
}
@media (hover: hover) and (pointer: fine) {
  .g-btn--primary:hover:not(:disabled) {
    background-color: var(--g-accent-strong);
    box-shadow: var(--g-btn-primary-shadow-hover);
  }
}
.g-btn--primary:active:not(:disabled) {
  background-color: var(--g-accent-press);
  box-shadow: var(--g-btn-primary-shadow-press);
}

/* The specular sweep. A single transform on a pseudo — GPU only, no repaint,
   and it is the whole "liquid" tell. Disabled under reduced-motion (§3). */
.g-btn--primary::after {
  content: '';
  position: absolute;
  top: -60%; bottom: -60%; left: -40%;
  width: 36%;
  background-image: linear-gradient(100deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.42) 50%, rgba(255,255,255,0) 100%);
  transform: translate3d(-260%, 0, 0) skewX(-18deg);
  pointer-events: none;
  opacity: 0;
}
@media (hover: hover) and (pointer: fine) {
  .g-btn--primary:hover::after { animation: g-sweep var(--g-t-slower) var(--g-ease-out) 1; }
}

.g-btn--ghost {
  background-color: transparent;
  background-image: var(--g-sheen-none);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  color: var(--g-text-2);
}
@media (hover: hover) and (pointer: fine) {
  .g-btn--ghost:hover:not(:disabled) { background-color: var(--g-fill-hover); color: var(--g-text); box-shadow: none; transform: none; }
}
.g-btn--ghost:active:not(:disabled) { background-color: var(--g-fill-press); box-shadow: none; }

.g-btn--danger { color: var(--g-text-on-red); background-color: var(--g-red); background-image: var(--g-sheen-none); -webkit-backdrop-filter: none; backdrop-filter: none; }
html[data-theme="dark"] .g-btn--danger { color: var(--g-text-on-red); }
@media (prefers-color-scheme: dark) { html:not([data-theme="light"]) .g-btn--danger { color: var(--g-text-on-red); } }

.g-btn--quiet { color: var(--g-text-2); font-weight: var(--g-fw-medium); }

.g-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--g-ctl-h); height: var(--g-ctl-h);
  padding: 0; border: 0;
  border-radius: var(--g-r-pill);
  color: var(--g-text-2);
  background-color: transparent;
  font-family: inherit;          /* a <button> does not inherit the page font */
  font-size: var(--g-fs-md);
  line-height: 1;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--g-t-fast) var(--g-ease),
              color var(--g-t-fast) var(--g-ease),
              transform var(--g-t-fast) var(--g-ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .g-icon-btn:hover { background-color: var(--g-fill-hover); color: var(--g-text); }
}
.g-icon-btn:active { transform: scale(0.90); background-color: var(--g-fill-press); transition-duration: var(--g-t-instant); }
.g-icon-btn--sm { width: var(--g-ctl-h-sm); height: var(--g-ctl-h-sm); }
.g-icon-btn--glass {
  background-color: var(--g-fill-2);
  -webkit-backdrop-filter: var(--g-blur-2);
  backdrop-filter: var(--g-blur-2);
  box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-e1);
}

/* Button group — one continuous glass slab, hairlines between */
.g-btn-group { display: inline-flex; align-items: stretch; }
.g-btn-group > .g-btn { border-radius: 0; }
.g-btn-group > .g-btn:first-child { border-top-left-radius: var(--g-r-ctl); border-bottom-left-radius: var(--g-r-ctl); }
.g-btn-group > .g-btn:last-child  { border-top-right-radius: var(--g-r-ctl); border-bottom-right-radius: var(--g-r-ctl); }
.g-btn-group > .g-btn + .g-btn { box-shadow: var(--g-edge-2), var(--g-spec-2), inset 1px 0 0 var(--g-hairline); }


/* ============================================================================
   §9  FORM CONTROLS
   ============================================================================ */
.g-field { display: flex; flex-direction: column; gap: var(--g-s-2); min-width: 0; }
.g-label {
  font-size: var(--g-fs-xs); line-height: var(--g-lh-xs); letter-spacing: var(--g-tr-xs);
  font-weight: var(--g-fw-semi); color: var(--g-text-2);
}
.g-hint  { font-size: var(--g-fs-xs); color: var(--g-text-3); }
.g-error-text { font-size: var(--g-fs-xs); color: var(--g-red); font-weight: var(--g-fw-medium); }

.g-input, .g-select, .g-textarea {
  width: 100%;
  min-height: var(--g-ctl-h);
  padding: 0 var(--g-s-3);
  border: 0;
  border-radius: var(--g-r-ctl);
  font-family: inherit;
  font-size: var(--g-fs-md);
  letter-spacing: var(--g-tr-md);
  color: var(--g-text);
  background-color: var(--g-fill-sunken);
  box-shadow: inset 0 0 0 1px var(--g-hairline), inset 0 1px 2px rgba(0,0,0,0.06);
  transition: box-shadow var(--g-t-fast) var(--g-ease),
              background-color var(--g-t-fast) var(--g-ease);
  -webkit-appearance: none;
  appearance: none;
}
/* ---------------------------------------------------------------------------
   R6-41 — THE RULE, WRITTEN DOWN ONCE SO NOBODY REDISCOVERS IT:

     A CONTROL TOKEN MAY BE A PILL ONLY WHILE THE CONTROL'S HEIGHT IS FIXED.
     ANYTHING THAT GROWS MUST CLAMP ITS RADIUS.

   .g-input and .g-select are fixed-height (min-height + one line of text never
   exceeds --g-ctl-h), so a 999px --g-r-ctl is correct theme identity there and
   they are deliberately NOT touched. .g-textarea is the opposite: min-height is
   a FLOOR and resize:vertical hands the user the rest.

   The arithmetic, with --g-s-3 = 12px (:246, not overridden by any theme).
   CSS 4.5's overlapping-curve clamp gives r_eff = min(declared, w/2, h/2), so a
   999px token on a 96px-tall well resolves to r_eff = 48px. The left border arc
   sits inset(y) = r - sqrt(r^2 - (r-y)^2) in from the edge, and the first line
   of text begins at y = padding-top = 12px:
       at rest (h=96, r_eff=48):  48 - sqrt(48^2 - 36^2)  = 16.25px  >  12px
                                  -> 4.25px of the first characters are OUTSIDE
                                     the well before the user types anything
       dragged to h=200:         100 - sqrt(100^2 - 88^2) = 52.50px  >> 12px
                                  -> the entire first line is outside
   The ceiling 14px is not arbitrary: it is the largest --g-r-ctl any non-pill
   theme ships (pop) AND this file's own default at :236. It binds rather than
   being swallowed by the h/2 clamp — at the 96px min-height r_eff would be 48px,
   so 14px is a real reduction at every height the user can drag to.

   WHY THIS IS THREE THEME-SCOPED RULES AND NOT `min(var(--g-r-ctl), 14px)`
   ---------------------------------------------------------------------------
   Because terra defines --g-r-ctl as a FOUR-CORNER value (18px 10px 18px 10px —
   the case the note at :339 warned about). min() takes calculations, not lists,
   so `min(var(--g-r-ctl), 14px)` is INVALID AT COMPUTED-VALUE TIME in terra and
   border-radius falls to its initial value — 0px, square corners, in the one
   theme built entirely on uneven ones. Measured in-browser, not assumed, and the
   two-declaration fallback trick does not rescue it. Clamping the scalar
   --g-r-md instead has the same defect by another route: terra's --g-r-md is
   14px while its --g-r-ctl is 18px 10px 18px 10px, so terra would silently lose
   its river-stone corner. Overriding only the three pill themes leaves all nine
   non-pill themes byte-identical BY CONSTRUCTION — not one declaration above is
   touched for them. NOTE THE COST: a future pill theme will not be covered here
   and must be added to this list.

   The ~= is deliberate and is NOT a typo. It is exactly equivalent to = for this
   single-token attribute, but js/theme.js:157 builds the theme roster by regex-
   scanning every stylesheet for [data-ui-theme="id"], and this file is <link>ed
   BEFORE css/themes.css — an = here would insert these three ids early into
   Theme.ids() and silently reorder the theme gallery in Settings. ~= is
   invisible to that regex. (An app-injected <style> block can safely use =,
   because it lands after themes.css; this file cannot.)
   --------------------------------------------------------------------------- */
.g-textarea { padding: var(--g-s-3); min-height: 96px; resize: vertical; line-height: var(--g-lh-md); }
[data-ui-theme~="tahoe"]  .g-textarea,
[data-ui-theme~="halo"]   .g-textarea,
[data-ui-theme~="aurora"] .g-textarea { border-radius: 14px; }
.g-input::placeholder, .g-textarea::placeholder { color: var(--g-placeholder); }
.g-input:hover, .g-select:hover, .g-textarea:hover { box-shadow: inset 0 0 0 1px var(--g-hairline-strong), inset 0 1px 2px rgba(0,0,0,0.06); }
.g-input:focus, .g-select:focus, .g-textarea:focus {
  outline: none;
  background-color: var(--g-fill-nested);
  box-shadow: inset 0 0 0 1px var(--g-accent), var(--g-focus-ring);
}
/* The outer 4px wash was a hard-coded rgba(179,40,32,0.14) — this file's own
   default --g-red at 14%, frozen as a literal and therefore applied theme-blind
   in all 12 themes. --g-red-bg is the token that means exactly this, and it is
   defined in all 36 theme blocks. Same two-layer stack, same geometry; only the
   colour of the second layer changes, from a stale literal to the live token. */
.g-input--invalid, .g-textarea--invalid { box-shadow: inset 0 0 0 1px var(--g-red), 0 0 0 4px var(--g-red-bg); }

/* select gets a chevron drawn with a mask-free background-image (a literal
   gradient token would not draw an arrow, so this is an inline SVG data URI —
   it is theme-neutral 50% grey and reads on both). */
.g-select {
  padding-right: var(--g-s-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1.5 1.75 6 6.25l4.5-4.5' fill='none' stroke='%238A91A1' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--g-s-3) center;
  cursor: pointer;
}

/* Search field with a leading icon slot */
.g-search { position: relative; display: flex; align-items: center; }
.g-search > .g-input { padding-left: var(--g-s-8); }
.g-search > .g-search-icon {
  position: absolute; left: var(--g-s-3); display: inline-flex;
  color: var(--g-text-3); pointer-events: none;
}

/* Switch — label > input[type=checkbox] + span.g-switch-track */
.g-switch { display: inline-flex; align-items: center; gap: var(--g-s-3); cursor: pointer; -webkit-tap-highlight-color: transparent; border-radius: var(--g-r-pill); }
.g-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.g-switch-track {
  position: relative;
  width: 50px; height: 30px; flex: none;
  border-radius: var(--g-r-pill);
  background-color: var(--g-fill-sunken);
  box-shadow: inset 0 0 0 1px var(--g-hairline), inset 0 1px 2px rgba(0,0,0,0.10);
  transition: background-color var(--g-t) var(--g-ease-in-out),
              box-shadow var(--g-t) var(--g-ease-in-out);
}
.g-switch-track::after {
  content: '';
  position: absolute; top: 3px; left: 3px;
  width: 24px; height: 24px;
  border-radius: var(--g-r-circle);
  background-color: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,0.22), 0 3px 8px -2px rgba(0,0,0,0.24);
  transition: transform var(--g-t) var(--g-ease-glass);
}
.g-switch input:checked + .g-switch-track {
  background-color: var(--g-accent-fill);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,255,255,0.24);
}
.g-switch input:checked + .g-switch-track::after { transform: translate3d(20px, 0, 0); }
.g-switch input:focus-visible + .g-switch-track { box-shadow: var(--g-focus-ring); }

/* Checkbox / radio */
.g-check { display: inline-flex; align-items: center; gap: var(--g-s-2); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.g-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.g-check-box {
  width: 20px; height: 20px; flex: none;
  border-radius: 7px;
  background-color: var(--g-fill-sunken);
  box-shadow: inset 0 0 0 1px var(--g-hairline-strong);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--g-t-fast) var(--g-ease), box-shadow var(--g-t-fast) var(--g-ease);
}
.g-check-box::after {
  content: '';
  width: 10px; height: 6px;
  border-left: 2px solid #fff; border-bottom: 2px solid #fff;
  border-bottom-left-radius: 1px;
  transform: rotate(-45deg) scale(0.4) translate3d(0, -1px, 0);
  opacity: 0;
  transition: opacity var(--g-t-fast) var(--g-ease-out), transform var(--g-t-fast) var(--g-ease-pop);
}
.g-check input:checked + .g-check-box { background-color: var(--g-accent-fill); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.14), inset 0 1px 0 rgba(255,255,255,0.26); }
.g-check input:checked + .g-check-box::after { opacity: 1; transform: rotate(-45deg) scale(1) translate3d(0, -1px, 0); }
.g-check input:focus-visible + .g-check-box { box-shadow: var(--g-focus-ring); }
.g-check--radio .g-check-box { border-radius: var(--g-r-circle); }
.g-check--radio .g-check-box::after { width: 8px; height: 8px; border: 0; border-radius: var(--g-r-circle); background: #fff; transform: scale(0.3); }
.g-check--radio input:checked + .g-check-box::after { transform: scale(1); }

/* Segmented control — the macOS Tahoe / iOS picker. The sliding pill is a
   pseudo driven by --g-seg-i (index) and --g-seg-n (count), set inline. */
.g-segment {
  position: relative;
  display: inline-flex;
  padding: 3px;
  border-radius: var(--g-r-pill);
  background-color: var(--g-fill-sunken);
  box-shadow: inset 0 0 0 1px var(--g-hairline), inset 0 1px 2px rgba(0,0,0,0.07);
  --g-seg-i: 0;
  --g-seg-n: 2;
}
.g-segment::before {
  content: '';
  position: absolute;
  top: 3px; bottom: 3px; left: 3px;
  width: calc((100% - 6px) / var(--g-seg-n));
  border-radius: var(--g-r-pill);
  background-color: var(--g-solid-4);
  box-shadow: 0 1px 2px rgba(0,0,0,0.14), 0 4px 10px -4px rgba(0,0,0,0.20), inset 0 1px 0 rgba(255,255,255,0.55);
  transform: translate3d(calc(var(--g-seg-i) * 100%), 0, 0);
  transition: transform var(--g-t) var(--g-ease-glass);
  pointer-events: none;
}
.g-segment > .g-tab {
  position: relative;
  z-index: 1;
  flex: 1 1 0;
  display: inline-flex; align-items: center; justify-content: center;
  height: calc(var(--g-ctl-h) - 6px);
  padding: 0 var(--g-s-4);
  border: 0; background: none;
  border-radius: var(--g-r-pill);
  font-family: inherit; font-size: var(--g-fs-sm); font-weight: var(--g-fw-semi);
  color: var(--g-text-3);
  cursor: pointer; white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--g-t-fast) var(--g-ease);
}
.g-segment > .g-tab[aria-selected="true"], .g-segment > .g-tab.is-active { color: var(--g-text); }


/* ============================================================================
   §10  CHIPS, BADGES, AVATARS, PROGRESS
   ============================================================================ */
.g-chip {
  display: inline-flex; align-items: center; gap: var(--g-s-1);
  height: 26px; padding: 0 10px;
  border: 0;
  border-radius: var(--g-r-pill);
  font-family: inherit;          /* .g-chip is valid on a <button>, and a
                                    <button> does not inherit the page font */
  font-size: var(--g-fs-xs); line-height: 1; font-weight: var(--g-fw-semi);
  letter-spacing: var(--g-tr-xs);
  color: var(--g-text-2);
  background-color: var(--g-slate-bg);
  box-shadow: inset 0 0 0 1px var(--g-hairline);
  white-space: nowrap;
  -webkit-appearance: none;
  appearance: none;
  transition: transform var(--g-t-fast) var(--g-ease-pop), background-color var(--g-t-fast) var(--g-ease);
}
.g-chip--btn { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.g-chip--btn:active { transform: scale(0.94); }
.g-chip--green  { color: var(--g-green);  background-color: var(--g-green-bg);  }
.g-chip--amber  { color: var(--g-amber);  background-color: var(--g-amber-bg);  }
.g-chip--blue   { color: var(--g-blue);   background-color: var(--g-blue-bg);   }
.g-chip--violet { color: var(--g-violet); background-color: var(--g-violet-bg); }
.g-chip--red    { color: var(--g-red);    background-color: var(--g-red-bg);    }
.g-chip--slate  { color: var(--g-slate);  background-color: var(--g-slate-bg);  }
.g-chip--glass {
  background-color: var(--g-fill-2);
  -webkit-backdrop-filter: var(--g-blur-2);
  backdrop-filter: var(--g-blur-2);
  box-shadow: var(--g-edge-2), var(--g-spec-2);
}
.g-chip--selected { color: var(--g-accent); background-color: var(--g-accent-soft); box-shadow: inset 0 0 0 1px var(--g-accent-soft); }

.g-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--g-r-pill);
  font-size: var(--g-fs-2xs); font-weight: var(--g-fw-bold); line-height: 1;
  color: var(--g-text-on-accent);
  background-color: var(--g-accent-fill);
  font-variant-numeric: tabular-nums;
}
.g-badge--quiet { color: var(--g-text-2); background-color: var(--g-fill-press); }

.g-dot { width: 8px; height: 8px; border-radius: var(--g-r-circle); flex: none; background-color: var(--g-text-3); }
.g-dot--green { background-color: var(--g-green); }
.g-dot--amber { background-color: var(--g-amber); }
.g-dot--red   { background-color: var(--g-red);   }
.g-dot--blue  { background-color: var(--g-blue);  }
.g-dot--live  { background-color: var(--g-green); animation: g-pulse 2s var(--g-ease-in-out) infinite; }

.g-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none;
  border-radius: var(--g-r-circle);
  font-size: var(--g-fs-xs); font-weight: var(--g-fw-bold);
  color: var(--g-text-2);
  background-color: var(--g-fill-press);
  box-shadow: inset 0 0 0 1px var(--g-hairline), inset 0 1px 0 rgba(255,255,255,0.30);
  overflow: hidden;
  user-select: none;
}
.g-avatar--sm { width: 26px; height: 26px; font-size: var(--g-fs-2xs); }
.g-avatar--lg { width: 48px; height: 48px; font-size: var(--g-fs-md); }
.g-avatar-stack { display: inline-flex; }
.g-avatar-stack > .g-avatar + .g-avatar { margin-left: -10px; box-shadow: inset 0 0 0 1px var(--g-hairline), 0 0 0 2px var(--g-solid-2); }

.g-progress {
  height: 8px; width: 100%;
  border-radius: var(--g-r-pill);
  background-color: var(--g-fill-sunken);
  box-shadow: inset 0 0 0 1px var(--g-hairline);
  overflow: hidden;
}
.g-progress-fill {
  height: 100%;
  border-radius: var(--g-r-pill);
  background-color: var(--g-accent-fill);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.30);
  transition: width var(--g-t-slow) var(--g-ease-glass);
}


/* ============================================================================
   §11  NAV CHROME + THE iOS STICKY PATTERN
   ============================================================================ */

/* ---- 11.1 Top bar ---------------------------------------------------------
   ALWAYS carries an opaque background-color under the glass. If the blur is
   unsupported, or iOS drops the sheen, the bar is still a solid ground and the
   content behind it never bleeds through into the title. */
.g-topbar {
  position: sticky;
  top: 0;
  z-index: var(--g-z-chrome);
  display: flex; align-items: center; gap: var(--g-s-3);
  height: var(--g-chrome-h);
  padding: 0 var(--g-pad-page);
  padding-top: var(--g-sat);
  box-sizing: content-box;
  background-color: var(--g-fill-1);
  background-image: var(--g-sheen-1);
  -webkit-backdrop-filter: var(--g-blur-1);
  backdrop-filter: var(--g-blur-1);
  box-shadow: inset 0 -1px 0 var(--g-hairline), 0 1px 12px -6px rgba(0,0,0,0.20);
  border-radius: 0;
}
.g-topbar--floating {
  position: sticky;
  top: calc(var(--g-sat) + var(--g-s-3));
  margin: var(--g-s-3) var(--g-pad-page);
  padding-top: 0;
  border-radius: var(--g-r-chrome);
  box-shadow: var(--g-edge-1), var(--g-spec-1), var(--g-shadow-1);
}
.g-topbar-title { font-size: var(--g-fs-lg); font-weight: var(--g-fw-bold); letter-spacing: var(--g-tr-lg); color: var(--g-text); margin: 0; }
.g-spacer { flex: 1 1 auto; min-width: 0; }

/* ---- 11.2 Bottom tab bar (mobile) ---------------------------------------- */
.g-tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--g-z-nav);
  display: flex; align-items: stretch;
  height: var(--g-tabbar-h);
  padding-bottom: var(--g-sab);
  background-color: var(--g-fill-1);
  background-image: var(--g-sheen-1);
  -webkit-backdrop-filter: var(--g-blur-1);
  backdrop-filter: var(--g-blur-1);
  box-shadow: inset 0 1px 0 var(--g-hairline), 0 -1px 16px -8px rgba(0,0,0,0.24);
}
.g-tabbar--floating {
  left: var(--g-s-4); right: var(--g-s-4);
  bottom: calc(var(--g-sab) + var(--g-s-4));
  padding-bottom: 0;
  border-radius: var(--g-r-xl);
  box-shadow: var(--g-edge-1), var(--g-spec-1), var(--g-shadow-3);
}
.g-tabbar-item {
  flex: 1 1 0;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  border: 0; background: none;
  border-radius: var(--g-r-md);
  font-family: inherit; font-size: var(--g-fs-2xs); font-weight: var(--g-fw-semi);
  letter-spacing: var(--g-tr-2xs);
  color: var(--g-text-3);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--g-t-fast) var(--g-ease), transform var(--g-t-fast) var(--g-ease-out);
}
.g-tabbar-item.is-active { color: var(--g-accent); }
.g-tabbar-item:active { transform: scale(0.92); }

/* ---- 11.3 Sidebar -------------------------------------------------------- */
.g-sidebar {
  width: var(--g-sidebar-w);
  flex: none;
  display: flex; flex-direction: column; gap: var(--g-s-1);
  padding: var(--g-s-4);
  background-color: var(--g-fill-1);
  background-image: var(--g-sheen-1);
  -webkit-backdrop-filter: var(--g-blur-1);
  backdrop-filter: var(--g-blur-1);
  box-shadow: inset -1px 0 0 var(--g-hairline);
}
.g-nav-item {
  display: flex; align-items: center; gap: var(--g-s-3);
  min-height: var(--g-ctl-h);
  padding: 0 var(--g-s-3);
  border: 0; background: none;
  border-radius: var(--g-r-ctl);
  font-family: inherit; font-size: var(--g-fs-sm); font-weight: var(--g-fw-medium);
  color: var(--g-text-2);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--g-t-fast) var(--g-ease),
              color var(--g-t-fast) var(--g-ease),
              transform var(--g-t-fast) var(--g-ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .g-nav-item:hover { background-color: var(--g-fill-hover); color: var(--g-text); }
}
.g-nav-item:active { transform: scale(0.98); background-color: var(--g-fill-press); }
.g-nav-item.is-active {
  color: var(--g-text);
  font-weight: var(--g-fw-semi);
  background-color: var(--g-fill-nested);
  box-shadow: inset 0 0 0 1px var(--g-hairline), inset 0 1px 0 rgba(255,255,255,0.35);
}
.g-nav-item.is-active .g-nav-rail { opacity: 1; }
.g-nav-rail { width: 3px; height: 18px; border-radius: var(--g-r-pill); background-color: var(--g-accent); opacity: 0; flex: none; transition: opacity var(--g-t-fast) var(--g-ease); }
.g-nav-section { margin-top: var(--g-s-4); padding: 0 var(--g-s-3) var(--g-s-1); }

/* ---- 11.4 THE iOS STICKY PATTERN — use this pair, never one div -----------
   iOS WebKit refuses to pin a position:sticky element that is ALSO its own
   overflow-x scroller. Chrome pins it and tells you everything is fine. It is
   not. Two elements, two jobs:

     <div class="g-sticky-bar">              <- position: sticky, NO overflow
       <div class="g-sticky-scroll">         <- overflow-x: auto, NOT sticky
         ...wide content...
       </div>
     </div>

   The bar carries an OPAQUE background-color (not a gradient), so even if the
   blur or the sheen fails to paint on a device, the bar is never see-through.
   Add .g-sticky-bar--glass for the blur on top of that solid ground. */
.g-sticky-bar {
  position: -webkit-sticky;
  position: sticky;
  top: var(--g-sticky-top, 0px);
  z-index: var(--g-z-sticky);
  overflow: visible;                       /* MUST stay visible. see above. */
  background-color: var(--g-solid-1);      /* SOLID. never a gradient here.  */
  box-shadow: inset 0 -1px 0 var(--g-hairline);
}
.g-sticky-bar--glass {
  background-color: var(--g-fill-1);
  -webkit-backdrop-filter: var(--g-blur-1);
  backdrop-filter: var(--g-blur-1);
}
.g-sticky-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  overscroll-behavior-x: contain;
}
.g-sticky-scroll::-webkit-scrollbar { height: 6px; }
.g-sticky-scroll::-webkit-scrollbar-thumb { background-color: var(--g-scroll-thumb); border-radius: var(--g-r-pill); }
.g-sticky-scroll > .g-sticky-inner { min-width: max-content; display: flex; align-items: center; gap: var(--g-s-2); }

/* Same trap, vertical variant: a sticky column header inside a scroll region.
   The scroller is the WRAPPER, the sticky thing is a CHILD of the content. */
.g-scroll-region {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.g-scroll-region > .g-scroll-content > .g-sticky-head {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: var(--g-z-sticky);
  background-color: var(--g-solid-1);
  box-shadow: inset 0 -1px 0 var(--g-hairline);
}

/* Anything that must never be see-through on iOS. */
.g-solid-ground {
  background-color: var(--g-solid-1) !important;
  background-image: none !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}


/* ============================================================================
   §12  MENUS, POPOVERS, TOOLTIPS
   ----------------------------------------------------------------------------
   Open/close contract (identical for every floating layer in this file):
     closed   : no class          -> visibility hidden, opacity 0, transform out
     opening  : .is-open          -> visible, opacity 1, transform in  (ease-out)
     closing  : .is-closing       -> visible, opacity 0, transform out (ease-in)
   js/glass.js drives it and removes .is-closing on transitionend, so nothing
   ever disappears without animating. Adding .is-open by hand also works.
   ============================================================================ */
.g-menu, .g-popover {
  position: absolute;
  z-index: var(--g-z-popover);
  min-width: 200px;
  max-width: min(92vw, 380px);
  padding: var(--g-s-2);
  border-radius: var(--g-r-menu);
  background-color: var(--g-fill-3);
  background-image: var(--g-sheen-3);
  -webkit-backdrop-filter: var(--g-blur-3);
  backdrop-filter: var(--g-blur-3);
  box-shadow: var(--g-edge-3), var(--g-spec-3), var(--g-shadow-3);
  color: var(--g-text);
  transform-origin: var(--g-origin, top center);
  visibility: hidden;
  opacity: 0;
  transform: translate3d(0, -6px, 0) scale(0.96);
  pointer-events: none;
  transition:
    opacity var(--g-t-fast) var(--g-ease-in),
    transform var(--g-t-fast) var(--g-ease-in),
    visibility 0s linear var(--g-t-fast);
}
.g-menu.is-open, .g-popover.is-open {
  visibility: visible;
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
  pointer-events: auto;
  transition:
    opacity var(--g-t) var(--g-ease-out),
    transform var(--g-t) var(--g-ease-glass),
    visibility 0s;
}
.g-menu.is-closing, .g-popover.is-closing {
  visibility: visible;
  opacity: 0;
  transform: translate3d(0, -4px, 0) scale(0.97);
  pointer-events: none;
  transition:
    opacity var(--g-t-fast) var(--g-ease-in),
    transform var(--g-t-fast) var(--g-ease-in),
    visibility 0s linear var(--g-t-fast);
}
.g-popover { padding: var(--g-s-4); }

.g-menu-item {
  display: flex; align-items: center; gap: var(--g-s-3);
  width: 100%;
  min-height: 36px;
  padding: 0 var(--g-s-3);
  border: 0; background: none;
  border-radius: var(--g-r-sm);
  font-family: inherit; font-size: var(--g-fs-sm); font-weight: var(--g-fw-medium);
  color: var(--g-text);
  text-align: left; text-decoration: none;
  cursor: pointer; white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--g-t-instant) var(--g-ease), color var(--g-t-instant) var(--g-ease);
}
@media (hover: hover) and (pointer: fine) {
  .g-menu-item:hover { background-color: var(--g-fill-hover); }
}
.g-menu-item:active { background-color: var(--g-fill-press); }
.g-menu-item.is-active { background-color: var(--g-fill-sel); color: var(--g-accent); font-weight: var(--g-fw-semi); }
.g-menu-item--danger { color: var(--g-red); }
.g-menu-item-hint { margin-left: auto; font-size: var(--g-fs-xs); color: var(--g-text-3); font-variant-numeric: tabular-nums; }
.g-menu-sep { height: 1px; margin: var(--g-s-2) var(--g-s-2); background-color: var(--g-hairline); border: 0; }
.g-menu-label { padding: var(--g-s-2) var(--g-s-3) var(--g-s-1); font-size: var(--g-fs-2xs); font-weight: var(--g-fw-semi); letter-spacing: 0.07em; text-transform: uppercase; color: var(--g-text-3); }

.g-tooltip {
  position: absolute;
  z-index: var(--g-z-tooltip);
  max-width: 260px;
  padding: 6px 10px;
  /* R6-41 (see :1134): this GROWS. max-width:260px exists precisely so the text
     wraps, and a tooltip is a block — the first line is pinned at y=6px however
     tall the box gets, so the arc intrusion grows without bound. Measured in the
     three pill themes: one line (h=28.8) intrudes 2.70px and clears the 10px
     padding, but from ~3 lines (h>=54) it does not, and at five lines (h=96,
     r_eff=48) it is 24.76px — 14.76px of the first characters outside the box.
     Ceiling 12px = the largest --g-r-sm any non-pill theme ships (pop, terra),
     and --g-r-sm is single-valued in all 12 themes, so min() is safe on it and
     all nine non-pill themes resolve byte-identically. 12px < h/2 even at one
     line (14.4), so the clamp binds rather than being swallowed. */
  border-radius: min(var(--g-r-sm), 12px);
  font-size: var(--g-fs-xs); line-height: 1.4; font-weight: var(--g-fw-medium);
  color: var(--g-text);
  background-color: var(--g-fill-4);
  -webkit-backdrop-filter: var(--g-blur-3);
  backdrop-filter: var(--g-blur-3);
  box-shadow: var(--g-edge-4), var(--g-spec-4), var(--g-shadow-2);
  visibility: hidden; opacity: 0;
  transform: translate3d(0, 3px, 0);
  pointer-events: none;
  transition: opacity var(--g-t-instant) var(--g-ease-in), transform var(--g-t-instant) var(--g-ease-in), visibility 0s linear var(--g-t-instant);
}
.g-tooltip.is-open { visibility: visible; opacity: 1; transform: none; transition: opacity var(--g-t-fast) var(--g-ease-out), transform var(--g-t-fast) var(--g-ease-out), visibility 0s; }


/* ============================================================================
   §13  OVERLAYS — scrim, modal, sheet, drawer
   ----------------------------------------------------------------------------
   The scrim itself is the blurred layer and it fades via OPACITY, so the blur
   radius never animates (rule 2). While closed the whole overlay is
   visibility:hidden, which means the browser skips painting it entirely —
   a hidden overlay costs nothing even though its backdrop-filter is declared.
   ============================================================================ */
.g-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--g-z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--g-s-4);
  padding-top: calc(var(--g-sat) + var(--g-s-4));
  padding-bottom: calc(var(--g-sab) + var(--g-s-4));
  background-color: var(--g-scrim);
  -webkit-backdrop-filter: var(--g-blur-scrim);
  backdrop-filter: var(--g-blur-scrim);
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--g-t) var(--g-ease-in), visibility 0s linear var(--g-t);
}
.g-overlay.is-open {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: opacity var(--g-t-slow) var(--g-ease-out), visibility 0s;
}
.g-overlay.is-closing {
  visibility: visible;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--g-t) var(--g-ease-in), visibility 0s linear var(--g-t);
}
.g-overlay--bottom { align-items: flex-end; padding: 0; }
.g-overlay--right  { align-items: stretch; justify-content: flex-end; padding: 0; }
.g-overlay--left   { align-items: stretch; justify-content: flex-start; padding: 0; }

/* ---- Modal --------------------------------------------------------------- */
.g-modal {
  position: relative;
  width: 100%;
  max-width: var(--g-modal-w);
  max-height: 100%;
  display: flex; flex-direction: column;
  border-radius: var(--g-r-modal);
  background-color: var(--g-fill-4);
  background-image: var(--g-sheen-4);
  -webkit-backdrop-filter: var(--g-blur-4);
  backdrop-filter: var(--g-blur-4);
  box-shadow: var(--g-edge-4), var(--g-spec-4), var(--g-shadow-4);
  color: var(--g-text);
  overflow: hidden;
  transform: translate3d(0, 14px, 0) scale(0.965);
  opacity: 0;
  transition: opacity var(--g-t) var(--g-ease-in), transform var(--g-t) var(--g-ease-in);
}
.g-overlay.is-open > .g-modal {
  transform: translate3d(0, 0, 0) scale(1);
  opacity: 1;
  transition: opacity var(--g-t-slow) var(--g-ease-out), transform var(--g-t-slow) var(--g-ease-glass);
}
.g-overlay.is-closing > .g-modal {
  transform: translate3d(0, 8px, 0) scale(0.98);
  opacity: 0;
}
.g-modal--sm { max-width: var(--g-modal-w-sm); }
.g-modal--lg { max-width: var(--g-modal-w-lg); }

.g-modal-hd {
  display: flex; align-items: center; gap: var(--g-s-3);
  padding: var(--g-s-5) var(--g-pad-sheet);
  flex: none;
  box-shadow: inset 0 -1px 0 var(--g-hairline);
}
.g-modal-title { font-size: var(--g-fs-xl); font-weight: var(--g-fw-bold); letter-spacing: var(--g-tr-xl); color: var(--g-text); margin: 0; }
.g-modal-body {
  padding: var(--g-pad-sheet);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  flex: 1 1 auto;
  min-height: 0;
}
.g-modal-ft {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--g-s-2);
  padding: var(--g-s-4) var(--g-pad-sheet);
  flex: none;
  box-shadow: inset 0 1px 0 var(--g-hairline);
}

/* ---- Bottom sheet -------------------------------------------------------- */
.g-sheet {
  position: relative;
  width: 100%;
  max-width: 640px;
  max-height: 92vh;
  max-height: 92dvh;
  display: flex; flex-direction: column;
  padding-bottom: var(--g-sab);
  border-radius: var(--g-r-sheet) var(--g-r-sheet) 0 0;
  background-color: var(--g-fill-3);
  background-image: var(--g-sheen-3);
  -webkit-backdrop-filter: var(--g-blur-3);
  backdrop-filter: var(--g-blur-3);
  box-shadow: var(--g-edge-3), var(--g-spec-3), var(--g-shadow-4);
  color: var(--g-text);
  overflow: hidden;
  transform: translate3d(0, 100%, 0);
  transition: transform var(--g-t) var(--g-ease-in);
}
.g-overlay.is-open > .g-sheet { transform: translate3d(0, 0, 0); transition: transform var(--g-t-slow) var(--g-ease-glass); }
.g-overlay.is-closing > .g-sheet { transform: translate3d(0, 100%, 0); }
.g-sheet-grabber {
  width: 40px; height: 5px;
  margin: 10px auto 4px;
  border-radius: var(--g-r-pill);
  background-color: var(--g-grabber);
  flex: none;
}

/* ---- Side drawer --------------------------------------------------------- */
.g-drawer {
  position: relative;
  width: 100%;
  max-width: var(--g-drawer-w);
  height: 100%;
  display: flex; flex-direction: column;
  padding-top: var(--g-sat);
  padding-bottom: var(--g-sab);
  border-radius: var(--g-r-sheet) 0 0 var(--g-r-sheet);
  background-color: var(--g-fill-3);
  background-image: var(--g-sheen-3);
  -webkit-backdrop-filter: var(--g-blur-3);
  backdrop-filter: var(--g-blur-3);
  box-shadow: var(--g-edge-3), var(--g-spec-3), var(--g-shadow-4);
  color: var(--g-text);
  overflow: hidden;
  transform: translate3d(100%, 0, 0);
  transition: transform var(--g-t) var(--g-ease-in);
}
.g-overlay.is-open > .g-drawer { transform: translate3d(0, 0, 0); transition: transform var(--g-t-slow) var(--g-ease-glass); }
.g-overlay.is-closing > .g-drawer { transform: translate3d(100%, 0, 0); }
.g-drawer--left { border-radius: 0 var(--g-r-sheet) var(--g-r-sheet) 0; transform: translate3d(-100%, 0, 0); }
.g-overlay.is-closing > .g-drawer--left { transform: translate3d(-100%, 0, 0); }

@media (max-width: 560px) {
  .g-modal { max-width: 100%; border-radius: var(--g-r-sheet); }
  .g-drawer { max-width: 100%; border-radius: 0; }
}


/* ============================================================================
   §14  TOASTS
   ============================================================================ */
.g-toast-stack {
  position: fixed;
  left: 50%;
  bottom: calc(var(--g-sab) + var(--g-s-5));
  z-index: var(--g-z-toast);
  transform: translate3d(-50%, 0, 0);
  display: flex; flex-direction: column-reverse; align-items: center; gap: var(--g-s-2);
  width: min(440px, calc(100vw - var(--g-s-8)));
  pointer-events: none;
}
.g-toast-stack--top { bottom: auto; top: calc(var(--g-sat) + var(--g-s-5)); flex-direction: column; }
.g-toast {
  display: flex; align-items: center; gap: var(--g-s-3);
  width: 100%;
  padding: var(--g-s-3) var(--g-s-4);
  border-radius: var(--g-r-md);
  font-size: var(--g-fs-sm); font-weight: var(--g-fw-medium);
  color: var(--g-text);
  background-color: var(--g-fill-4);
  background-image: var(--g-sheen-4);
  -webkit-backdrop-filter: var(--g-blur-3);
  backdrop-filter: var(--g-blur-3);
  box-shadow: var(--g-edge-4), var(--g-spec-4), var(--g-shadow-3);
  pointer-events: auto;
  opacity: 0;
  transform: translate3d(0, 14px, 0) scale(0.96);
  transition: opacity var(--g-t) var(--g-ease-in), transform var(--g-t) var(--g-ease-in);
}
.g-toast.is-open { opacity: 1; transform: none; transition: opacity var(--g-t) var(--g-ease-out), transform var(--g-t-slow) var(--g-ease-pop); }
.g-toast.is-closing { opacity: 0; transform: translate3d(0, 8px, 0) scale(0.97); }
.g-toast-stack--top .g-toast { transform: translate3d(0, -14px, 0) scale(0.96); }
.g-toast-stack--top .g-toast.is-open { transform: none; }
.g-toast--success .g-toast-icon { color: var(--g-green); }
.g-toast--error   .g-toast-icon { color: var(--g-red);   }
.g-toast-icon { flex: none; display: inline-flex; }
.g-toast-msg { flex: 1 1 auto; min-width: 0; }


/* ============================================================================
   §15  TABLES
   ----------------------------------------------------------------------------
   The wrapper is the glass pane; the table itself is transparent. The header
   uses .g-sticky-head inside .g-scroll-region so the iOS pattern from §11.4
   applies for free.
   ============================================================================ */
.g-table-wrap {
  border-radius: var(--g-r-card);
  overflow: hidden;
  background-color: var(--g-fill-2);
  background-image: var(--g-sheen-2);
  -webkit-backdrop-filter: var(--g-blur-2);
  backdrop-filter: var(--g-blur-2);
  box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2);
}
.g-table { width: 100%; border-collapse: collapse; font-size: var(--g-fs-sm); color: var(--g-text); }
.g-table th {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: var(--g-z-sticky);
  padding: var(--g-s-3) var(--g-s-4);
  text-align: left;
  font-size: var(--g-fs-2xs); font-weight: var(--g-fw-semi);
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--g-text-3);
  white-space: nowrap;
  /* SOLID ground — a sticky <th> over scrolling rows must never be see-through
     on iOS, and a gradient here is the exact thing that fails to paint. */
  background-color: var(--g-solid-1);
  box-shadow: inset 0 -1px 0 var(--g-hairline);
}
.g-table td {
  padding: var(--g-s-3) var(--g-s-4);
  box-shadow: inset 0 -1px 0 var(--g-hairline);
  vertical-align: middle;
}
.g-table tbody tr { transition: background-color var(--g-t-instant) var(--g-ease); }
@media (hover: hover) and (pointer: fine) {
  .g-table tbody tr:hover { background-color: var(--g-fill-hover); }
}
.g-table tbody tr.is-selected { background-color: var(--g-fill-sel); }
.g-table tbody tr:last-child td { box-shadow: none; }
.g-table--num td, .g-table td.g-num { font-variant-numeric: tabular-nums; font-feature-settings: var(--g-font-num); }

/* List row — the cheap repeated surface. NO backdrop-filter by design.
   The full reset below is load-bearing: .g-row is meant to work on a <div>
   AND on a <button>, and a <button> that only gets a background would still
   render the UA's 1px border and refuse to inherit the page font. */
.g-row {
  display: flex; align-items: center; gap: var(--g-s-3);
  width: 100%;
  min-height: var(--g-row-h);
  padding: var(--g-s-2) var(--g-s-4);
  border: 0;
  border-radius: var(--g-r-sm);
  background: none;
  color: var(--g-text);
  font-family: inherit;
  font-size: var(--g-fs-sm);
  line-height: var(--g-lh-sm);
  letter-spacing: var(--g-tr-sm);
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--g-t-instant) var(--g-ease), transform var(--g-t-fast) var(--g-ease-out);
}
@media (hover: hover) and (pointer: fine) { .g-row:hover { background-color: var(--g-fill-hover); } }
.g-row:active { background-color: var(--g-fill-press); transform: scale(0.995); }
.g-row.is-selected { background-color: var(--g-fill-sel); }
.g-list { display: flex; flex-direction: column; gap: 2px; }


/* ============================================================================
   §16  EMPTY / LOADING / ERROR STATES
   ============================================================================ */
.g-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--g-s-3);
  padding: var(--g-s-9) var(--g-s-5);
  text-align: center;
  color: var(--g-text-3);
}
.g-empty-art {
  display: inline-flex; align-items: center; justify-content: center;
  width: 68px; height: 68px;
  border-radius: var(--g-r-lg);
  color: var(--g-text-3);
  background-color: var(--g-fill-nested);
  box-shadow: inset 0 0 0 1px var(--g-hairline), inset 0 1px 0 rgba(255,255,255,0.35);
}
.g-empty-title { font-size: var(--g-fs-lg); font-weight: var(--g-fw-semi); color: var(--g-text); margin: 0; }
.g-empty-msg { font-size: var(--g-fs-sm); color: var(--g-text-3); max-width: 42ch; margin: 0; }

.g-error-state {
  display: flex; align-items: flex-start; gap: var(--g-s-3);
  padding: var(--g-s-4);
  /* R6-41 (see :1134): this GROWS, and align-items:flex-start pins the icon and
     title to the top-left corner — the worst possible arrangement — while the
     message length sets the height. Unlike .g-toast it never re-centres, and
     unlike .g-row it paints a real ground (--g-red-bg) plus a 1px inset ring, so
     the arc cuts visibly through the icon. Measured in the three pill themes at
     a realistic four-line message (h=147.3, r_eff=73.63): the arc reaches
     27.8px in at y=16 against 16px of padding — 11.8px of overlap. It clears
     below h~109px and spills above it. Ceiling 14px = the largest --g-r-md any
     non-pill theme ships (pop, terra); --g-r-md is single-valued in all 12
     themes, so min() is safe and the nine non-pill themes are byte-identical.
     This one is not cosmetic housekeeping: `align-items:flex-start` + --g-r-md
     is the .ws-engine-banner recipe, and .g-error-state is what those banners
     are meant to be converted TO. Left unclamped it would hand the converted
     banners the same bug back. */
  border-radius: min(var(--g-r-md), 14px);
  color: var(--g-text);
  background-color: var(--g-red-bg);
  box-shadow: inset 0 0 0 1px var(--g-hairline);
}
.g-error-state .g-error-icon { color: var(--g-red); flex: none; }
.g-error-title { font-size: var(--g-fs-sm); font-weight: var(--g-fw-semi); color: var(--g-red); margin: 0 0 2px; }

.g-skeleton {
  position: relative;
  border-radius: var(--g-r-sm);
  background-color: var(--g-skel);
  overflow: hidden;
}
.g-skeleton::after {
  content: '';
  position: absolute; inset: 0;
  background-image: var(--g-skel-shine);
  transform: translate3d(-100%, 0, 0);
  animation: g-shimmer 1.5s var(--g-ease-in-out) infinite;
}
.g-skeleton--text { height: 12px; }
.g-skeleton--title { height: 18px; width: 45%; }
.g-skeleton--line { height: 12px; width: 100%; }
.g-skeleton--line-sm { height: 12px; width: 62%; }
.g-skeleton--circle { border-radius: var(--g-r-circle); width: 34px; height: 34px; }
.g-skeleton--block { height: 100px; border-radius: var(--g-r-md); }

.g-spinner {
  width: 20px; height: 20px;
  border-radius: var(--g-r-circle);
  border: 2px solid var(--g-hairline-strong);
  border-top-color: var(--g-accent);
  animation: g-spin 800ms linear infinite;
  flex: none;
}
.g-spinner--sm { width: 14px; height: 14px; border-width: 1.5px; }
.g-spinner--lg { width: 30px; height: 30px; border-width: 2.5px; }
.g-loading { display: inline-flex; align-items: center; gap: var(--g-s-2); color: var(--g-text-3); font-size: var(--g-fs-sm); }
.g-btn.is-loading { color: transparent; pointer-events: none; }
.g-btn.is-loading .g-spinner { position: absolute; top: 50%; left: 50%; margin: -10px 0 0 -10px; border-top-color: currentColor; }


/* ============================================================================
   §17  UTILITIES
   ============================================================================ */
.g-divider { height: 1px; border: 0; margin: 0; background-color: var(--g-hairline); }
.g-divider--v { width: 1px; height: auto; align-self: stretch; }

.g-stack   { display: flex; flex-direction: column; gap: var(--g-gap); }
.g-stack-2 { display: flex; flex-direction: column; gap: var(--g-s-2); }
.g-hstack  { display: flex; align-items: center; gap: var(--g-gap); min-width: 0; }
.g-hstack-2{ display: flex; align-items: center; gap: var(--g-s-2); min-width: 0; }
.g-wrap    { flex-wrap: wrap; }
.g-grid    { display: grid; gap: var(--g-gap); grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }

.g-scroll {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--g-scroll-thumb) transparent;
}
.g-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.g-scroll::-webkit-scrollbar-track { background: transparent; }
.g-scroll::-webkit-scrollbar-thumb {
  background-color: var(--g-scroll-thumb);
  border-radius: var(--g-r-pill);
  border: 3px solid transparent;
  background-clip: padding-box;
}
.g-scroll::-webkit-scrollbar-thumb:hover { background-color: var(--g-scroll-thumb-hover); }

/* Screen-reader-only, focusable variant included for skip links. */
.g-sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.g-sr-focusable:focus, .g-sr-focusable:focus-visible {
  position: static; width: auto; height: auto; margin: 0;
  overflow: visible; clip: auto; clip-path: none; white-space: normal;
}

/* Body scroll lock while an overlay is open (js/glass.js sets this). */
.g-locked { overflow: hidden !important; touch-action: none; }

/* Promote only while animating — js/glass.js adds and removes this. Leaving
   will-change on permanently is how you burn GPU memory for nothing. */
.g-animating { will-change: transform, opacity; }


/* ============================================================================
   §18  KEYFRAMES  (transform/opacity only — nothing here triggers layout)
   ============================================================================ */
@keyframes g-spin { to { transform: rotate(360deg); } }

@keyframes g-shimmer {
  0%   { transform: translate3d(-100%, 0, 0); }
  100% { transform: translate3d(100%, 0, 0); }
}

@keyframes g-pulse {
  0%, 100% { opacity: 1;    transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.85); }
}

@keyframes g-sweep {
  0%   { transform: translate3d(-260%, 0, 0) skewX(-18deg); opacity: 0; }
  12%  { opacity: 1; }
  100% { transform: translate3d(560%, 0, 0) skewX(-18deg);  opacity: 0; }
}

@keyframes g-fade-in { from { opacity: 0; } to { opacity: 1; } }

@keyframes g-rise {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}
.g-rise { animation: g-rise var(--g-t-slow) var(--g-ease-glass) both; }
.g-fade { animation: g-fade-in var(--g-t) var(--g-ease-out) both; }

/* ============================================================================
   §OVERLAY DEPTH GUARD — added 2026-08-02 by the orchestrator.

   The nested-glass de-blur rules in this file are DESCENDANT selectors, so they
   stop applying the instant an overlay is portaled to <body> — which is exactly
   what several overlays here do (image lightbox, uiPrompt, command palette, the
   Websites modals/menus/popovers). Portaling is the normal fix for z-index and
   clipping, so this will keep happening; the guard has to live outside the DOM
   relationship.

   js/glass.js sets .g-overlay-open on <html> while any overlay is open. While it
   is set, background surfaces drop their blur: they sit behind a scrim, so the
   blur is invisible work — the GPU was compositing layers nobody can see. The
   overlay itself, and anything inside it, keeps full glass.

   Uses :not() rather than re-declaring each surface so it degrades to "no blur"
   rather than "wrong colour" if a lane invents a new surface class.
   ============================================================================ */
:root.g-overlay-open .glass-1:not(.g-overlay):not(.g-overlay *),
:root.g-overlay-open .glass-2:not(.g-overlay):not(.g-overlay *),
:root.g-overlay-open .glass-3:not(.g-overlay):not(.g-overlay *),
:root.g-overlay-open .glass-4:not(.g-overlay):not(.g-overlay *) {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}


/* ============================================================================
   §19  STRUCTURE — the primitives that consume the §1.14 structural tokens.
   Added 2026-08-03 for the RUN 4 theme system (css/themes.css).

   WHY THIS SITS AT THE BOTTOM OF THE FILE
   ---------------------------------------------------------------------------
   Several primitives above declare `border: 0` (.g-btn, .g-icon-btn, .g-input,
   .g-select, .g-textarea, .g-chip). Same specificity, so the LAST rule wins —
   putting the border here means those declarations did not have to be touched
   at all. With the default tokens this computes to `0px solid transparent`,
   which is exactly what `border: 0` computed to. Zero visual change, zero
   layout change (index.html sets box-sizing: border-box globally, so a themed
   2px border eats padding instead of growing the control).

   WHAT IT BUYS
   ---------------------------------------------------------------------------
   Ink's hard black outlines and Pop's thick ones become one token pair, and
   Verde's engraved double rule becomes a pseudo nobody has to remember. No
   theme needs a single line of component CSS.
   ============================================================================ */

/* (19.1) the themeable border, on every surface and control at once */
.glass-1, .glass-2, .glass-3, .glass-4,
.g-chrome, .g-card, .g-sheet-surface, .g-modal-surface,
.g-solid-1, .g-solid-2, .g-solid-3, .g-solid-4,
.g-menu, .g-popover, .g-modal, .g-sheet, .g-drawer, .g-toast,
.g-btn, .g-icon-btn--glass, .g-input, .g-select, .g-textarea, .g-chip {
  border: var(--g-border-w) solid var(--g-border-c);
}

/* (19.2) .g-solid-* never declared a position, and 19.3 hangs an absolutely
   positioned pseudo off these. Without this the rule would escape to whatever
   positioned ancestor it found and draw in the wrong place. */
/* :where() for the same reason as §5 — a containing-block fallback must never outrank an
   element that positions itself. */
:where(.g-solid-1, .g-solid-2, .g-solid-3, .g-solid-4) { position: relative; }

/* (19.3) THE ENGRAVED RULE — Verde's double line, set in from the pane edge.
   Default is a transparent 1px line at inset 0, i.e. invisible and free.
   pointer-events:none so it can never eat a click, and it is drawn inside the
   pane's own padding (>= 14px everywhere) so it cannot cross live text. */
.glass-1::after, .glass-2::after, .glass-3::after, .glass-4::after,
.g-chrome::after, .g-card::after, .g-sheet-surface::after, .g-modal-surface::after,
.g-solid-1::after, .g-solid-2::after, .g-solid-3::after, .g-solid-4::after,
.g-menu::after, .g-modal::after {
  content: '';
  position: absolute;
  inset: var(--g-rule-inset);
  border-radius: var(--g-rule-r);
  border: 1px solid var(--g-rule-c);
  pointer-events: none;
  z-index: 0;
}
