:root {
  color-scheme: light;

  /* v04i / v04u — project thumbnail aspect ratio for padding-top trick.
     Default to 21:9 cinema (9/21 = 42.8571%). App.jsx updates this
     dynamically when /api/data returns a different episode.aspect_ratio. */
  --thumb-ratio: 42.8571%;
  /* v06q — same project aspect, expressed as a native CSS aspect-ratio
     value. Every thumbnail / hero / gallery frame should reference
     `var(--project-aspect)` instead of hard-coding `21 / 9` so changing
     the project aspect (or the user's local override via
     localStorage `frameflow.aspect-override`) cascades everywhere. */
  --project-aspect: 21 / 9;

  /* surfaces */
  --bg: #2A332A;
  --card-bg: rgba(224, 217, 199, 0.92);
  --card-bg-solid: #E0D9C7;
  --card-bg-light: rgba(238, 232, 215, 0.78);
  --card-bg-dark: rgba(45, 61, 42, 0.78);
  --card-border: #C9B98C;
  --card-border-dark: rgba(201, 185, 140, 0.45);
  --card-border-metallic: rgba(212, 188, 132, 0.85);
  --sidebar-bg: #2D3D2A;
  --sidebar-bg-trans: rgba(45, 61, 42, 0.82);

  /* ink */
  --ink: #2A2620;
  --ink-muted: #786E5E;
  --ink-soft: #B5AE9C;
  --ink-on-dark: #E8D9B5;
  --ink-on-dark-muted: #B8A881;

  /* accents */
  --leaf: #7FA85E;
  --leaf-ink: var(--leaf);     /* the accent when it is TEXT; a skin may brighten it for dark panels */
  --amber: #D4A574;
  --teal: #5A9B95;
  --tan: #C9BC9C;
  --archive: #A39A87;

  /* 15 Sep 2026 — the forest family that used to be typed straight into the stylesheets
     (buttons, toggles, tags, bevels, foil edges, shadows). Same values as before, so the forest
     look is unchanged; a preset overrides them so every control follows its palette.
     Hugo: "we still have a lot of green for the buttons. looks NOTHING like the mockups". */
  --card-bg-light-solid: #EEE8D7;
  --ok: #7FA85E;               /* success / done / online — semantic, not the accent */
  --ok-deep: #5C8A3E;
  --warn: #D4A574;             /* pending / in progress — semantic, not the accent */
  --leaf-deep: #5C8A3E;        /* the darker green of button/bar gradients */
  --leaf-bright: #7FCB52;      /* the lighter green of the same gradients */
  --ink-on-accent: #F4EFE0;    /* text on a leaf/amber button */
  --nav-active: #E8C684;       /* the gold of the active menu item */
  --paper: #FBF6E2;            /* segmented-control active, top */
  --paper-2: #EFE4C2;          /* segmented-control active, bottom */
  --hi: #FFF8DC;               /* bevel catch-light (255,248,220) */
  --hi-2: #FFF5D7;             /* (255,245,215) */
  --hi-3: #FFF0C8;             /* (255,240,200) */
  --foil: #D4BC84;             /* gold-foil edge (212,188,132) */
  --tan-deep: #78643C;         /* (120,100,60) */
  --gold-deep: #B48C50;        /* (180,140,80) */
  --gold-deep-2: #A07846;      /* (160,120,70) */
  --shadow-ink: #281E0F;       /* warm shadow (40,30,15) */
  --shadow-ink-2: #3C2D19;     /* (60,45,25) */
  --ink-deep: #3C2D19;         /* TEXT that used to be --shadow-ink-2 (15 Sep 2026) - presets map it to their ink */
  --ink-deep-2: #281E0F;       /* TEXT that used to be --shadow-ink (15 Sep 2026) */
  /* ---- ROLE tokens (15 Sep 2026): the same values, split by USE. Text that shares a name with a
     surface (cream = pale surface AND light text; forest = dark surface AND dark text) reads its
     --ink-<name> twin, so a preset can keep text legible while it recolours the surface. ---- */
  --ink-cream: var(--cream);
  --ink-cream-2: var(--cream-2);
  --ink-cream-3: var(--cream-3);
  --ink-cream-4: var(--cream-4);
  --ink-cream-5: var(--cream-5);
  --ink-cream-6: var(--cream-6);
  --ink-cream-7: var(--cream-7);
  --ink-cream-8: var(--cream-8);
  --ink-cream-9: var(--cream-9);
  --ink-cream-10: var(--cream-10);
  --ink-hi: var(--hi);
  --ink-hi-2: var(--hi-2);
  --ink-hi-3: var(--hi-3);
  --ink-paper: var(--paper);
  --ink-paper-2: var(--paper-2);
  --ink-parchment: var(--parchment);
  --ink-forest: var(--forest);
  --ink-forest-2: var(--forest-2);
  --ink-forest-3: var(--forest-3);
  --ink-forest-4: var(--forest-4);
  --ink-forest-5: var(--forest-5);
  --ink-forest-6: var(--forest-6);
  --ink-bg: var(--bg);
  --ink-sidebar-bg: var(--sidebar-bg);
  --ink-umber: var(--umber);
  --ink-umber-2: var(--umber-2);
  --ink-umber-3: var(--umber-3);
  --ink-umber-4: var(--umber-4);
  --ink-tan-deep: var(--tan-deep);
  --ink-taupe: var(--taupe);
  --ink-taupe-2: var(--taupe-2);
  --ink-taupe-3: var(--taupe-3);
  --ink-taupe-4: var(--taupe-4);
  --ink-taupe-5: var(--taupe-5);
  --ink-moss: var(--moss);
  --surface-forest: var(--forest);
  --surface-forest-2: var(--forest-2);
  --surface-forest-3: var(--forest-3);
  --surface-forest-4: var(--forest-4);
  --surface-forest-5: var(--forest-5);
  --surface-forest-6: var(--forest-6);
  --shade: #141A12;            /* dark green shadow/glass tints (20,26,18) */
  --shade-2: #1C2A1C;          /* (28,42,28) */
  --shade-3: #122016;          /* (18,32,22) */
  --shade-4: #0A160E;          /* (10,22,14) */

  /* 15 Sep 2026 — pass two: the cream / gold / green / umber SHADES the stylesheets typed in
     (the most used ones, exact old values). A preset derives each from its own base tokens. */
  --cream: #FFFCEB;
  --cream-2: #FCF7E6;
  --cream-3: #F0EBD8;
  --cream-4: #ECE6D6;
  --cream-5: #FFFAEB;
  --cream-6: #E8DCBC;
  --cream-7: #F0EAD8;
  --cream-8: #E8E1CE;
  --cream-9: #EEE4C8;
  --cream-10: #F5EFE2;
  --parchment: #D9D2BF;
  --gold: #C49A3F;
  --gold-2: #E8C363;
  --gold-3: #E8BC5A;
  --gold-4: #C8A05F;
  --gold-5: #C9A84C;
  --gold-6: #C4882A;
  --gold-7: #9A7B3E;
  --gold-8: #C9A13C;
  --gold-9: #B49150;
  --gold-10: #D4AF37;
  --gold-11: #C4A24A;
  --gold-12: #C9A24B;
  --gold-13: #E3BF45;
  --gold-14: #C89B33;
  --gold-15: #C49C5A;
  --gold-16: #E89E4F;
  --gold-17: #D8B25A;
  --gold-18: #C9A875;
  --olive: #6E8B4E;
  --olive-2: #5F8C46;
  --olive-3: #4F7A36;
  --moss: #5A6E3A;
  --forest: #283C1E;
  --forest-2: #2E5A18;
  --forest-3: #3F5220;
  --forest-4: #3F6B2E;
  --pale-green: #96BE78;
  --olive-4: #4F8A3A;
  --forest-5: #2E6628;
  --olive-5: #6B8A5A;
  --olive-6: #6BAA5A;
  --forest-6: #3C6428;
  --olive-7: #5F8C44;
  --olive-8: #6F8C5E;
  --olive-9: #4F6A37;
  --olive-10: #789860;
  --olive-11: #678454;
  --mint: #DAE8C8;
  --umber: #3A3527;
  --umber-2: #5A4E32;
  --umber-3: #3C321E;
  --umber-4: #5A4B32;
  --taupe: #786C54;
  --taupe-2: #968A74;
  --taupe-3: #6B6350;
  --taupe-4: #6F6553;
  --taupe-5: #786E58;
  --shade-5: #141C12;
  --shade-6: #080E0A;
  --shade-7: #0F1612;

  /* what a shade lightens / darkens toward (15 Sep 2026). White and black in the forest; a dark
     preset lightens toward a lifted panel colour instead, so 'lighter' never means 'mid-grey'. */
  --mix-light: #FFFFFF;
  --mix-dark: #000000;

  --status-accent: #7FCB52;    /* the project status pill on the dark header (15 Sep 2026) */

  /* 15 Sep 2026 — pass three: colours that were typed INLINE in JSX or as JS constants (Reports
     charts, milestone badges, admin role chips, Delete/Remove buttons, the top-bar ring). Forest
     defaults are the exact old values; a preset maps each one (mapping notes in new-tokens.md). */
  --accent: var(--leaf);            /* generate.css var(--accent, …) rules now follow the presets */
  --accent-strong: var(--leaf);     /* primary "go" fill — the forest primaries are plain leaf */
  --danger: #8A2A1F;                /* destructive text: Delete / Remove / errors / over budget */
  --danger-border: rgba(196, 90, 90, 0.45);
  --warn-deep: #7A4218;             /* dark amber text on a warn tint (reversible-action eyebrow) */
  /* Reports charts — src/Views.jsx RV_PALETTE / RV_C read these at render time */
  --chart-1: #6E9E54;               /* primary series (API / generation, renders, active shots) */
  --chart-2: #5E8FB0;
  --chart-3: #C9A84C;
  --chart-4: #9C7BB0;
  --chart-5: #D08A4A;
  --chart-6: #6FB2A6;
  --chart-7: #B0654E;
  --chart-ok: #6E9E54;              /* generation success */
  --chart-fail: #C0573E;            /* generation failure, over budget */
  --chart-labor: #C9A84C;           /* labour cost series */
  --chart-xtra: #A8794A;            /* extra-costs series */
  --chart-prompt: #C9A84C;          /* the Prompts line on Trends */
  --chart-line: #5E8C46;            /* the hours-over-time line */
  /* Milestone type badges — src/RightColumn.jsx TYPE_STYLE (tint + its ink) */
  --badge-phase: #E89E4F;      --badge-phase-ink: #6E3E14;
  --badge-review: #D4A548;     --badge-review-ink: #5A4720;
  --badge-kickoff: #5090C0;    --badge-kickoff-ink: #1F4360;
  --badge-default: #78643C;    --badge-default-ink: #5A5142;
  /* Admin permissions-matrix role chips — views-pages.css .admin-matrix-head--* (tint hue) */
  --role-admin: #C4604A;
  --role-director: #5090C0;
  --role-lead: #40A8A8;
  --role-artist: #966EC8;
  --role-reviewer: #9A9A8A;
  --role-editor: #CE688A;

  /* status pill tints (cream-mixed) */
  --tint-leaf: rgba(127, 168, 94, 0.15);
  --tint-amber: rgba(212, 165, 116, 0.18);
  --tint-teal: rgba(90, 155, 149, 0.15);
  --tint-tan: rgba(201, 188, 156, 0.22);
  --tint-archive: rgba(163, 154, 135, 0.18);

  /* radii */
  --r-lg: 20px;
  --r-md: 12px;
  --r-sm: 8px;
  --r-pill: 100px;

  /* effects */
  --shadow-card:
    0 1px 2px rgba(40, 30, 15, 0.06),
    0 12px 32px rgba(40, 30, 15, 0.10);
  --inner-highlight: linear-gradient(180deg, rgba(255,255,255,0.12), transparent 16px);
  --card-blur: blur(24px) saturate(1.05);

  /* type */
  --font-display: "Söhne Breit Halbfett", "Bebas Neue", "Anton", "Founders Grotesk Bold", "Archivo Black", system-ui, sans-serif;
  --font-body: "Söhne Buch", "Inter", "SF Pro Text", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace;
  --tnum: "tnum" 1, "lnum" 1;
}

