/* ===========================================================================
 * Troph-e design tokens
 *
 * Every value here is traced to a section of
 * internal-docs/design-system/styleguide.md, which derived them by pixel
 * sampling and arc fitting the 12 mockup frames. Nothing is invented. Where
 * the styleguide is silent, this file says so and leaves the gap.
 *
 * THIS IS THE ONLY FILE ALLOWED TO CONTAIN RAW HEX, PX OR MS VALUES.
 * test/lint/css_token_lint_test.rb enforces that. Everything else consumes
 * var(--…). If you need a value that is not here, add it here first.
 * =========================================================================== */

@import url("https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,600&display=swap");

:root {
  /* -------------------------------------------------------------------------
   * §2.1 The base — an ambient gradient, not a background colour
   *
   * No screen has a flat background. Two large soft olive-gold glows sit on the
   * ANTI-DIAGONAL: top-right and bottom-left. Measured on 01-dashboard-v1.png,
   * TR (944,80) #3F371D is the brightest point, TL (30,90) #0A0904 the darkest.
   * Mobile shows the identical pattern — this is ONE system across both
   * platforms, not a separate, more neutral mobile theme.
   * ---------------------------------------------------------------------- */
  --bg-base: #0B0A04;            /* warm near-black */
  --bg-glow: #3F371D;            /* olive-gold ambient light, top-right */
  --bg-glow-secondary: #3A331A;  /* the dimmer bottom-left glow */

  /* Applied to body in base.css. Kept here so the two glow stops stay beside
     the colours they use. */
  --bg-ambient:
    radial-gradient(120% 90% at 100% 0%, var(--bg-glow) 0%, transparent 60%),
    radial-gradient(120% 90% at 0% 100%, var(--bg-glow-secondary) 0%, transparent 60%),
    var(--bg-base);

  /* -------------------------------------------------------------------------
   * §2.2 Surfaces — translucent white washes. THE LOAD-BEARING DECISION.
   *
   * Cards are NOT filled with a colour. They are white at low alpha over the
   * gradient above. Every card in the mocks is measurably brighter on its
   * glow-facing side: one card fill drifts #242219 → #2C281E across 296px.
   *
   * Flatten any of these to hex and the entire depth model dies — cards stop
   * sitting IN the gradient and start floating ON it as flat grey rectangles.
   * Each level stacks on the one below, so a chip inside a card lands at
   * roughly 21% effective white. That stacking IS the depth model (§6).
   *
   * The alphas below were solved independently on desktop and mobile renders
   * and agreed to within ±0.003. They are measurements, not taste.
   * ---------------------------------------------------------------------- */
  --surface-1: rgba(255, 255, 255, 0.10);    /* cards, panels, list containers  (0.098 / 0.096) */
  --surface-2: rgba(255, 255, 255, 0.12);    /* card nested in a card; chips     (0.122 / 0.125) */
  --surface-3: rgba(255, 255, 255, 0.145);   /* status pills on a table row      (0.145)         */
  --surface-header: rgba(255, 255, 255, 0.055); /* table header row              (0.055)         */
  --surface-input: transparent;              /* inputs — the border does the work (0.015 ≈ none) */

  --border-default: rgba(255, 255, 255, 0.18); /* card and input borders, 1px  (0.188/0.199/0.205) */
  --divider: rgba(255, 255, 255, 0.12);        /* table row separators, top-bar underline (0.123) */

  --border-width: 1px;

  /* -------------------------------------------------------------------------
   * §2.3 Gold — the only chromatic colour in the entire interface
   *
   * Every other hue in a mock (trophy renders, club crests, photography) is
   * CONTENT, not chrome. Introducing a second UI hue is a real departure.
   *
   * --gold-500 is not a separate colour: #F5D673 at 80% over the dark base
   * computes to #CEB462, which is #D0B461 to within rounding. So the rule is
   * ONE gold at TWO opacities — 80% at rest, 100% when selected or active.
   * That is the whole interactive-border language.
   * ---------------------------------------------------------------------- */
  --gold-100: #F5D673;  /* selected card border, active stepper ring, gradient start */
  --gold-300: #F2D371;  /* gold text — outline-button labels, "Back" links */
  --gold-500: #D0B461;  /* resting outline-button border (= gold-100 @ 80%) */
  --gold-700: #AE9552;  /* gradient end */
  --gold-900: #937F48;  /* deepest sampled tone */

  /* Horizontal, left-to-right, and genuinely flat vertically — a vertical scan
     down the primary button returns a constant #D1B561. Verified identical on
     the desktop "Create New Troph-e" and the mobile "Share" buttons, so this is
     a real shared token and not two hand-tuned fills. Also used on the logo
     mark, the hamburger tile, the donut arc and the active pagination dot. */
  --gradient-gold: linear-gradient(90deg, var(--gold-100) 0%, var(--gold-700) 100%);

  --gold-rest-opacity: 0.8;
  --gold-active-opacity: 1;

  /* -------------------------------------------------------------------------
   * §2.4 Text
   * ---------------------------------------------------------------------- */
  --text-primary: #FFFFFF;                       /* headings, values, field labels */
  --text-secondary: rgba(255, 255, 255, 0.80);   /* row labels, body copy       → #D4D4D2 */
  --text-tertiary: rgba(255, 255, 255, 0.70);    /* metadata, timestamps        → #BDBCBB */
  --text-placeholder: rgba(255, 255, 255, 0.55); /* input placeholders          → #A9A8A3 */
  --text-gold: #F2D371;                          /* links, outline-button labels */
  --text-on-gold: #141316;                       /* labels on gold fills (darkest measured) */

  /* -------------------------------------------------------------------------
   * §2.5 Semantic colour — DELIBERATELY ABSENT. See D15.
   *
   * Across all 12 frames there is no success, warning, error or info colour.
   * The Trophy History Log carries status with a neutral white-wash pill
   * ("Shared") versus de-emphasised plain text ("Not Shared") — no colour.
   *
   * This is a genuine unmade design decision, and a hard one: a conventional
   * red fights the gold and a conventional green looks alien beside it. Do not
   * fill this gap casually. Whoever designs the destructive-action, validation
   * and credit-exhausted states owns it.
   * ---------------------------------------------------------------------- */

  /* -------------------------------------------------------------------------
   * §3 Typography
   *
   * THE TYPEFACE IS A PLACEHOLDER (D14). The FigJam board carries no font
   * metadata. §3 identifies the letterform DNA confidently — geometric sans,
   * double-storey `a`, single-storey `g` with an open hooked descender — but
   * refuses to name the font, and directs DM Sans as the closest freely
   * licensed match. Chase the real font from whoever built the Accelerate mocks.
   *
   * Every size below assumes a 0.71 cap ratio. A different typeface shifts them
   * by up to a pixel. Two weights only: no light, no black, no italics anywhere.
   * ---------------------------------------------------------------------- */
  --font-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --font-weight-regular: 400;
  --font-weight-semibold: 600;

  --type-display-size: 24px;   --type-display-leading: 28px;  /* desktop page title, donut % */
  --type-h2-size: 20px;        --type-h2-leading: 26px;       /* wizard panel title; mobile hero name */
  --type-h3-size: 18px;        --type-h3-leading: 23px;       /* card and section titles */
  --type-body-lg-size: 16px;   --type-body-lg-leading: 21px;  /* input values; mobile screen titles */
  --type-body-size: 14px;      --type-body-leading: 20px;     /* labels, buttons, nav, table cells */
  --type-caption-size: 12px;   --type-caption-leading: 16px;  /* metadata, timestamps (16–18 observed) */

  /* -------------------------------------------------------------------------
   * §4 Spacing — base unit 4. Observed: 4, 8, 12, 16, 20, 24, 32, 40, 64.
   * The scale is deliberately gappy: --space-7 (28px) and --space-9 (36px) are
   * absent because they never appear in the mocks. Do not add them casually.
   * ---------------------------------------------------------------------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-16: 64px;

  --stepper-pitch: 60px;   /* §4, the one value off the 4px scale */

  /* -------------------------------------------------------------------------
   * §5 Corner radii
   *
   * D16: the 16px desktop / 12px mobile split is COMMITTED TO, not unified.
   * It is measured, real, and matches the two postures in §9.
   * D17: every input is --radius-sm, including the history-log search field,
   * which the mocks draw as a pill — §5 calls that "almost certainly an
   * oversight" and it is the only input in 12 frames that differs.
   * ---------------------------------------------------------------------- */
  --radius-pill: 999px;  /* buttons, chips, status pills */
  --radius-lg: 16px;     /* DESKTOP cards and panels; the app window frame */
  --radius-md: 12px;     /* MOBILE cards; the gold icon tile; nested cards */
  --radius-sm: 8px;      /* inputs, textareas, the multi-select list box */

  /* -------------------------------------------------------------------------
   * §4 Shell geometry — the two postures in §9
   * ---------------------------------------------------------------------- */
  --shell-admin-width: 960px;
  --shell-admin-content: 920px;   /* dashboard/table pages, 20px page padding */
  --shell-player-width: 393px;
  --topbar-height: 76px;          /* identical on both platforms */
  /* Where anything sticky in the admin shell stops: clear of the pinned top
     bar, with the same breathing room it had before the bar stayed put (D170). */
  --sticky-offset: calc(var(--topbar-height) + var(--space-5));
  --rail-width: 274px;            /* wizard screens only */
  --panel-width: 622px;           /* wizard content panel, at x=306 */
  --wizard-rail-width: 240px;     /* the step tracker's column, left of the panel */
  --wizard-tile-min: 220px;       /* two design tiles per row in the 622px panel, as drawn */
  --wizard-preview-width: 240px;  /* the Troph-e Preview card beside the plaque fields */
  --wizard-preview-art-height: 120px;

  --icon-size: 24px;
  --icon-tile-size: 40px;         /* F05's brand-variant icon tile, 12px radius */
  --brand-wordmark-height: 14px;  /* TROPH-E's cap height, about the old 18px semibold wordmark's */
  --brand-mark-height: calc(var(--brand-wordmark-height) * 349 / 274); /* the mark to the wordmark, as troph-e.app draws them */
  --brand-gap: var(--space-1);
  --icon-decorative-size: 45px;
  --button-height: 40px;
  --table-row-height: 56px;
  --touch-target-min: 44px;       /* not from the mocks — an accessibility floor */

  /* -------------------------------------------------------------------------
   * §6 Depth — there are NO drop shadows anywhere in 12 frames.
   *
   * Depth is built from exactly three things: the translucent-wash stack, 1px
   * borders at 18% white, and the ambient glow behind everything. Adding a
   * box-shadow would be visibly foreign. If a new surface must read as raised,
   * the honest extension is another wash level plus a brighter border.
   * There is deliberately no --shadow-* token here.
   * ---------------------------------------------------------------------- */

  /* -------------------------------------------------------------------------
   * Focus ring — NOT from the mocks. §10 records that no focus state is drawn
   * anywhere, and warns that a default browser outline looks broken on this
   * palette and that gold-on-gold will not read against gold borders.
   *
   * Solved once, centrally, and the offset is the mechanism: a 2px gap pushes
   * the ring off the component and onto the near-black base, so a white ring
   * reads at full strength against BOTH a dark card and a gold-filled button.
   * That is why the offset is a token and not a decoration.
   * ---------------------------------------------------------------------- */
  --focus-ring-colour: rgba(255, 255, 255, 0.95);
  --focus-ring-outline: 2px solid var(--focus-ring-colour);
  --focus-ring-offset: 2px;

  /* -------------------------------------------------------------------------
   * Motion — §10: nothing is specified anywhere in the source. The product's
   * core promise is ANIMATED trophies, so the Spotlight reveal is arguably the
   * most important undesigned artefact in the product.
   *
   * These two are a conservative baseline for chrome only (a hover, a
   * disclosure). They are not a motion language and must not be used to
   * improvise the reveal.
   * ---------------------------------------------------------------------- */
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --easing-standard: cubic-bezier(0.2, 0, 0, 1);

  /* -------------------------------------------------------------------------
   * Scaffolding tokens — NOT from the mocks. The 12 frames have no overlay
   * layer and no styleguide page, so these values were never measured; they
   * are reasonable defaults, not derived data, and should be revisited if a
   * real overlay design or styleguide layout is ever specified.
   * ---------------------------------------------------------------------- */
  --blur-overlay: 12px;      /* shells.css sticky CTA backdrop-filter */
  --grid-min-column: 200px;  /* styleguide.css swatch grid minmax() floor */
  /* =========================================================================
   * THE 2026-09-01 DESIGN SESSION — D27 to D31.
   *
   * Everything below this line closes a gap the sections above deliberately
   * left open, and each one is a real decision, not an inference. The
   * provenance is the design hand-off package (semantic colour, the overlay
   * layer, and the full interaction-state set for every control), which
   * supersedes §2.5's "deliberately absent" and §10's "undesigned" where the
   * two disagree. Read D27–D31 in docs/decisions.md before changing any of it.
   * ====================================================================== */

  /* -------------------------------------------------------------------------
   * D27 — Semantic colour. §2.5 above said this was absent and warned that a
   * conventional red fights the gold and a conventional green looks alien
   * beside it. Both warnings stand; the answer is to stay inside the warm
   * family. Brick and moss are desaturated enough to sit next to gold without
   * competing, and they are the ONLY two hues allowed to join it.
   *
   * NEVER introduce #FF0000-family red or #00C853-family green. Warning has no
   * colour of its own — it reuses gold. Neutral/informational status has no hue
   * at all: it stays a --surface-3 pill, exactly as the mocks drew it.
   * ---------------------------------------------------------------------- */
  --success: #A8B26E;                            /* moss — borders, icon strokes */
  --success-text: #BCC488;                       /* lifted for text contrast on dark */
  --success-wash: rgba(168, 178, 110, 0.16);
  --success-border: rgba(168, 178, 110, 0.45);
  --success-surface: rgba(52, 52, 34, 0.94);     /* toast body, moss-tinted */

  --danger: #C98268;                             /* brick — borders, icon strokes */
  --danger-text: #D69078;                        /* lifted for text contrast on dark */
  --danger-wash: rgba(201, 130, 104, 0.14);
  --danger-border: rgba(201, 130, 104, 0.45);
  --danger-rest: rgba(201, 130, 104, 0.7);       /* resting destructive-button border */
  --danger-wash-hover: rgba(201, 130, 104, 0.10);
  --danger-wash-active: rgba(201, 130, 104, 0.16);
  --danger-field-wash: rgba(201, 130, 104, 0.06); /* invalid input fill — quieter than a pill */
  --danger-surface: rgba(56, 44, 36, 0.94);      /* toast body, brick-tinted */

  /* Warning has no hue of its own. It is gold, at pill strength. */
  --warning-wash: rgba(245, 214, 115, 0.10);
  --warning-border: rgba(245, 214, 115, 0.45);

  /* -------------------------------------------------------------------------
   * D28 — The interactive gold ramp.
   *
   * §2.3 established one gold at two opacities. That covers rest and selected;
   * it does not cover hover and active, which no mock draws. The rule the
   * hand-off settles on: FILLED gold shifts the gradient (hover lifts it about
   * 6%, active darkens it), OUTLINE gold keeps its border and gains a wash.
   * Neither ever changes opacity — that treatment belongs to `disabled` alone,
   * so the two can never be confused.
   * ---------------------------------------------------------------------- */
  --gold-rest: rgba(245, 214, 115, 0.8);         /* == --gold-500, as a border alpha */
  --gradient-gold-hover: linear-gradient(90deg, #FBE38C 0%, #BCA25C 100%);
  --gradient-gold-active: linear-gradient(90deg, #D9BC62 0%, #96803F 100%);
  --gold-wash-hover: rgba(245, 214, 115, 0.08);
  --gold-wash-active: rgba(245, 214, 115, 0.14);
  --gold-wash-selected: rgba(245, 214, 115, 0.13); /* selectable tile, selected */
  --gold-halo: rgba(245, 214, 115, 0.18);        /* the soft ring on a focused input */

  --opacity-disabled: 0.35;

  /* Hover washes for whole rows and list items. A table row is quieter than a
     menu item because there are twenty of them on screen and one of it. */
  --surface-hover-row: rgba(255, 255, 255, 0.04);
  --surface-hover-item: rgba(255, 255, 255, 0.07);
  --surface-selected: rgba(255, 255, 255, 0.10);  /* selected listbox option, active menu item */

  /* Inputs in states the mocks never drew. --surface-input stays `transparent`
     (the lint test asserts it exactly): the hand-off's 0.015 alpha is under
     half a value of 255 over this base and is not distinguishable from none.
     Disabled is visible, because the point of it is to look switched off. */
  --surface-input-disabled: rgba(255, 255, 255, 0.03);
  --border-input-disabled: rgba(255, 255, 255, 0.10);
  --border-control: rgba(255, 255, 255, 0.4);    /* unchecked radio and checkbox ring */
  --text-disabled: rgba(255, 255, 255, 0.30);
  --text-label-disabled: rgba(255, 255, 255, 0.45);
  --text-muted: rgba(255, 255, 255, 0.6);        /* inactive tab-bar item */
  --text-option: rgba(255, 255, 255, 0.85);      /* unselected listbox/menu option */

  /* -------------------------------------------------------------------------
   * D29 — The overlay layer, without a shadow.
   *
   * §6 records that 12 frames contain no drop shadow, and that adding one
   * would look visibly foreign. But a modal has to read as floating above the
   * page, and every other system on earth solves that with a shadow.
   *
   * This one solves it with the three things the system already has: a scrim
   * that darkens what is behind, a WARM TINTED surface (not another white
   * wash — a wash over a scrim goes muddy), and a border brighter than any
   * card's. The blur does the rest. Still no shadow, anywhere.
   * ---------------------------------------------------------------------- */
  /* The two CONTENT plates. Neither is chrome, and neither is a wash — a
     trophy render needs a darker ground than any surface so the render's own
     light reads, and a club crest needs a light one because crests are drawn
     for white paper. The cream plate is the only light surface in the system
     and it exists solely to make somebody else's logo legible. */
  --plate-render: #050402;
  --artwork-max-width: 420px;      /* the render frame on the 920px admin surface */

  /* The prompt library, in the platform admin.
     --prompt-compare-min is the narrowest a comparison column may get before
     the two sides stack: below this a rendered trophy and its prompt are both
     too small to judge, and judging them is the entire purpose of the screen.
     --prompt-art-size is the square a trial's image is drawn at — trophies are
     generated 1:1 (see the seeded request options), so a square frame crops
     nothing. */
  --prompt-compare-min: 320px;
  --prompt-model-min: 220px;     /* a model comparison column: five fit the workbench width (D134, D149) */
  --prompt-art-size: 280px;
  --prompt-palette-min: 180px;

  /* THE PLATFORM ADMIN'S FRAME — 1280 on every one of its pages (D170).
     It began as the prompt workbench's alone: the founders rewrite prompts on
     1280-1600px laptops and every workbench page is words beside the pictures
     they produce. It was a page's opt-in, and the logo and tabs moved sideways
     between two tabs, so it became the role's: set by the layout from the
     acting role, never by a page. The club admin's frame stays at the drawn 960.
     --workbench-side-width is the pinned right column on the version page and
     the editor: wide enough for a 2x2 grid of draws a person can actually see,
     narrow enough to leave the prose a readable measure.
     --prompt-art-large is a single trial's picture on its own page. 280 was the
     cap everywhere, including in a 920px card; a 1K render deserves more.
     --prompt-editor-min/max bound the body textarea, which now grows with its
     text instead of scrolling inside a scrolling page. */
  --shell-workbench-width: 1280px;
  --workbench-side-width: 440px;
  --prompt-art-large: 640px;
  --prompt-editor-min: 320px;
  --prompt-editor-max: 2400px;
  --prompt-prose-measure: 72ch;
  --workbench-field-min: 170px;    /* two draw-form fields across the side column */
  --workbench-picker-width: 300px; /* a version picker: "v12 · Previously live — …" */
  --workbench-picker-narrow: 200px;/* the version switcher in the page header */
  --workbench-count-width: 88px;   /* the 1-3 count beside "Draw N more" */
  --artwork-batch-min: 260px;      /* one frame per recipient, several across */
  --plate-crest: #F2EDDE;

  --scrim: rgba(5, 4, 2, 0.7);
  --scrim-blur: 3px;
  --overlay-surface: rgba(44, 40, 26, 0.92);
  --overlay-blur: 24px;
  --border-raised: rgba(255, 255, 255, 0.26);

  /* -------------------------------------------------------------------------
   * D30 — Focus, resolved as a ring whose COLOUR depends on the component.
   *
   * The ring above (--focus-ring-outline, white, offset 2px) was solved before
   * any component existed, against §10's warning that gold-on-gold will not
   * read. That warning is real but narrower than it looked: it only applies to
   * components that are THEMSELVES gold.
   *
   * So the ring keeps the foundation's geometry — 2px wide, 2px clear of the
   * component — and only its colour changes. Gold on a neutral component; it
   * is the brand colour and it is what the eye looks for. White on a
   * gold-filled one, where a gold ring would vanish. Brick on a destructive
   * one, so the warning colour carries through to the keyboard path.
   *
   * These are OUTLINE colours, not box-shadows. The hand-off draws the ring as
   * `box-shadow: 0 0 0 2px #0B0A04, 0 0 0 4px #F5D673` — a painted gap of base
   * colour and then the ring — and that is not used here, for two reasons.
   * A box-shadow is clipped by any `overflow: hidden` ancestor, which the
   * table, the check list and the thumbnail all have; and the repo bans
   * box-shadow outright, which is the better rule, because every legitimate
   * use of one on this palette has an outline equivalent. The painted gap
   * costs nothing to lose: an outline-offset gap shows whatever is behind the
   * component, and on this system that is always near-black or a dark wash.
   * ---------------------------------------------------------------------- */
  --focus-colour-neutral: var(--gold-100);
  --focus-colour-on-gold: var(--focus-ring-colour);
  --focus-colour-danger: var(--danger);

  /* Inputs do not take the offset ring at all. They already have a border in
     exactly the right place, so focus recolours that border to full gold and
     lays a soft translucent halo flush against it — the field lighting up,
     rather than a ring drawn around it. */
  --focus-halo-width: 3px;

  /* -------------------------------------------------------------------------
   * D31 — Control geometry the shells did not need but components do.
   * ---------------------------------------------------------------------- */
  /* The resting height of an INPUT. Equal to --button-height today and kept
     separate on purpose: a taller field is a plausible future change and it
     should not silently move every button with it. */
  --control-height: 40px;
  --control-height-mobile: 44px;   /* every input grows on the player surface */
  --cta-height: 48px;              /* the sticky mobile CTA, taller than a button */
  --control-indicator: 24px;       /* radio and checkbox box */
  --control-indicator-dot: 12px;   /* the gold dot inside a selected radio */
  --radius-control: 6px;           /* checkbox corner — smaller than --radius-sm */
  --stepper-circle: 28px;
  --stepper-connector: 24px;
  --pagination-size: 28px;
  --table-header-height: 40px;
  --tabbar-icon-label: 11px;       /* the one type size below --type-caption */
  --thumb-sm: 48px;                /* timeline item thumbnail */
  --thumb-md: 64px;                /* award list row thumbnail */
  --cabinet-card-max: 296px;       /* DD09 strip card; on the 353px player column the card is narrower still, so the next one peeks */
  --donut-size: 140px;   /* the figure; the arc's own width is in the SVG's
                            user units and lives beside its radius in the component */
  --textarea-height: 150px;   /* the personalise-message field */
  --checklist-height: 280px;  /* the recipient list, about seven rows */
  /* Stacking order. Four levels: the player's bottom tab bar, which is chrome
     the page scrolls under; a popover anchored to a control; a modal that owns
     the screen; and a toast that must sit over all of them because it reports
     on what the modal just did. The tab bar is lowest — a modal covers it, and
     it covers only page content and the sticky CTA that shares its edge. */
  --z-banner: 40;     /* the analytics banner (D217): over page content, under every bar, menu and listbox */
  --z-tabbar: 50;
  --z-topbar: 50;     /* the admin top bar, pinned while the page scrolls under it */
  --z-popover: 100;
  --z-modal: 200;
  --z-toast: 300;

  --border-empty: rgba(255, 255, 255, 0.25);  /* the dashed empty-state edge */
  --surface-skeleton-2: rgba(255, 255, 255, 0.08);
  --surface-skeleton-3: rgba(255, 255, 255, 0.06);
  --skeleton-bar: 14px;
  --duration-shimmer-step: 200ms;   /* stagger between skeleton bars */

  --divider-strong: rgba(255, 255, 255, 0.2);   /* stepper connector, timeline rail */
  --border-pending: rgba(255, 255, 255, 0.3);   /* a step not reached yet */
  --text-pending: rgba(255, 255, 255, 0.5);
  --surface-tabbar: rgba(255, 255, 255, 0.05);

  /* The player surface, spine steps 7-8. The bottom tab bar's own height,
     WITHOUT the safe-area inset — callers add `env(safe-area-inset-bottom)`
     themselves, because a token cannot carry a value the browser computes.
     8px top padding + a 44px mobile control + 12px bottom padding. It exists so
     the sticky CTA can clear the bar rather than sharing its strip. */
  --tabbar-height: 64px;

  /* What the iOS app's own bars cover at the bottom of the web view (D211).
     A player page in the app runs under the glass tab bar without
     `viewport-fit=cover`, so `env(safe-area-inset-bottom)` reports 0 there;
     the shell writes the real figure onto <html> after every render and
     layout. Zero in a browser and on Android, whose web view stops above
     its bar. */
  --native-inset-bottom: 0px;

  --menu-width: 240px;
  --modal-width: 400px;
  --gallery-width: 720px;             /* the Acceptance page's screenshot modal, wider for a picture */
  --engraving-max-width: 320px;       /* the plate's text while the picture is drawn (D104) */

  /* The review studio (D151): the decision column beside the picture, which
     takes the rest of the 920px content width, and each version's thumbnail
     in the strip beneath it. */
  --review-side-width: 320px;
  --review-thumb-size: 72px;

  /* The Studio (D169): the founders' Create screen in the wide shell. The
     brief column is theirs (460px at 1480) less our narrower shell; the rest
     is the draw, whose decision column reuses the review studio's width.
     The gallery's tiles fold at --studio-tile-min. */
  --studio-brief-width: 480px;
  --studio-tile-min: 180px;

  /* The club admin's own three screens. styleguide.md §4 measures the desktop
     card grids at 3 x 296px and 2 x 452px on 16px gaps, inside a 920px content
     width; the two `--dashboard-*-min` values are those measurements used as
     grid minimums so the rows fold instead of overflowing below 960, which the
     mocks never draw. */
  --dashboard-card-min: 296px;
  --dashboard-card-wide-min: 452px;
  /* A nested card grid inside a card. §4 MEASURES these at 2 x 200px on a 12px
     gap, but 200 as a grid MINIMUM is a pixel too greedy: inside a 452px card
     the two columns plus the gap need 412px and the card's own padding leaves
     411, so `auto-fit` folds them into one column at exactly the width the
     mock draws them side by side. The minimum is the fold threshold, not the
     drawn size — `1fr` still takes them out to 200 and past it. */
  --dashboard-nested-min: 176px;
  --history-date-width: 160px;     /* each end of its date range (D197) */
  --history-date-min-width: 140px; /* a whole date beside the calendar icon */
  /* Ui::PageComponent's narrow width and its rail (D170). 640 is a form column
     a person reads down without their eye leaving it; the rail takes what is
     left of the 920 content width beside it, less the gap. */
  --page-narrow-width: 640px;
  --page-rail-width: 256px;
  --club-profile-colour-min: 220px;  /* primary and secondary, side by side */
  --club-logo-preview-size: 120px;   /* the club's logo on Club Profile (D185) */
  --overlay-inset: 6px;            /* popover padding — options inset from the border */
  --icon-stroke: 1.8;              /* Lucide default; 2.2–3 on a check inside a fill */
  --icon-sm: 16px;
  --icon-md: 18px;                 /* the size icons actually render at inside controls */
  --icon-lg: 24px;
  --icon-xl: 32px;                 /* empty-state glyph */
  --spinner-size: 14px;
  --spinner-stroke: 2px;
  --border-width-emphasis: 1.5px;  /* radio/checkbox ring, thicker than a card border */
  --border-width-stepper: 2px;
  --border-width-navtab: 2px;      /* NV07 current-tab underline, in the top bar's rule */
  --rule-width: 2px;               /* leaderboard left rule, timeline rail */
  --caret-width: 1.5px;

  /* Motion for chrome only — a hover, a spinner, a shimmer. Still not a motion
     language; the reveal below is, and it is deliberately a separate scale. */
  --duration-shimmer: 1600ms;
  --duration-spin: 800ms;
  --toast-dwell: 5000ms;

  /* =========================================================================
   * THE SPOTLIGHT REVEAL — D97.
   *
   * The first motion in the product that is content rather than chrome, and
   * the artefact styleguide.md §10 calls "arguably the single most important
   * design artefact in the product — and it does not exist yet."
   *
   * It is built from the one idea the whole system already has: A TROPHY
   * CABINET LIT AT NIGHT, with light arriving from off-screen (§1). So the
   * reveal is not the trophy appearing — it is the LIGHT appearing, crossing
   * the plate, and leaving the trophy behind it. That also means it works on
   * the opaque JPEG every existing troph-e already is: nothing here needs a
   * cut-out, so D48 stays open and unspent (D97).
   *
   * These are a different scale from --duration-fast/base above on purpose.
   * Chrome should be imperceptible; this should be watchable once and then get
   * out of the way. The whole sequence is under two seconds.
   * ====================================================================== */
  --reveal-duration-light: 900ms;   /* the light crossing the plate */
  --reveal-duration-copy: 420ms;    /* one line of the engraving arriving */
  --reveal-delay-copy: 560ms;       /* copy starts BEFORE the light finishes */
  --reveal-stagger: 90ms;           /* between lines, so it reads as reading */
  --reveal-lift: 10px;              /* how far a line rises into place */
  --reveal-scale-from: 1.04;        /* settles INTO the frame, never pops out */
  --reveal-dim: 0.18;               /* how dark the plate starts */

  /* Symmetric, so brightness rises across the WHOLE duration and tracks the
     band crossing the plate. A hard-decelerating curve was tried first and was
     wrong in a way only measurement showed: it put 71% of the change in the
     first quarter of the time, so the plate was fully lit before the light that
     was supposed to be lighting it had arrived.

     The band itself is LINEAR. Light crossing a room does not ease. Under the
     shared curve it crossed in about 160ms of a 900ms animation and read as a
     flicker rather than a sweep.

     The copy uses the system's own standard curve, because the engraving is
     chrome even when its arrival is not. */
  --reveal-easing-light: cubic-bezier(0.45, 0.05, 0.55, 0.95);
  --reveal-easing-sweep: linear;
  --reveal-easing-copy: var(--easing-standard);

  /* The sweep itself. Gold, because gold is the only chromatic colour in this
     interface (§1) — and translucent, because it passes OVER artwork a club
     paid for and must leave no tint behind it. */
  --reveal-sweep: rgba(245, 214, 115, 0.28);
  --reveal-sweep-angle: 105deg;
}

/* Respect a stated preference for reduced motion.
 *
 * The reveal durations collapse here too, but that is only half of it: a
 * zero-duration animation still RUNS, and its first keyframe would flash. The
 * other half is in player.css, which refuses to arm the reveal at all under
 * this preference, so the Spotlight renders in its finished state and every
 * word of it is present. Reduced motion means less motion, never less
 * content. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    --duration-base: 0ms;
    --reveal-duration-light: 0ms;
    --reveal-duration-copy: 0ms;
    --reveal-delay-copy: 0ms;
    --reveal-stagger: 0ms;
  }
}

/* D170 — club admin screens. Appended by the club admin screens' rework, kept
   in one block so the shell's own tokens above stay untouched. */
:root {
  /* The medium crest (Ui::CrestComponent): its size and ring. */
  --club-preview-crest-size: 56px;
  --club-preview-ring-width: 6px;

  /* The crest at the head of the club admin's rail (F11): the identity tile's
     size, so the club's mark and the account's initials at the rail's foot are
     one size, with a ring scaled down from the preview's. */
  --crest-size-sm: 32px;
  --crest-ring-width-sm: 3px;
}

/* D176 — the platform admin's rail shell. A 240px rail of grouped destinations
   on the left, and the page header pinned as the bar above the content. The
   content column is capped and left-aligned, never centred. Below the compact
   breakpoint the rail keeps only its icons. */
:root {
  --sidebar-width: 240px;
  --sidebar-width-compact: 72px;
  --topbar-height-rail: 64px;
  --page-gutter: 32px;
  --page-max-width: 1200px;
  --rail-item-height: 36px;
  --rail-child-height: 32px;
  --rail-dot-size: 4px;
  --rail-heading-min: 280px;
  --identity-tile: 32px;
  --pill-height-sm: 20px;
  --count-min-width: 20px;

  /* The rail's own wash: a step below --surface-1, so the content area reads
     as the lit part of the cabinet and the rail as its frame. */
  --surface-sidebar: rgba(255, 255, 255, 0.035);

  /* The eyebrow voice the type scale lacked: group labels in the rail now,
     column headers and stat labels in later changes. */
  --type-eyebrow-size: 11px;
  --type-eyebrow-leading: 16px;
  --tracking-eyebrow: 0.06em;
}

/* D177 — the admin table, its toolbar and its pager. 48px rows in the admin
   shells (the 56 stays wherever a row is a thumb's target), a 40px chevron
   column, and the 32px segmented control above. */
:root {
  --table-row-height-dense: 48px;
  --table-chevron-width: 40px;
  --table-truncate-width: 320px;
  --table-footer-height: 48px;
  --segmented-height: 32px;
  --toolbar-filter-width: 200px;
  --toolbar-search-width: 260px;
}


/* D178 — report and record pages: the stat tile's figure, and the rail beside
   a record, wider than a form's 256 because it holds facts and a status
   control, not help text. */
:root {
  --type-stat-size: 28px;
  --type-stat-leading: 34px;
  --stat-tile-min: 180px;
  --page-rail-width-detail: 320px;

  /* Code-shaped text — a backtrace, a provider's reply, a {{include:}} marker —
     needs its own columns; set in DM Sans it is hard to read (D178). */
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

/* D179 — the prompt library's thumbnails in a 48px table row. */
:root {
  --prompt-thumb-size: 32px;
  --prompt-col-name: 34%;
  --prompt-col-draws: 22%;
  /* Below this the library's tables scroll inside their frame rather than
     squeezing five columns until their headers overlap. */
  --prompt-table-min: 760px;
}

/* D187 — comments on a troph-e. No photo exists for anybody, so a commenter is
   an initials tile: 32px in a comment row, 40px where a person heads a page. */
:root {
  --avatar-sm: 32px;
  --avatar-md: 40px;
}

/* D221 — the public site: the landing page at / for a visitor, /see-the-value,
   and the header and footer the sign-in, sign-up, reset and legal pages share
   with it. Ported from the founders' troph-e.app, whose look alternates the
   app's near-black with a warm paper band. The paper and its inks are the only
   new colours, and they are marketing surfaces only: nothing inside the app
   takes them. Gold stays the one chromatic colour. */
:root {
  --site-paper: #F4F1EA;                         /* the light bands */
  --site-paper-deep: #E9E4D8;                    /* see-the-value's closing band */
  --site-ink: #141310;                           /* headings on paper */
  --site-ink-secondary: rgba(20, 19, 16, 0.72);  /* body copy on paper */
  --site-ink-tertiary: rgba(20, 19, 16, 0.55);
  --site-rule: rgba(20, 19, 16, 0.18);           /* rules and cell edges on paper */
  --site-gold-ink: #6E5A20;                      /* gold text on paper: 5.9:1 */
  --site-black: #080705;                         /* full-bleed photography's backdrop */
  --site-scrim-strong: rgba(8, 7, 5, 0.94);
  --site-scrim: rgba(8, 7, 5, 0.6);
  --site-scrim-soft: rgba(8, 7, 5, 0.18);
  --site-band: rgba(245, 214, 115, 0.06);        /* the see-the-value teaser's gold-tinted band */

  --site-header-height: 76px;
  --site-header-height-phone: 64px;
  --site-logo-width: 168px;
  --site-logo-width-phone: 128px;
  --site-gutter: clamp(16px, 5vw, 96px);
  --site-max-width: 1440px;
  --site-section-space: clamp(72px, 10vw, 140px);
  --site-measure: 620px;
  --site-measure-wide: 920px;
  --site-hero-measure: 720px;       /* the founders' hero copy column */
  --site-mode-title-measure: 300px; /* keeps "Troph-e." whole on its own line */
  --site-logo-width-small: 112px;   /* a phone narrower than 420 */

  --site-type-hero: clamp(48px, 7.4vw, 120px);
  --site-type-display: clamp(40px, 5.6vw, 88px);
  --site-type-title: clamp(28px, 2.6vw, 36px);
  --site-type-step: clamp(22px, 2vw, 28px);
  --site-type-lead: clamp(17px, 1.6vw, 22px);
  --site-type-body: 17px;
  --site-leading-display: 0.98;
  --site-tracking-display: -0.045em;
  --site-tracking-eyebrow: 0.18em;

  --site-tile-height: clamp(380px, 44vw, 640px);
  --site-mode-visual-height: clamp(280px, 26vw, 360px);
  --site-cabinet-width: 600px;
  --site-hero-min-height: 720px;
  --site-hero-phone-min-height: 860px;
  --site-cta-min-height: 640px;
  --site-value-tile-min: 200px;
  --site-lightbox-control: 48px;
  --site-image-zoom: 1.035;
}
