/* ============================================================================
   NomNum, design tokens
   THE single place colour, material, type scale and motion are defined. Every
   page links this file first, and nothing downstream should contain a raw hex,
   rgb() or hsl() literal: use a var() from here, or color-mix() on one. If you
   need a value that does not exist yet, add it here with a name that says its
   ROLE, not its appearance.

   THE DESIGN LANGUAGE, in one paragraph (measured paper, docs/DESIGN_PLAN.md,
   amended by the sea-glass pass). One cool ground, brighter surfaces, hairline
   rules, near-black type. Colour appears where it means a state: the accent for
   actions, the measurement ramp for provenance and band position.

   MEASURED PAPER STILL GOVERNS SURFACES; IT NO LONGER GOVERNS CONTROLS. The
   flattening pass took depth off everything, and the owner sent the buttons
   back for it ("that depth button effect which we had before"). The line drawn
   here is the one that survived review: a PANEL is paper and separates with a
   hairline, a CONTROL is an object and has a thickness you can press. Cards,
   bands and sections still get no gradient and no glow.

   Four rules keep it honest, and scripts/token-contrast.mjs enforces the first
   three on every run rather than trusting the numbers written here:
     1. --accent-cyan and --accent-mint are LIGHT. They never carry text.
     2. --foreground, --foreground-muted and --accent-deep are TEXT colours,
        each verified >=4.5:1 on every ground in this file.
     3. Fills clear the 3:1 non-text floor against --band-track.
     4. Anything carrying white text clears 4.5:1 AT EVERY STOP, which for
        --grad-cta means both ends of the sweep, not just the dark one. That
        is pinned in tests/s07 against the PAINTED stops, because a by-name
        assertion let a repointed gradient through once already.
   ========================================================================= */