/* ---- judge round 2 (15 Sep 2026): component tokens ---- */
/* Every value below is the EXACT literal a stylesheet or JSX used to type (Paradise Found renders
   byte-identically); a preset in themes.css overrides the ones it wants. Groups: the cross-cutting
   set agreed for this round (inputs, raised panel, the one CTA, soft danger reds, role chips, the
   sidebar stage bar, the three floating buttons), status pills (--st-*), ring/arc gradients
   (--ring-*, --arc-*), notes kinds (--tint-*), reds/blues/purples/teals/greys, gold + amber text,
   the image-editor dark UI (--ied-*), near-black glass tints (--shade-8..) and cream/ivory shades.
   --fab-1 = top (notepad), --fab-2 = middle (to-do), --fab-3 = bottom (assistant). --stage-bar is
   the DONE segments of PIPELINE STAGE, --stage-bar-current the lit one. */
:root {
  --input-bg: color-mix(in srgb, var(--cream) 85%, transparent);
  --input-border: var(--card-border);
  --panel-raised: var(--card-bg-light-solid);
  --cta-bg: var(--leaf);
  --cta-ink: var(--ink-on-accent);
  --danger-soft: #C45A5A;
  --danger-soft-2: #C4604A;
  --danger-ink: #6E1F0E;
  --danger-deep: #963C2D;
  --ok-border: rgba(95, 140, 70, 0.45);
  --role-admin-ink: #6E1F0E;
  --role-director-ink: #1F4360;
  --role-director-line: #3A6EA0;
  --role-lead-ink: #1A4A48;
  --role-lead-line: #288282;
  --role-artist-ink: #3F2466;
  --role-artist-line: #7350AA;
  --role-reviewer-ink: #4F4A40;
  --role-editor-ink: #6B2440;
  --role-editor-line: #B04A6E;
  --role-producer: var(--leaf);
  --role-producer-ink: var(--ink-forest-2);
  --role-supervisor: var(--gold-16);
  --role-supervisor-ink: color-mix(in srgb, var(--ink-tan-deep) 81%, var(--mix-dark));
  --role-tester: var(--gold-12);
  --role-tester-ink: color-mix(in srgb, var(--ink-tan-deep) 67%, var(--mix-dark));
  --stage-bar: var(--ok);
  --stage-bar-current: var(--warn);
  --fab-1: linear-gradient(150deg, color-mix(in srgb, var(--gold-14) 88%, var(--mix-light)), var(--gold-22) 70%);
  --fab-2: linear-gradient(150deg, var(--leaf), var(--olive-3) 70%);
  --fab-3: linear-gradient(150deg, color-mix(in srgb, var(--gold-10) 75%, var(--mix-light)), var(--gold) 70%);
  --white: #FFFFFF;
  --black: #000000;
  --ink-on-leaf: #1F2A1D;
  --ink-strong: #1F2A1F;
  --olive-12: #3F6A26;
  --ink-olive-12: var(--olive-12);
  --leaf-pale: #A8C77F;
  --leaf-pale-2: #9CCB7F;
  --leaf-2: #6E9E54;
  --warn-red: #B5563D;
  --panel-cream: #F4EFE0;
  --ink-toast: #F4E9CC;
  --toast-ok: #3A5630;
  --signal-green: #28C040;
  --signal-amber: #FFB020;
  --signal-red: #E02818;

  /* Donut segments and the pipeline bar (16 Sep 2026). Hugo: "the colours of the donut and
     progress bar are COMPLETELY wrong". They were painted straight from the shared palette and
     the traffic-light signals, so a skin could not move them without dragging every pill along.
     Defaults alias exactly what the gradients read before, so Paradise Found is unchanged. */
  --donut-first-pass: var(--tan);
  --donut-concept: var(--warn);
  --donut-render: var(--teal);
  --donut-completed: var(--ok);
  --donut-upscale: var(--amber);
  --bar-lo: var(--signal-green);
  --bar-mid: var(--signal-amber);
  --bar-hi: var(--signal-red);

  /* The donut's unfilled ring. Was an inline expression inside TopBar.jsx, so no skin
     could repaint it. This default is that exact expression, so Paradise Found is unchanged. */
  --donut-track: color-mix(in srgb, var(--card-border) 18%, transparent);
  /* The crisp glass highlight along each arc's outer edge. Defaults to --mix-light so
     Paradise Found is unchanged; a dark skin that remaps --mix-light to a grey must set
     this to real white or the highlight goes dull and the ring stops reading as glass. */
  --donut-sheen-base: var(--mix-light);
  /* The stat glyph inside the disc in the topbar's 4-stat row. It lives inside a fixed-size disc
     with place-items:center, so a bigger glyph cannot move anything - see the note in
     test/skinContract.test.js. (18 Sep 2026, Hugo: "all of the presets should have the new big
     ones" - 28px, the size the glass skins had since 16 Sep; it was 24px for forest and paper.) */
  --tb-chip-glyph: 28px;
  /* The stat disc itself. The stat row's height is set by its label/number/sub stack, which is
     taller than the disc, so a bigger disc re-centres in the same row rather than growing it
     (measured 18 Sep 2026: band and row boxes identical at 48 and 64px, 2268 and 1280 wide).
     64px for every skin since 18 Sep 2026 (was 48px outside the glass family). */
  --tb-chip-size: 64px;

  /* Each donut arc gets its own lo/mid/hi so a single arc can travel the accent ramp
     instead of being three shades of one hue. Defaults reproduce the old stops exactly. */
  --donut-first-pass-lo: color-mix(in srgb, var(--donut-first-pass) 60%, var(--mix-dark));
  --donut-first-pass-mid: var(--donut-first-pass);
  --donut-first-pass-hi: color-mix(in srgb, var(--donut-first-pass) 60%, var(--mix-light));
  --donut-concept-lo: color-mix(in srgb, var(--donut-concept) 60%, var(--mix-dark));
  --donut-concept-mid: var(--donut-concept);
  --donut-concept-hi: color-mix(in srgb, var(--donut-concept) 60%, var(--mix-light));
  --donut-render-lo: color-mix(in srgb, var(--donut-render) 60%, var(--mix-dark));
  --donut-render-mid: var(--donut-render);
  --donut-render-hi: color-mix(in srgb, var(--donut-render) 60%, var(--mix-light));
  --donut-completed-lo: color-mix(in srgb, var(--donut-completed) 60%, var(--mix-dark));
  --donut-completed-mid: var(--donut-completed);
  --donut-completed-hi: color-mix(in srgb, var(--donut-completed) 60%, var(--mix-light));
  --donut-upscale-lo: color-mix(in srgb, var(--donut-upscale) 60%, var(--mix-dark));
  --donut-upscale-mid: var(--donut-upscale);
  --donut-upscale-hi: color-mix(in srgb, var(--donut-upscale) 60%, var(--mix-light));
  --pill-bg: #FDFAF4;
  --st-upscaled: var(--gold-5);
  --st-upscaled-ink: #7A5212;
  --st-video-hero: #4AAA5A;
  --st-video-wip: #3AAAB8;
  --st-video-wip-ink: #1F5C56;
  --st-hero: #5A9A4A;
  --st-hero-ink: var(--ink-forest-5);
  --st-wip: var(--gold-6);
  --st-wip-ink: var(--warn-deep);
  --st-first-pass: #A8956A;
  --st-first-pass-ink: #6F5E3E;
  --st-prompt: #8A9AB0;
  --st-prompt-ink: #3F4E64;
  --st-pending: #9A9A8A;
  --st-pending-ink: #5A5A4E;
  --st-pending-2: #B0A892;
  --st-pending-2-ink: #6E665A;
  --st-archive: #7A7A6A;
  --st-archive-ink: #4F4A40;
  --st-omitted: #B58A82;
  --st-omitted-ink: #7A4138;
  --st-retake: #E07856;
  --st-retake-ink: #7A3A22;
  --st-retake-2: #C4603A;
  --st-retake-2-ink: #8A3A20;
  --ring-upscaled-1: #FFE9A8;
  --ring-upscaled-2: #E0BC68;
  --ring-upscaled-3: #8E6418;
  --ring-video-hero-1: #C9F09A;
  --ring-video-hero-2: var(--leaf-bright);
  --ring-video-wip-1: #9CE0DA;
  --ring-video-wip-2: #3FB5AA;
  --ring-video-wip-3: #0F4D48;
  --ring-hero-1: #C2DEA0;
  --ring-hero-2: var(--leaf);
  --ring-wip-1: #FFD487;
  --ring-wip-2: var(--gold-16);
  --ring-wip-3: var(--warn-deep);
  --ring-first-pass-1: #F2E8C6;
  --ring-first-pass-2: #D4C28E;
  --ring-first-pass-3: #8E7B52;
  --ring-prompt-1: #E8DCB8;
  --ring-prompt-2: var(--tan);
  --ring-prompt-3: #7A6E50;
  --ring-pending-1: #E4DCC6;
  --ring-pending-2: var(--tan);
  --ring-pending-3: #8E8470;
  --ring-archive-1: #D4CCB8;
  --ring-archive-2: var(--archive);
  --ring-archive-3: #5E564A;
  --arc-shots-lo: #1F4360;
  --arc-shots-mid: #5090C0;
  --arc-shots-hi: #9CC6E0;
  --arc-days-lo: #5A4014;
  --arc-days-mid: #D4A548;
  --arc-days-hi: #F5DC9A;
  --arc-hours-lo: #6E3E14;
  --arc-hours-mid: #D08A4F;
  --arc-hours-hi: #F5C295;
  --arc-status-lo: #234812;
  --arc-status-mid: var(--leaf-bright);
  --arc-status-hi: #C9F09A;
  --arc-review-lo: #0F4D48;
  --arc-review-mid: #3FB5AA;
  --arc-review-hi: #9CE0DA;
  --arc-notes-lo: #6A4218;
  --arc-notes-mid: var(--gold-16);
  --arc-notes-hi: #FFD487;
  --arc-rejected-lo: #5A1A0F;
  --arc-rejected-mid: #C4604A;
  --arc-rejected-hi: #F0A88C;
  --sand: #D4C9A8;
  --sand-2: #E5D9B0;
  --amber-deep: #B8845C;
  --amber-pale: #F0C97D;
  --teal-deep: #3D7F79;
  --teal-pale: #7AB8B2;
  --teal-bright: #3FB5AA;
  --tint-shot: #3E6B8C;
  --tint-character: #7A4DB0;
  --tint-animal: #3F8C6B;
  --tint-location: #B07A2E;
  --tint-prop: #8C6A3F;
  --tint-ref: #6B6B5A;
  --tint-edit: #B0512E;
  --tint-general: #5A7A4E;
  /* Notes page ink (17 Sep 2026). The kind + source tags, the kind filter chips and the no-image
     letter read these, never the --tint-* colours above, so a skin can make them readable on its own
     chip colour. Forest = exactly the tints (Paradise Found unchanged). NotesPage.jsx passes them. */
  --note-kind-shot: var(--tint-shot);
  --note-kind-character: var(--tint-character);
  --note-kind-animal: var(--tint-animal);
  --note-kind-location: var(--tint-location);
  --note-kind-prop: var(--tint-prop);
  --note-kind-ref: var(--tint-ref);
  --note-kind-edit: var(--tint-edit);
  --note-kind-project: var(--tint-general);
  --note-kind-other: var(--grey-5);
  --note-src-modal: var(--tint-general);
  --note-src-pdf: var(--tint-edit);
  --note-src-edit: var(--tint-shot);
  --note-src-general: var(--tint-ref);
  --note-src-other: var(--grey-5);
  /* the "All" chip's text when it is the active filter, and the colours the active chip and the
     no-image square mix their tint into */
  --note-chip-all: var(--ink-moss);
  --note-chip-base: var(--mix-light);
  --note-thumb-base: var(--mix-light);
  --cat-technical: #7A8A99;
  --cat-audio: var(--blue-14);
  --cat-accuracy: #A63D2E;
  --cat-vfx: #7C5CA6;
  --cat-redo: var(--red-1);
  --danger-2: #B0432F;
  --danger-2-ink: #9C3B27;
  --danger-3: #B03A2E;
  --danger-3-ink: #8C2F24;
  --danger-4: #A04A3D;
  --red-1: #B4462F;
  --red-1-deep: #8E2F1C;
  --red-2: #B4452F;
  --red-3: #B4553F;
  --red-4: #8B2A14;
  --red-5: #8A2B1A;
  --red-6: #8A2E2E;
  --red-7: #8A2F2F;
  --red-8: #8A3A2F;
  --red-9: #8A3B23;
  --red-10: #A4552E;
  --red-11: #9C3B33;
  --red-12: #AA3333;
  --red-13: #B3261E;
  --red-14: #B3402E;
  --red-15: #B4633A;
  --red-16: #A85F4A;
  --red-17: #B44632;
  --red-18: #B04646;
  --red-19: #A04637;
  --red-20: #C4513A;
  --red-21: #A85A5A;
  --red-22: #C2611F;
  --red-23: #B5613A;
  --red-24: #C54A3A;
  --red-25: #C66A3A;
  --red-26: #A04E26;
  --red-27: #DC5050;
  --red-27-ink: #F4B8B8;
  --red-28: #8C342A;
  --red-29: #782C28;
  --red-30: #E08A8A;
  --red-31: #B45037;
  --orange-1: #DC8C5A;
  --orange-1-ink: #FFB890;
  --ink-on-danger: #FFF6F2;
  --blue: #5078AA;
  --blue-2: #4A73A8;
  --blue-3: #3F6699;
  --blue-4: #2F5688;
  --blue-5: #609EC4;
  --blue-5-ink: #2A5A6E;
  --blue-6: #789EC8;
  --blue-7: #24405F;
  --blue-8: #4A7BB0;
  --blue-9: #6B8BC4;
  --blue-10: #7FA8DC;
  --blue-11: #E1E8F8;
  --blue-12: #D2E2F5;
  --blue-13: #AAC6E8;
  --blue-14: #4A6F8C;
  --blue-15: #5F8FB0;
  --blue-16: #3E6B8C;
  --blue-17: #3AA4D8;
  --blue-18: #4AA7D8;
  --blue-19: #78B4DC;
  --blue-20: #1F4A66;
  --blue-21: #2C4760;
  --blue-22: #788CA8;
  --blue-23: #3C5C76;
  --blue-24: #2F4C63;
  --blue-26: #508CAF;
  --blue-27: #37698C;
  --blue-28: #DCF5FF;
  --blue-29: #14283C;
  --blue-30: #96B2D2;
  --blue-31: #607A9C;
  --blue-32: #D2E0F0;
  --blue-33: #E1EEFF;
  --blue-34: #141E32;
  --blue-35: #B0C6DE;
  --blue-36: #161E26;
  --blue-37: #06222E;
  --blue-38: #D6EEFA;
  --blue-39: #14181C;
  --lock: #3AAAB8;
  --lock-ink: #06303A;
  --lock-line: #D2F4FA;
  --purple: #785AA0;
  --purple-2: #967EBE;
  --purple-3: #8264AA;
  --purple-4: #6A4A8A;
  --purple-5: #5A3F8A;
  --purple-6: #966EC4;
  --teal-2: #3E7F79;
  --teal-2-ink: #2F6660;
  --teal-3: #3C8282;
  --teal-3-ink: #2F6F6C;
  --teal-4-ink: #1A4A45;
  --teal-4-hi: #DCFFFA;
  --teal-4-lo: #0F322D;
  --grey-1: #787E8A;
  --grey-1-ink: #10151C;
  --grey-2: #E8ECF2;
  --grey-3: #788076;
  --grey-3-ink: #6C7268;
  --grey-4: #787878;
  --grey-4-ink: #555555;
  --grey-5: #888888;
  --grey-6: #BBBBBB;
  --grey-7: #AAAAAA;
  --grey-8: #EEEEF0;
  --grey-8-ink: #4A4A52;
  --grey-9: #9696A0;
  --grey-10: #E0E0E6;
  --grey-11: #EEEEEE;
  --grey-12: #2B2B2B;
  --grey-13: #141414;
  --grey-14: #B4BEAA;
  --grey-15: #8A9080;
  --grey-16: #99AA99;
  --ink-gold: #8A6D1F;
  --ink-gold-2: #A87A18;
  --ink-gold-3: #6B4E00;
  --ink-gold-4: #8A5A12;
  --ink-gold-5: #8A5D2A;
  --late-ink: #9A5A1A;
  --gold-star: #F4C95D;
  --amber-2: #E8A850;
  --amber-2-line: #B07C38;
  --amber-3: #B8743A;
  --amber-4: #B06A3A;
  --ink-on-amber: #3A2410;
  --ink-on-gold: #1A2415;
  --ink-on-gold-2: #241D0E;
  --ink-on-gold-3: #1A160A;
  --ink-on-gold-4: #1A1A1A;
  --ink-on-leaf-3: #101208;
  --gold-19: #B4A050;
  --gold-20: #946E23;
  --gold-21: #E8C68A;
  --gold-22: #A87420;
  --forest-7: #3D7A1E;
  --forest-8: #3D6628;
  --tan-2: #DCD2B4;
  --tan-3: #E8D9B0;
  --tan-4: #A09678;
  --tan-deep-2: #8C7850;
  --tan-deep-3: #8E7A52;
  --taupe-6: #786E5A;
  --taupe-8: #786E50;
  --umber-6: #3A2F1F;
  --umber-7: #5A4F33;
  --ink-2: #2E2A20;
  --ink-3: #2A2A20;
  --ink-4: #2B2A24;
  --ink-5: #4F4634;
  --ink-6: #6B6450;
  --ink-7: #6B665A;
  --ink-8: #7A7058;
  --ink-9: #8A8478;
  --ink-slide-sub: #3F4538;
  --cream-11: #FFFCF0;
  --cream-12: #FFFDF4;
  --cream-13: #FFFCF4;
  --cream-14: #FFFCF2;
  --cream-15: #FDFAF2;
  --cream-16: #FFFDF8;
  --cream-17: #FFFEF7;
  --cream-18: #FFFDF6;
  --cream-19: #FBF7EC;
  --cream-20: #FBF7EA;
  --cream-21: #FCF7EB;
  --cream-22: #FCF8EC;
  --cream-23: #FAFAF2;
  --cream-24: #FFFCF5;
  --cream-25: #FFFDF2;
  --cream-26: #F5EBCD;
  --cream-27: #F3EEDB;
  --cream-28: #E8DABC;
  --cream-29: #EFE7D2;
  --ivory: #FFFFF0;
  --ivory-2: #FFFFFA;
  --ivory-3: #FFFFF5;
  --mint-2: #F5FAEB;
  --mint-3: #F4F9EE;
  --mint-4: #F3F7EA;
  --mint-5: #EAF2E2;
  --mint-6: #F0F4E9;
  --mint-7: #F2F7F5;
  --ied-ink: #E9E6DC;
  --ied-ink-2: #EBE8DC;
  --ied-ink-3: #F2EFE4;
  --ied-ink-4: #E2DED2;
  --ied-ink-5: #E6E2D6;
  --ied-bg: #14170F;
  --ied-bg-2: #0B0D08;
  --ied-bg-3: #1A1D16;
  --ied-bg-4: #191B16;
  --ied-bg-5: #14160F;
  --ied-bg-6: #0C0D0A;
  --ied-bg-7: #1A1F1A;
  --ied-bg-8: #222222;
  --ied-bg-9: #161911;
  --ied-bg-10: #161814;
  --ied-bg-11: #0D0F0B;
  --ied-bg-12: #0C0E0A;
  --ied-bg-13: #080907;
  --shade-8: #141810;
  --shade-9: #14120C;
  --shade-10: #140F05;
  --shade-11: #0F140C;
  --shade-12: #1E281C;
  --shade-13: #141812;
  --shade-14: #141C11;
  --shade-15: #141E12;
  --shade-16: #1C241C;
  --shade-17: #141C14;
  --shade-18: #142016;
  --shade-19: #121E12;
  --shade-20: #1C2C1C;
  --shade-21: #142018;
  --shade-22: #28382C;
  --shade-23: #283223;
  --shade-24: #1C2218;
  --shade-25: #26221C;
  --shade-26: #12100A;
  --shade-27: #1E1810;
  --shade-28: #0E100B;
  --shade-29: #12160E;
  --shade-30: #0C0F08;
  --shade-31: #141008;
  --shade-32: #080602;
  --shade-33: #14120E;
  --shade-34: #1C241A;
  --shade-35: #282319;
  --shade-36: #14140A;
  --shade-37: #14180F;
  --shade-38: #14190F;
  --shade-39: #0F120C;
  --shade-40: #1E1A10;
  --shade-41: #080C06;
  --shade-42: #060A05;
  --shade-43: #121A10;
  --shade-44: #10180D;
  --shade-45: #161E13;
  --shade-46: #0A0E08;
  --shade-47: #0A120C;
  --shade-48: #0E1A12;
  --shade-49: #11160D;
  --shade-50: #14130F;
  --shade-51: #1A2A1F;
  --shade-52: #131F17;
  --shade-53: #0A130D;
  --shade-54: #1A261A;
  --shade-55: #1E2A1C;
  --shade-56: #211E18;
  --shade-57: #2C2820;
  --shade-58: #262219;
  --shade-59: #23281F;
  --shade-60: #1A1F18;
  --shade-61: #2F3A24;
  --shade-62: #28241C;
  --shade-63: #141006;
  --shade-64: #140E08;
  --cream-30: #F5EFE0;
  --amber-5: #B47850;
  --blue-40: #5AAAB8;
  --blue-41: #4A78C4;
  --blue-41-ink: #29508A;
  --ink-blue-37: var(--blue-37);
  --ink-mint-7: var(--mint-7);
  --ink-mint-5: var(--mint-5);
  --ink-blue-14: var(--blue-14);
  --ink-mint-4: var(--mint-4);
  --ink-blue-23: var(--blue-23);
  --ink-blue-24: var(--blue-24);
  --ink-blue-7: var(--blue-7);
  --ink-grey-7: var(--grey-7);
  --ink-mint-3: var(--mint-3);
  --ink-grey-11: var(--grey-11);
  --ink-ied-bg-6: var(--ied-bg-6);
  --ink-blue-4: var(--blue-4);
  --ink-blue-3: var(--blue-3);
  --ink-purple-4: var(--purple-4);
  --ink-grey-5: var(--grey-5);
  --ink-blue-16: var(--blue-16);
  --ink-purple-5: var(--purple-5);
  --ink-blue-32: var(--blue-32);
  --ink-blue-20: var(--blue-20);
  --ink-blue-21: var(--blue-21);
  --ink-grey-12: var(--grey-12);
  --ink-grey-16: var(--grey-16);
  --ink-forest-7: var(--forest-7);
  --ink-grey-15: var(--grey-15);
}

