/*
 * forge-theme.css — Premium Visual System token layer.
 * Source: docs/FORGE_PREMIUM_VISUAL_SYSTEM_SPEC_2026-07-22.md §1 (tokens),
 *         §2 (component elevation pass), §5.3 (tooltip bubble), §7 (snippets).
 *
 * Rollout contract (spec §6, step 1): this file only *defines* custom
 * properties and a small set of additive component classes. Nothing in
 * dist/index.html or dist/app-*.js is REQUIRED to reference it — every
 * consumer uses var(--ft-*, <existing-fallback>), so linking this file is a
 * pure enhancement, and NOT linking it changes nothing visually.
 *
 * Self-contained: no external assets, no imports, no network fetch.
 * Dark-first only (the portal ships no light theme today) — see spec §1.
 * prefers-reduced-motion respected at the bottom of this file.
 */

:root {
  /* Native-control dark rendering (2026-07-23): the app is dark-first, but
     without color-scheme the OS renders select dropdowns / date pickers in
     light mode with unreadable pale option text. */
  color-scheme: dark;
  /* ---- Color: surfaces (warm-carbon instrument panel) ---- */
  --ft-bg:             #0b0a08;
  --ft-bg-secondary:   #12100d;
  --ft-surface-raised: #171412;
  --ft-surface-inset:  #0e0c0a;
  --ft-surface-2:      #181311;
  --ft-surface-2-end:  #14100e;
  --ft-border:         #2a2622;
  --ft-border-hairline: rgba(255,255,255,.07);

  /* ---- Color: text ---- */
  --ft-foreground:        #f2efe9;
  --ft-foreground-strong: #f8f6f4;
  --ft-muted-foreground:  #a8a29a;
  --ft-muted-2:           #857a6f;

  /* ---- Color: brand (ember reserved for transformation / CTA / activation —
     never a generic chrome tint, per Molten Forge spec 2.1) ---- */
  --ft-ember:        #f59e0b;
  --ft-ember-strong: #fbbf24;
  --ft-ember-ink:    #1c1205;
  --ft-copper:       #c47a4f;
  --ft-teal:         #38b7aa;

  /* ---- Color: semantic status ---- */
  --ft-ok:   #4ade80;
  --ft-warn: #facc15;
  --ft-crit: #f87171;
  /* f-056 (2026-09-07): the topbar unread-notification count badge painted
     var(--ft-foreground-strong) text on a solid var(--ft-crit) fill — a
     generic "body text on the page background" token, not tuned for THIS
     specific solid-red chip, and in light mode both happened to resolve
     dark (foreground-strong #14100c on crit #b93940 measured 3.36:1). Same
     per-accent "-ink" convention --ft-ember-ink already uses for text that
     must always read against that one accent's own fill, in either theme,
     regardless of how each theme's general text tokens flip: the dark
     palette's crit (#f87171) is light enough that DARK ink reads best
     there (6.84:1), while the light palette's crit (#b93940) is dark enough
     that WHITE ink reads best there (5.64:1) — the same light/dark flip
     --ft-ember-ink already makes for the same reason. */
  --ft-crit-ink: #1c1205;
  --ft-ring: #f59e0b;

  /* ---- Elevation / depth scale ---- */
  --ft-elev-0: none;
  --ft-elev-1: 0 1px 0 rgba(255,255,255,.03) inset;
  --ft-elev-2: 0 8px 24px rgba(0,0,0,.35);
  --ft-elev-3: 0 30px 90px rgba(0,0,0,.6);
  --ft-glow-ember: 0 0 0 1px rgba(245,158,11,.24), 0 8px 28px rgba(245,158,11,.12);
  --ft-row-hover: rgba(255,255,255,.025);

  /* ---- Radius ---- */
  --ft-radius-sm:   8px;
  --ft-radius-md:   10px;
  --ft-radius-lg:   14px;
  --ft-radius-xl:   16px;
  --ft-radius-full: 999px;

  /* ---- Spacing (4px base) ---- */
  --ft-space-1: 4px;
  --ft-space-2: 8px;
  --ft-space-3: 12px;
  --ft-space-4: 16px;
  --ft-space-5: 20px;
  --ft-space-6: 24px;
  --ft-space-8: 32px;
  --ft-space-10: 40px;

  /* ---- Typography ---- */
  --ft-font-sans:    'Geist', system-ui, sans-serif;
  --ft-font-display: 'Sora', var(--ft-font-sans);
  --ft-font-mono:    'Geist Mono', monospace;
  --ft-text-display: 700 22px/1.25 var(--ft-font-display);
  --ft-text-h1:      700 16.5px/1.35 var(--ft-font-sans);
  --ft-text-h2:      700 13.5px/1.4 var(--ft-font-sans);
  --ft-text-body:    400 12.5px/1.6 var(--ft-font-sans);
  --ft-text-caption: 600 10px/1.4 var(--ft-font-sans);
  --ft-text-data:    600 12px/1.4 var(--ft-font-mono);

  /* ---- Motion (Forge Assembly Motion System) ----
     Restraint per owner directive: motion only on state changes, no
     gratuitous animation, no bounce/overshoot. */
  --ft-motion-fast: 160ms;
  --ft-motion-base: 280ms;
  --ft-motion-slow: 520ms;
  --ft-ease-forged: cubic-bezier(0.22, 1, 0.36, 1);
  --ft-motion-max-translate: 12px;

  /* ---- Tokenised shell palette (fix/inline-hex-light-mode, 2026-09-06) ----
     dist/index.html and dist/app-*.js used to paint these as bare inline hex
     literals; 278 distinct colors are now folded into the semantic entries
     below. Every dark value here is the exact hex the shell already shipped,
     so dark mode is unchanged — these exist so light mode has something real
     to override. Each consumer still carries its original hex as the var()
     fallback, so an unlinked stylesheet renders exactly as it did before. */
  /* Surfaces */
  --ft-surface-3:      #1c1612;
  --ft-border-2:       #3a332c;
  --ft-border-warm:    #4d423a;
  --ft-cool-surface:   #12161c;
  --ft-cool-surface-2: #1c1c1c;
  --ft-cool-border:    #232631;
  --ft-parchment:      #ede0d3;
  --ft-ember-tint:     #fff5e6;
  /* Warm text ramp (most prominent -> most muted) */
  --ft-foreground-2: #e1dad4;
  --ft-foreground-3: #d4cbc4;
  --ft-foreground-4: #c6bcb3;
  --ft-muted-0:      #bcb1a7;
  --ft-muted-1:      #a1938b;
  --ft-muted-3:      #6b6259;
  --ft-muted-4:      #555555;
  --ft-parchment-2:  #dcd3c1;
  --ft-parchment-3:  #cbbda7;
  /* Cool text ramp */
  --ft-cool-foreground: #eceef2;
  --ft-cool-2:          #c4cbd4;
  --ft-cool-muted:      #9ca6b1;
  --ft-cool-muted-1:    #8992a0;
  --ft-cool-muted-2:    #79838e;
  --ft-cool-muted-3:    #68737f;
  --ft-neutral-mid:     #8f8f8f;
  --ft-neutral-mid-2:   #999999;
  /* Ember family */
  --ft-ember-bright: #f0a500;
  --ft-ember-yellow: #fcd34d;
  --ft-ember-soft:   #f5c98f;
  --ft-ember-dim:    #e3c46a;
  --ft-ember-sand:   #debe7f;
  --ft-ember-sand-2: #e3bf77;
  --ft-ember-peach:  #ffb27a;
  --ft-ember-wheat:  #e9d5b5;
  --ft-ember-muted:  #8a7a5b;
  --ft-khaki:        #9e895e;
  --ft-khaki-2:      #a8977a;
  /* Status: success */
  --ft-ok-fg:   #7ee787;
  --ft-ok-2:    #4caf87;
  --ft-ok-soft: #8bec9f;
  --ft-ok-mint: #9be9c4;
  /* Status: critical */
  --ft-crit-fg:     #ff8b8b;
  --ft-crit-soft:   #ff9b9b;
  --ft-crit-softer: #ffb4b4;
  --ft-crit-strong: #f05050;
  --ft-crit-deep:   #b00020;
  --ft-crit-deep-2: #a02a2a;
  /* Status: information (new family — the shell had no info token) */
  --ft-info:        #3f7fe0;
  --ft-info-2:      #4aa0d8;
  --ft-info-3:      #4090d0;
  --ft-info-bright: #6ab7ff;
  --ft-info-fg:     #8fb4f5;
  --ft-info-soft:   #a9c4fa;
  --ft-violet:      #c9a7f5;
  /* Tinted status surfaces */
  --ft-surface-ok:     #1a3a2a;
  --ft-surface-crit:   #3a1a1a;
  --ft-surface-crit-2: #3e2a2a;
  --ft-surface-crit-3: #5c2020;
  --ft-surface-warn:   #3a2a1a;
  --ft-surface-warn-2: #50423a;
  --ft-surface-info:   #1a2a3a;
  --ft-surface-info-2: #2a2a3e;
  --ft-surface-info-3: #1a1a2e;
  --ft-surface-copper: #b45309;

  /* ---- Channel tokens for rgba() literals (fix/inline-hex-light-mode) ----
     The shell builds most of its subtle surfaces, hairline borders and hover
     states from rgba(255,255,255,<alpha>) -- white ink laid over a dark ground.
     A hex token cannot express that; the CHANNELS have to flip, not the colour.
     So these hold a bare "r,g,b" triple that rgba() interpolates:
       background: rgba(var(--ft-overlay-rgb,255,255,255), .03)
     In dark the value IS 255,255,255, so every one of those 534 declarations
     computes byte-identically to what it did before. In light it becomes 0,0,0
     and the same alphas read as gentle shading on paper instead of vanishing.
     Each call keeps its original triple as the var() fallback, so an unlinked
     stylesheet still renders the dark shell exactly.
     NOT included, deliberately: the 23 modal/tour backdrops built from
     rgba(3,4,6,.72) and friends. A backdrop DIMS the page behind a dialog; it
     must stay dark in light mode, so those keep their literals. */
  --ft-overlay-rgb: 255,255,255;
  --ft-chrome-rgb:  14,16,20;

  /* ---- Legacy/alias namespace (fix/theme-normalization, 2026-09-06) ----
     Several dist/app-*.js modules (and this file itself, in the Tier-D
     .wt-/.cv- rules above) reference custom-property names that were never
     defined anywhere: --fg1/--fg2/--fg3/--surface1/--surface2/--surface3
     (a hand-rolled namespace app-crm.js and others assumed existed),
     --accent/--forge-danger/--forge-success/--forge-warning (an older
     semantic-color naming convention), and a handful of --ft-* names that
     don't match this file's actual token names one-for-one
     (--ft-accent(-soft), --ft-border-faint/-strong, --ft-danger, --ft-focus
     (-ring), --ft-muted, --ft-shadow-sm/-lg, --ft-surface(-0/-1), --ft-text).
     Every alias below points at a REAL --ft-* token above, never at a
     literal color, so it flips automatically with [data-theme] / the light
     media query the same as everything else in this file — do not hardcode
     a color here. --ft-dash-cols is intentionally NOT aliased: it is a
     numeric grid-column-count set inline per element (dist/index.html),
     not a color, and it already has its own `repeat(var(--ft-dash-cols, 1),
     ...)` fallback in the .ft-dash-grid rule below. */
  --fg1: var(--ft-foreground);
  --fg2: var(--ft-muted-foreground);
  --fg3: var(--ft-muted-2);
  --surface1: var(--ft-surface-raised);
  --surface2: var(--ft-surface-2);
  --surface3: var(--ft-surface-inset);
  --accent: var(--ft-ember);
  --ft-accent: var(--ft-ember);
  --ft-accent-soft: rgba(245, 158, 11, .12);
  --ft-text: var(--ft-foreground);
  --ft-muted: var(--ft-muted-foreground);
  --ft-surface: var(--ft-surface-raised);
  --ft-surface-0: var(--ft-bg);
  --ft-surface-1: var(--ft-surface-raised);
  --ft-border-faint: var(--ft-border-hairline);
  --ft-border-strong: var(--ft-border);
  --ft-danger: var(--ft-crit);
  --forge-danger: var(--ft-crit);
  --forge-success: var(--ft-ok);
  --forge-warning: var(--ft-warn);
  --ft-focus: var(--ft-ring);
  --ft-focus-ring: var(--ft-ring);
  --ft-shadow-sm: var(--ft-elev-2);
  --ft-shadow-lg: var(--ft-elev-3);
}