:root {
  /* ---- 1. THE GROUND ------------------------------------------------------
     WHITE. The owner's direction, given plainly after the all-teal pass:
     "Blue and Green gradients with white and then a darker color." The cream
     ground was rejected long before ("I hate the background color, it is not
     refreshing") and refreshing still governs: this is a cool white with a
     whisper of blue, not a warm paper. The teal Mist ground is gone with the
     teal system it belonged to.

     Depth survives the change. Surfaces are pure white and the ground sits a
     step below them, so a raised thing is still raised by light as well as by
     shadow - the half of the depth effect the shadows cannot supply alone. */
  --background: #fafcfe;
  --background-secondary: #edf3fa;
  --surface: #ffffff;
  --surface-elevated: #ffffff;
  /* INK: the owner's "darker color" - deep navy, not #000. A warm ink over a
     cool ground is the muddy combination this file exists to prevent, and the
     same navy anchors the hero's dark room and the pressed sweep, so the
     darkest thing on every surface is one colour. */
  --foreground: #0b1e3b;
  --foreground-muted: #44586e;
  --border: #d7e2ee;
  --border-strong: #b9c9da;

  /* ---- 2. THE ACCENT RAMP (actions, selection, the intelligent moments) ---
     BLUE INTO GREEN, the owner's brief restated in review after the all-teal
     pass collapsed the blue half: "Blue and Green gradients with white and
     then a darker color." ROYAL BLUE carries action, EMERALD carries good
     news and the far end of the CTA sweep, and the two lights are the fresh
     ends of each. The pairing is the point rather than decoration - the
     primary button is a gradient FROM the blue TO the green, so the two
     halves of the brief are the same object.

     The LIGHTS rule survives every repaint this file has been through:
     --accent-cyan (light blue) and --accent-mint (mint) never carry text.
     Both accents clear AA with white - royal #1d4ed8 is 6.70:1 and emerald
     #047857 is 5.49:1 - which is what lets the gradient carry white text
     across its WHOLE length rather than only at its dark end. That was the
     defect the old --grad-cta had to be measured for, and it is measured
     again here. */
  --accent-blue: #1d4ed8;
  --accent-blue-deep: #1e3a8a;
  --accent-cyan: #93c5fd;
  --accent-emerald: #047857;
  --accent-emerald-deep: #065f46;
  --accent-mint: #a7f3d0;
  --accent: var(--accent-blue);
  --accent-deep: var(--accent-blue-deep);
  /* THE ACCENT'S TEXT ROLE, NAMED SEPARATELY FROM ITS FILL ROLE.
     --accent-deep painted 138 text sites and 31 backgrounds, and --accent
     another 60 and 9. On a white ground one dark blue serves both; on E5's
     peacock field the fills are still correct (white on royal blue is 6.70:1)
     and only the TEXT is unreadable. One name doing two jobs is the defect, so
     the text role gets its own name and the fill keeps the old one. Here it
     aliases straight back, which is what keeps the landing page and the legal
     pages rendering exactly as they did. */
  --accent-text: var(--accent-blue-deep);
  --accent-text-alt: var(--accent-emerald);
  --accent-ink: #ffffff;
  /* INK ON A BRIGHT FILL, which is NOT the same role as ink on the accent even
     though on this palette both are white. --accent-deep is a dark navy in both
     palettes and always takes white; a token like --green flips from a deep
     emerald here to a light mint on the field and takes dark ink there. Naming
     them separately is what stops one from dragging the other: E5's first pass
     pointed --accent-ink at the dark peacock to fix a light mint badge and
     turned every .chip.active into dark-on-navy at 1.54:1. */
  --ink-on-bright: #ffffff;

  /* ---- 3. MATERIALS -------------------------------------------------------
     There is no glass any more. The eight glass tokens (tint, edge, highlight
     and two blurs) were deleted in the measured-paper pass: frosted panels say
     "premium software", and an instrument face is opaque. That still holds.
     SURFACES are --surface with a --border hairline and at most --shadow-sm.
     Depth belongs to the CONTROLS instead, and its tokens live in §6. */

  /* ---- 3b. THE MEASUREMENT RAMP (docs/DESIGN_PLAN.md §6) ------------------
     NOTHING CONSUMES THESE YET. They are added ahead of the components that
     will use them so the palette can be argued about and contrast-checked on
     its own, rather than in the same commit that moves a hundred surfaces.

     The luminous ramp above answers "is something nice happening here?", which
     is not a question about the data. This ramp answers the two questions an
     instrument has to answer: WHERE DID THIS NUMBER COME FROM, and WHERE DOES
     IT SIT AGAINST ITS TARGET. The claims ledger established that the app can
     already tell measured from modelled from guessed; until now that
     distinction arrived as small grey text beside a bold number that looked
     equally certain either way.

     CONTRAST, MEASURED not assumed. This block used to carry a table of ratios
     against grounds named by hex. The table was deleted rather than retuned in
     the sea-glass pass, because a hand-copied figure is exactly the "one rule
     written twice, then drifting" this file warns about, and every number in
     it was already stale from two repaints earlier. scripts/token-contrast.mjs
     reads the CURRENT grounds out of this file and re-derives all of it: every
     TEXT token >=4.5:1 on all three grounds, every fill >=3:1 on --band-track,
     the two provenances >=3:1 against each other. Run it, do not read a table.
     ---------------------------------------------------------------------- */

  /* PROVENANCE. What kind of number is this? The left rule on a row, and the
     fill of a tolerance bar. Three values because the data has three kinds. */
  --m-measured: #14151a; /* a label or a database row */
  --m-modelled: #5e6a6d; /* computed from ingredient tables; cool slate */
  /* NOT --foreground-muted, which is a TEXT role and sits too close to
     --m-measured to work as a fill beside it: at the sea-glass values that
     pairing measures 3.01:1, a hair over the 3:1 non-text floor and under it
     at the two palettes before this one, which is how a bar that was half
     measured and half modelled once read as one solid bar. This is that slate
     moved until it clears the floor with room to spare: 3.26:1. */
  --m-estimated: transparent; /* the person's own guess: outline, never a fill */
  /* the one gradient that survives the pass, because it carries information:
     hatching IS the statement "we do not know this precisely" */
  --m-hatch: repeating-linear-gradient(
    45deg,
    var(--m-modelled) 0 1px,
    rgba(255, 255, 255, 0) 1px 4px
  );

  /* BAND. Where does the reading sit against its target range? */
  --band-under: #3d6a8a;
  --band-in: var(--success); /* the palette's green, already verified as a text colour */
  /* over-budget is a HALDI moment, warm attention, never an alarm: the
     no-shame check bars the alarm tokens from over states. */
  --band-over: #8a5a00;
  --band-alarm: var(--danger); /* chili, and only ever a genuine alarm */
  /* the unfilled part of every bar. #e4e6e4 was the first choice and measured
     1.12:1 against the proposed ground, which makes the bar's EXTENT invisible:
     you could see the fill and not how far the target was. Darkened until the
     track reads as a track (1.44:1) while every fill still clears 3:1 on it. */
  --band-track: #c3cbd8;

  /* ---- 3c. THE LIVING THALI (food illustration, not interface chrome) ----
     Steel stays cool grey even on a warm page because it is an OBJECT the
     page holds, not a surface of the page; the fills are the foods the brief
     names: dal pours gold, palak lands green, rice mounds white. */
  --tk-steel: #d8dade;
  --tk-steel-deep: #b9bcc2;
  --tk-well: #eceef1;
  --tk-dal: #e8b54a;
  --tk-palak: #3a7d57;
  --tk-rice: #fffdf6;
  --tk-curd: #fff4dc;
  --tk-haldi: #d99306;

  /* ---- 4. STATUS ---------------------------------------------------------- */
  /* success IS the palette's green, deliberately: with blue leading action,
     "good news" and "the far end of the CTA" being one colour is coherence
     rather than collision. Warning and danger stay WARM against the cool
     ground, which is what makes an alert read as an interruption at all. */
  --success: #047857;
  --success-soft: #d6efe4;
  --warning: #8a5a00;
  --warning-soft: #f7ecd2;
  /* CHILI. Rare emphasis only; never an over-budget state (enforced by
     scripts/no-shame.mjs, not remembered). */
  --danger: #b8442c;
  --danger-soft: #f6ded6;

  /* ---- 5. GEOMETRY -------------------------------------------------------- */
  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-xl: 34px;
  --radius-pill: 999px;

  /* ---- 6. ELEVATION ------------------------------------------------------
     DEPTH IS BACK ON THE CONTROLS, and only on the controls. The measured-paper
     pass (0164c65) deleted --shadow-md, --shadow-floating and both glows on the
     argument that "four levels of elevation on a flat page is a hierarchy
     nothing earned". That argument still holds for SURFACES: cards, bands and
     panels separate with hairlines below, and none of them gets a shadow back.

     It was wrong about BUTTONS. The owner asked for "that depth button effect
     which we had before", and a thing you press is exactly the thing that has
     to look pressable: a raised object that compresses under a finger. A flat
     rectangle that shrinks 2.8% is a state change, not a physical one. So the
     three-layer press survives (scale, lift, shadow) and gets its missing
     layer back - a resting elevation for the press to move AWAY from.

     The shadow ink is the new blue-black, not the old warm 18,20,28: a warm
     shadow under a cool control is the muddy edge this file keeps re-learning.
     The glows read --accent-rgb rather than carrying their own copy of the
     blue, which is the defect the triplet note at the bottom of this file
     records: the Rice repaint moved every hex and left the orbs indigo. */
  --shadow-sm: 0 1px 2px rgba(6, 47, 49, 0.06), 0 2px 8px rgba(6, 47, 49, 0.05);
  --shadow-md: 0 2px 6px rgba(6, 47, 49, 0.08), 0 10px 24px rgba(6, 47, 49, 0.09);
  /* the RESTING depth of a control: a tight contact shadow plus a soft cast,
     so the pill sits ON the page rather than being printed into it */
  --shadow-raised: 0 1px 1px rgba(6, 47, 49, 0.1), 0 3px 8px rgba(6, 47, 49, 0.12);
  --shadow-pressed: 0 1px 2px rgba(6, 47, 49, 0.16), 0 2px 5px rgba(6, 47, 49, 0.12);
  /* the accent's own light, for primaries at rest and on hover. Not a drop
     shadow: it is the colour of the button, thrown. */
  --glow-accent: 0 8px 22px rgba(var(--accent-rgb), 0.3);
  --glow-accent-soft: 0 5px 14px rgba(var(--accent-rgb), 0.2);
  /* the two INTERNAL layers that make a pill read as a moulded object rather
     than a coloured box: a lit top edge and a shaded floor, both inset. */
  --bevel-raised:
    inset 0 1px 0 rgba(var(--white-rgb), 0.34), inset 0 -2px 4px rgba(var(--shade-rgb), 0.16);
  --bevel-pressed:
    inset 0 2px 5px rgba(var(--shade-rgb), 0.3), inset 0 -1px 0 rgba(var(--white-rgb), 0.14);

  /* ---- 7. MOTION ---------------------------------------------------------
     Two modes, and they must never be confused. PRODUCT motion (instant to
     standard) belongs to anything a person does many times a day: pressing,
     selecting, typing, navigating. STORY motion (slow, cinematic) belongs to
     the homepage and onboarding, where the point is the telling. Using a
     cinematic duration on a quantity stepper is how a beautiful product
     becomes an exhausting one. */
  --motion-instant: 100ms;
  --motion-fast: 160ms;
  --motion-medium: 260ms;
  --motion-slow: 520ms;
  --motion-cinematic: 900ms;
  /* the press pair, from the physical-button spec: compress fast, release
     with a little overshoot so the glass feels sprung rather than snapped */
  --motion-press: 90ms;
  --motion-release: 180ms; /* §2.2: spring back in ~180ms */
  --ease-standard: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.55, 0, 1, 0.45);
  --ease-spring: cubic-bezier(0.34, 1.42, 0.64, 1);

  /* ---- 8. TYPE -----------------------------------------------------------
     Manrope is already self-hosted here as a variable font (200-800), which is
     why it is the face: it is legal to ship, it is one file, and its wide
     apertures survive being set at 9vw. The scale is deliberately split. The
     top four sizes are for STORYTELLING and appear on the homepage and in
     onboarding; the bottom four are the product's working sizes and stay
     Apple-restrained no matter what the storytelling pages are doing. */
  --font: 'Manrope', Inter, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* The prose ceiling came DOWN in the measured-paper pass: the old ramp ran
     to 144px for slogans while the day's calorie unit rendered at 11.5px.
     Prose now tops out at 54px and only a READING (--text-readout, 67px) may
     be larger, which is the thesis in two numbers. */
  --text-hero: clamp(2rem, 4.2vw, 3.4rem);
  --text-statement: clamp(1.7rem, 3.2vw, 2.6rem);
  --text-section: clamp(1.4rem, 2.4vw, 2rem);
  --text-feature: clamp(1.15rem, 1.6vw, 1.4rem);
  --text-lead: clamp(1.05rem, 1.5vw, 1.4rem);
  --text-body: 1rem;
  --text-ui: 0.9375rem;
  --text-caption: 0.8125rem;
  /* READOUT: the only role in the product allowed to be large, and the reason
     the four sizes above it will come down (docs/DESIGN_PLAN.md §6).
     Measured on the real dashboard at 768px before this existed: the day's
     calorie unit was 11.5px and the footer's decorative wordmark was 80.6px,
     seven times the size of the number the app exists to produce. A reading is
     not a caption. NOTHING CONSUMES THESE YET; they arrive with the tolerance
     bar. */
  --text-readout: clamp(2.4rem, 6vw, 4.2rem);
  --text-readout-sm: clamp(1.4rem, 3vw, 2rem);
  /* display type needs negative tracking to stop looking loose; UI type does
     not, and applying the display value to 13px body copy is a classic tell */
  --track-display: -0.03em;
  --track-tight: -0.015em;
  --leading-display: 1.02;
  --leading-body: 1.6;

  /* ========================================================================
     THE BRIDGE
     Everything below is a legacy role name kept alive and repointed at the
     palette above. The app is ~3,400 lines of CSS written against these
     names; repointing them re-skins every surface in one move and lets the
     redesign replace them screen by screen without a broken intermediate
     state. Each block dies when its last consumer is rewritten. Nothing here
     introduces a NEW literal: if a value appears twice, one of them is wrong.
     ===================================================================== */

  /* neutral scale, formerly the blue ramp and briefly a warm sand one. It is
     a COOL neutral again, and this time the name is honest: these are the
     blue-greys of the white ground, so a surface built from them sits in the
     same light as the page instead of floating a warm rectangle on it. */
  --blue-50: #f7fafd;
  --blue-75: #f3f7fb;
  --blue-100: var(--background);
  --blue-150: #ecf2f9;
  --blue-200: #e3ecf6;
  --blue-250: #dae6f2;
  --blue-300: #d0e0ee;
  --blue-350: var(--foreground-muted);
  --blue-400: #c5d8e8;
  --blue-450: #b8cee2;
  --blue-500: #a7c2d9;
  --blue-550: #95b6d0;
  --blue-600: var(--accent-blue);
  --blue-650: var(--accent-blue);
  --blue-700: var(--accent-blue-deep);
  --blue-750: var(--accent-blue-deep);
  --blue-800: var(--accent-emerald-deep);
  --blue-850: var(--accent-emerald-deep);
  --blue-900: var(--foreground);
  --blue-950: var(--foreground);

  /* the accent ramp's light end: LIGHT BLUE tints for washes and chosen
     tiles, so a picked card reads as the same family as the button that
     picked it */
  --sky-100: #eef5fd;
  --sky-200: #dfebfa;
  --sky-300: #cee1f6;
  /* the chosen fill's weakest channel must sit >=20 tint units below the
     plain pair (scripts/no-inverted-tiles.mjs). The palak pass learned this
     the expensive way: its first value left a gap of 16 and four
     standing-plan tiles stopped looking chosen. Measured again at the
     blue-on-white values against --blue-250, the darkest reach of the plain
     pair's sweep. */
  --sky-400: #b9d4f1;
  --sky-500: #98c0ea;
  --sky-600: var(--accent-blue);
  --sky-650: var(--accent-blue);
  --sky-700: var(--accent-blue-deep);
  --sky-800: var(--accent-emerald-deep);
  --sky-900: var(--accent-blue-deep);
  --sky-950: var(--accent-emerald-deep);

  /* ---- page + surfaces ---- */
  --bg: var(--background);
  --page-base: var(--background);
  --surface2: var(--blue-50);
  --surface3: var(--blue-150);

  /* The page ground. Not a ramp any more: a single very faint pool of light
     low on the screen, fixed to the viewport, so the page reads as lit rather
     than painted. The previous version was a four-stop yellow linear-gradient
     stretched over the document, which is exactly the "saturated background
     everywhere" this system rules out. */

  /* ---- placards and washes ----
     One pale luminous wash for a plain card, one clearly deeper luminous fill
     for a CHOSEN one. The gap between them is what makes selection legible;
     scripts/no-inverted-tiles enforces that the chosen fill is genuinely
     deeper than the plain pair rather than a shade away from it. */
  --sec-a: #f6fafd;
  --sec-b: #e9f1fa;
  --sec-from: #f6fafd;
  --sec-to: #eef4fb;
  --sec-ink: var(--foreground);
  --sec-well: rgba(255, 255, 255, 0.72);
  --sec-line: rgba(255, 255, 255, 0.9);
  --sec-shadow: var(--shadow-sm);
  --sage: var(--sky-300);
  --sage-soft: var(--sky-300);
  --hero-from: var(--surface);
  --hero-to: var(--sky-100);

  /* the CHOSEN fill: the luminous ramp at low opacity over white, so a picked
     card looks lit from underneath rather than filled in with a colour */
  --tile-ink: var(--foreground);
  --tile-muted: #3f5b55;

  /* ---- text roles ---- */
  --ink: var(--foreground);
  --ink-strong: var(--foreground);
  --muted: var(--foreground-muted);
  --on-accent: #ffffff;
  /* the ink ON the primary CTA gradient, split from --on-accent because the
     two palettes disagree: the white system's CTA is blue and carries white,
     the peacock CTA is GOLD and must carry navy (white on gold read 2.08:1 -
     no-inverted-tiles caught it on every converted page's Build My Plate) */
  --cta-ink: var(--on-accent);
  --on-accent-soft: rgba(255, 255, 255, 0.9);
  --link-on-dark: #c8ede4;
  --numc: var(--accent-blue);
  --accent-soft: var(--sky-400);
  /* --coral, --magenta, --violet and --indigo were here, and every one of them
     was a fruit or a flower pointing at a blue or a green: --coral held
     --blue-500, --magenta held --blue-400, --violet held the emerald and
     --indigo held the ink. Two were used, two were used by nothing at all.
     Deleted rather than renamed - a second name for a value that already has
     one is how a palette ends up with four words for the same blue, and the
     two live call sites now name the token that actually holds the colour. */
  --tab-active: var(--foreground);

  /* ---- lines, shadows, objects ---- */
  --line: var(--border);
  --line-strong: var(--border-strong);
  --objwhite: var(--blue-50);
  --objshadow: var(--blue-300);
  --white-rgb: 255, 255, 255;
  /* the CHROME grounds (topbar, nav drawer, the legal callouts) used to build
     their glass straight from --white-rgb, which is also the sparkle channel
     for the hero plate's glints. When the landing joined the dark family the
     grounds had to go navy while the glints stayed light, and one triplet
     cannot be both: the white topbar floating on the navy field was the first
     defect the conversion screenshot showed. Grounds read this; shine keeps
     --white-rgb. */
  --bar-rgb: 255, 255, 255;
  --shade-rgb: 0, 0, 0;
  /* The rgba() triplets are a SECOND COPY of the accent colours, and a copy is
     where a repaint goes to die: the Rice/Ghee/Haldi pass retuned every hex
     token and the homepage still floated indigo orbs, because the orbs read
     these. Each triplet must be the channels of the token named beside it. */
  --ink-rgb:
    11, 30, 59; /* --foreground #0b1e3b, the navy anchor: cool shadows over a cool ground */
  --accent-rgb: 29, 78, 216; /* --accent-blue #1d4ed8, royal blue */
  --emerald-rgb: 4, 120, 87; /* --accent-emerald #047857 */
  --cyan-rgb: 147, 197, 253; /* --accent-cyan #93c5fd, light blue */
  --shadow-ink: 11, 30, 59;
  --shadow: var(--shadow-sm);
  --shadow-card: var(--shadow-sm);
  /* --shadow-lift is what a thing that genuinely floats casts: it goes back to
     a real second level, because the flattening made a modal and a table cell
     cast the same shadow. Surfaces still separate with hairlines. */
  --shadow-lift: var(--shadow-md);

  /* ---- gradients ----
     ONE gradient, and it is the brief. --grad-cta runs the warm blue into the
     green, which is the whole palette stated on the object a person touches
     most. It came back with the depth pass: the measured-paper flattening took
     the primary down to a single flat fill, and a flat fill is the one thing a
     "depth button effect" cannot be built from.

     The rule that governed it before governs it now, and it is the reason this
     is safe rather than decorative: EVERY STOP CARRIES WHITE TEXT. Royal blue
     is 6.70:1 with white and emerald 5.49:1, so the label is AA anywhere along
     the sweep, including the middle. The old failure this defends against is a
     gradient measured only at its dark end, with white text going 3:1 by the
     time it reaches the light one. tests/s07 parses the PAINTED stops rather
     than these token names, because repointing --grad-cta at a light colour
     sailed straight past a by-name assertion once already. */
  --grad-cta: linear-gradient(135deg, var(--accent-blue) 0%, var(--accent-emerald) 100%);
  /* the gradient names, stated once so the brief and the stylesheet agree.
     --grad-primary IS the CTA above; --grad-hero is the owner's "darker
     color" as a room - the ink navy sweeping into a deep green, so the dark
     end of the product carries both halves of the brief just as the button
     does; --grad-bg is the white page wash; --grad-press aliases the
     deepened sweep below. The hero literals live only here (no-raw-colors
     permits literals in this file alone). */
  /* THE CLIPPED-HEADING SWEEP. .na-title and .card .title paint their text with
     background-clip:text, so for those two selectors the BACKGROUND is the text
     colour and --accent-text cannot reach it. Named separately so the peacock
     block can move it without touching the primary button. */
  --grad-title: linear-gradient(
    135deg,
    var(--accent-blue-deep) 0%,
    var(--accent-emerald-deep) 100%
  );
  --grad-primary: var(--grad-cta);
  --grad-hero: linear-gradient(160deg, var(--foreground) 0%, #064e3b 100%);
  --grad-bg: linear-gradient(180deg, var(--background) 0%, var(--background-secondary) 100%);
  /* THE SAME SWEEP AT TINT STRENGTH. The owner's review of the first white
     home: the light surfaces "should also match the color combo but lighter
     gradient", not a flat light blue that is "not even glassy or glossy or
     gradient like". So the tiles a person chooses from carry the identical
     blue-into-green diagonal the hero and the primary carry, pale enough to
     hold ink; the gloss is the bevel highlight sitting OVER the sweep, which
     is what a solid fill could never give it. Deep variant for hover, so the
     glass darkens under the hand instead of going flat white. */
  --grad-wash: linear-gradient(135deg, #f2f7fe 0%, #e9f1fc 42%, #e2f4ec 100%);
  --grad-wash-deep: linear-gradient(135deg, #e7effc 0%, #ddeaf9 42%, #d5eee3 100%);
  /* the bright non-text green, for moments that never carry body text */
  --accent-lagoon: #10b981;
  /* SAND, the one warm accent (v3 §2.1): over-budget attention, never red.
     The hex is the thali's dal gold on purpose - the warmth of food, not of
     alarm. --band-over above is its text-grade partner. */
  --sand: #e8b54a;
  /* the pressed sweep: the same two colours, deepened, so a held button looks
     like the same object under load rather than a different colour */
  --grad-deep: linear-gradient(135deg, var(--accent-blue-deep) 0%, var(--accent-emerald-deep) 100%);
  --grad-press: var(--grad-deep);
  /* THE SIGNATURE BAND. It was navy - #171a2e to #241e4a - and it was the one
     colour in the product that came from nowhere: not the pale blue, not the
     periwinkle, not the CurryPlate blue. Every surface that used it (the
     footer on eight pages, the call-to-action bands, the plate band, the
     homepage statement) became the one dark rectangle on an otherwise light
     product, and each needed its own white-on-dark type rules to stay legible.
     It is now the same light material as everything else: a white ground with
     a --sky wash from the top left and a periwinkle one from the top right.
     Text on it is the ordinary --foreground, so there is no second type scheme
     to keep in step. */
  /* the intelligence sweep: cyan into blue into violet, used ONLY where the
     product is actively working something out. It is a light source, so it is
     never a text bed and always sits behind or beneath content. */

  /* ---- status, legacy names ---- */
  --green: var(--success);
  --green-ink: #175539;
  --green-deep: #175539;
  --green-950: #0f4128;
  --green-soft: #4ea37b;
  --gold: #b8860b;
  --gold-soft: #e8c877;
  --warn: var(--warning);
  --warn-alt: #a86518;
  --warn-ink: #7a460e;
  --bad: var(--danger);
  --bad-soft: #d9605c;
  --green-rgb: 4, 120, 87;
  --warn-rgb: 154, 90, 18;
  --gold-rgb: 232, 200, 119;
  --bad-rgb: 179, 51, 47;
  --accent-blue-rgb: 29, 78, 216; /* mirrors --accent-rgb; see the triplet note above */
  --forest-rgb: 4, 120, 87; /* mirrors --emerald-rgb */

  /* ---- photo tints ----
     Warm on purpose: each sits over a specific food photograph, where a blue
     wash would read as wrong. Decoration over imagery, never a surface. */
  --tint-spice: 60, 40, 20;
  --tint-curry: 120, 70, 10;
  --tint-biryani: 110, 30, 8;
  --tint-south: 20, 70, 45;
  --tint-dosa: 140, 100, 20;
  --tint-ingredients: 90, 80, 60;
  --tint-balanced: 100, 70, 30;
  --photo-scrim: 8, 8, 6;

  /* ---- media backdrops ---- */
  --media-backdrop: #111111;
  --camera-backdrop: #000000;
  --shade: #000000;

  /* ---- type + geometry, legacy names ---- */
  --serif: var(--font);
  --sans: var(--font);
  --r: var(--radius-md);
}

/* ============================================================================
   D1 · THE SEAFOAM FIELD
   Everything above this line is the WHITE system, and it stays exactly as it is
   because the landing page is the anchor and must not move. Everything below is
   the app's world, scoped to `html[data-theme='peacock']` for the reason E5
   recorded: tokens.css is linked by index.html too, and repointing these names
   on :root would repaint the anchor. The attribute name survives from E5 even
   though D1 turned the palette light, because five HTML files and the checks
   address the app by it; renaming the scope would touch every page for zero
   rendered difference.

   R1 TURNS THE ROOM DARK AGAIN, on the owner's brief: dark blue, dark
   maroon, yellow, glass. Text is LIGHT on the field and the dark frost,
   white on the blue and maroon jewels, NAVY on the gold action fills. Every
   role below is a var() chain or color-mix() of theme.css tokens - no
   colour can drift here without failing the purge grep - and
   scripts/token-contrast.mjs enforces the text floors on the RESOLVED
   values. Maroon is a surface family only: the no-shame rule keeps the red
   family out of warning, danger and overflow states, which stay gold.
   ========================================================================= */
html[data-theme='peacock'] {
  --peacock-deep: var(--field-a);
  --peacock: color-mix(in srgb, var(--field-a) 50%, var(--field-b));
  --feather: var(--field-b);
  --foam: var(--text);

  --field: linear-gradient(170deg, var(--field-a), var(--field-b));
  --field-lit:
    radial-gradient(700px at 15% 8%, var(--blob-1), transparent 60%),
    radial-gradient(900px at 88% 30%, var(--blob-2), transparent 60%),
    var(--field);

  --glass-section: linear-gradient(150deg, var(--frost-a), var(--frost-b));
  /* the card tier is the frost family with a whiter top stop: nested panels
     must still separate from the section under grayscale, D1's own proof */
  --glass-card: linear-gradient(150deg, var(--frost-solid-a), var(--frost-b));
  --glass-primary:
    linear-gradient(115deg, var(--gloss), transparent 46%),
    radial-gradient(120% 90% at 18% 0%, var(--gloss-soft), transparent 48%),
    linear-gradient(140deg, var(--deep-cta-a), var(--deep-cta-b));
  --glass-primary-hover:
    linear-gradient(115deg, var(--gloss), transparent 46%),
    radial-gradient(120% 90% at 18% 0%, var(--gloss-soft), transparent 48%),
    linear-gradient(
      140deg,
      color-mix(in srgb, var(--aqua) 14%, var(--deep-cta-a)),
      color-mix(in srgb, var(--aqua) 8%, var(--deep-cta-b))
    );
  --glass-dialog: linear-gradient(150deg, var(--frost-solid-a), var(--frost-solid-b));
  --glass-nav: var(--glass-section);
  --glass-blur-section: 16px;
  --glass-blur-card: 12px;
  --glass-blur-dialog: 20px;
  --glass-edge: var(--rim);
  --glass-rim: var(--rim-top);
  --glass-edge-dialog: var(--rim);
  --glass-inset: inset 0 1px 0 var(--rim-top);
  --glass-cast: var(--shadow-card);
  --glass-cast-soft: var(--shadow-card);
  --glass-footer-cast: var(--glass-inset), var(--shadow-card);
  --glass-cast-heavy: var(--shadow-card);
  --glass-glow-primary: var(--glow-primary);
  --glass-hover: color-mix(in srgb, var(--ink) 6%, transparent);

  /* solid OPAQUE stand-ins for the surface gradients, because color-mix()
     needs a COLOUR and 80 call sites hand it --surface. The glassy pass
     thinned the frost pair to alpha .55/.35, and a translucent MEAN stopped
     being a usable colour: flattened over nothing it reads mid-grey and s07's
     placard audit measured 3.91:1 for a surface that renders at 13:1. These
     are the composites of rendered frost over the field, stated opaquely. */
  --surface-section: color-mix(in srgb, var(--on-deep) 5%, var(--field-b));
  --surface: color-mix(in srgb, var(--on-deep) 9%, var(--field-b));
  --surface-elevated: color-mix(in srgb, var(--on-deep) 13%, var(--field-b));
  --surface-primary: color-mix(in srgb, var(--deep-a) 50%, var(--deep-b));
  /* wells are recesses: on a dark theme a well is a deeper dark than the
     pane it sits in, with the light text keeping 13:1+ inside it */
  --well: color-mix(in srgb, var(--field-a) 75%, var(--field-b));
  --background: var(--field-a);
  --background-secondary: var(--field-b);
  --foreground: var(--text);
  --foreground-muted: color-mix(in srgb, var(--text) 82%, transparent);
  --border: var(--rim);
  --border-strong: color-mix(in srgb, var(--ink) 24%, transparent);

  /* the scales the app's components read, rebuilt on the field pair */
  --blue-50: color-mix(in srgb, var(--feather) 12%, var(--peacock-deep));
  --blue-75: color-mix(in srgb, var(--feather) 16%, var(--peacock-deep));
  --blue-100: var(--peacock-deep);
  --blue-150: color-mix(in srgb, var(--feather) 24%, var(--peacock-deep));
  --blue-200: color-mix(in srgb, var(--feather) 34%, var(--peacock-deep));
  --blue-250: color-mix(in srgb, var(--feather) 44%, var(--peacock-deep));
  --blue-300: color-mix(in srgb, var(--feather) 54%, var(--peacock-deep));
  --blue-400: color-mix(in srgb, var(--feather) 68%, var(--peacock-deep));
  --blue-450: color-mix(in srgb, var(--feather) 76%, var(--peacock-deep));
  --blue-500: color-mix(in srgb, var(--feather) 86%, var(--peacock-deep));
  --blue-550: var(--feather);
  --sky-100: color-mix(in srgb, var(--aqua) 8%, var(--peacock-deep));
  --sky-200: color-mix(in srgb, var(--aqua) 12%, var(--peacock-deep));
  --sky-300: color-mix(in srgb, var(--aqua) 18%, var(--peacock-deep));
  --sky-400: color-mix(in srgb, var(--aqua) 26%, var(--peacock-deep));
  --sky-500: color-mix(in srgb, var(--aqua) 34%, var(--peacock-deep));
  --surface2: var(--surface-section);
  --surface3: color-mix(in srgb, var(--feather) 30%, var(--peacock-deep));
  --objwhite: var(--frost-solid-a);
  --objshadow: color-mix(in srgb, var(--ink) 18%, transparent);
  --sec-a: var(--surface-section);
  --sec-b: var(--surface);
  --sec-from: var(--surface-section);
  --sec-to: var(--surface);
  --sec-well: var(--well);
  --sec-line: var(--glass-edge);
  --sage: var(--sky-300);
  --sage-soft: var(--sky-300);
  --hero-from: var(--surface-section);
  --hero-to: var(--surface);
  --tile-ink: var(--foam);
  --tile-muted: var(--foreground-muted);
  --grad-wash: var(--glass-section);
  --grad-wash-deep: var(--glass-card);
  --grad-bg: var(--field);
  /* accent TEXT on a dark room is the bright pair: gold for emphasis, pale
     royal for the alternate voice - royal itself is a FILL at 3.1:1 and
     never carries body text */
  --accent-text: var(--family-ink);
  --accent-text-alt: var(--royal-light);
  --grad-title: linear-gradient(135deg, var(--family-ink) 0%, var(--royal-light) 100%);
  --numc: var(--family-ink);
  --ink-on-bright: var(--navy-ink);
  --accent-soft: var(--sky-400);
  --link-on-dark: var(--on-deep);
  --tab-active: var(--foam);

  /* the ACTION split: royal blue is the structural accent (focus rings,
     borders, selected fills, where white text rides at 6.5:1+ on the glass
     pair), and GOLD is the primary action fill carrying --accent-ink, which
     is navy at 12:1. --on-accent stays white because the selected tiles and
     the doors are the blue jewels. */
  --accent: var(--royal);
  --accent-blue: var(--royal);
  --accent-deep: var(--deep-cta-b);
  --accent-cyan: var(--royal-light);
  --accent-emerald: var(--royal);
  --accent-lagoon: var(--royal);
  --accent-ink: var(--navy-ink);
  --on-accent: var(--on-deep);
  --on-accent-soft: var(--on-deep-2);
  /* gold CTA carries navy, same 12:1 pairing as the app's primary pill */
  --cta-ink: var(--accent-ink);
  --grad-cta: var(--grad-btn);
  --grad-deep: var(--grad-btn-press);
  --grad-press: var(--grad-btn-press);
  --glow-accent: var(--glow-primary);
  --glow-accent-soft: var(--glow-primary);
  /* bevels: the light edge still catches the top; the recess is the dark
     under the glass, not a gray */
  --bevel-raised:
    inset 0 1px 0 color-mix(in srgb, var(--on-deep) 34%, transparent),
    inset 0 -2px 4px color-mix(in srgb, var(--navy-ink) 44%, transparent);
  --bevel-pressed:
    inset 0 2px 5px color-mix(in srgb, var(--navy-ink) 64%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--on-deep) 14%, transparent);
  --camera-backdrop: var(--field-b);
  --media-backdrop: var(--field-b);

  /* states. Pale royal carries good-news TEXT (8:1 on the dark panes);
     gold carries warnings, danger and overflow - maroon is OUT of the state
     palette by the no-shame rule, so the red family never judges a meal. */
  --success: var(--royal-light);
  --success-soft: color-mix(in srgb, var(--royal) 22%, transparent);
  /* warning and danger ride the DEEP gold, one step below the accent gold:
     s24 is right that an edit affordance and an error must never share a
     computed colour, and bright gold is the accent voice now */
  --warning: var(--gold-deep);
  --warning-soft: color-mix(in srgb, var(--sand) 22%, transparent);
  --danger: var(--gold-deep);
  --danger-soft: color-mix(in srgb, var(--sand) 18%, transparent);
  --green: var(--success);
  --green-ink: var(--success);
  --green-deep: var(--success);
  --green-950: var(--success);
  --green-soft: var(--success);
  /* R1: --gold and --gold-soft are theme.css PRIMARIES now; redeclaring
     them here as var(--sand) made a cycle with theme's --sand: var(--gold)
     and the whole gold family went guaranteed-invalid - the katori ring
     painted stroke:none and var(--sand) fell back to the inherited ink. */
  --warn: var(--sand-ink);
  --warn-alt: var(--sand-ink);
  --warn-ink: var(--sand-ink);
  --bad: var(--danger);
  --bad-soft: var(--danger);

  /* the measurement ramp: measured is the full light ink, modelled a
     distinct dimmer step, the track a whisper of light over the field -
     1.43/3.28/3.64 measured at these mixes */
  --m-measured: var(--foam);
  --m-modelled: color-mix(in srgb, var(--ink) 45%, var(--field-b));
  /* fills hold 3:1 against the dark track by being LIGHT: pale royal for
     under, a whiter blue for in-band, gold for overflow. */
  --band-under: var(--royal-light);
  --band-in: color-mix(in srgb, var(--royal-light) 45%, var(--ink));
  --band-over: var(--gold);
  --band-track: color-mix(in srgb, var(--ink) 14%, transparent);

  --shadow-sm: var(--shadow-card);
  --shadow-md: var(--shadow-card);
  --shadow-raised: var(--shadow-card);
  --shadow-pressed: inset 0 2px 6px color-mix(in srgb, var(--navy-ink) 70%, transparent);
  --shadow-lift: var(--shadow-card);

  /* ---- the landing dialect -------------------------------------------------
     index/privacy/terms speak token names the app never uses (--bg, --muted,
     the rgb triplets home.css feeds to rgba()). While those pages lived on the
     white system the peacock block could ignore them; the owner's directive
     "this page colors should be applied to every page" put data-theme=peacock
     on all three, and every name below that stayed undefined resolved to its
     WHITE value - a half-converted page, light cards floating on the navy
     field, which no-dark-bands now rightly fails on a dark ground. Aliases
     only; the family values live in theme.css. */
  --bg: var(--field-a);
  --ink-strong: var(--on-deep);
  --muted: color-mix(in srgb, var(--ink) 72%, transparent);
  --line: color-mix(in srgb, var(--ink) 16%, transparent);
  --line-strong: color-mix(in srgb, var(--ink) 30%, transparent);
  /* the full-bleed hero room: the body already paints the field, but .hero
     paints its own ground, so it gets the same field rather than white - and
     it carries the maroon swish itself, because an opaque room over the body
     would otherwise hide the one stroke the owner asked to see first */
  --grad-hero:
    linear-gradient(115deg, transparent 30%, var(--swish-a) 46%, var(--swish-b) 58%, transparent 76%),
    linear-gradient(160deg, var(--field-a), var(--field-b));
  --accent-mint: var(--gold-soft);
  --blue-350: var(--royal-light);
  /* rgb triplets for home.css's rgba() washes: royal for accent glows, gold
     where the white system used emerald, pale royal where it used cyan, and
     the light ink. Triplets cannot be var() chains; these are the family hexes
     (#3c64c8, #f5c84c, #8fb2f0, #eef2fa) written as channels. */
  --accent-rgb: 60, 100, 200;
  --emerald-rgb: 245, 200, 76;
  --cyan-rgb: 143, 178, 240;
  /* NOT the text ink: on the landing this triplet is the cool-shadow and
     solid-bar anchor ("cool shadows over a cool ground"). Aliasing it to the
     light ink channels painted the desktop topbar white and would have cast
     white shadows; it stays the field's own navy, which also restores the
     bar-equals-hero-top-stop invariant home.css documents. */
  --ink-rgb: 10, 15, 30;
  /* chrome bars go field-navy glass (#161c38 as channels); --white-rgb stays
     white here because it is the glint channel, not a ground */
  --bar-rgb: 22, 28, 56;
  /* the policy pages' section header and the plate diagram base: the white
     system's palest wash, which under peacock is the frost room */
  --sec-a: var(--field-b);
  --sec-b: var(--field-a);
  --sec-from: var(--field-b);
  --sec-to: var(--field-a);
  --sec-well: color-mix(in srgb, var(--field-b) 72%, transparent);
  --sec-line: color-mix(in srgb, var(--ink) 24%, transparent);
}