/* ---- judge round 2, follow-up (15 Sep 2026) ---- */
:root {
  /* Accent TEXT. On the forest look the accent is legible as text, so the default IS --leaf;
     a pale-panel skin should deepen it toward its ink, because a saturated accent at full
     strength can measure ~1.4:1 on a pale panel. */
  --ink-accent: var(--leaf);
}

/* ===========================================================================
   SCALES + COMPONENT TOKENS — token pass, 15 Sep 2026
   ---------------------------------------------------------------------------
   EVERY default below is the EXACT literal it replaces, so Paradise Found (the
   forest look, body with no data-theme) renders identically. Anything here that
   is palette-dependent gets a per-preset value in styles/themes.css; the SCALES
   (type, weight, tracking, radius, duration, easing, z-index, geometry) are
   shared by every preset and are NOT overridden there.

   Converters: use these names, never the literal. Where two names carry the
   same value (--fs-12 and --fs-sm) the NUMERIC one is the source of truth and
   the semantic one is an alias — either is safe; prefer the numeric one in a
   stylesheet, the semantic one reads better in JSX.
   =========================================================================== */
:root {

  /* ---- TYPE SCALE ------------------------------------------------------
     The sizes actually in use, smallest first. The half-steps are real (they
     appear 100+ times each); they are named, not collapsed, because snapping
     10.5 to 11 would move pixels. 14px is the document base (styles/base.css). */
  --fs-7-5: 7.5px;
  --fs-8-5: 8.5px;
  --fs-9: 9px;
  --fs-9-5: 9.5px;
  --fs-10: 10px;
  --fs-10-5: 10.5px;
  --fs-11: 11px;
  --fs-11-5: 11.5px;
  --fs-12: 12px;
  --fs-12-5: 12.5px;
  --fs-13: 13px;
  --fs-13-5: 13.5px;
  --fs-14: 14px;
  --fs-15: 15px;
  --fs-16: 16px;
  /* display sizes — Reports stat numerals, empty-state glyphs, page headings */
  --fs-17: 17px;
  --fs-18: 18px;
  --fs-20: 20px;
  --fs-22: 22px;
  --fs-23: 23px;
  --fs-24: 24px;
  --fs-26: 26px;
  --fs-28: 28px;
  --fs-30: 30px;
  --fs-32: 32px;
  --fs-34: 34px;
  --fs-36: 36px;
  --fs-38: 38px;
  --fs-44: 44px;
  --fs-48: 48px;
  /* semantic aliases (the names the JSX audit proposed) */
  --fs-2xs: var(--fs-10);      /* tiny meta, micro tags */
  --fs-xs: var(--fs-11);       /* eyebrows, uppercase micro-labels, meta rows */
  --fs-sm: var(--fs-12);       /* secondary labels, table cells, helper text */
  --fs-body: var(--fs-13);     /* default body / control text */
  --fs-base: var(--fs-14);     /* the document base size */

  /* ---- FONT WEIGHTS ---------------------------------------------------- */
  --fw-med: 500;               /* body copy that needs a little presence */
  --fw-semi: 600;              /* secondary labels, eyebrows, table headers */
  --fw-bold: 700;              /* the workhorse: labels, values, buttons, chips */
  --fw-heavy: 800;             /* micro-caps on tiny badges, where 700 will not read */

  /* ---- LETTER-SPACING (tracking) ---------------------------------------
     Suffix = the em value. 0.14 / 0.16 / 0.18 are three widths of ONE role
     (the uppercase eyebrow) — named apart because merging them moves pixels. */
  --track-005: 0.005em;        /* optical tracking on display headings */
  --track-01: 0.01em;
  --track-02: 0.02em;
  --track-03: 0.03em;
  --track-04: 0.04em;          /* small bold labels and buttons */
  --track-05: 0.05em;
  --track-06: 0.06em;
  --track-08: 0.08em;
  --track-10: 0.10em;
  --track-12: 0.12em;
  --track-14: 0.14em;          /* the standard eyebrow */
  --track-16: 0.16em;
  --track-18: 0.18em;

  /* ---- RADII -----------------------------------------------------------
     --r-sm (8), --r-md (12), --r-lg (20) and --r-pill (100px) are defined
     above and unchanged. NOTE --r-pill is 100px and --r-round is 999px: those
     are DIFFERENT numbers (they diverge on anything taller than 200px), so a
     999px site must use --r-round and must never be folded into --r-pill. */
  --r-xs: 6px;                 /* mini buttons, badges, inline chips */
  --r-7: 7px;                  /* off-scale hand-nudge; named so it stops spreading */
  --r-9: 9px;                  /* off-scale hand-nudge */
  --r-panel: 10px;             /* inner panels, list rows, medium cards */
  --r-card: 14px;              /* the modal / large-card shape */
  --r-round: 999px;            /* fully-rounded pill */

  /* ---- DURATIONS + EASINGS ---------------------------------------------
     --dur-1 (120ms) is the house standard: 570+ occurrences. Numeric rungs
     ascend; the semantic aliases point at them. */
  --dur-0: 100ms;              /* quickest feedback, dense lists and toolbars */
  --dur-1: 120ms;              /* the default state change */
  --dur-2: 140ms;              /* move / lift: transform, box-shadow, card hover */
  --dur-3: 180ms;
  --dur-4: 220ms;
  --dur-5: 240ms;
  --dur-6: 320ms;
  --dur-fast: var(--dur-1);
  --dur-med: var(--dur-2);
  --dur-slow: var(--dur-5);
  --dur-arc: 720ms;            /* the progress arc / donut sweep */
  --dur-pulse: 1.6s;           /* the "working" heartbeat pulse */
  --ease-glide: cubic-bezier(0.2, 0.7, 0.3, 1);   /* signature soft-out */
  --ease-pop: cubic-bezier(0.22, 1, 0.36, 1);     /* modals, toasts, cards in */
  /* the project-switch dim (base.css): the content under the header softens while the next
     project loads, and comes back the moment its rows are on screen */
  --switch-dim-dur: 480ms;
  --switch-dim-ease: cubic-bezier(0.4, 0.0, 0.2, 1);
  --switch-dim-opacity: 0.82;

  /* ---- Z-INDEX LADDER --------------------------------------------------
     The order below IS the current app stacking order, lowest to highest, and
     every value is the literal already in use — nothing moves. Read it top to
     bottom to see what sits above what.

       100   --z-sticky          sticky chrome (header, sidebar, shot header)
       200   --z-sticky-2        sticky rows + the sequence backdrop
       250   --z-header-menu     header dropdowns
       300   --z-backdrop        .modal-backdrop (styles/modal.css:8)
       400   --z-canvas-overlay  canvas full-bleed overlay
       500   --z-scrim           generate-page scrim
       999   --z-profile-gate    the blocking complete-profile card
      1000   --z-dropdown        dropdown / picker panels
      1001   --z-dropdown-close  the close button over one
      1200   --z-menu-backdrop   click-away layer under a floating menu
      1201   --z-menu            that menu
      1300   --z-notice          canvas notice + the batch-dispatch backdrop
      1500   --z-video           the video player
      2000   --z-modal           a modal over the app
      2100   --z-modal-2         a modal over a modal
      2150   --z-merge-bar       the assets merge bar, just over --z-modal-2
      2200   --z-modal-3
      2300   --z-modal-4
      2400   --z-modal-5
      2600   --z-modal-6         the deepest routine modal stack
      4000   --z-dialog          full-page dialogs / confirm backdrops
      4001   --z-dialog-close    the close button over one
      4500   --z-audio-dock      the floating audio dock
      5000   --z-overlay         page overlays (asset review, login, uploads)
      5600   --z-header-pop      the header avatar / notification popover
      6000   --z-popover         floating bubbles (assistant, notepad, to-do)
      6200   --z-addlib          the add-from-library overlay
      6250   --z-shotedit        the shot-edit overlay, just over it
      6300   --z-mobile-nav      mobile nav bar
      6450   --z-mobile-scrim    mobile drawer scrim
      6500   --z-mobile-drawer   mobile drawer
      6600   --z-mobile-burger   mobile burger button
      6900   --z-hover-preview   the click-through hover-preview picker
      7000   --z-toast           toasts + the crop overlay
      7200   --z-deck-lightbox   the deck viewer lightbox
      8000   --z-fullscreen      full-screen media
      9000   --z-crop            the crop / mask editor overlay
      9001   --z-crop-panel      its panel
     10000   --z-lightbox        the image lightbox, above everything routine
     99999   --z-crash           the ErrorBoundary crash card

     The four "+1" rungs are written as calc() so the pairing stays visible. */
  --z-sticky: 100;
  --z-sticky-2: 200;
  --z-header-menu: 250;
  --z-backdrop: 300;
  --z-canvas-overlay: 400;
  --z-scrim: 500;
  --z-profile-gate: 999;
  --z-dropdown: 1000;
  --z-dropdown-close: calc(var(--z-dropdown) + 1);
  --z-menu-backdrop: 1200;
  --z-menu: calc(var(--z-menu-backdrop) + 1);
  --z-notice: 1300;
  --z-video: 1500;
  --z-modal: 2000;
  --z-modal-2: 2100;
  --z-merge-bar: 2150;
  --z-modal-3: 2200;
  --z-modal-4: 2300;
  --z-modal-5: 2400;
  --z-modal-6: 2600;
  --z-dialog: 4000;
  --z-dialog-close: calc(var(--z-dialog) + 1);
  --z-audio-dock: 4500;
  --z-overlay: 5000;
  --z-header-pop: 5600;
  --z-popover: 6000;
  --z-addlib: 6200;
  --z-shotedit: 6250;
  --z-mobile-nav: 6300;
  --z-mobile-scrim: 6450;
  --z-mobile-drawer: 6500;
  --z-mobile-burger: 6600;
  --z-hover-preview: 6900;
  --z-toast: 7000;
  --z-deck-lightbox: 7200;
  --z-fullscreen: 8000;
  --z-crop: 9000;
  --z-crop-panel: calc(var(--z-crop) + 1);
  --z-lightbox: 10000;
  --z-crash: 99999;

  /* ---- GEOMETRY CONSTANTS ----------------------------------------------
     --glass-blur was READ but never DEFINED: styles/backdrop.css:40, 41, 61, 62
     say blur(var(--glass-blur, 18px)), so the app's single glass knob has
     always fallen back and done nothing. 18px is the value it fell back to, so
     defining it moves no pixel and turns the knob back on. */
  --glass-blur: 18px;
  --blur-scrim: 4px;           /* modal / lightbox scrim blur — suffix = px */
  --blur-scrim-2: 2px;
  --blur-scrim-3: 3px;
  --blur-scrim-6: 6px;
  --hairline-w: 1px;           /* box-shadow: 0 0 0 1px — the crisp hairline ring */
  --ring-w: 2px;               /* focus / selection ring: 0 0 0 2px, outline 2px */
  --ring-offset: 2px;          /* outline-offset on the same treatment */
  --sidebar-w: 240px;          /* nav rail — sidebar.css:55 (::after), :78, :79 */
  --sidebar-w-collapsed: 64px; /* sidebar.css:67 (::after), :106, :107 */
  --r-shell: 26px;             /* the main panel's two left corners (header.css .main-content) */
  --shot-status-col-w: 296px;  /* the shot row's right column (divider + pill/version + 72px ring). ONE width
                                  in every state: fresh load, after Settings, any thumbnail size (17 Sep 2026:
                                  an old 230px rule squeezed it after a Settings visit). responsive.css narrows it. */
  --shell-corner-aa: 0.5px;    /* the half pixel a corner mask fades over, so its curve is smooth */
  --ph-style-pop-w: 264px;     /* the header's style switcher (StylePill): popover width */
  --ph-style-swatch: 14px;      /* ... one colour chip */
  --ph-style-swatch-gap: 3px;   /* ... space between chips */
  --shot-row-ph-h: 135px;       /* a project switch's placeholder row (shots.css .shot-row-ph) before any real
                                   row was measured; afterwards it copies the last shot row's height */

  /* ---- SMALL PAINTS THAT USED TO BE TYPED IN (16 Sep 2026) ---------------
     Hugo: "Triple check everything i mentioned is a variable". A recolour audit found these
     colours ignoring every skin. Each value here is exactly what the component used to type,
     so Paradise Found paints the same; a skin family re-points them at its own colours. */
  --thumb-tag-bg: rgba(0, 0, 0, 0.35);                                  /* shots.css .shot-thumb-tag plate */
  --thumb-tag-ink: color-mix(in srgb, var(--white) 90%, transparent);   /* its SH0010 text */
  --thumb-inset-hi: rgba(255, 255, 255, 0.18);                          /* shots.css .shot-thumb top line */
  --media-thumb-inset-hi: rgba(255, 255, 255, 0.10);                    /* footer-row.css .media-thumb top line */
  --panel-text-shadow-color: rgba(0, 0, 0, 0.35);                      /* the 1px text shadow of dark panels */
  --donut-shadow-color: var(--shade-38);                                /* topbar.css .tb-donut drop shadows */
  --donut-join-shadow: var(--black);                                    /* TopBar.jsx: the shade where two arcs meet */
  --donut-focus-glow: var(--black);                                     /* TopBar.jsx: the halo of a focused arc */
  --fab-ink: var(--white);                                              /* the icons on the round floating buttons */
  --status-pill-bevel-hi: rgba(255, 255, 255, 0.30);                    /* header.css .ph-status-pill */
  --status-pill-bevel-lo: rgba(0, 0, 0, 0.18);
  --status-pill-drop: rgba(0, 0, 0, 0.20);
  --status-pill-fill-mix: 18%;       /* the project status tag: how much of its colour tints the fill */
  --status-pill-line-mix: 50%;       /* ... and its rim */
  --status-list-fill-mix: 14%;       /* the same tag in the project switcher list */
  --status-list-line-mix: 45%;

  /* ---- THE PROJECT SWITCHER (17 Sep 2026) ---------------------------------
     Hugo: "im gonna have so many projects, it will be massive. Make little cards instead on one
     row". The picker (ProjectHeader.jsx, header.css .ph-project-strip) is ONE sideways-scrolling
     row of fixed-size cards, so it is the same height for 2 projects or 50. Opening and closing is
     ONE motion: the panel's height, its glass, the label and the cards share one speed and curve,
     and every gap sits INSIDE the clipped box so nothing snaps when the panel shuts. */
  --ph-proj-card-w: 220px;             /* one project card */
  --ph-proj-card-h: 96px;
  --ph-proj-card-gap: 8px;             /* between two cards */
  --ph-proj-card-r: var(--r-panel);    /* the corner the list rows had */
  --ph-proj-card-pad-y: 10px;          /* the rows' padding, kept */
  --ph-proj-card-pad-x: 12px;
  --ph-proj-card-line-gap: 4px;        /* name to subtitle; icon to label on the two action cards */
  --ph-proj-card-lift: 1px;            /* hover lift; the row keeps this much room above the cards */
  /* under the cards, for Chrome's thin sideways scrollbar. The scrollbar is 10 SCREEN px at any app
     scale, and the page is zoomed (index.html sets --ui-zoom), so the room is 12 screen px turned
     into page px: at 80% scale it is 15px, or the bar would cover the cards' bottom edge. */
  --ph-proj-strip-gutter-screen: 12px;
  --ph-proj-strip-gutter: calc(var(--ph-proj-strip-gutter-screen) / var(--ui-zoom, 1));
  --ph-proj-open-gap: 14px;            /* the subtitle line to the rule above SWITCH TO */
  --ph-proj-rule-gap: 12px;            /* that rule to SWITCH TO */
  --ph-proj-head-gap: 8px;             /* SWITCH TO to the cards */
  --ph-proj-slide: 0px;                /* how far the label and cards drift while they fade: none, so
                                          SWITCH TO never moves; the panel edge closes over it */
  --ph-picker-dur: var(--dur-5);       /* the header's expand speed (the search pill's too) */
  --ph-picker-ease-open: var(--ease-glide);              /* opens fast, settles soft */
  --ph-picker-ease-close: cubic-bezier(0.4, 0, 0.2, 1);  /* closes with no first-frame lurch */

  /* ---- THE GLASS SHADOW STACKS -----------------------------------------
     The signature bevel + lift. The copies are NOT interchangeable — .glass,
     .view-page and .topbar each use different opacities — so there are two
     tokens, one per stack, and each may only be adopted by its own site:
       --shadow-glass       styles/backdrop.css:44    (.glass)
       --shadow-glass-page  styles/views-pages.css:26 (.view-page)
     .topbar and .glass-dark are deliberately NOT tokenised: two of their
     layers are pure-black shadows, which the audit leaves literal. */
  --shadow-glass:
    inset 0 1px 0 color-mix(in srgb, var(--hi) 65%, transparent),
    inset 1px 0 0 color-mix(in srgb, var(--hi-2) 35%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--shadow-ink-2) 8%, transparent),
    inset -1px 0 0 color-mix(in srgb, var(--shadow-ink-2) 5%, transparent),
    0 2px 6px color-mix(in srgb, var(--shadow-ink) 12%, transparent),
    0 14px 28px color-mix(in srgb, var(--shade) 22%, transparent),
    0 24px 56px color-mix(in srgb, var(--shade) 34%, transparent);
  --shadow-glass-page:
    inset 0 1px 0 color-mix(in srgb, var(--hi) 65%, transparent),
    inset 1px 0 0 color-mix(in srgb, var(--hi-2) 35%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--shadow-ink-2) 6%, transparent),
    inset -1px 0 0 color-mix(in srgb, var(--shadow-ink-2) 4%, transparent),
    0 2px 6px color-mix(in srgb, var(--shadow-ink) 8%, transparent),
    0 8px 18px color-mix(in srgb, var(--shade) 14%, transparent),
    0 18px 40px color-mix(in srgb, var(--shade) 20%, transparent);

  /* ---- HAIRLINES -------------------------------------------------------
     THE UNDEFINED-VARIABLE BUG. styles/edit-plan.css (12 sites) and
     styles/review.css (3) read a phantom --rule with an rgba(0,0,0,a) fallback,
     and styles/views-pages.css:2857 reads a phantom --line with an
     rgba(0,0,0,0.14) fallback; neither --rule nor --line is defined anywhere,
     so the fallback paints 100% of the time and the reference is decoration.
     FOUR different alphas are in use, so a single --rule would silently
     restyle three of them — hence four tokens, suffix ascending by strength.
     They are NOT named --rule / --line on purpose: defining those two would
     change three sites the moment it landed. Each site gets swapped by hand.
       --line-soft    0.08  edit-plan 81, 329, 397, 801, 1017
       --line-soft-2  0.10  review 1388
       --line-soft-3  0.14  edit-plan 30, 54, 91, 233, 1223 · review 1398 ·
                            views-pages 2857 (the --line site)
       --line-soft-4  0.16  edit-plan 290 · review 1466                     */
  --line-soft: color-mix(in srgb, var(--black) 8%, transparent);
  --line-soft-2: color-mix(in srgb, var(--black) 10%, transparent);
  --line-soft-3: color-mix(in srgb, var(--black) 14%, transparent);
  --line-soft-4: color-mix(in srgb, var(--black) 16%, transparent);

  /* ---- NEW APP-CHROME COLOURS ------------------------------------------ */
  --sunken-bg: color-mix(in srgb, var(--black) 18%, transparent);        /* inset panel on dark chrome */
  --tile-add-border: color-mix(in srgb, var(--black) 22%, transparent);  /* dashed "+ ADD" tile outline */
  --canvas-capture-bg: #26231A;   /* painted behind a Canvas storyboard capture (CanvasPage.jsx:1972) */
  --icon-select-chev: #8A7B53;    /* the select chevron drawn as a data: URI (generate.css:711). A custom
                                     property cannot be interpolated into url(), so that site needs
                                     mask-image + background-color, not a plain swap. */
  --avatar-grad-1: oklch(0.62 0.06 60);  /* reference-avatar initials circle, views-pages.css:2786 */
  --avatar-grad-2: oklch(0.45 0.04 30);  /* kept as oklch: hex would round and move the colour */
  --red-32: #B5392F;              /* Presentations remove/clear red — tag X, Clear all, past-deck icon */
  --ink-red-32: var(--red-32);    /* its TEXT twin (presentations.css:204, 337) */
  --red-33: #DC3545;              /* past-deck Delete hover fill + border (rgba(220,53,69,a)) */
  --red-34: #C4392F;              /* past-deck Delete hover TEXT */
  --ink-red-34: var(--red-34);
  --ink-gold-6: #A0541F;          /* the Combine button's text on a 14% gold tint */
  --tag-outro: #7A5A8A;           /* extra-slide tag chips. NOT --purple / --teal-3 / --blue-23 / */
  --tag-grid: #3F6B6B;            /* --st-retake: none of those is equal, and reusing one moves pixels */
  --tag-agenda: #3F5A6B;
  --tag-retake: #6B3F55;
  --shade-65: #0E120B;            /* deck lightbox stage */
  --shade-66: #161B0F;            /* text-only slide background */
  --shade-67: #1A221A;            /* grid cell inside a multi-image slide */
  --shade-68: #1D221B;            /* deck image-swap picker cell */

  /* ---- DECK TEMPLATE PALETTE (--ptpl-*) --------------------------------
     The four client-deck templates (dark cinematic, clean client, production
     report, editorial). These are DELIBERATELY not overridden in themes.css:
     a deck Hugo sends a client must look the same whichever UI preset he is
     running. They live here so they are named, findable and in one place.
     Four near-identical papers (#F4F2EA / #F4F2EC / #F8F6EE / #EEECE4) and
     four near-identical inks (#1B1A16 / #1C1A17 / #1F1C14 / #1C2117) are kept
     apart on purpose — merging them would change rendering and is Hugo's call.
     The veil tokens are the SOLID colour; each site applies its own alpha. */
  --ptpl-dark-panel: #2E3527;
  --ptpl-clean-panel: #F4F2EA;
  --ptpl-report-panel: #F4F2EC;
  --ptpl-clean-veil-hi: #F8F6EE;
  --ptpl-report-veil-lo: #EEECE4;
  --ptpl-clean-cover: #F3EFE6;
  --ptpl-editorial-panel: #FAF7F1;
  --ptpl-ink: #1B1A16;
  --ptpl-ink-editorial: #1C1A17;
  --ptpl-ink-clean: #1F1C14;
  --ptpl-ink-card: #1C2117;
  --ptpl-ink-body: #4A463C;
  --ptpl-ink-body-2: #45423A;
  --ptpl-ink-body-3: #4A443C;
}