/* SCOPE NOTE (was: HONEST SCOPE NOTE — the debt it described is now paid).

   History: dist/index.html and every dist/app-*.js were built dark-first with
   HARDCODED inline colours (style="color:#f8f6f4;background:#0b0908"), NOT
   var(--ft-*) references, for the overwhelming majority of the shell's surfaces
   and text. Flipping the tokens below therefore did NOT relight the app, and a
   client who chose Light saw mostly-dark inline-styled chrome. That is why Light
   was pulled from Settings and OS-follow was commented out.

   fix/inline-hex-light-mode (2026-09-06) paid it, in two passes.

   Pass 1 — hex. 1,893 bare hex literals across dist/index.html and 25
   dist/app-*.js became var(--ft-*, <the same hex>): the original hex stays as
   the fallback, so an unlinked or failed stylesheet renders exactly as before.
   278 distinct colours — the product of years of copy-paste drift, including
   twelve near-identical off-whites and twelve near-identical near-blacks — fold
   into the 82 semantic entries in this file. 94.3% of rewritten sites land on a
   token whose dark value is within dE 3.5 of the hex it replaced (imperceptible);
   the dark theme is otherwise byte-for-byte what it was.

   Pass 2 — rgba channels. Tokenising every hex was still not enough: the shell
   builds its subtle surfaces, hairline borders and hover states from
   rgba(255,255,255,<alpha>) — white ink over a dark ground, which no colour token
   can express. Rendered in a real browser with the OS set to light, .fg-topbar was
   still painting rgba(10,11,14,.72) under correctly-flipped dark ink: 1.04:1. So
   537 of those now interpolate a channel token (--ft-overlay-rgb /
   --ft-chrome-rgb) that inverts 255,255,255 -> 0,0,0 in light. Same measurement
   after: the only text left below 4.5:1 is the decorative "/" breadcrumb
   separator, which sits at the same ratio in DARK (1.98:1) and is therefore the
   original design's choice, not a light-mode defect.

   What is deliberately NOT tokenised, and why:
     - 23 modal/tour backdrops (rgba(3,4,6,.72) and friends). A backdrop DIMS the
       page behind a dialog; it must stay dark in light mode too.
     - 3 declarations inside @media (prefers-contrast:more). A forced-contrast
       override must paint absolute black/white, never the themed palette. (This
       pass tokenised them once and tests/premium-visual-tokens.test.mjs caught it.)
     - 96 declarations already scoped to [data-theme="light"] in dist/app-*.js:
       light values already, tokenising them would double-apply.
     - 9 sites where var() is invalid, not merely unwise: one canvas strokeStyle,
       four SVG presentation attributes (fill=/stroke=), two setAttribute("fill")
       calls, the two sparkStroke/sparkFill values feeding those attributes, and
       <meta name="theme-color">.
     - 6 standalone pages that deliberately do not link this file (404.html,
       offline.html, operator-feedback.html/.js, forge-chat-widget.js,
       esign-canvas.js). Verified by reading getComputedStyle on each: every --ft-*
       resolves empty there, so tokenising would advertise a theme they cannot
       follow.
     - 366 brand/status colour washes, e.g. rgba(245,158,11,.12). These read as a
       tint on paper as well as on carbon; they are the remaining known gap and are
       cosmetic, not a readability one.
     - 37 matches that are not colours at all (support ticket #4819, order #2840
       and similar demo copy).
   tests/theme-inline-hex.test.mjs pins every one of these categories so the count
   cannot silently grow back, and tests/theme-light-parity.test.mjs stops the two
   copies of the light palette drifting apart. */
