/* ─────────────────────────────────────────────
   base.css
   Shared foundation — the element reset and the design-token palette.
   Linked FIRST by every page that uses either; module stylesheets
   (allium.css, admin.css) load after it and may override.

   WHY THIS FILE EXISTS (Item 232). These declarations lived in
   allium.css, a file named for one module. admin.html linked that
   stylesheet solely to resolve the tokens its inline styles reference,
   which made the ordinary test for dead CSS — "no consumer in
   allium.js" — invalid for the whole file. Hoisting the shared part
   here restores that test for allium.css, and gives the tokens an
   owner that no module name misdescribes.

   SCOPE IS DELIBERATELY NARROW: the reset and the palette, nothing
   else. No body rule and no components. body is page layout, and the
   pages disagree about it — allium.css anchors its document to the top
   with padding, auth.css centres a card in the viewport — so neither
   is the shared one and each keeps its own. Putting a component here
   would make this a component library; that was considered and
   declined.

   NOT NAMED FOR A MODULE OR A STACK, ON PURPOSE. zenesi.css was
   rejected: only Allium's pages link this today, so that name would
   claim an application-wide scope the file has not earned — which is
   Item 232's own defect running the other way. It is named for what it
   contains, which stays true however many pages adopt it. Item 253
   re-ruled the scope and reached the same answer: Allium.html,
   admin.html, login.html and register.html, and no others.

   ── HOW A TOKEN NAME IS ORDERED (Item 253, Phase D) ──
   THE FIRST SEGMENT NAMES THE FAMILY. Two word orders are in use and
   they mean different things:

     --surface-<role>    the head is `surface`: a ground in its own
                         right, distinguished by the role it plays.
                         --surface-page, --surface-inset,
                         --surface-chrome, --surface-badge.
     --<family>-surface  the head is the FAMILY, and `surface` is a
                         SLOT within it alongside -text and -border.
                         Read --error-surface as "the error family's
                         surface", never as "a surface for errors".
                         --success-surface and --accent-surface are
                         the same shape.

   TWO FORMS DEPART FROM THAT AND BOTH ARE DELIBERATE. The interaction
   washes, --hover-surface and --hover-chrome, look like the second
   form but their suffix names the GROUND THE WASH PAIRS WITH, not a
   slot — the note at those tokens states the pairing outright. And
   --on-accent / --on-scrim are their own form: what is drawn ON a
   named ground.

   SO --accent-surface AND --hover-surface SHARE A SHAPE AND NOT A
   GRAMMAR — one names a slot, the other names a partner. That is the
   trap this paragraph exists to disarm, and it is the reason a new
   ground should take the --surface-<role> form: of the four it is the
   only one that cannot be read two ways.

   WRITTEN DOWN AT PHASE D, HAVING ALREADY DESCRIBED EVERY NAME IN
   THIS FILE WHILE BEING RECORDED NOWHERE. That is the fault Item 253
   exists to correct, one level up from a colour: consistency is
   evidence of a convention, not a record of one. The radius scale
   below is the worked example — a real rule, obeyed nearly
   everywhere, documented in no comment, which is exactly how nine
   off-scale values accumulated without any of them looking wrong.

   ── TEXT ON A GROUND: TWO GRAMMARS, BOTH CORRECT (Item 253, Phase D) ──
   NAMING A GROUND OFTEN MEANS NAMING WHAT IS DRAWN ON IT, and this
   palette does that two different ways:

     --on-<ground>       --on-accent, --on-scrim, --on-scrim-dim. The
                         relation is in the prefix.
     --<family>-text     --error-text, --success-text, --accent-text.
                         One slot of a three-slot family, beside
                         -surface and -border.

   NEITHER IS WRONG AND NEITHER IS TO BE FOLDED INTO THE OTHER. Each is
   internally consistent and each is documented at its own tokens; what
   was missing is any record that BOTH exist, which is how a reader
   arrives at one of them and assumes it is the rule. A rename would in
   any case reach admin.html's inline style attributes and admin.js's
   HTML strings — see the hazard below — for no visual gain at all.

   AND THE RULE THAT EXPLAINS WHY SO FEW SUCH TOKENS EXIST:
   A GROUND GETS A NAMED ON-COLOUR ONLY WHEN IT IS NOT NEUTRAL. Every
   neutral ground takes the ordinary --text-* ladder and needs nothing
   of its own — --surface-page, --surface-inset, --surface,
   --surface-chrome and --surface-badge between them carry primary,
   secondary and tertiary text with no extra name anywhere. Only accent,
   scrim, error and success step outside that ladder. BEFORE ADDING AN
   ON-TOKEN, ASK WHETHER --text-* ALREADY WORKS ON THAT GROUND.

   THE ACCENT FAMILY CARRIES BOTH GRAMMARS, AND THAT IS TWO JOBS RATHER
   THAN A CONTRADICTION (Item 260). --on-accent is what is drawn ON the
   accent where the accent is a GROUND. --accent-text is the accent used
   AS text, and its grounds are mostly NEUTRAL — .field-val a and
   .kebab-btn.active sit on --surface, .admin-badge--active on
   --surface-badge. So --accent-text is NOT an on-token, and the rule
   above is untouched by it: it is the accent family's text slot, which
   is precisely what lets one name serve neutral and non-neutral grounds
   alike. Read the two together as: --accent is the FILL, --accent-text
   is the INK, --on-accent is what goes on top of the fill.

   --accent-surface IS STILL THE ONE NON-NEUTRAL GROUND WITH NO
   ON-TOKEN — AND THE CONCLUSION OUTLIVED ITS ORIGINAL REASON, WHICH
   WAS FALSE. This note used to say its button and tag consumers write
   var(--accent) for their text "and read correctly". THAT WAS NEVER
   MEASURED: Item 260 measured it at 1.97:1, the weakest pairing in the
   palette, and the developer had independently called the same colour
   "thin" on admin.css's badge. They
   now write var(--accent-text), at 5.19:1. No --on-accent-surface is
   added and none is wanted, because a family slot already covers it.
   TWO CORRECTIONS OF FACT RIDE WITH THAT, BOTH THE ENUMERATION FAULT
   THIS FILE KEEPS NAMING: those consumers are FIVE and not four —
   .tag, .edit-collection-add, .edit-collection-bulk-add,
   .page-header-btn[aria-pressed="true"] and .kebab-btn.active, the
   middle two sharing one declaration, which is how the count went
   wrong. The remaining consumer, .app-title-input, takes
   --text-primary instead, and that is not an inconsistency: an
   editable field's content is content, which is why .rename-input does
   the same on the same ground.

   ── HAZARD, AND IT IS THE REASON ITEM 253's PHASE A WAS FIVE FILES ──
   A TOKEN NAME HERE IS NOT CONTAINED BY THE STYLESHEETS. admin.html
   carries fifty-six var(--…) references inside inline style attributes,
   and admin.js WRITES var(--…) into HTML strings at three sites. Both
   are invisible to any search of the .css files. Renaming a token here
   without updating them breaks those elements SILENTLY — an
   unresolvable var() with no fallback computes to nothing, with no
   error, no console warning, and no test that can see it, because the
   harness loads no CSS and jsdom does no layout.
   BEFORE RENAMING ANYTHING BELOW, RUN:
     git grep -n -e "--the-token-name"
   from the repo root. It respects .gitignore by construction and
   searches tracked files only. Do not trust a stylesheet-only search.
   ───────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  /* ── What the BROWSER draws (Item 253, Phase D) ──
     TOKENS PAINT WHAT A STYLESHEET DRAWS AND DO NOT REACH WHAT THE UA
     DRAWS. A checkbox is painted almost entirely by the browser — no
     background or color declaration reaches its box, its border or its
     tick — and the same is true of a <select>'s popup list however the
     closed control is styled, and of every scrollbar on the page.
     Without this declaration those stay LIGHT while the palette around
     them flips, which is not a token fault and cannot be fixed with one.

     IT IS NOT A TOKEN, SO IT TAKES NO VALUE IN THE DARK BLOCK BELOW.
     `light dark` states that this document supports both and lets the
     UA follow the system preference; the dark block overrides values,
     and there is no value here to override.

     SETTLED FOR ALL FOUR PAGES AT PHASE D, WHICH IS HOW auth.css ASKED
     FOR IT TO BE SETTLED. Phase B put the first and only color-scheme
     in the solution in auth.css, for login.html's "Keep me signed in"
     checkbox, and deliberately left open whether it belonged here —
     recording that it was a question to settle ONCE for four pages
     rather than twice. Phase D found the identical case on
     Allium.html, which builds a checkbox for every boolean field in
     edit mode and a <select> in its modals, and admin.html's
     .role-select. Same control, same fault, same page flipping around
     it, so the same answer.

     SAFE BECAUSE EVERY PAGE PAINTS ITS OWN CANVAS. color-scheme moves
     the UA's default background too, so a page relying on the
     browser's white would have flipped. None does: allium.css,
     admin.css and auth.css each paint body with --surface-page, and
     this file declares no body rule. The reach of this line is
     scrollbars, checkboxes and select popups — nothing else. */
  color-scheme: light dark;

  /* ── Surface ladder (Item 253) ──
     THREE RUNGS, AND THE ORDER HOLDS IN BOTH THEMES: sorted by
     lightness, page < inset < surface in light AND in dark. That is
     what makes it a ladder rather than three unrelated greys, and it
     is why --surface-inset is named for its ROLE — a recessed area
     WITHIN a surface — instead of the sequence number it used to carry
     as --surface-2. ITS CONSUMERS: the expanded Section header, the
     nested editor groups (Item 244), .tray-item-icon and .thumb-wrap in
     allium.css, and every input and select on admin.html.

     THAT LIST ENUMERATES, SO IT GOES WRONG BY GROWTH RATHER THAN BY
     EDIT — the same failure mode the --on-accent note below names, and
     it had already happened here. .tray-item-icon took this token at
     Phase C's delivery 4 and was never added; Phase D found the gap
     while checking whether .thumb-wrap belonged on this rung, and added
     both. If a rule takes var(--surface-inset), it belongs in this
     sentence and this sentence belongs updated with it.

     THE --surface-<role> WORD ORDER IS NOT ARBITRARY. The header's
     naming-order note says what it means, and what the reversed form
     --<family>-surface means instead. */
  --surface-page: #f2f1ee;
  --surface-inset: #f7f6f3;
  --surface: #ffffff;

  /* ── Page-level chrome (Item 256, Finding 1) ──
     A SURFACE FOR REGIONS THAT GROUP PAGE-LEVEL CONTROLS, and it is named
     for that role rather than for a rung, because it is not on the ladder:
     the ladder is structural depth WITHIN a page, and this is the page's
     own chrome. Its one consumer today is .page-header in allium.css.

     IT DELIBERATELY EQUALS --surface-page IN BOTH THEMES, AND THAT PARITY
     IS THE POINT RATHER THAN AN OVERSIGHT. The Page Header is meant to
     read frameless — controls floating on the page background, plainly
     page-level and not section-level chrome — and at parity it still
     does. What the token buys is that the region becomes ADDRESSABLE: the
     appearance can diverge later by changing one value here, instead of
     by hunting a hard-coded colour or retuning a shared palette entry
     that four pages consume.

     WHY IT IS NOT A LADDER RUNG, IN NUMBERS. --hover-surface sits BELOW
     --surface-page in light and ABOVE --surface in dark, so the rung that
     maximises an interaction wash in light minimises it in dark — the two
     themes rank the three rungs in OPPOSITE orders. Borrowing a rung
     would therefore trade a light-mode problem for a dark-mode one. A
     token of its own is not forced to pick a rung at all, and each theme
     can take whatever value that theme eventually needs. Same reasoning
     that keeps the interaction washes off the ladder below.

     IT HAS A PAIRED WASH SINCE ITEM 259: --hover-chrome. Move this value
     and that one moves with it — they are two halves of one relation,
     which is the whole reason the wash family is named for its ground.

     THE ELEMENT IS DEFERRED. Item 256 introduces the token only;
     #allium-header, the chrome band that would hold #page-header and
     future siblings, remains Item 226's.

     IT MUST CARRY A VALUE IN BOTH PALETTE BLOCKS. The dark block below
     overrides only the names it lists, so a light-only declaration here
     would keep #f2f1ee under prefers-color-scheme: dark and paint a
     near-white band across the top of a dark page. */
  --surface-chrome: #f2f1ee;

  /* ── Neutral chip ground (Item 253, Phase D) ──
     THE GROUND OF A SMALL NEUTRAL MARK LAID ON A SURFACE — today
     admin.css's .admin-badge and nothing else. A population of one is
     not an argument against the token: --surface-chrome above and
     --hover-chrome below each have one consumer too, and what the name
     buys is that the value stops misdescribing itself.

     IT COMPLETES A PAIRING THIS PALETTE ALREADY MAKES TWICE. A mark
     drawn on a ground needs both halves named — --accent with
     --on-accent, --scrim with --on-scrim, --accent-surface with
     --accent. The solution has four such chips: the sync badge takes
     the solid accent pair, .tag the accent tint, .thumb-num the scrim,
     and .admin-badge is the neutral one whose ground was the only half
     missing.

     THIS GROUND CARRIES TWO TEXT COLOURS, NOT ONE. --text-tertiary at
     rest, and --accent on .admin-badge--active, where the amber IS the
     active/inactive signal rather than decoration. NO --on-badge IS
     ADDED, and there are now two reasons rather than one: both colours
     already exist and are already named for their roles, and a ground
     carrying two on-colours could not be served by a single name
     anyway.

     THE SECOND COLOUR WAS FOUND BY WALKING THE PAGE, NOT BY READING
     THE RULE. It lived in an inline style written by admin.js, where no
     stylesheet census can see it — Item 245's recorded blind spot —
     and Phase D moved it into .admin-badge--active so both halves of
     both variants sit in CSS. An earlier draft of this note described
     the pairing from admin.css alone and was wrong about the screen:
     the fault of describing what renders from a comment rather than
     from what produces it.

     WHAT IT REPLACED, AND THAT WAS THE WHOLE DEFECT. The badge took
     --hover-surface as a RESTING background. The PAIRING was right —
     the badge sits on --surface — and only the STATE was wrong: an
     interaction token doing surface duty on a control that has no
     hover state at all.

     THE VALUE IS UNCHANGED, AND THAT WAS RULED RATHER THAN ASSUMED.
     Phase D does not invent values, so this token carries exactly what
     the badge already rendered and not one pixel moved. What has never
     been ruled is whether that value is RIGHT for a badge — it was
     borrowed from the wash before any token existed for the job.
     Revisit only with a walk behind it, or if this ground ever needs
     rungs of its own.

     BYTE-IDENTICAL TO --hover-surface IN BOTH THEMES, AND THAT IS
     INHERITANCE RATHER THAN DESIGNED PARITY — the opposite of
     --surface-chrome's parity with --surface-page above, which is a
     decision. These two sit on different axes: one is a resting
     ground, the other an interaction state, and either can move
     without the other. DO NOT UNIFY THEM ON THE STRENGTH OF THE VALUE.
     Matching by value is the fault Item 253 exists to correct.

     IT MUST CARRY A VALUE IN BOTH PALETTE BLOCKS, for the reason
     --surface-chrome states above. */
  --surface-badge: #f0efe9;

  /* ── Interaction washes (Item 259) ──
     A HOVER WASH IS A RELATION BETWEEN TWO COLOURS, AND UNTIL ITEM 259
     THIS WAS ONE ABSOLUTE VALUE — --hover-bg — APPLIED AGAINST THREE
     DIFFERENT GROUNDS. That single modelling error is why the wash read
     correctly in most places and thinly in one, and why it could not be
     repaired by retuning it: measured separation from --surface is 15-22
     points in light and 8 in dark; from --surface-chrome, 2-5 light and
     20 dark. No one value is right against every ground in both themes,
     because the grounds do not move together — see the opposite-order
     paragraph at --surface-chrome above.

     THE FAMILY IS KEYED TO THE GROUND IT PAINTS ON, so the pairing is
     legible at the name: --hover-surface goes with --surface,
     --hover-chrome with --surface-chrome. A future surface that hosts
     interactive controls wants a wash named for it, not a borrowed one.

     BOTH SIT OFF THE SURFACE LADDER, DELIBERATELY. An interaction wash
     moves toward CONTRAST, not up a depth ramp — in light these sit
     BELOW their grounds, in dark ABOVE them. Structural depth and
     interaction state are two axes, so they get two naming families.
     That is why these are not --surface-hover.

     --hover-surface ALSO SERVES THE --surface-inset CONSUMERS — the
     three .edit-* containers in allium.css — AND THAT IS A DECISION,
     NOT AN OMISSION. It separates from that ground by 7-10 light and 14
     dark, which reads adequately; a --hover-inset would be a third value
     bought for a case that already works. Add one only if a walk says
     those controls read weak.

     EVERY CONSUMER OF THIS TOKEN IS NOW AN INTERACTION STATE, WHICH IS
     WHAT ITS NAME CLAIMS. Verified by reading all nineteen sites in
     allium.css and the one in admin.css at Item 253's Phase D: after
     that delivery every one is a :hover or an :active. If a resting
     background ever takes this token again, the name is the thing that
     went wrong — not the value.

     THERE WERE TWO THAT DID, AND PHASE D SETTLED THEM SEPARATELY
     BECAUSE THEY WERE NOT THE SAME CASE. admin.css's .admin-badge took
     --surface-badge above: a NEW token at the same value, because no
     existing ground fitted a neutral chip, so not one pixel moved.
     allium.css's .thumb-wrap took --surface-inset: an EXISTING rung,
     because a bordered well holding an image is a recessed area within
     a surface, which did move pixels — deliberately, and for the
     better in both themes.

     THE RULE THE SPLIT PRODUCED, AND IT OUTRANKS THE TWO DECISIONS:
     REUSE AN EXISTING TOKEN UNLESS THERE IS A RECOGNISED NEED FOR A NEW
     ONE. A new name is warranted by a role nothing existing covers, not
     by the convenience of leaving the pixels alone.

     --hover-chrome's DARK VALUE IS THE OLD SHARED ONE, UNCHANGED, AND
     THE ASYMMETRY IS THE POINT. Dark was never the defect: #2a2a28 on
     #161614 is a 20-point step and was confirmed by eye. Only the light
     value moves — a 2-5 point step becomes 13-17. The two themes change
     by different amounts here because the fault was in one of them.

     BOTH MUST CARRY A VALUE IN BOTH PALETTE BLOCKS, for the reason
     --surface-chrome states above: the dark block overrides only the
     names it lists, so a light-only declaration would carry a light wash
     into dark mode silently. */
  --hover-surface: #f0efe9;
  --hover-chrome: #e5e3dd;

  --border: rgba(0,0,0,0.1);
  --border-mid: rgba(0,0,0,0.14);

  --text-primary: #1a1a18;
  --text-secondary: #6b6a65;
  --text-tertiary: #a09f9a;

  --accent: #E9A23B;
  --accent-surface: #fdf3e3;

  /* ── The accent used AS TEXT (Item 260) ──
     --accent IS THE FILL AND THIS IS THE INK, AND THE SPLIT EXISTS
     BECAUSE ONE VALUE CANNOT DO BOTH JOBS. #E9A23B sits at relative
     luminance 0.435 — near the middle of the range — so it reads
     against dark grounds and not against light ones. Drawn as text on
     a light ground it measured between 1.88:1 and 2.17:1 everywhere.

     READ THOSE NUMBERS AS MEASUREMENTS, NOT AS A COMPLIANCE DEBT.
     WCAG's 4.5:1 was the yardstick used to compute them, and it is a
     convenient published scale — NOT A STANDARD THIS PROJECT HAS
     ADOPTED. The developer ruled on 2026-08-23b that WCAG AA is not a
     concern at this stage, and the standard had entered the documents
     the session before by Claude's own choice, unprompted. WHAT MADE
     THIS WORTH DOING WAS THE DEVELOPER'S OWN EYE: the admin badge's
     amber was recorded as "thin in light" on Item 242 BEFORE anything
     was measured, so the numbers explained an observation rather than
     manufacturing one. IF A FUTURE SESSION FINDS A NUMBER HERE AND NO
     CORRESPONDING COMPLAINT ABOUT HOW SOMETHING LOOKS, THE NUMBER IS
     NOT BY ITSELF A REASON TO ACT.

     THE LIGHT VALUE IS CONSTRAINED FROM BELOW BY ITS DARKEST GROUND,
     WHICH IS --surface-badge AND NOT THE ONE YOU WOULD GUESS. At the
     4.5:1 yardstick that caps this token at luminance 0.1525 there,
     against 0.1623 on
     --accent-surface and 0.1833 on plain --surface. #9C5405 sits at
     0.134 and clears all four grounds it meets: 5.70:1 on --surface,
     5.19:1 on --accent-surface, 5.05:1 on --surface-chrome, 4.95:1 on
     --surface-badge. IT WAS CHOSEN BELOW THE CEILING RATHER THAN ON
     IT, so a future light ground does not reopen the value.

     THE RESERVATION ON THIS VALUE IS STRUCTURAL, NOT A BAD CHOICE OF
     HEX, AND THAT WAS ESTABLISHED THE EXPENSIVE WAY. Phase 1 judged an
     earlier candidate, #8F5E12, legible and amber but "very close to
     brown". The repair proposed was chroma: the contrast bar
     constrains LUMINANCE only, so a fully saturated colour at the same
     or lower luminance should read further from brown at no cost. The
     arithmetic is correct — #9C5405 is 100% saturated against 87% and
     sits LOWER, so it also passes by a wider margin, which is why it
     was kept. THE PERCEPTUAL PAYOFF WAS MEASURED AT NIL: the developer
     reported the difference "barely perceptible". A DISTINCTION BELOW
     THE PERCEPTUAL THRESHOLD IS NOT A DISTINCTION WORTH ENCODING, and
     this paragraph exists because a previous version of it encoded one
     — asserting the colour "reads further from brown" before anyone
     had looked.

     SO DO NOT SPEND A SESSION HUNTING A BETTER HEX HERE. The legal
     window is luminance 0.134 to 0.183 — the ceiling set by
     --surface-badge at the 4.5:1 yardstick — and EVERYTHING INSIDE IT
     IS A DARK GOLD, because the brightness that would make it read
     amber is exactly what costs contrast. The two properties are the
     same property. "Legible, amber, close to brown" is the price of a
     high-contrast accent ink at 12-15px on a white ground, and the
     only routes past it are OUTSIDE this token: larger or bolder text,
     or giving those consumers a dark ground instead of a light one.
     Both are design changes to the consumers, not a retune here.

     THE DARK VALUE IS --accent's OWN, AND THAT IS PARITY BY
     MEASUREMENT RATHER THAN BY DESIGN. On dark grounds #E9A23B already
     reads at 7.36:1 on --surface and 7.33:1 on --accent-surface, so
     there was nothing to fix and inventing a second dark amber would
     have moved pixels for no reason. THE TWO MAY DIVERGE LATER; they
     are not the same token and must not be collapsed into one on the
     strength of the value, which is the fault Item 253 exists to
     correct.

     SO THE WHOLE VISIBLE CHANGE OF THIS TOKEN IS LIGHT-MODE ONLY.
     A dark-mode walk cannot discriminate anything here — it renders
     exactly what it rendered before.

     ITS CONSUMERS: allium.css's .field-val a, .tag,
     .edit-collection-add, .edit-collection-bulk-add,
     .page-header-btn[aria-pressed="true"], .kebab-btn.active and
     .modal-select:focus; admin.css's .admin-badge--active; auth.css's
     .auth-link a and .auth-field input:focus. THIS LIST ENUMERATES, so
     it goes wrong by growth rather than by edit — if a rule draws the
     accent as text or as a focus ring, it belongs here and this
     sentence belongs updated with it.

     THE LAST TWO ARE NOT TEXT, AND THEY ARE HERE BY RULING. A focus
     ring is the only thing telling a keyboard user where they are, so
     it was worth the same treatment as text; a hover tint is not
     available to a keyboard at all.

     THE REMAINING NON-TEXT USES OF --accent STAY ON --accent, AND
     THAT IS SETTLED RATHER THAN OUTSTANDING — the hovered level's
     --level-line, the collection button and kebab borders, the
     checklist check's border, .app-title-input's border, and
     .sync-btn[data-state="pending"]'s glyph. They measure around 2:1
     against their grounds, from the same single cause as the text did.
     THEY WERE LOOKED AT AND JUDGED CORRECT, REPEATEDLY: --level-line
     was walked and approved by eye at Items 237, 256 and 258. NO ITEM
     WAS RAISED FOR THEM, DELIBERATELY. Changing them on the strength
     of the number alone would undo presentation the developer has
     already signed off three times. */
  --accent-text: #9C5405;

  /* ── Text and marks drawn ON the accent (Item 253, Phase C) ──
     ONE VALUE, NO DARK OVERRIDE, AND THAT ABSENCE IS DELIBERATE:
     --accent is #E9A23B in BOTH palette blocks, so the colour that has
     to read against it does not flip either. If --accent ever gains a
     dark variant, this token has to be revisited with it.

     THE VALUE WENT FROM #ffffff TO #1a1a18 AT ITEM 260, AND THE
     STRUCTURE ABOVE IS WHAT MADE THAT A ONE-LINE FIX. White on the
     accent measured 2.17:1 in BOTH themes; near black measures
     8.05:1. Because the
     ground does not flip, ONE value still serves both themes and this
     token still needs no dark override — the paragraph above is
     unchanged by the change, which is why direction (iii) was taken:
     --accent itself never moved, so nothing here was reopened.

     IT MUST STAY A LITERAL. #1a1a18 is also --text-primary's light
     value, and writing var(--text-primary) here would be a silent
     catastrophe: that token FLIPS to #f0efe9 in dark, which on the
     accent is 1.88:1. THE PARITY IS INHERITANCE, NOT DESIGN — the same
     distinction --surface-badge draws against --hover-surface, and the
     same instruction: do not unify them on the strength of the value.

     ITS CONSUMERS ARE THINGS SITTING ON var(--accent) AND NOTHING
     ELSE: allium.css's completed-checklist tick, the sync badge, the
     primary modal button, the open Section kebab
     (.section-kebab.active) and the hovered collection-add buttons
     (.edit-collection-add:hover, .edit-collection-bulk-add:hover);
     admin.css's .admin-btn and .admin-icon; auth.css's .auth-btn.
     Those last two carried a literal `white` through Phases A and B
     precisely because this token did not exist yet.

     TWO OF THOSE JOINED AT ITEM 260, AND EACH HAD BEEN MISSING FOR A
     DIFFERENT REASON. The collection-add hovers took var(--surface),
     which FLIPS — so they read white-on-amber in light exactly like
     the other five and escaped only in dark; aligning them was
     proposed once before on the wrong grounds and correctly reversed,
     and it is right now only because the value here is dark.
     .admin-icon was worse hidden: it declares no color at all, and its
     mark was TWO `white` LITERALS INSIDE admin.html's INLINE SVG,
     where no stylesheet census can see them — Item 245's recorded
     blind spot, the same shape as the badge's inline style before it.
     They became currentColor in the same delivery.

     THE .admin-btn ENTRY NOW COVERS SIX BUTTONS, NOT FOUR. admin.js's
     .toggle-active-btn and .revoke-btn took the class rather than
     keeping the inline styles they were built with, so every button on
     admin.html resolves its text colour from here. THIS LIST
     ENUMERATES, so it is a list that goes wrong by growth rather than
     by edit — if a rule takes var(--accent) as a background, its text
     belongs here and this sentence belongs updated with it.

     AND IT DID GO WRONG BY GROWTH, WITHIN DAYS OF SAYING SO.
     .section-kebab.active took var(--accent) as a background at Item
     256 on 2026-08-18 and was not added here; Item 253's Phase D found
     it while counting the accent grounds and added it above. The
     warning was correct and the habit it asks for is what failed.

     THREE WHITES IN allium.css DELIBERATELY DO NOT TAKE IT, AND THIS
     IS THE NOTE THAT SAYS SO RATHER THAN LEAVING IT TO BE REDISCOVERED
     AS AN OVERSIGHT. .thumb-num sits on rgba(0,0,0,0.45); .lightbox-nav
     and .lightbox-close sit inside .lightbox, whose background is
     rgba(0,0,0,0.9). They are white because they are on BLACK, not
     because they are on the accent. Giving them this token would make
     its name false for three of its five consumers AND would couple
     them: retune --on-accent toward the amber and the lightbox
     controls move for no reason. Text-on-accent and text-on-scrim are
     two axes, and two axes get two naming families — the same
     reasoning that keeps the interaction washes off the surface ladder
     above. They belong with the scrim and overlay cluster, WHICH HAS
     HAD A SCALE SINCE ITEM 253's PHASE C DELIVERY 4 — six tokens on
     three roots in allium.css — and --on-scrim is the one they take.
     This clause used to end "which has no scale yet"; delivery 4
     falsified it and did not come back to edit it, which is why
     Phase D found it. allium.css's own note at those tokens says
     --on-scrim is the token this comment promised. */
  --on-accent: #1a1a18;

  --amber: #f59e0b;

  /* ── Status (Item 253, resolving Item 244) ──
     ERROR WAS RECOVERED, NOT INVENTED. These three values, and their
     dark counterparts below, were already written out by hand at three
     sites in allium.css; they are canonical because that file is the
     reference AND because it held the only COMPLETE definition — the
     only one with a dark variant. admin.css and auth.css used a
     slightly different light pair (#fdf0ee / #e8b4b0) with no dark
     variant at all, and they now follow these.

     SUCCESS IS HALF INVENTED. The light trio is exactly what shipped,
     unchanged. The dark trio did not exist anywhere and was derived by
     mirroring the transform the error dark block already demonstrates.
     ACCEPTED FOR A PHASE 1 LOOK WHEN WRITTEN, AND THAT CONDITION IS
     NOW DISCHARGED. Phase B walked it on register.html, which is the
     only page in the solution that renders a success notice — so if it
     had not been looked at there it would not have been looked at at
     all — and it reads correctly. The clause is corrected rather than
     deleted: an acceptance condition that was met is worth more on the
     record than one that merely disappears.

     THE BORDER FORMS ARE ASYMMETRIC ON PURPOSE: error borders are an
     rgba of the hue in both themes, success-border is a solid in light
     because that is the shipped value and preserving it exactly was
     the ruling. Reconcile only if a Phase 1 walk says it reads wrong. */
  --error-text: #c0392b;
  --error-surface: #fdf2f2;
  --error-border: rgba(192,57,43,0.25);
  --success-text: #276749;
  --success-surface: #edfaf3;
  --success-border: #a8dfc0;

  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
  /* -- Corner radius (Item 253, Phase D) --
     THE SCALE IS EXHAUSTIVE. Every border-radius in the solution takes
     one of these three, and the exemptions below are the whole of the
     list. Before Phase D nothing said so, and the scale was the only
     cluster in this file carrying no comment at all — which is exactly
     how nine off-scale values accumulated across three stylesheets
     without any of them looking like a mistake to whoever wrote them.

     WHICH RUNG IS A QUESTION ABOUT THE CONTROL, NOT ABOUT THE NEAREST
     VALUE, and that sentence is here because Phase D got it wrong first
     and the page said so within the hour. A FIXED CORNER READS
     PROPORTIONALLY ROUNDER ON A SMALL BOX THAN ON A LARGE ONE, so a
     single rung applied across four control sizes does not unify them,
     it flattens them — which is the same reasoning Item 237 used to give
     the Section Tile a PERCENTAGE radius so that five Tiles at five
     sizes read as one shape. The rung therefore follows the size of the
     thing it rounds:
       --radius-sm  small inline controls and chips — a badge, a count,
                    a tick box, a row-level button
       --radius-md  full-size controls — a primary button, a text input
       --radius-lg  containers — a card, a panel, a section
     THE FAULT THAT PRODUCED THIS PARAGRAPH, NAMED SO IT IS NOT REPEATED:
     the first pass snapped all nine off-scale values onto --radius-sm
     because sm was the rung the files already used most. THAT IS
     CHOOSING A TOKEN BY NEAREST VALUE, WHICH IS THE EXACT FAULT ITEM 253
     EXISTS TO CORRECT. ROLE WINS. It showed immediately on admin.html,
     where a 15px primary button and an 11px inline button came out with
     the same corner and the small one stopped looking like the small one.

     THE EXEMPTIONS ARE SHAPE IDIOMS, NOT RUNGS, and each was ruled by
     an item rather than reached for: 0 on the deep-tail card (Item
     258); 18% on the Section Tile (Item 237, proportional on purpose so
     that five Tiles at five sizes read as ONE shape); 50% for a circle;
     99px for a pill. A shape is not a size, so none of them is a
     candidate to be snapped onto a rung here.

     RECORDED AND DELIBERATELY NOT ACTED ON: THE LADDER IS
     ARITHMETICALLY REGULAR AND PERCEPTUALLY IS NOT. The step is a flat
     +4, so 6 -> 10 is a 67% jump while 10 -> 14 is 40%. Meanwhile the
     small end does most of the work — the large end serves a handful of
     declarations — and EVERY off-scale value Phase D's survey found sat
     between 4 and 8, straddling the single smallest rung, with not one
     above 6. That is what a scale with too little resolution at the
     bottom looks like from the outside: someone wanting slightly
     rounder than 6 has nowhere on the ladder to go and writes 7.
     Adding or re-spacing a rung INVENTS values, which is the defer side
     of the line Item 232 drew, so Phase D snapped the strays onto an
     existing rung and left the ladder alone. Revisit only with a walk
     behind it. */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface-page: #161614;
    --surface-inset: #1c1c1a;
    --surface: #222220;

    /* At parity with --surface-page, as in light (Item 256). */
    --surface-chrome: #161614;

    /* Equal to --hover-surface below by inheritance, not by design —
       see the note at the light declaration (Item 253, Phase D). */
    --surface-badge: #2a2a28;

    /* Only --hover-chrome's LIGHT value moved at Item 259; dark keeps the
       step it always had, which was never the defect. */
    --hover-surface: #2a2a28;
    --hover-chrome: #2a2a28;

    --border: rgba(255,255,255,0.09);
    --border-mid: rgba(255,255,255,0.13);

    --text-primary: #f0efe9;
    --text-secondary: #9a9990;
    --text-tertiary: #5a5955;

    --accent: #E9A23B;
    --accent-surface: #2a2110;

    /* Equal to --accent by MEASUREMENT, not by design (Item 260): on
       dark grounds the accent already reads at 7.36:1, so there was
       nothing to fix and no second dark amber to invent. The two are
       separate tokens and may diverge — do not collapse them. */
    --accent-text: #E9A23B;
    --amber: #f59e0b;

    --error-text: #e07070;
    --error-surface: #2a1818;
    --error-border: rgba(192,57,43,0.35);
    --success-text: #6ab98a;
    --success-surface: #16261c;
    --success-border: rgba(39,103,73,0.35);
  }
}
