/* ————————————————————————————————————————————————
   Fasset Business — design tokens
   Warm-paper light (primary) + dark themes.
   Bar: NATURAL-DESIGN-AUDIT.md — typographic scarcity,
   warm material color, no lines, ease-out physics.
   ———————————————————————————————————————————————— */

/* ————— self-hosted variable faces (no third-party font requests) ————— */

@font-face {
  font-family: "General Sans";
  src: url("../fonts/GeneralSans-Variable.woff2") format("woff2");
  font-weight: 200 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("../fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
/* font-display: swap, settled Oct 2026. `optional` let a slow first load keep
   the fallback for the whole page life, so General Sans and Geist Mono could
   silently never appear. Swap always arrives; the metric-matched fallback
   below keeps the swap from shifting the layout. Preload the General Sans
   woff2 on every page so the swap lands before first paint in practice. */
/* metric-compatible fallback — no layout shift while the woff2 arrives */
@font-face {
  font-family: "General Sans Fallback";
  src: local("Arial");
  size-adjust: 101.5%;
  ascent-override: 98%;
  descent-override: 25%;
  line-gap-override: 0%;
}

:root {
  /* surfaces — steps of lightness, never shadow */
  --bg: oklch(0.1684 0.0032 150);
  --bg-sunken: oklch(0.1543 0.0032 150);
  --surface: oklch(0.1913 0.0032 150);
  --surface-2: oklch(0.209 0.0032 150);
  --input: oklch(0.2002 0.0032 150);
  --bg-selected: oklch(0.2478 0.0034 150);
  --bg-hover: oklch(0.2178 0.0032 150);
  --overlay: oklch(0.2002 0.0032 150);

  /* lines — used sparingly; whitespace does the separating */
  --border: oklch(1 0 0 / 0.08);
  --border-faint: oklch(1 0 0 / 0.05);
  --border-strong: oklch(1 0 0 / 0.13);

  /* text. Both read 4.5:1 or better on every dark surface (BB R5B-18, Oct
     2026: faint was 3.2:1 and failed AA); faint stays a step under subtle. */
  --text-subtle: oklch(0.7200 0.005 140);
  --text-faint: oklch(0.6260 0.005 140);
  --text-default: oklch(0.9249 0.003 140);
  --text-strong: oklch(0.9851 0.002 140);

  /* ink — the chrome color. Buttons are ink, not brand. (dark: inverted) */
  --ink: oklch(0.9463 0.0057 140);
  --ink-down: oklch(0.8807 0.008 140);
  --on-ink: oklch(0.205 0.015 150);

  /* the one accent + status hues (dots and near-transparent tints only) */
  --accent: oklch(0.7475 0.1458 161.2);
  --accent-down: oklch(0.6698 0.134 161.1);
  --accent-tint: oklch(0.7475 0.1458 161.2 / 0.11);
  /* the accent and the red at the weight small text needs. Dark: the accent
     already clears 4.5:1; the red goes lighter against the dark sheet. */
  --accent-text: var(--accent);
  --negative: oklch(0.6829 0.1453 24.7);
  --negative-tint: oklch(0.6829 0.1453 24.7 / 0.1);
  --negative-text: oklch(0.7300 0.1400 24.7);
  --warning: oklch(0.7458 0.1097 70.0);
  --warning-tint: oklch(0.7458 0.1097 70.0 / 0.1);

  --on-accent: oklch(0.174 0.0194 164.2);

  /* type — Geist stays the default voice for legacy pages (landing,
     onboarding, films). The app overrides to General Sans in app.css. */
  --font: "Geist", -apple-system, system-ui, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
  --text-12: 12px;
  --text-13: 13px;
  --text-14: 14px;
  --text-16: 16px;
  --text-18: 18px;
  --text-20: 20px;
  --text-24: 24px;
  --text-30: 30px;
  --text-42: 42px;

  /* spacing. Derived from the designed screens (BB, Sep 2026): these steps
     carry 81% of every padding, margin and gap. A screen that needs a step
     not here has found a real gap: add it here, never in the screen. */
  --space-2: 2px;
  --space-4: 4px;
  --space-6: 6px;
  --space-8: 8px;
  --space-10: 10px;
  --space-12: 12px;
  --space-14: 14px;
  --space-16: 16px;
  --space-20: 20px;
  --space-24: 24px;
  --space-32: 32px;
  --space-36: 36px;
  --space-40: 40px;
  --space-44: 44px;
  --space-56: 56px;

  /* vertical rhythm, named for what it separates */
  --rhythm-heading-body: var(--space-6);
  --rhythm-body-actions: var(--space-16);
  --rhythm-item: var(--space-14);
  --rhythm-group: var(--space-32);
  --rhythm-section: var(--space-56);
  --rhythm-label: var(--space-8);
  --rhythm-hint: var(--space-6);
  --rhythm-field: var(--space-20);
  --rhythm-paragraph: var(--space-12);
  --rhythm-panel: var(--space-24);

  /* the page column and the small control height */
  --content-max: 1040px;
  --content-pad: var(--space-40);
  --control-sm: 28px;

  /* variable-font weights — interpolated, deliberately off the standard stops */
  --w-body: 450;
  --w-medium: 530;
  --w-title: 460;

  /* shape — instrument-grade: small radii, squared pills for chips */
  --r-tag: 4px;
  --r-control: 6px;
  --r-card: 8px;
  --r-overlay: 12px;
  /* the large floating surface: .main, .panel, .doc-sheet, bottom sheets */
  --r-surface: 16px;

  /* layers. One ladder for everything that floats. The selected row sits
     between the panel scrim and the panel (see .row.selected in app.css). */
  --z-sticky: 2;
  --z-scrim: 50;
  --z-selected: 51;
  --z-panel: 52;
  --z-cmdk: 60;
  --z-doc: 70;
  --z-overlay: 80;     /* select, menu, popover: above any panel or sheet */
  --z-toast: 90;
  --z-veil: 100;

  /* figures use the UI font with tabular-nums — aligned digits, no terminal look */
  --font-num: var(--font);

  /* elevation — dark mode: luminance stacking + pure-black float shadows */
  --hl: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  --elev-1: 0 1px 2px rgba(0, 0, 0, 0.35);
  --elev-2: 0 4px 14px rgba(0, 0, 0, 0.30), 0 1px 3px rgba(0, 0, 0, 0.30),
            inset 0 0 0 1px rgba(255, 255, 255, 0.05);
  --elev-3: 0 16px 48px rgba(0, 0, 0, 0.40), 0 4px 12px rgba(0, 0, 0, 0.30),
            inset 0 0 0 1px rgba(255, 255, 255, 0.07);
  --card-bg: var(--surface-2);
  --shadow-card: none;
  --shadow-card-hover: none;

  /* status carriers — dot hues; text stays neutral except errors */
  --st-neutral: oklch(0.649 0.0114 261.8);
  --st-positive: var(--accent);
  --st-warning: oklch(0.7458 0.1097 70.0);
  --st-error: oklch(0.6829 0.1453 24.7);

  /* curated category palette — assigned by name, never random */
  --cat-1: oklch(0.7083 0.1503 53.1); --cat-2: oklch(0.7455 0.1489 161.9); --cat-3: oklch(0.646 0.1423 253.9); --cat-4: oklch(0.6557 0.1677 288.0);
  --cat-5: oklch(0.6566 0.1614 8.1); --cat-6: oklch(0.7458 0.1097 70.0); --cat-7: oklch(0.7164 0.1025 188.6); --cat-8: oklch(0.6484 0.103 126.0);

  /* motion — a real easing library. Fast start, long soft landing.
     Everything decelerates into place; exits run faster than entrances. */
  --ease: cubic-bezier(0.215, 0.61, 0.355, 1);          /* out-cubic — the workhorse */
  --ease-out-soft: cubic-bezier(0.16, 1, 0.3, 1);       /* out-expo — draw-ins, hero entrances */
  --ease-snappy: cubic-bezier(0.23, 1, 0.32, 1);        /* out-quint — pops, toggles, menus */
  --ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);        /* sheets & side panels */
  --dur-1: 120ms;
  --dur-2: 160ms;
  --dur-3: 200ms;
  --dur-enter: 260ms;
  --dur-exit: 120ms;
  --dur-pop: 180ms;    /* select, menu and popover entrance */

  /* overlay shadow alias (legacy name → elevation-3) */
  --overlay-shadow: var(--elev-3);
  /* the dim layer under a panel or a bottom sheet */
  --scrim: rgba(0, 0, 0, 0.35);

  --focus-ring: oklch(0.7475 0.1458 161.2 / 0.55);

  color-scheme: dark;
}

/* ————— light — the primary theme. Warm paper, green-cast neutrals,
   ink chrome. Nothing pure white-on-white; every gray carries the
   brand's temperature. ————— */
[data-theme="light"] {
  --bg: oklch(0.9946 0.0018 120);            /* warm near-white paper */
  --bg-sunken: oklch(0.9672 0.0062 122);     /* linen — the app wallpaper */
  --surface: oklch(0.9946 0.0018 120);
  --surface-2: oklch(0.9748 0.0048 120);
  --input: oklch(0.9946 0.0018 120);
  --bg-selected: oklch(0.9531 0.0065 125);
  --bg-hover: oklch(0.9707 0.0048 120);
  --overlay: oklch(0.9968 0.0012 120);

  --border: oklch(0.9269 0.006 120);
  --border-faint: oklch(0.9524 0.0048 120);
  --border-strong: oklch(0.8792 0.0085 120);

  /* darkened Oct 2026 (BB R5B-18): faint measured 2.9:1 and failed AA; both
     now reach 4.5:1 on every light surface, faint a visible step under subtle */
  --text-subtle: oklch(0.4600 0.0088 130);
  --text-faint: oklch(0.5340 0.0072 125);
  --text-default: oklch(0.2811 0.0093 140);
  --text-strong: oklch(0.2019 0.0108 145);   /* warm ink, never #000 */

  --ink: oklch(0.2331 0.0231 152);           /* green-cast black — the button color */
  --ink-down: oklch(0.3054 0.0262 152);
  --on-ink: oklch(0.9861 0.0025 120);

  --accent: oklch(0.6061 0.1275 162.0);
  --accent-down: oklch(0.5324 0.1119 161.9);
  --accent-tint: oklch(0.6061 0.1275 162.0 / 0.09);
  /* small-text versions: --accent is 3.6:1 and --negative 4.08:1 on paper.
     Dots, icons, chart lines and large figures keep the base hue. */
  --accent-text: oklch(0.5160 0.1275 162.0);
  --negative: oklch(0.6113 0.1641 25.4);
  --negative-tint: oklch(0.6113 0.1641 25.4 / 0.08);
  --negative-text: oklch(0.5200 0.1800 25.4);
  --warning: oklch(0.6293 0.1129 68.7);
  --warning-tint: oklch(0.6293 0.1129 68.7 / 0.09);

  --on-accent: oklch(1 0 0);

  /* elevation — ink-tinted, near-invisible: 1px contact + soft ambient.
     Never a generic gray blob. */
  --hl: none;
  --elev-1: 0 1px 1px rgba(20, 26, 18, 0.05), 0 3px 6px -2px rgba(20, 26, 18, 0.03);
  --elev-2: 0 0 1px rgba(20, 26, 18, 0.06), 0 4px 12px rgba(20, 26, 18, 0.07);
  --elev-3: 0 0 1px rgba(20, 26, 18, 0.08), 0 8px 28px 4px rgba(10, 14, 8, 0.09);
  --card-bg: oklch(1 0 0);
  --shadow-card: 0 0 0 1px rgba(20, 26, 18, 0.028),
                 0 1px 1px rgba(20, 26, 18, 0.04),
                 0 3px 6px -2px rgba(20, 26, 18, 0.02);
  --shadow-card-hover: 0 0 0 1px rgba(20, 26, 18, 0.035),
                       0 1px 12px 4px rgba(20, 26, 18, 0.05),
                       0 3px 6px -2px rgba(20, 26, 18, 0.02);

  --st-neutral: oklch(0.6224 0.0154 140);
  --st-positive: var(--accent);
  --st-warning: oklch(0.6293 0.1129 68.7);
  --st-error: oklch(0.6113 0.1641 25.4);

  --cat-1: oklch(0.6594 0.1516 50.6); --cat-2: oklch(0.6061 0.1275 162.0); --cat-3: oklch(0.5947 0.1473 255.4); --cat-4: oklch(0.5708 0.1754 286.4);
  --cat-5: oklch(0.6026 0.1654 9.0); --cat-6: oklch(0.6293 0.1129 68.7); --cat-7: oklch(0.6329 0.0985 188.0); --cat-8: oklch(0.5828 0.0997 127.1);

  --overlay-shadow: var(--elev-3);
  --scrim: rgba(18, 24, 14, 0.16);

  /* focus is ink, not brand: the quiet tell. 0.55, not 0.35: 0.35 measured
     2.23:1 on paper and WCAG 1.4.11 asks 3:1 of a focus indicator. */
  --focus-ring: oklch(0.2019 0.0108 145 / 0.55);

  color-scheme: light;
}

/* ————— base ————— */

html, body {
  overscroll-behavior-y: none;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text-default);
  font-family: var(--font);
  font-size: var(--text-13);
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-variant-numeric: tabular-nums;
  font-synthesis: none;
  -webkit-tap-highlight-color: transparent;
}