[data-theme="light"] {
  color-scheme: light;
  /* Channel flip: white ink over dark ground becomes black ink over paper */
  --ft-overlay-rgb: 0,0,0;
  --ft-chrome-rgb:  255,255,255;
  /* Base surfaces */
  --ft-bg:             #f7f4ee;
  --ft-bg-secondary:   #efe9df;
  --ft-surface-raised: #ffffff;
  --ft-surface-inset:  #f1ece2;
  --ft-surface-2:      #ffffff;
  --ft-surface-2-end:  #f4efe6;
  --ft-border:         #ddd4c6;
  /* Base text */
  --ft-foreground-strong: #14100c;
  --ft-foreground:        #241d15;
  --ft-muted-foreground:  #6b6255;
  --ft-muted-2:           #6f6963;
  /* Brand + semantic accents (dark values are unreadable on paper: ember 1.96:1, crit 2.52:1, ok 1.59:1, warn 1.40:1 — all now solved to >= 4.5:1) */
  --ft-ember:        #944e00;
  --ft-ember-strong: #895e00;
  --ft-ember-ink:    #ffffff;
  --ft-copper:       #a45e35;
  --ft-teal:         #007e72;
  --ft-ok:           #006714;
  --ft-warn:         #6d5200;
  --ft-crit:         #b93940;
  --ft-crit-ink:     #ffffff;
  --ft-border-hairline: rgba(20,16,10,.09);
  /* Surfaces */
  --ft-surface-3:      #faf7f1;
  --ft-border-2:       #c9bfae;
  --ft-border-warm:    #c4b8a4;
  --ft-cool-surface:   #eef1f5;
  --ft-cool-surface-2: #f2f2f2;
  --ft-cool-border:    #d3d7e0;
  --ft-parchment:      #f0e4d5;
  --ft-ember-tint:     #fdf0d9;
  /* Warm text ramp (most prominent -> most muted) */
  --ft-foreground-2: #2a2724;
  --ft-foreground-3: #3d3936;
  --ft-foreground-4: #524d49;
  --ft-muted-0:      #5d5853;
  --ft-muted-1:      #6c6561;
  --ft-muted-3:      #726c67;
  --ft-muted-4:      #707070;
  --ft-parchment-2:  #343029;
  --ft-parchment-3:  #4a4339;
  /* Cool text ramp */
  --ft-cool-foreground: #343537;
  --ft-cool-2:          #393d42;
  --ft-cool-muted:      #40464c;
  --ft-cool-muted-1:    #51575f;
  --ft-cool-muted-2:    #626870;
  --ft-cool-muted-3:    #697179;
  --ft-neutral-mid:     #5f5f5f;
  --ft-neutral-mid-2:   #4d4d4d;
  /* Ember family */
  --ft-ember-bright: #864d00;
  --ft-ember-yellow: #836800;
  --ft-ember-soft:   #755524;
  --ft-ember-dim:    #574500;
  --ft-ember-sand:   #69531d;
  --ft-ember-sand-2: #654d0c;
  --ft-ember-peach:  #753d0d;
  --ft-ember-wheat:  #79694e;
  --ft-ember-muted:  #736448;
  --ft-khaki:        #705e38;
  --ft-khaki-2:      #7d6e54;
  /* Status: success */
  --ft-ok-fg:   #006a14;
  --ft-ok-2:    #00724e;
  --ft-ok-soft: #007533;
  --ft-ok-mint: #307d5d;
  /* Status: critical */
  --ft-crit-fg:     #9d353c;
  --ft-crit-soft:   #a2494c;
  --ft-crit-softer: #a05d5f;
  --ft-crit-strong: #ba1629;
  --ft-crit-deep:   #ae001f;
  --ft-crit-deep-2: #c04742;
  /* Status: information (new family — the shell had no info token) */
  --ft-info:        #0054af;
  --ft-info-2:      #0077ac;
  --ft-info-3:      #006fac;
  --ft-info-bright: #0068a9;
  --ft-info-fg:     #315f99;
  --ft-info-soft:   #5370a1;
  --ft-violet:      #6a4e94;
  /* Tinted status surfaces */
  --ft-surface-ok:     #e2f4ea;
  --ft-surface-crit:   #fbe6e6;
  --ft-surface-crit-2: #f7e2e2;
  --ft-surface-crit-3: #f2d4d4;
  --ft-surface-warn:   #fbeedb;
  --ft-surface-warn-2: #efe0cd;
  --ft-surface-info:   #e4eef8;
  --ft-surface-info-2: #e6e7f3;
  --ft-surface-info-3: #e8e8f4;
  --ft-surface-copper: #f5dcc4;
}
/* fix/inline-hex-light-mode (2026-09-06): OS-follow RE-ENABLED. This block was
   turned off on 2026-09-06 because most of the shell and dist/app-*.js painted
   light-on-dark inline hex that no token could reach, so flipping :root's palette
   for anyone whose OS prefers light produced unreadable text (two independent
   client reports). That debt is now paid: 1,884 bare hex literals across
   dist/index.html and 30 dist/*.js files were rewritten to var(--ft-*, <same hex>),
   and every token below carries a light value verified at >= 4.5:1 on --ft-bg.
   The declarations are generated from the [data-theme="light"] rule above and
   MUST stay byte-identical to it — tests/theme-light-parity.test.mjs asserts that,
   so edit the rule above and let the test catch this copy. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) {
    color-scheme: light;
    /* Channel flip: white ink over dark ground becomes black ink over paper */
    --ft-overlay-rgb: 0,0,0;
    --ft-chrome-rgb:  255,255,255;
    /* Base surfaces */
    --ft-bg:             #f7f4ee;
    --ft-bg-secondary:   #efe9df;
    --ft-surface-raised: #ffffff;
    --ft-surface-inset:  #f1ece2;
    --ft-surface-2:      #ffffff;
    --ft-surface-2-end:  #f4efe6;
    --ft-border:         #ddd4c6;
    /* Base text */
    --ft-foreground-strong: #14100c;
    --ft-foreground:        #241d15;
    --ft-muted-foreground:  #6b6255;
    --ft-muted-2:           #6f6963;
    /* Brand + semantic accents (dark values are unreadable on paper: ember 1.96:1, crit 2.52:1, ok 1.59:1, warn 1.40:1 — all now solved to >= 4.5:1) */
    --ft-ember:        #944e00;
    --ft-ember-strong: #895e00;
    --ft-ember-ink:    #ffffff;
    --ft-copper:       #a45e35;
    --ft-teal:         #007e72;
    --ft-ok:           #006714;
    --ft-warn:         #6d5200;
    --ft-crit:         #b93940;
    --ft-crit-ink:     #ffffff;
    --ft-border-hairline: rgba(20,16,10,.09);
    /* Surfaces */
    --ft-surface-3:      #faf7f1;
    --ft-border-2:       #c9bfae;
    --ft-border-warm:    #c4b8a4;
    --ft-cool-surface:   #eef1f5;
    --ft-cool-surface-2: #f2f2f2;
    --ft-cool-border:    #d3d7e0;
    --ft-parchment:      #f0e4d5;
    --ft-ember-tint:     #fdf0d9;
    /* Warm text ramp (most prominent -> most muted) */
    --ft-foreground-2: #2a2724;
    --ft-foreground-3: #3d3936;
    --ft-foreground-4: #524d49;
    --ft-muted-0:      #5d5853;
    --ft-muted-1:      #6c6561;
    --ft-muted-3:      #726c67;
    --ft-muted-4:      #707070;
    --ft-parchment-2:  #343029;
    --ft-parchment-3:  #4a4339;
    /* Cool text ramp */
    --ft-cool-foreground: #343537;
    --ft-cool-2:          #393d42;
    --ft-cool-muted:      #40464c;
    --ft-cool-muted-1:    #51575f;
    --ft-cool-muted-2:    #626870;
    --ft-cool-muted-3:    #697179;
    --ft-neutral-mid:     #5f5f5f;
    --ft-neutral-mid-2:   #4d4d4d;
    /* Ember family */
    --ft-ember-bright: #864d00;
    --ft-ember-yellow: #836800;
    --ft-ember-soft:   #755524;
    --ft-ember-dim:    #574500;
    --ft-ember-sand:   #69531d;
    --ft-ember-sand-2: #654d0c;
    --ft-ember-peach:  #753d0d;
    --ft-ember-wheat:  #79694e;
    --ft-ember-muted:  #736448;
    --ft-khaki:        #705e38;
    --ft-khaki-2:      #7d6e54;
    /* Status: success */
    --ft-ok-fg:   #006a14;
    --ft-ok-2:    #00724e;
    --ft-ok-soft: #007533;
    --ft-ok-mint: #307d5d;
    /* Status: critical */
    --ft-crit-fg:     #9d353c;
    --ft-crit-soft:   #a2494c;
    --ft-crit-softer: #a05d5f;
    --ft-crit-strong: #ba1629;
    --ft-crit-deep:   #ae001f;
    --ft-crit-deep-2: #c04742;
    /* Status: information (new family — the shell had no info token) */
    --ft-info:        #0054af;
    --ft-info-2:      #0077ac;
    --ft-info-3:      #006fac;
    --ft-info-bright: #0068a9;
    --ft-info-fg:     #315f99;
    --ft-info-soft:   #5370a1;
    --ft-violet:      #6a4e94;
    /* Tinted status surfaces */
    --ft-surface-ok:     #e2f4ea;
    --ft-surface-crit:   #fbe6e6;
    --ft-surface-crit-2: #f7e2e2;
    --ft-surface-crit-3: #f2d4d4;
    --ft-surface-warn:   #fbeedb;
    --ft-surface-warn-2: #efe0cd;
    --ft-surface-info:   #e4eef8;
    --ft-surface-info-2: #e6e7f3;
    --ft-surface-info-3: #e8e8f4;
    --ft-surface-copper: #f5dcc4;
  }
}


/* ==========================================================================
   fix/select-dropdown-readability (2026-09-06): native select option popup
   readability across all theme states (dark default, explicit light, system
   light). Bug: Firefox renders option popups with light text on white
   background (ignoring the select's own colors), and switching to
   color-scheme: light invokes the OS's light-mode popup. Inline styles in
   dist/app-*.js hardcode pale text (#eceef2, #e8e8ee, #d4cbc4) which fails on
   light backgrounds. These rules ensure readable options and closed controls
   in all three states. The !important on closed controls in light mode is
   necessary because inline hex literals are the documented light-mode debt
   in this file's own "HONEST SCOPE NOTE" comment — inline styles override
   class-based tokens without the override. ========================================================================== */

select option,
select optgroup {
  background-color: var(--ft-surface-raised);
  color: var(--ft-foreground-strong);
}

select option:checked,
select option:hover {
  background-color: var(--ft-surface-2);
  color: var(--ft-foreground-strong);
}

/* Light theme: explicit data-theme="light" */
[data-theme="light"] select {
  color: var(--ft-foreground-strong) !important;
  background-color: var(--ft-surface-raised) !important;
}