/* ---- light and edge (16 Sep 2026) ---- */
:root {
  /* The dark line drawn OUTSIDE a panel. With the light rim already on the inside, the pair
     reads as a bevelled edge catching light instead of a rectangle drawn on the page. The
     forest look has no such line, so the default is transparent and nothing changes. */
  --ring-contact: transparent;

  /* ---- MATERIAL SYSTEM (16 Sep 2026) ----
     Hugo's spec: the mockup differs from us in MATERIAL and LIGHT, not hue. Surfaces need a
     depth ladder, top edges need to catch light, panels need soft internal colour pools, and
     'borders' must never be real borders because a border changes the box and moves the page.
     Defaults below are inert for Paradise Found: nothing in the forest look reads them. ---- */
  --surf-page: var(--bg);
  --surf-recessed: var(--sidebar-bg);
  --surf-container-1: var(--card-bg);
  --surf-container-2: var(--card-bg);
  --surf-raised-1: var(--card-bg);
  --surf-raised-2: var(--card-bg);
  --surf-card-1: var(--card-bg);
  --surf-card-2: var(--card-bg);
  --surf-card-3: var(--card-bg);
  --surf-input: var(--input-bg);
  --edge-1: var(--card-border);
  --edge-2: var(--card-border);
  --edge-3: var(--card-border);
  --spec-1: transparent;
  --spec-2: transparent;
  --spec-3: transparent;
  --elev-1: var(--shadow-card);
  --elev-2: var(--shadow-card);
  --elev-3: var(--shadow-card);
  --pool-hot: transparent;
  --pool-cool: transparent;
  --pool-violet: transparent;
  --bloom-hot: none;
  --bloom-cool: none;
  --bloom-violet: none;
  --grain-opacity: 0;
  --vignette: transparent;
  /* Accent glow. A dark skin bleeds light into the surface behind a lit element; the forest
     look does not glow at all, so these are none by default. */
  --glow-hot: none;
  --glow-cool: none;
  --glow-soft: none;
}