/* headings: tighter leading, balanced wrap, a touch of negative tracking */
h1, h2, h3, h4 {
  margin: 0; font-weight: var(--w-medium); color: var(--text-strong);
  line-height: 1.15; letter-spacing: -0.011em; text-wrap: balance;
}
p { margin: 0; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
input, select, textarea { font: inherit; color: var(--text-default); }
/* keep inputs >=16px on mobile so iOS Safari doesn't zoom the page on focus */
@media (max-width: 640px) {
  input, select, textarea { font-size: 16px; }
}
::placeholder { color: var(--text-faint); }
strong { font-weight: var(--w-medium); }

:focus { outline: none; }
:focus-visible {
  outline: 1.5px solid var(--focus-ring);
  outline-offset: 2px;
}

/* selection is ink at 10% — even highlighting is on-system */
::selection { background: oklch(0.7475 0.1458 161.2 / 0.25); }
[data-theme="light"] ::selection { background: oklch(0.2019 0.0108 145 / 0.11); }

.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; line-height: 1.2; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ————— layout primitives: vertical rhythm between siblings —————
   A stack puts one gap between its children from the rhythm tokens, so no
   screen writes its own margin to space things out. Written .stack.stack so
   the gap outranks a margin a child brings for itself. */
.stack.stack > * { margin-block: 0; }
.stack.stack > * + * { margin-top: var(--stack-gap, var(--rhythm-item)); }
.stack.stack > :is(h1, h2, h3, h4, .stack-h) + * { margin-top: var(--rhythm-heading-body); }
.stack.stack > .stack-actions { margin-top: var(--rhythm-body-actions); }
.stack-tight { --stack-gap: var(--rhythm-heading-body); }
.stack-group { --stack-gap: var(--rhythm-group); }
.stack-section { --stack-gap: var(--rhythm-section); }
/* the inline sibling: things in a row with one gap, wrapping when they must */
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cluster-gap, var(--space-8)); }
.cluster > * { margin: 0; }
.cluster-links { --cluster-gap: var(--space-16); }
.cluster-end { justify-content: flex-end; }
/* a row of buttons: one family, one gap, level by construction */
.stack-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-8); }
.stack-actions.stack-actions > * { margin: 0; }