/* Light theme: system preference (prefers-color-scheme: light) with no
   explicit data-theme attribute set */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) select {
    color: var(--ft-foreground-strong) !important;
    background-color: var(--ft-surface-raised) !important;
  }
}

/* ==========================================================================
   Component classes — spec §2 / §7. Additive, opt-in, no shell rewrite.
   ========================================================================== */

/* ---- 2.1 KPI card (sparkline-ready, trend delta pill, provenance chip) --- */
.ft-kpi-card {
  border-radius: var(--ft-radius-lg);
  border: 1px solid var(--ft-border-hairline);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
  padding: var(--ft-space-4);
  box-shadow: var(--ft-elev-1);
  cursor: pointer;
  transition: transform var(--ft-motion-base) var(--ft-ease-forged),
              box-shadow var(--ft-motion-base) var(--ft-ease-forged),
              border-color var(--ft-motion-base) var(--ft-ease-forged);
}
.ft-kpi-card:hover, .ft-kpi-card:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--ft-elev-2);
  border-color: rgba(245,158,11,.2);
  outline: none;
}
.ft-kpi-label { font: var(--ft-text-caption); color: var(--ft-muted-foreground); text-transform: none; }
.ft-kpi-value { font: var(--ft-text-display); color: var(--ft-foreground-strong); }
.ft-kpi-delta {
  font: var(--ft-text-data);
  padding: 2px 7px;
  border-radius: var(--ft-radius-full);
  background: color-mix(in srgb, currentColor 14%, transparent);
}
.ft-kpi-spark { height: 28px; margin-top: var(--ft-space-2); opacity: .85; }
.ft-kpi-provenance {
  margin-top: var(--ft-space-2);
  opacity: 0;
  transform: translateY(4px);
  font: var(--ft-text-caption);
  color: var(--ft-muted-2);
  text-transform: none;
  transition: opacity var(--ft-motion-fast) var(--ft-ease-forged),
              transform var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-kpi-card:hover .ft-kpi-provenance,
.ft-kpi-card:focus-visible .ft-kpi-provenance { opacity: 1; transform: none; }

/* ---- 2.2 Section panel variants ------------------------------------------ */
.ft-panel {
  border-radius: var(--ft-radius-lg);
  border: 1px solid var(--ft-border-hairline);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
  padding: var(--ft-space-5);
  box-shadow: var(--ft-elev-1);
}
.ft-panel--decision {
  border-color: rgba(245,201,143,.2);
  background: linear-gradient(145deg, rgba(245,201,143,.07), rgba(255,255,255,.01));
}
.ft-panel--alert {
  border-color: rgba(245,158,11,.18);
  background: linear-gradient(140deg, rgba(245,158,11,.07), rgba(251,191,36,.03));
}

/* ---- 2.3 Table rows ------------------------------------------------------- */
.ft-table-row { transition: background var(--ft-motion-fast) var(--ft-ease-forged); }
.ft-table-row:hover { background: var(--ft-row-hover); }
.ft-table-head { position: sticky; top: 0; background: var(--ft-surface-2); z-index: 1; }

/* ---- 2.5 Badges / status pills -------------------------------------------- */
.ft-badge {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 var(--ft-space-2);
  border-radius: var(--ft-radius-full);
  font: var(--ft-text-caption);
  text-transform: none;
}
.ft-badge--ember {
  background: color-mix(in srgb, var(--ft-ember) 11%, transparent);
  color: var(--ft-ember-strong);
  border: 1px solid color-mix(in srgb, var(--ft-ember) 20%, transparent);
}
.ft-badge--ok   { background: color-mix(in srgb, var(--ft-ok) 12%, transparent);   color: var(--ft-ok); }
.ft-badge--warn { background: color-mix(in srgb, var(--ft-warn) 12%, transparent); color: var(--ft-warn); }
.ft-badge--crit { background: color-mix(in srgb, var(--ft-crit) 12%, transparent); color: var(--ft-crit); }

/* ---- §7.2 Connector card --------------------------------------------------- */
.ft-connector-card {
  border-radius: var(--ft-radius-lg);
  border: 1px solid var(--ft-border-hairline);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
  padding: var(--ft-space-4);
  transition: border-color var(--ft-motion-fast) var(--ft-ease-forged),
              box-shadow var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-connector-card:hover {
  border-color: rgba(255,255,255,.14);
  box-shadow: var(--ft-elev-2);
}
.ft-connector-card[data-status="disconnected"] { opacity: .6; }

/* ---- Buttons (primary / secondary), motion-tokened ------------------------ */
.ft-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--ft-space-2);
  border-radius: var(--ft-radius-sm);
  padding: var(--ft-space-2) var(--ft-space-3);
  font: var(--ft-text-h2);
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform var(--ft-motion-fast) var(--ft-ease-forged),
              box-shadow var(--ft-motion-fast) var(--ft-ease-forged),
              border-color var(--ft-motion-fast) var(--ft-ease-forged),
              background var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-btn:disabled { opacity: .5; cursor: not-allowed; }
.ft-btn--primary {
  background: linear-gradient(145deg, var(--ft-ember), var(--ft-ember-strong));
  color: var(--ft-ember-ink);
  border: none;
}
.ft-btn--primary:hover:not(:disabled), .ft-btn--primary:focus-visible:not(:disabled) {
  box-shadow: var(--ft-glow-ember);
  outline: none;
}
.ft-btn--secondary {
  background: rgba(255,255,255,.05);
  color: var(--ft-foreground);
  border: 1px solid var(--ft-border-hairline);
}
.ft-btn--secondary:hover:not(:disabled), .ft-btn--secondary:focus-visible:not(:disabled) {
  border-color: rgba(255,255,255,.18);
  outline: none;
}
/* ---- Canonical control vocabulary, Phase 5A design-system-unification
   (2026-07-28): ghost / danger / icon / size variants, so every module's
   *-btn family (fsoc-btn, forge-btn, fteam-btn-*, pb-btn, forge-fb-btn,
   fdp-btn-*, cr-btn, fimport-btn-*, fb-btn) can declare the SAME property
   values as this canonical set instead of inventing its own padding,
   radius, weight, or hover behavior. Class names stay per-module (renaming
   every call site was out of scope for a consolidation pass), but every
   family's CSS-in-JS rule now mirrors these values exactly. */
.ft-btn--ghost {
  background: transparent;
  color: var(--ft-muted-foreground);
  border: 1px solid var(--ft-border-hairline);
}
.ft-btn--ghost:hover:not(:disabled), .ft-btn--ghost:focus-visible:not(:disabled) {
  border-color: rgba(255,255,255,.18);
  color: var(--ft-foreground);
  outline: none;
}
.ft-btn--danger {
  background: color-mix(in srgb, var(--ft-crit) 14%, transparent);
  color: var(--ft-crit);
  border: 1px solid color-mix(in srgb, var(--ft-crit) 30%, transparent);
}
.ft-btn--danger:hover:not(:disabled), .ft-btn--danger:focus-visible:not(:disabled) {
  background: color-mix(in srgb, var(--ft-crit) 22%, transparent);
  outline: none;
}
.ft-btn--icon {
  width: 32px;
  height: 32px;
  padding: 0;
  justify-content: center;
  border-radius: var(--ft-radius-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--ft-muted-2);
  font-size: 1.1rem;
  line-height: 1;
}
.ft-btn--icon:hover:not(:disabled), .ft-btn--icon:focus-visible:not(:disabled) {
  background: rgba(255,255,255,.06);
  color: var(--ft-foreground);
  outline: none;
}
.ft-btn--sm { height: 26px; padding: 0 var(--ft-space-2); font-size: .78rem; }

/* ---- NATIVE-FIRST EMPTY STATE (2026-07-23, item 2) -------------------------
   Foundational empty-state format for every real-tenant module with no data
   yet: description + a green "Forge-native" chip + a STACKED pair of CTAs
   (enlarged primary "Start using this module" over a visually secondary
   "Connect an existing tool instead") + a hint line. First built ad hoc in
   dist/app-billing.js (Estimates); these shared classes are the single
   source of that pattern so every module adopts the identical shape/size
   instead of re-implementing it. The primary CTA is deliberately taller,
   wider, and bolder than .ft-btn--primary — the visual hierarchy must
   actively encourage the native workflow over connecting an external tool. */
.ft-empty-native {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--ft-space-2); max-width: 460px; margin: 0 auto; padding: var(--ft-space-6) var(--ft-space-4);
}
.ft-empty-native-chip {
  display: inline-flex; align-items: center; height: 22px; padding: 0 var(--ft-space-3);
  border-radius: var(--ft-radius-full); font: var(--ft-text-caption); font-weight: 600;
  background: color-mix(in srgb, var(--ft-ok, #4ade80) 14%, transparent);
  color: var(--ft-ok, #4caf87);
  border: 1px solid color-mix(in srgb, var(--ft-ok, #4ade80) 30%, transparent);
}
.ft-empty-native-what { margin: 0; font: var(--ft-text-body); color: var(--ft-foreground); line-height: 1.5; }
.ft-empty-native-actions {
  display: flex; flex-direction: column; align-items: stretch; gap: var(--ft-space-3);
  width: 100%; max-width: 320px; margin-top: var(--ft-space-2);
}
/* Enlarged, bolder primary — visually dominant over the secondary connect
   option so the native path reads as the obvious next step. */
.ft-empty-native-cta {
  display: inline-flex; align-items: center; justify-content: center;
  height: 48px; padding: 0 var(--ft-space-5); border-radius: var(--ft-radius-md);
  border: none; cursor: pointer; font: var(--ft-text-h2); font-size: 1rem; font-weight: 700;
  background: linear-gradient(145deg, var(--ft-ember), var(--ft-ember-strong));
  color: var(--ft-ember-ink);
  box-shadow: var(--ft-elev-1);
  transition: transform var(--ft-motion-fast) var(--ft-ease-forged),
              box-shadow var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-empty-native-cta:hover:not(:disabled), .ft-empty-native-cta:focus-visible:not(:disabled) {
  box-shadow: var(--ft-glow-ember); outline: none; transform: translateY(-1px);
}
.ft-empty-native-cta:disabled { opacity: .5; cursor: not-allowed; transform: none; }
/* Clearly secondary — smaller, outline-only, no fill — the connect path is
   available but never competes visually with the primary CTA above it. */
.ft-empty-native-secondary {
  display: inline-flex; align-items: center; justify-content: center;
  height: 36px; padding: 0 var(--ft-space-4); border-radius: var(--ft-radius-sm);
  border: 1px solid var(--ft-border-hairline); background: transparent;
  color: var(--ft-muted-foreground); cursor: pointer; font: var(--ft-text-caption); font-size: .85rem;
  transition: border-color var(--ft-motion-fast) var(--ft-ease-forged), color var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-empty-native-secondary:hover, .ft-empty-native-secondary:focus-visible {
  border-color: rgba(255,255,255,.22); color: var(--ft-foreground); outline: none;
}
.ft-empty-native-hint { margin: var(--ft-space-2) 0 0; font: var(--ft-text-caption); color: var(--ft-muted-2); line-height: 1.5; max-width: 400px; }

/* ---- Canonical recurring state patterns, Phase 5A design-system-
   unification (2026-07-28) — same structural shape as .ft-empty-native
   (centered column, max-width, consistent gaps) extended to the three
   other states every real-tenant module needs: loading, error/retry, and
   gated/upgrade. Role-aware gating logic (who sees this state, and when)
   is untouched — this only unifies the PRESENTATION once a module decides
   to show one of these states. ---- */
.ft-loading-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--ft-space-2); max-width: 460px; margin: 0 auto; padding: var(--ft-space-6) var(--ft-space-4);
  color: var(--ft-muted-foreground);
}
.ft-loading-state-spinner {
  width: 28px; height: 28px; border-radius: var(--ft-radius-full);
  border: 2px solid var(--ft-border-hairline);
  border-top-color: var(--ft-ember);
  animation: ft-spin var(--ft-motion-slow) linear infinite;
}
@keyframes ft-spin { to { transform: rotate(360deg); } }
.ft-loading-state-copy { margin: 0; font: var(--ft-text-body); color: var(--ft-muted-foreground); }

.ft-error-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--ft-space-2); max-width: 460px; margin: 0 auto; padding: var(--ft-space-6) var(--ft-space-4);
}
.ft-error-state-chip {
  display: inline-flex; align-items: center; height: 22px; padding: 0 var(--ft-space-3);
  border-radius: var(--ft-radius-full); font: var(--ft-text-caption); font-weight: 600;
  background: color-mix(in srgb, var(--ft-crit) 14%, transparent);
  color: var(--ft-crit);
  border: 1px solid color-mix(in srgb, var(--ft-crit) 30%, transparent);
}
.ft-error-state-what { margin: 0; font: var(--ft-text-body); color: var(--ft-foreground); line-height: 1.5; }
.ft-error-state-retry {
  display: inline-flex; align-items: center; justify-content: center;
  height: 36px; padding: 0 var(--ft-space-4); border-radius: var(--ft-radius-sm);
  border: 1px solid var(--ft-border-hairline); background: transparent;
  color: var(--ft-foreground); cursor: pointer; font: var(--ft-text-caption); font-size: .85rem;
  margin-top: var(--ft-space-2);
  transition: border-color var(--ft-motion-fast) var(--ft-ease-forged), color var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-error-state-retry:hover, .ft-error-state-retry:focus-visible {
  border-color: rgba(255,255,255,.22); outline: none;
}

.ft-gated-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--ft-space-2); max-width: 460px; margin: 0 auto; padding: var(--ft-space-6) var(--ft-space-4);
}
.ft-gated-state-chip {
  display: inline-flex; align-items: center; height: 22px; padding: 0 var(--ft-space-3);
  border-radius: var(--ft-radius-full); font: var(--ft-text-caption); font-weight: 600;
  background: color-mix(in srgb, var(--ft-ember) 14%, transparent);
  color: var(--ft-ember-strong);
  border: 1px solid color-mix(in srgb, var(--ft-ember) 30%, transparent);
}
.ft-gated-state-what { margin: 0; font: var(--ft-text-body); color: var(--ft-foreground); line-height: 1.5; }
.ft-gated-state-cta {
  display: inline-flex; align-items: center; justify-content: center;
  height: 48px; padding: 0 var(--ft-space-5); border-radius: var(--ft-radius-md);
  border: none; cursor: pointer; font: var(--ft-text-h2); font-size: 1rem; font-weight: 700;
  background: linear-gradient(145deg, var(--ft-ember), var(--ft-ember-strong));
  color: var(--ft-ember-ink);
  box-shadow: var(--ft-elev-1);
  margin-top: var(--ft-space-2);
  transition: transform var(--ft-motion-fast) var(--ft-ease-forged), box-shadow var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-gated-state-cta:hover, .ft-gated-state-cta:focus-visible {
  box-shadow: var(--ft-glow-ember); outline: none; transform: translateY(-1px);
}

/* ---- §5.3 Guidance tooltip bubble ------------------------------------------ */
.ft-tooltip {
  max-width: 280px;
  padding: var(--ft-space-3) var(--ft-space-4);
  border-radius: var(--ft-radius-md);
  border: 1px solid var(--ft-border-hairline);
  background: var(--ft-surface-raised);
  box-shadow: var(--ft-elev-2);
  font: var(--ft-text-body);
  color: var(--ft-foreground);
  opacity: 0;
  transform: translateY(4px) scale(.98);
  transition: opacity var(--ft-motion-fast) var(--ft-ease-forged),
              transform var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-tooltip[data-open="true"] { opacity: 1; transform: none; }
.ft-tooltip-title { font: var(--ft-text-h2); color: var(--ft-foreground-strong); margin-bottom: var(--ft-space-1); }
.ft-tooltip-dismiss {
  font: var(--ft-text-caption);
  color: var(--ft-muted-2);
  cursor: pointer;
  background: none;
  border: none;
  padding: 4px 6px;
  text-transform: none;
}

/* ---- §5.2 Anchor pulse (two iterations only — never a loop) --------------- */
@keyframes ft-anchor-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(245,158,11,.35); }
  100% { box-shadow: 0 0 0 10px rgba(245,158,11,0); }
}
.ft-anchor-pulse { animation: ft-anchor-pulse var(--ft-motion-slow) var(--ft-ease-forged) 2; }

/* ---- §3 Adaptive Dashboard Grid ------------------------------------------- */
/* --ft-dash-cols is set inline by JS (dist/index.html Component.dashboardDensity())
   per spec §3.4 — one JS source of truth for column count, CSS only owns the
   mobile/tablet hard-overrides below. */
.ft-dash-grid {
  display: grid;
  /* fix/dashboard-layout-audit (2026-07-23): a fixed repeat(N, minmax(0,1fr))
     lets the track shrink to a sliver whenever N columns don't evenly divide
     the remaining row width after a span:2 widget claims its share (e.g. a
     lone span:1 "My work" card forced into a ~130px leftover column next to
     a full-width "Money snapshot" — text wrapping every 1-2 words). A 240px
     floor keeps every widget readable; the row wraps to fewer columns
     instead of squeezing one down to nothing. --ft-dash-cols still caps the
     max column count (dashboardDensity()), this only adds the min. */
  grid-template-columns: repeat(var(--ft-dash-cols, 1), minmax(min(240px, 100%), 1fr));
  grid-auto-flow: dense;
  gap: var(--ft-space-4);
}
.ft-dash-grid[data-scale="compact"] .ft-widget { min-height: 140px; }
.ft-dash-grid[data-scale="medium"]  .ft-widget { min-height: 200px; }
.ft-dash-grid[data-scale="large"]   .ft-widget { min-height: 280px; }
.ft-dash-grid[data-scale="hero"]    .ft-widget { min-height: 200px; }
@media (max-width: 1023px) {
  .ft-dash-grid { grid-template-columns: repeat(min(2, var(--ft-dash-cols, 1)), minmax(min(240px, 100%), 1fr)) !important; }
}
@media (max-width: 767px) {
  .ft-dash-grid { grid-template-columns: 1fr !important; }
}
/* fix/dashboard-layout-audit (2026-07-23, finding 3): the floating
   "Company Workspaces" (dist/app-launch.js, right:14px;bottom:14px) and
   "Data Connectors" (dist/app-implementation.js, right:14px;bottom:58px)
   buttons are position:fixed bottom-right; on shorter viewports they sit
   on top of the last row of dashboard widgets/tooltips. Reserve room at
   the foot of the dashboard view (both buttons stack to ~100px tall) so
   real content is never hidden beneath them. */
.fg-view:has(> .ft-dash-grid) {
  padding-bottom: 120px;
}

.ft-widget {
  position: relative;
  border-radius: var(--ft-radius-lg);
  border: 1px solid var(--ft-border-hairline);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
  padding: var(--ft-space-4);
  box-shadow: var(--ft-elev-1);
  display: flex;
  flex-direction: column;
  transition: border-color var(--ft-motion-base) var(--ft-ease-forged);
}
.ft-widget[data-span="2"] { grid-column: span 2; }
.ft-widget[data-pinned="true"] { border-color: rgba(245,158,11,.28); }
.ft-widget-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--ft-space-2);
  margin-bottom: var(--ft-space-2);
}
.ft-widget-title { margin: 0; font: var(--ft-text-h2); color: var(--ft-foreground-strong); }
.ft-widget-body { flex: 1; font: var(--ft-text-body); color: var(--ft-muted-foreground); }
.ft-widget-actions { display: flex; align-items: center; gap: 2px; }
.ft-widget-iconbtn {
  width: 24px; height: 24px; border-radius: 6px; border: none; background: none;
  color: var(--ft-muted-2); cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-size: 13px; line-height: 1;
}
.ft-widget-iconbtn:hover, .ft-widget-iconbtn:focus-visible { background: rgba(255,255,255,.06); color: var(--ft-foreground); }
.ft-widget-iconbtn[aria-pressed="true"] { color: var(--ft-ember-strong); }
.ft-dash-tray {
  display: flex; flex-wrap: wrap; gap: var(--ft-space-2); margin-top: var(--ft-space-4);
}
.ft-dash-tray-chip {
  height: 28px; padding: 0 var(--ft-space-3); border-radius: var(--ft-radius-full);
  border: 1px dashed var(--ft-border-hairline); background: none; color: var(--ft-muted-foreground);
  font: var(--ft-text-caption); text-transform: none; cursor: pointer;
}
.ft-dash-tray-chip:hover { border-color: rgba(245,158,11,.3); color: var(--ft-ember-strong); }
.ft-dash-reset {
  height: 30px; padding: 0 var(--ft-space-3); border-radius: var(--ft-radius-sm); border: none;
  background: none; color: var(--ft-muted-2); font: var(--ft-text-caption); text-transform: none; cursor: pointer;
}
.ft-dash-reset:hover { color: var(--ft-foreground); text-decoration: underline; }