/* ---- nav ink (16 Sep 2026) ---- */
:root {
  /* The sidebar's labels used --ink-on-accent, the same token as text sitting ON an accent
     fill. A skin that sets a dark ink-on-accent (correct for a bright button) therefore
     painted the menu near-black on near-black chrome. The sidebar now has its own role; the
     default IS --ink-on-accent, so the forest look is unchanged. */
  --ink-nav: var(--ink-on-accent);
}

/* ---- skin texture index (17 Sep 2026) ----
   Which part of a texture tile a box shows: styles/skin-paper.css sets it (inside its
   --sk-texture gate) from sibling-index() on the card wrappers, and each card's background
   position is this index times a step. It must be a REGISTERED integer: an unregistered custom
   property holding sibling-index() resolves on the card itself, so every card got the same
   offset (measured in the sandbox). Nothing reads it outside that gate, so the forest look and
   every skin without a texture paint exactly as before. */
@property --sk-tex-i {
  syntax: "<integer>";
  inherits: true;
  initial-value: 0;
}

/* ---- where the project photo sits, and the brand ornament's box (18 Sep 2026, Athenian Marble) ----
   --sk-photo-position: the anchor of a project's photo (backdrop.css, body.has-backdrop-image). The
   default is the place every photo always had; a skin block may set it (Athenian Marble: 50% 0%, its
   temple behind the title). Position only - nothing filters, blends or tints the photo. It is read on
   the body, where the skin sets it, so it is never stale.
   --orn-brand-*: the box of the brand ornament right after the rail's wordmark (sidebar.css
   .sb-title::after, absolutely positioned: it moves nothing). The paper family paints it through a
   mask only when a skin gives it a colour and an image. Geometry, the same in every skin: a skin
   block never sets these (test/skinContract.test.js). The other ornaments are whole-box masks
   (topbar.css, footer-row.css): their size and place inside the box are paint tokens of the family. */