/* ---- fix/click-depth-phase2 (2026-07-31): dashboard quick-jump rows ------
   Shared shape for "Recently visited" and "Quick access" — both sit BELOW
   the main widget grid, small and unobtrusive so neither competes with
   "Do this next" for attention (spec: dismissible/unobtrusive). ---- */
.ft-quickrow { margin-top: var(--ft-space-5); }
.ft-quickrow-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--ft-space-2); }
.ft-quickrow-label {
  font: var(--ft-text-caption); letter-spacing: .08em; text-transform: uppercase;
  color: var(--ft-muted-2); margin-bottom: var(--ft-space-2);
}
.ft-quickrow-head .ft-quickrow-label { margin-bottom: 0; }
.ft-quickrow-list, .ft-quickrow-cards { display: flex; flex-wrap: wrap; gap: var(--ft-space-2); }
.ft-quickrow-chip {
  height: 30px; padding: 0 var(--ft-space-3); border-radius: var(--ft-radius-full);
  border: 1px solid var(--ft-border-hairline); background: rgba(255,255,255,.025);
  color: var(--ft-muted-foreground); font: var(--ft-text-caption); text-transform: none; cursor: pointer;
  transition: border-color var(--ft-motion-fast) var(--ft-ease-forged), color var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-quickrow-chip:hover, .ft-quickrow-chip:focus-visible { border-color: rgba(245,158,11,.3); color: var(--ft-ember-strong); }
.ft-quickrow-dismiss {
  height: 24px; padding: 0 var(--ft-space-2); border-radius: var(--ft-radius-sm); border: none;
  background: none; color: var(--ft-muted-2); font: var(--ft-text-caption); text-transform: none; cursor: pointer;
}
.ft-quickrow-dismiss:hover, .ft-quickrow-dismiss:focus-visible { color: var(--ft-foreground); text-decoration: underline; }
.ft-quickcard {
  display: inline-flex; align-items: center; gap: var(--ft-space-2);
  padding: var(--ft-space-2) var(--ft-space-3); border-radius: var(--ft-radius-md);
  border: 1px solid var(--ft-border-hairline);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
  color: var(--ft-foreground); font: var(--ft-text-body); font-weight: 600; cursor: pointer;
  transition: border-color var(--ft-motion-fast) var(--ft-ease-forged), transform var(--ft-motion-fast) var(--ft-ease-forged);
}
.ft-quickcard:hover, .ft-quickcard:focus-visible { border-color: rgba(245,158,11,.28); transform: translateY(-1px); }
.ft-quickcard-go { color: var(--ft-ember-strong); font-weight: 700; }
.ft-quickrow-restore { margin-top: var(--ft-space-3); }

/* ---- Productive-density workspace primitives ---------------------------
   Reusable by Settings first, then other overview/detail pages. The primary
   workspace holds operational controls; the contextual rail holds status,
   next actions, and honest availability states. ------------------------- */
.ft-page-workspace {
  display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(250px, .72fr);
  gap: var(--ft-space-4); align-items: start;
}
.ft-primary-workspace, .ft-context-rail {
  display: flex; flex-direction: column; gap: var(--ft-space-4); min-width: 0;
}
.ft-group-section {
  overflow: hidden; border: 1px solid var(--ft-border-hairline);
  border-radius: var(--ft-radius-lg);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
  box-shadow: var(--ft-elev-1);
}
.ft-group-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--ft-space-3);
  padding: 14px var(--ft-space-4); border-bottom: 1px solid var(--ft-border-hairline);
}
.ft-group-title { margin: 0; color: var(--ft-foreground); font: var(--ft-text-body); font-weight: 650; }
.ft-group-description { margin-top: 3px; color: var(--ft-muted-2); font: var(--ft-text-caption); }
/* f-018 (2026-09-07 client light-mode audit): .ft-group-action/-icon and
   .ft-state-chip used to pair a var(--ft-ember-strong) (or hardcoded ember)
   TEXT color with a raw, theme-invariant `rgba(245,158,11,X)` BACKGROUND —
   correct on the dark palette these were authored against, but on
   [data-theme="light"] that fixed amber tint composites over the (now
   near-white) card at nowhere near the luminance the light palette's own
   darker --ft-ember-strong (#895e00) was chosen against, so text measured
   as low as 1.24:1. Backgrounds now color-mix() against the SAME token as
   the text (the established pattern .ft-badge--ok already uses correctly
   above), so the tint's luminance always tracks the current theme's own
   accent value instead of a fixed dark-mode literal. */
.ft-group-action {
  min-height: 36px; padding: 0 var(--ft-space-3); border-radius: var(--ft-radius-sm);
  border: 1px solid color-mix(in srgb, var(--ft-ember-strong, #f59e0b) 25%, transparent);
  background: color-mix(in srgb, var(--ft-ember-strong, #f59e0b) 8%, transparent);
  color: var(--ft-ember-strong, #efbd6c); font: var(--ft-text-caption); font-weight: 650; cursor: pointer;
}
.ft-group-row {
  width: 100%; display: grid; grid-template-columns: 36px minmax(0,1fr) auto;
  align-items: center; gap: var(--ft-space-3); padding: 13px var(--ft-space-4);
  border: 0; border-top: 1px solid rgba(255,255,255,.05); background: transparent;
  color: inherit; text-align: left; font-family: inherit;
}
button.ft-group-row { cursor: pointer; }
.ft-group-head + .ft-group-row { border-top: 0; }
button.ft-group-row:hover, button.ft-group-row:focus-visible { background: var(--ft-row-hover); }
.ft-group-icon {
  width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
  border-radius: 9px; background: color-mix(in srgb, var(--ft-ember-strong, #f59e0b) 11%, transparent);
  color: var(--ft-ember-strong, #f5b851);
  font: var(--ft-text-caption); font-weight: 700;
}
.ft-group-row-title { display: block; color: var(--ft-foreground-strong, #eee9e6); font: var(--ft-text-body); font-weight: 600; }
.ft-group-row-meta { display: block; margin-top: 3px; color: var(--ft-muted-2); font: var(--ft-text-caption); line-height: 1.45; }
.ft-state-chip {
  padding: 4px 8px; border-radius: var(--ft-radius-full);
  background: color-mix(in srgb, var(--ft-ember-strong, #f59e0b) 14%, transparent);
  color: var(--ft-ember-strong); font: var(--ft-text-caption); font-weight: 650; white-space: nowrap;
}
/* f-057 (2026-09-07): Settings' "Push notifications" row is dist/forge-push.js
   mounted at #forge-push-mount, which the markup gives class="ft-group-row"
   (docs/CRAWLER_TARPIT.md-adjacent — see dist/index.html's Settings section)
   so it lines up with every other settings row's padding/border. But
   .ft-group-row (above) is `display: grid; grid-template-columns: 36px
   minmax(0,1fr) auto` — built for the icon-span + text-span + trailing-span
   TRIPLET every other row's markup provides. forge-push.js (its own
   isolated module — see its header: "touches nothing else's DOM") renders
   exactly ONE child into that container once it mounts (.forge-push-control,
   wrapping a title/description/button, no icon), which the grid
   auto-placed straight into track 1 — the 36px icon column — collapsing it
   to a 36px-wide well the title/description text wrapped into one word per
   line, 304px tall. Both sides of that boundary meet in this one shared
   file: override the mount's own grid to a plain block (nothing else in
   .ft-group-row's declaration — border/padding/background — needs to
   change), then lay the control out with the SAME title/description
   typography .ft-group-row-title/.ft-group-row-meta use and the SAME
   secondary-button values .ft-btn--secondary uses (Phase 5A's canonical
   control vocabulary — see that class's own comment above: every module's
   own *-btn family mirrors these values rather than getting folded into one
   shared class name). */
#forge-push-mount.ft-group-row { display: block; }
.forge-push-control {
  display: flex; flex-wrap: wrap; align-items: center;
  column-gap: var(--ft-space-3); row-gap: 6px;
}
.forge-push-title {
  flex: 1 1 100%; display: block;
  color: var(--ft-foreground-strong, #eee9e6); font: var(--ft-text-body); font-weight: 600;
}
.forge-push-desc {
  flex: 1 1 220px; min-width: 0; display: block;
  color: var(--ft-muted-2); font: var(--ft-text-caption); line-height: 1.45;
}
.forge-push-btn {
  flex: none; margin-left: auto;
  display: inline-flex; align-items: center; gap: var(--ft-space-2);
  border-radius: var(--ft-radius-sm); padding: var(--ft-space-2) var(--ft-space-3);
  font: var(--ft-text-h2); cursor: pointer;
  background: rgba(255,255,255,.05); color: var(--ft-foreground); border: 1px solid var(--ft-border-hairline);
}
.forge-push-btn:hover, .forge-push-btn:focus-visible { border-color: rgba(255,255,255,.18); outline: none; }
.ft-context-card {
  padding: var(--ft-space-4); border: 1px solid var(--ft-border-hairline);
  border-radius: var(--ft-radius-lg);
  background: linear-gradient(180deg, var(--ft-surface-2), var(--ft-surface-2-end));
}
.ft-context-card-accent {
  border-color: rgba(245,158,11,.18);
  background: linear-gradient(145deg, rgba(245,158,11,.09), rgba(251,191,36,.025));
}
.ft-context-label { color: var(--ft-muted-foreground, #a88b63); font: var(--ft-text-caption); letter-spacing: .08em; text-transform: uppercase; }
.ft-context-value { color: var(--ft-foreground-strong); font: 600 25px/1.2 var(--ft-font-mono); }
.ft-progress-track { height: 6px; overflow: hidden; border-radius: var(--ft-radius-full); background: rgba(255,255,255,.06); }
.ft-progress-value { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg,var(--ft-ember),var(--ft-ember-strong)); }
.ft-context-copy { margin: 0; color: var(--ft-muted-2); font: var(--ft-text-caption); line-height: 1.55; }
.ft-context-action {
  width: 100%; min-height: 42px; margin-top: var(--ft-space-2); padding: var(--ft-space-2) 10px;
  border: 1px solid var(--ft-border-hairline); border-radius: 9px;
  background: rgba(255,255,255,.025); color: var(--ft-foreground-3, #d7cec7); font-family: inherit; text-align: left; cursor: pointer;
}
.ft-context-action strong, .ft-context-action span { display: block; }
.ft-context-action span { margin-top: 2px; color: var(--ft-muted-2); font: var(--ft-text-caption); }
@media (max-width: 860px) {
  .ft-page-workspace { grid-template-columns: 1fr; }
  .ft-context-rail { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); }
}
@media (max-width: 560px) {
  .ft-context-rail { display: flex; }
  .ft-group-head { align-items: flex-start; flex-direction: column; }
  .ft-group-action { width: 100%; }
  .ft-group-row { grid-template-columns: 34px minmax(0,1fr); }
  .ft-group-row > :last-child:not(:nth-child(2)) { grid-column: 2; justify-self: start; }
}

/* ---- 2026-09-05 web-audit + watchers (feat/enrichment-phase1) ------------- */
/* dist/app-web-audit.js (.wa-*) and dist/app-watchers.js (.wt-*) — layout/
   typography rules only; every color/spacing value is a var(--ft-*) token
   or reuses .ft-badge*/.ft-btn*/.ft-loading-state*/.ft-error-state*/
   .ft-empty-native*/.ft-gated-state* from above (design-system-unification-
   guard.test.mjs: no bespoke color, no new *-btn family). CSP policy for
   this wave forbids a runtime-injected <style> element, so these rules live
   here instead of in the module files themselves. */
.wa-root, .wt-root { width: 100%; max-width: none; padding: var(--ft-space-5) var(--ft-space-4) var(--ft-space-8); box-sizing: border-box; }
.wa-header, .wt-header { margin-bottom: var(--ft-space-4); }
.wa-header h1, .wt-header h1 { font: var(--ft-text-h1); margin-bottom: 2px; }
.wa-sub, .wt-sub { color: var(--ft-muted-foreground); font: var(--ft-text-body); max-width: 720px; margin-bottom: var(--ft-space-3); }
.wa-composer, .wt-composer { border: 1px solid var(--ft-border-hairline); border-radius: var(--ft-radius-md); padding: var(--ft-space-4); margin-bottom: var(--ft-space-4); background: var(--ft-surface-2); }
.wa-composer-note, .wt-composer-note { color: var(--ft-muted-foreground); font: var(--ft-text-caption); margin-bottom: var(--ft-space-3); }
.wa-field-label, .wt-field-label { display: block; font: var(--ft-text-caption); font-weight: 600; color: var(--ft-foreground); margin: var(--ft-space-2) 0 4px; }
.wa-input, .wt-input { display: block; width: 100%; max-width: 480px; box-sizing: border-box; font: inherit; padding: 8px 10px; border-radius: var(--ft-radius-sm); border: 1px solid var(--ft-border-hairline); background: transparent; color: inherit; margin-bottom: var(--ft-space-2); }
.wt-textarea { max-width: 640px; font-family: var(--ft-font-mono); resize: vertical; }
.wt-kind-fields { margin-top: var(--ft-space-2); }
.wt-checkbox-row { display: flex; align-items: center; gap: 8px; margin: var(--ft-space-2) 0; }
.wt-checkbox-row label { font: var(--ft-text-caption); color: var(--ft-foreground); }
.wa-actions, .wt-actions { display: flex; gap: var(--ft-space-2); align-items: center; flex-wrap: wrap; margin-top: var(--ft-space-2); }
.wa-score { font-weight: 600; color: var(--ft-foreground); cursor: help; }
.wa-score-banner { margin: var(--ft-space-2) 0 var(--ft-space-3); font: var(--ft-text-h2); }
.wa-muted, .wt-muted { color: var(--ft-muted-foreground); }
.wa-table, .wt-table { width: 100%; border-collapse: collapse; margin-bottom: var(--ft-space-4); }
.wa-table th, .wt-table th, .wa-table td, .wt-table td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--ft-border-hairline); font: var(--ft-text-caption); vertical-align: top; }
.wa-table thead th, .wt-table thead th { color: var(--ft-muted-foreground); text-transform: uppercase; letter-spacing: .06em; font-size: .68rem; }
.wa-row-host, .wt-row-name { font-weight: 600; color: var(--ft-foreground); }
.wa-page-url, .wt-row-url { font-family: var(--ft-font-mono); font-size: .78rem; word-break: break-all; }
.wt-row-last-error { color: var(--ft-crit); }
.wa-page-detail-row td { background: var(--ft-surface-1); }
.wa-counts { display: grid; grid-template-columns: repeat(auto-fit,minmax(120px,1fr)); gap: var(--ft-space-2); margin-bottom: var(--ft-space-4); }
.wa-count-tile { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; padding: var(--ft-space-2); border: 1px solid var(--ft-border-hairline); border-radius: var(--ft-radius-sm); }
.wa-count-tile strong { font-size: 1.3rem; }
.wa-issues { display: flex; flex-direction: column; gap: var(--ft-space-3); margin-bottom: var(--ft-space-4); }
.wa-issue-group-title { display: flex; align-items: center; gap: 8px; font: var(--ft-text-body); margin-bottom: var(--ft-space-2); }
.wa-issue-card, .wt-alert-card { border: 1px solid var(--ft-border-hairline); border-radius: var(--ft-radius-sm); padding: var(--ft-space-2) var(--ft-space-3); margin-bottom: var(--ft-space-2); }
.wa-issue-title { font-weight: 600; margin: 0 0 4px; }
.wa-issue-evidence, .wa-issue-fix { margin: 0 0 4px; color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.wa-crawl-facts { border-top: 1px solid var(--ft-border-hairline); padding-top: var(--ft-space-3); margin-bottom: var(--ft-space-4); }
.wa-crawl-list { margin: 0; padding-left: 1.2em; color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.wa-warn-item, .wt-warn-item { color: var(--ft-ember-strong); }
.wa-empty, .wt-empty { color: var(--ft-muted-foreground); padding: var(--ft-space-3) 0; }
.wa-detail-head, .wt-detail-head { display: flex; gap: var(--ft-space-2); align-items: center; margin-top: var(--ft-space-2); }
.wa-detail-url, .wt-detail-url { color: var(--ft-muted-foreground); font: var(--ft-text-caption); font-family: var(--ft-font-mono); word-break: break-all; margin-bottom: var(--ft-space-2); }
.wt-detail-meta { color: var(--ft-muted-foreground); font: var(--ft-text-caption); margin-bottom: var(--ft-space-2); }
.wt-preview-host { margin-bottom: var(--ft-space-2); }
.wt-preview { border: 1px dashed var(--ft-border-hairline); border-radius: var(--ft-radius-sm); padding: var(--ft-space-3); }
.wt-diff-pre { white-space: pre-wrap; word-break: break-word; max-height: 320px; overflow: auto; background: var(--ft-surface-1); border-radius: var(--ft-radius-sm); padding: var(--ft-space-2); font: var(--ft-text-caption); font-family: var(--ft-font-mono); }
.wt-alerts { display: flex; flex-direction: column; gap: var(--ft-space-2); margin-bottom: var(--ft-space-4); }
.wt-alert-head { display: flex; align-items: center; gap: 8px; margin: 0 0 4px; }
.wt-alert-when { color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.wt-alert-summary { margin: 0 0 4px; }
.wt-alert-details summary { cursor: pointer; color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
@media (max-width: 620px) {
  .wa-table, .wt-table { display: block; overflow-x: auto; }
}

/* ---- Tier D (2026-09-06): Live website chat — dist/app-conversations.js,
   dist/forge-chat-widget.js. `cv-` prefix for the agent-inbox page (this
   file is loaded only inside the Forge app shell, never on the tenant's own
   site — the widget's own CSS is self-injected by forge-chat-widget.js,
   scoped by its own class prefix, since it must ship with zero external
   stylesheet dependency). ---------------------------------------------- */
.cv-page { display: flex; flex-direction: column; gap: var(--ft-space-3); }
.cv-page-title { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -.02em; }
.cv-embed-panel { border: 1px solid var(--ft-border-hairline); border-radius: var(--ft-radius-sm); padding: var(--ft-space-3); }
.cv-embed-body { margin-top: var(--ft-space-2); display: flex; flex-direction: column; gap: var(--ft-space-2); }
.cv-embed-code { white-space: pre-wrap; word-break: break-all; background: var(--ft-surface-1); border-radius: var(--ft-radius-sm); padding: var(--ft-space-2); font: var(--ft-text-caption); font-family: var(--ft-font-mono); }
.cv-embed-field { display: flex; flex-direction: column; gap: 4px; font: var(--ft-text-caption); color: var(--ft-muted-foreground); }
.cv-embed-input { font: inherit; padding: 6px 8px; border-radius: var(--ft-radius-sm); border: 1px solid var(--ft-border-hairline); background: var(--ft-surface-0); color: var(--ft-foreground); }
.cv-body { display: flex; gap: var(--ft-space-3); min-height: 420px; }
.cv-list-panel { flex: 0 0 280px; display: flex; flex-direction: column; gap: var(--ft-space-2); border-right: 1px solid var(--ft-border-hairline); padding-right: var(--ft-space-3); }
.cv-filter-row { display: flex; gap: 6px; }
.cv-filter--active { background: var(--ft-accent-soft); }
.cv-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; overflow-y: auto; }
.cv-row-btn { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 10px; border-radius: var(--ft-radius-sm); border: 1px solid transparent; background: none; cursor: pointer; text-align: left; font: inherit; color: inherit; }
.cv-row--active .cv-row-btn { border-color: var(--ft-border-hairline); background: var(--ft-surface-1); }
.cv-row-name { font-weight: 500; }
.cv-row-meta { color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.cv-thread-panel { flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--ft-space-2); min-width: 0; }
.cv-thread-head { display: flex; flex-direction: column; gap: 4px; border-bottom: 1px solid var(--ft-border-hairline); padding-bottom: var(--ft-space-2); }
.cv-thread-title { margin: 0; font-size: 16px; font-weight: 600; }
.cv-thread-sub { margin: 0; color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.cv-thread-actions { display: flex; gap: 8px; }
.cv-link-contact { margin-top: 4px; }
.cv-lead-select { font: inherit; padding: 4px 8px; border-radius: var(--ft-radius-sm); border: 1px solid var(--ft-border-hairline); background: var(--ft-surface-0); color: var(--ft-foreground); }
.cv-msg-log { flex: 1 1 auto; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: var(--ft-space-2) 0; }
.cv-msg { max-width: 70%; padding: 8px 10px; border-radius: var(--ft-radius-sm); }
.cv-msg--visitor { align-self: flex-start; background: var(--ft-surface-1); }
.cv-msg--agent { align-self: flex-end; background: var(--ft-accent-soft); }
.cv-msg--system { align-self: center; color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.cv-msg-body { margin: 0 0 4px; white-space: pre-wrap; word-break: break-word; }
.cv-msg-time { color: var(--ft-muted-foreground); font: var(--ft-text-caption); }
.cv-composer { display: flex; gap: 8px; align-items: flex-end; border-top: 1px solid var(--ft-border-hairline); padding-top: var(--ft-space-2); }
.cv-composer-input { flex: 1 1 auto; font: inherit; padding: 8px; border-radius: var(--ft-radius-sm); border: 1px solid var(--ft-border-hairline); background: var(--ft-surface-0); color: var(--ft-foreground); resize: vertical; }
.cv-composer-error { color: var(--ft-ember-strong); font: var(--ft-text-caption); }
@media (max-width: 720px) {
  .cv-body { flex-direction: column; }
  .cv-list-panel { flex: none; border-right: none; border-bottom: 1px solid var(--ft-border-hairline); padding-right: 0; padding-bottom: var(--ft-space-2); }
}

/* ---- Accessibility: respect reduced-motion preference --------------------- */
@media (prefers-reduced-motion: reduce) {
  .ft-kpi-card,
  .ft-kpi-provenance,
  .ft-table-row,
  .ft-connector-card,
  .ft-btn,
  .ft-tooltip,
  .ft-widget,
  .ft-quickcard,
  .ft-quickrow-chip,
  .ft-anchor-pulse,
  .ft-loading-state-spinner,
  .ft-gated-state-cta,
  .ft-error-state-retry {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
  }
  .ft-kpi-card:hover, .ft-kpi-card:focus-visible { transform: none; }
}

/* ftl- : ForgeTimeline (dispatch-board timeline), dist/forge-timeline.js — 2026-09-06 */
.ftl-section { margin-top: 8px; }
.ftl-root { position: relative; overflow-x: auto; border: 1px solid var(--ft-border, #d8dde3); border-radius: 8px; background: var(--ft-surface, #fff); }
.ftl-grid { position: relative; min-width: 100%; }
.ftl-ticks { position: relative; height: 24px; border-bottom: 1px solid var(--ft-border, #d8dde3); }
.ftl-tick { position: absolute; top: 0; font-size: 11px; color: var(--ft-muted, #6b7280); padding-left: 4px; border-left: 1px solid var(--ft-border-faint, #e8ebef); height: 100%; }
.ftl-tick-major { border-left-color: var(--ft-border, #c3c9d1); font-weight: 600; }
.ftl-row { position: relative; display: flex; border-bottom: 1px solid var(--ft-border-faint, #e8ebef); }
.ftl-row-label { flex: 0 0 140px; padding: 8px; font-size: 12px; color: var(--ft-text, #1f2937); border-right: 1px solid var(--ft-border-faint, #e8ebef); }
.ftl-track { position: relative; flex: 1 1 auto; }
.ftl-bar { position: absolute; border-radius: 4px; background: var(--ft-accent, #3b6fe0); color: #fff; font-size: 11px; padding: 2px 6px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor: grab; }
.ftl-bar:focus-visible { outline: 2px solid var(--ft-focus, #1d4ed8); outline-offset: 1px; }
.ftl-bar-clipped { background: repeating-linear-gradient(45deg, var(--ft-accent, #3b6fe0), var(--ft-accent, #3b6fe0) 6px, rgba(255,255,255,0.25) 6px, rgba(255,255,255,0.25) 12px); }
.ftl-now { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--ft-danger, #dc2626); }