:root {
  --sk-photo-position: center center;
  /* 24 Sep 2026 - how big a project's photo is drawn (backdrop.css). cover = today's value for every skin. A skin
     whose mockup shows the whole photo across the page width (the night-blue slate skin: the tree small, with its
     horizon above the stats band) sets `100% auto`; the page colour shows below the photo on a tall window. */
  --sk-photo-size: cover;
  --orn-brand-w: 20px;      /* the free room between the wordmark and the collapse button is 22.8px at 2268 */
  --orn-brand-h: 18px;
  --orn-brand-gap: 1.5px;   /* from the end of the word */
  --orn-brand-dy: 3px;      /* down from the top of the word's line */
}

/* ---- THE SEPARATION LADDER (24 Sep 2026) ----
   Hugo, on the Admin page in Neon Synth Wave and Rain At Dusk: "panels should ALWAYS be slightly lighter
   than the background so we have visual separation ... make that a rule." Every nesting level sits slightly apart
   from what it sits on: the page panel (.view-page) < a panel inside it (.view-page .glass) < a card inside that
   (Admin's invite form, Settings' theme cards) < a row or cell (Admin's user and membership rows, the matrix
   cells, integration rows). Forest (a pale skin) reads it as page panel #E0D9C7 < panel #EEE8D7 < card/row cream,
   each step 3+ L* apart; the glass family re-points every step to a light wash over the level below, and the
   paper family's copy is generated from these lines. A panel's muted ink is drawn a touch nearer the ink, so the
   greys stay readable on the panel's own fill. Measured by the skill's audit-separation.js; the token-level
   guard is test/skinSeparation.test.js.
   The CHECK cells (Admin's permission matrix, Settings' menu-preset pages, a document's role access): a granted
   cell is a SOLID fill with a high-contrast mark, a denied one keeps its quiet surface and muted dash. */
:root {
  --sep-panel: var(--card-bg-light-solid);
  --sep-panel-fill: color-mix(in srgb, var(--sep-panel) 92%, transparent);
  --sep-card-fill: color-mix(in srgb, var(--cream-2) 90%, transparent);
  --sep-row-fill: color-mix(in srgb, var(--cream) 94%, transparent);
  --sep-row-fill-hover: var(--cream);
  --sep-panel-ink-muted: color-mix(in srgb, var(--ink-muted) 84%, var(--ink));
  --check-on-fill: color-mix(in srgb, var(--olive-3) 82%, var(--forest));
  --check-on-ink: var(--ink-on-accent);
  /* READABLE WHEN DISABLED (24 Sep 2026, Hugo: a greyed Generate asset read as broken, and he does not accept
     "disabled is exempt"). A disabled control is not faded any more: it takes a quiet neutral fill with the ink at
     full strength (4.5:1 or more), so it reads clearly and still reads as not available. */
  --disabled-fill: color-mix(in srgb, var(--ink-muted) 24%, var(--card-bg-solid));
  --disabled-ink: var(--ink);
  --disabled-line: color-mix(in srgb, var(--ink-muted) 45%, transparent);
}
