/* ══ THE BACK OFFICE'S PALETTE — DECLARED ONCE ═════════════════════════════
   Paper on a desk: the ground is grey, the paper is white, the lines are
   hairlines and the lift is a shadow rather than a border. It is NOT the
   brand's palette, and that is the point — /backadmin, /app/test and
   /app/test/openai are one room for one reader (the founder, holding the admin
   token), and they answer to the workspace rather than to the storefront.

   WHY IT IS A FILE AND NOT THREE :root BLOCKS. It was three, for about an hour.
   The third copy is what made the case: tests/brand-palette.mjs §F counts
   brand-hex literals across public/ and only ever lets that number go DOWN, and
   #FFFFFF written a third time pushed it up by one. The number was right and
   the third copy was wrong. A palette written out once per page is a palette
   that drifts one page at a time, which is exactly the disease §E was written
   for on the brand side — sixteen copies, five of them wrong.

   IT DOES NOT DECLARE --chili, --pandan OR --dim, and it must not. §E holds two
   rules that bite in opposite directions: no page may DECLARE those three, and
   any page that USES one must LINK /shared/tokens.css. A back-office page links
   this file and no other, uses none of the brand's three, and satisfies both.
   --bo-dim is deliberately not the brand's --dim — a cool grey of THIS language,
   named so it can never be mistaken for a drifted copy of the brand's warm one.
   (Written without a colon after the brand token's name on purpose: a tool that
   scans for `--x:` and does not strip comments reads prose as a declaration, and
   §E was written the day exactly that happened to public/app/tour/index.html.)

   A page may add tokens of its own on top of this; it should not restate any
   token that is already here. */
:root{
  /* ground, paper, and the wash between them */
  --bg:#EDF0F4; --surface:#FFFFFF; --panel:#F3F5F8;
  --line:#DCE1E8; --line-strong:#C3CAD4;
  --ink:#0C0F14; --bo-dim:#5A6270;
  /* lift, not outline — a card is a sheet sitting on the desk */
  --lift:0 1px 2px rgba(16,24,40,.05), 0 6px 16px rgba(16,24,40,.06);
  --lift-hi:0 2px 4px rgba(16,24,40,.06), 0 12px 28px rgba(16,24,40,.09);
  /* go / hold / stop, each with the wash it is legible on */
  --go:#1F7A54; --go-ink:#14603F; --go-wash:#E7F5EE;
  --warn-ink:#8A5A00; --warn-wash:#FEF6E7;
  --stop:#B42318; --stop-wash:#FFF5F4;
  /* AND THE EDGE EACH WASH TAKES. A wash alone has no outline, and every pill
     and chip in this room is drawn WITH one — so a green chip beside a plain
     one was losing its border rather than changing its colour. Named here
     because a room may not restate a workspace token, and an unnamed hex typed
     into one page is how this palette reached sixteen copies the first time. */
  --go-edge:#9DCDB6; --warn-edge:#E8C98A; --stop-edge:#E7A9A2;
  /* ══ POWER — THE FOURTH SIGNAL, AND THE ONE THIS PALETTE NEVER HAD ═══════
     Arbiter, 2026-09-12, on a proposal that painted the Draw step red: "what to
     draw should not be red, cuz it's powerful need to give powerful feel."

     HE IS RIGHT, AND THE REPO ALREADY SAID SO IN WRITING. The /admin design
     system (docs/update-2026-09-08-…) reserves red for what CANNOT BE UNDONE
     and warns, in its own words, that spending it elsewhere "would teach the
     founder that a red frame means nothing". Drawing a picture costs money and
     is completely reversible — he simply does not keep it. By the rule already
     shipped, it was never red's to wear.

     WHAT WAS ACTUALLY MISSING WAS A THIRD MEANING. Measured across all 29 pages
     on 2026-09-12: green was worn by seven controls on /backadmin meaning
     log-in, upload, publish, save, spend-a-little, spend-a-lot AND the Yes on a
     delete. Red was clean — only Retire and ✕ delete. So the palette had a word
     for "safe" and a word for "gone" and NO word for "the machine is about to
     do something powerful that costs money", which is most of what this build
     now does.

     VIOLET, BECAUSE THIS ROOM ALREADY READS VIOLET AS MACHINE. --bo-ai below is
     the tint on a control the reader filled; the System check zone runs cyan
     into violet; the card being read pulses violet. This is that same family
     promoted to a fill, not a new colour introduced to a page that had none.
     8.1:1 on white — it can carry white text at button weight, which --bo-ai at
     #6b5bd6 cannot. */
  --pow:#5B3BD4; --pow-ink:#4B2FB8; --pow-wash:#F0ECFE; --pow-edge:#BFB0F2;
  /* OWNED — the fourth state, and it is not go/hold/stop. Somebody has bought
     this piece: it is neither a job to finish nor a thing gone wrong, so it
     gets a colour of its own rather than borrowing one that already means
     something. Arbiter's pick, 2026-09-11, pointing at a lavender chip. */
  --own:#42308F; --own-wash:#EDE7F8; --own-edge:#D3C9F0;
  /* PUT AWAY — the fifth, and the quietest on purpose. Retired is not finished
     and not a job either; it is a row that has been taken out of use. It reads
     as the workspace's own grey with just enough warmth to be a state rather
     than an absence, and it must stay quieter than green/amber/lavender so a
     row of chips is still read in that order. */
  --off:#4C5563; --off-wash:#EEF1F5;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  /* ⛔ THE TEXT FACE, NAMED — because three declarations in /backadmin's
     Settings room already asked for a --sans token and NOTHING DEFINED IT. A
     `font:` shorthand holding an unresolvable custom property is invalid at
     computed-value time, so the whole shorthand is dropped and the control
     inherits the page's 15px instead of the 12.5–13.5px it asked for. Nothing
     goes red for that: the boxes render, just a size and a half too big.
     Found 2026-09-14 while building the Race scope. The stack is the one
     /backadmin's own `body` rule has always spelled, moved here rather than
     repeated so the next page that wants it does not invent a fourth copy.
     ⚠️ AND THE TOKEN IS NAMED IN PROSE WITHOUT ITS var() WRAPPER ON PURPOSE:
     tests/brand-palette.mjs reads this file as text and requires every bare
     var() in a shared asset to carry a fallback. Writing the call in a comment
     is enough to trip it — which it did, once, and the check is right to be
     that literal about a file four pages depend on. */
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --r:10px;
}

/* ══ THE GROUND SWITCH — TWO ICONS, NO WORDS ═══════════════════════════════
   Arbiter, 2026-09-15: "simple 2 icon only", with a picture of iOS's Control
   Centre. NOT that control: those are two round tiles with labels under them
   and they belong to a settings panel. This is the SEGMENTED CONTROL this room
   already owns — the same shape as Staff / Merchants in the feed bar — so a
   reader who has used one has used the other.
   IT LIVES HERE RATHER THAN IN FOUR <style> BLOCKS for the reason at the head
   of this file: a control written out once per page is a control that drifts
   one page at a time. /backadmin has no markup for it and is unaffected. */
/* ⛔ EVERY TOKEN NAMED HERE CARRIES A HYPHEN, AND THAT IS NOT A STYLE CHOICE.
   tests/brand-palette.mjs §B refuses a fallback-less token reference in a shared
   asset — a shared file has to be self-sufficient — and its pattern matches only
   names with NO hyphen in them. So `--off-wash` and `--bo-dim` may be called by
   name; `--surface`, `--ink` and `--lift` may not, and the two places this
   control needs them are written as literals with a dark rule underneath. The
   file's own header records the same trap one rung along. */
.toprow{display:flex;align-items:center;gap:10px;margin-bottom:10px;min-height:30px;}
.toprow .tsw{margin-left:auto;}
.tsw{display:inline-flex;align-items:center;gap:2px;padding:2px;
  border:1px solid var(--line-strong);border-radius:9px;background:var(--off-wash);}
/* 44px OF TAP AREA FROM A 28px CONTROL, which is the floor on a phone. Bought
   with an invisible ::after rather than by drawing something bigger, so the row
   keeps its height and the thumb still lands. */
.tsw-b{display:flex;align-items:center;justify-content:center;width:28px;height:26px;
  border:0;border-radius:7px;background:transparent;color:var(--bo-dim);
  cursor:pointer;padding:0;position:relative;}
.tsw-b::after{content:"";position:absolute;top:-9px;bottom:-9px;left:-8px;right:-8px;}
.tsw-b svg{width:15px;height:15px;display:block;}
.tsw-b.on{background:#FFFFFF;color:#0C0F14;   /* = --surface / --ink above */
  box-shadow:0 1px 2px rgba(16,24,40,.10);}
.tsw-b:hover{color:#0C0F14;}
.tsw-b:focus-visible{outline:2px solid var(--pow-ink);outline-offset:2px;}
:root[data-theme="dark"] .tsw-b.on{background:#2A323D;color:#E9EDF3;box-shadow:none;}
:root[data-theme="dark"] .tsw-b:hover{color:#E9EDF3;}

/* ⛔ THE SUPPLIER MARKS STOP BLENDING WHEN THE LIGHTS GO OUT. Both PNGs are flat
   WHITE behind the glyph, and the benches multiply them so that white drops out
   against a tinted plate. Multiply against a DARK plate does the opposite: the
   white ground goes dark and the near-black glyph goes with it, leaving an empty
   square. On this ground the mark keeps its own white tile and no blend. */
:root[data-theme="dark"] .tab .lg,
:root[data-theme="dark"] .supplier .mark{mix-blend-mode:normal;background:#FFFFFF;}
:root[data-theme="dark"] .tab .lg{border-radius:4px;padding:1px;}

/* ══ A BLOCK THAT IS A LINE UNTIL HE WANTS IT ══════════════════════════════
   For the diagnostics only — the key check, and nothing that changes what a
   press does. A mode switch folded away would be a control he cannot see he has.
   The summary keeps the heading's own quiet label voice, so a folded block reads
   as one more label in the rail rather than as a widget. */
.foldblk>summary{display:flex;align-items:center;gap:9px;cursor:pointer;
  list-style:none;font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--bo-dim);}
.foldblk>summary::-webkit-details-marker{display:none;}
.foldblk>summary::after{content:"";width:7px;height:7px;margin-left:auto;flex:0 0 auto;
  border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);}
.foldblk[open]>summary::after{transform:rotate(225deg) translate(-2px,-2px);}
.foldblk>summary .n{margin-left:0;font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  font-size:10px;font-weight:700;color:var(--go-ink);}
.foldblk[open]>summary{margin-bottom:11px;}
.foldblk>summary:focus-visible{outline:2px solid var(--pow-ink);outline-offset:3px;border-radius:5px;}

/* ══ THE MODEL LIST, WITH THE SUPPLIER'S MARK ══════════════════════════════
   Arbiter, 2026-09-15: *"the color use their own logo color, not green. the logo
   be grey at first and when we choose it got the Logo color."*
   ⛔ GREY IS A FILTER RATHER THAN A SECOND ASSET. Both marks are flat white
   behind a single-colour glyph — #046CFC and #040404, measured off the PNGs the
   benches already serve — so one rule neutralises the blue one and softens the
   black one, with no second file to keep in step. Selected, the filter simply
   stops and the mark is its own colour again.
   ⛔ AND NOT `mix-blend-mode:multiply` HERE, which is what the tabs use: a tile
   with its own plate wants the plate, and multiply would drop it. */
.arkpick-tile{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:8px;background:var(--off-wash);
  border:1px solid var(--line-strong);overflow:hidden;}
.arkpick-tile img{width:20px;height:20px;object-fit:contain;display:block;
  filter:grayscale(1);opacity:.5;}
.arkpick-row[aria-selected="true"] .arkpick-tile img,
.arkpick-face .arkpick-tile img{filter:none;opacity:1;}
:root[data-theme="dark"] .arkpick-tile{background:#FFFFFF;border-color:var(--line-strong);}
/* THE TICK TAKES THE BENCH'S OWN INK where the page has named one, and the green
   only where it has not — `--pick-ink` is set on the wrapper by /shared/picker.js
   from the bench's own colour. */
.arkpick .arkpick-tick{color:var(--pick-ink, var(--go-ink));}
/* ⛔ THE TILE LEADS AND THE TWO LINES STACK BESIDE IT. His correction, made
   against the first draft of this sheet: "the grey font should be below. 2 line
   bold font up grey font below." The mark is a flex item; the words become a
   column of their own so the name is a name and the line under it is a
   description, instead of both running together into «GPT Image 2This
   deployment» — which is precisely what happened when they shared a row. */
.arkpick-face-stack{align-items:center;}
.arkpick-face-stack .arkpick-tx{display:block;font-weight:680;line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;}
.arkpick-face-stack .arkpick-sub{display:block;line-height:1.3;}
.arkpick-face-stack > .arkpick-tile{order:-1;}
.arkpick-face-stack .arkpick-facewords{display:flex;flex-direction:column;gap:1px;
  min-width:0;flex:1 1 auto;}

/* ══ THE PROMPT, FULL SCREEN ═══════════════════════════════════════════════
   /shared/promptsheet.js draws it; the long note lives there. Here because all
   four benches open the same sheet and a panel styled four times is a panel
   that drifts one page at a time.
   ⛔ EVERY TOKEN BELOW CARRIES A HYPHEN. tests/brand-palette.mjs §B refuses a
   fallback-less token reference in a shared asset and matches only names with
   no hyphen in them, so --surface, --ink and --lift are written as literals with
   a dark rule under each. The file's header records the same trap twice over. */
.psheet{position:fixed;inset:0;z-index:80;display:flex;align-items:center;
  justify-content:center;padding:clamp(12px,4vw,44px);
  background:rgba(12,15,20,.74);}
.psheet[hidden]{display:none;}
.psheet-box{display:flex;flex-direction:column;width:100%;max-width:820px;
  height:min(86vh,760px);border-radius:14px;overflow:hidden;
  background:#FFFFFF;   /* = --surface */
  box-shadow:0 24px 60px rgba(0,0,0,.42);}
.psheet-head{display:flex;align-items:center;gap:10px;padding:12px 16px;
  border-bottom:1px solid var(--line-strong);flex:0 0 auto;}
.psheet-lbl{font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  font-size:10.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--bo-dim);}
.psheet-n{margin-left:auto;font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  font-size:11px;color:var(--bo-dim);font-variant-numeric:tabular-nums;}
.psheet-x{display:flex;align-items:center;justify-content:center;width:30px;height:30px;
  border:0;border-radius:8px;background:transparent;color:var(--bo-dim);cursor:pointer;padding:0;}
.psheet-x svg{width:16px;height:16px;display:block;}
.psheet-x:hover{background:var(--off-wash);}
/* COPY WEARS THE CLOSE BUTTON'S CHROME, and that is the point rather than a
   shortcut: they sit side by side in the same corner, so two different shapes
   there would read as two different KINDS of control. The only thing that
   separates them is what happens when one of them lands — the tick, in the
   room's green, for the moment the clipboard actually took it. */
.psheet-copy{display:flex;align-items:center;justify-content:center;width:30px;height:30px;
  border:0;border-radius:8px;background:transparent;color:var(--bo-dim);cursor:pointer;padding:0;}
.psheet-copy svg{width:16px;height:16px;display:block;}
.psheet-copy:hover{background:var(--off-wash);}
.psheet-copy:focus-visible{outline:2px solid var(--pow-ink);outline-offset:2px;}
.psheet-copy.done{color:var(--go-ink);}
/* THE ANSWER SAID OUT LOUD AND DRAWN NOWHERE — a live region has to stay in the
   document to be announced, so it is taken off the screen rather than hidden.
   `display:none` and `visibility:hidden` both silence it. */
.sr-live{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);
  white-space:nowrap;}
/* AND THE COUNT STOPS BEING THE THING THAT PUSHES THE CORNER OUT. `psheet-n`
   carried `margin-left:auto`; with two buttons after it the gap belongs before
   the pair, not before the first of them. */
.psheet-n{margin-right:2px;}
.psheet-body{flex:1 1 auto;min-height:0;display:flex;}
/* ONE BOX, TWO FACES. The editable one writes back as he types; the read-only
   one keeps the whitespace, because most of what these feeds hold is a pasted
   JSON object and a structure read as a paragraph is not read at all. */
.psheet-ta,.psheet-pre{flex:1 1 auto;min-height:0;width:100%;margin:0;
  font-family:inherit;font-size:15px;line-height:1.72;
  color:#0C0F14;   /* = --ink */
  background:transparent;border:0;padding:18px clamp(16px,4vw,32px);
  overflow-y:auto;white-space:pre-wrap;overflow-wrap:anywhere;}
.psheet-ta{resize:none;display:block;}
.psheet-ta:focus,.psheet-pre:focus{outline:none;}
.psheet-pre{font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  font-size:13px;line-height:1.66;}
.psheet-foot{display:flex;align-items:center;gap:12px;padding:11px 16px;flex:0 0 auto;
  border-top:1px solid var(--line-strong);font-size:12.5px;color:var(--bo-dim);
  background:var(--off-wash);}
/* --go-ink RATHER THAN --go, AND NOT BY TASTE: §B matches only token names with
   no hyphen, so `--go` alone cannot be called by name here. The darker green is
   the right one for a filled button anyway — it carries white text at button
   weight, which the mid green does not. The same trade is written out at
   `.drop.armed` below. */
.psheet-done{margin-left:auto;border:0;border-radius:9px;font:inherit;font-size:13px;
  font-weight:650;padding:8px 18px;cursor:pointer;background:var(--go-ink);color:#FFFFFF;}
/* ⛔ AND THE DARK ROOM FLIPS THE INK, BECAUSE THE GREEN FLIPPED FIRST. `--go-ink`
   is a DARK green on white paper and a LIGHT mint on a dark ground — it has to
   be, or it would not carry on its own wash — so the white that reads on it in
   one room sits at about 1.8:1 in the other. Found in the same sweep as the
   calculator's two sums, which the Arbiter had to photograph before anybody
   noticed; this one was two pixels away from it and nobody had looked. The ink
   is the dark room's own ground, which is the darkest thing in the palette. */
:root[data-theme="dark"] .psheet-done{color:#0B0E13;}   /* = --bg, dark */
/* ── AND THE SAME TRADE ON EVERY BENCH'S PRESS ────────────────────────────
   MEASURED in the same sweep, which is the point of having built one: the
   press that spends money reads «Generate» in white on `--go`, and on the dark
   ground that is 3.38:1 — under the floor, on the largest control on the page.
   Its hover state was worse still: `.go:hover` reaches for `--go-ink`, the
   mint, where white lands at about 1.8:1.
   THE GREEN STAYS THE GREEN AND THE INK MOVES, which fixes both states with one
   declaration and keeps a press looking like a press in both rooms. 5.8:1 at
   rest, 10.3:1 hovered. Here rather than in four page files: `.go` is declared
   in all four and a state declared four times is a state that drifts one page
   at a time. */
/* ⛔ `:not([disabled])`, AND THE SWEEP IS WHAT PUT IT THERE. Written without it
   first, this rule outranked `.go[disabled]` — which paints the press on the
   room's own panel — and drove a DISABLED button to 1.21:1: a control that is
   off, with words nobody can read saying so, on two of the four benches. One
   fix, one new defect, caught in the next run of the same instrument. */
:root[data-theme="dark"] .go:not([disabled]){color:#0B0E13;}   /* = --bg, dark */
.psheet-done:focus-visible,.psheet-x:focus-visible{outline:2px solid var(--pow-ink);outline-offset:2px;}
:root[data-theme="dark"] .psheet-box{background:#151A21;}
:root[data-theme="dark"] .psheet-ta,
:root[data-theme="dark"] .psheet-pre{color:#E9EDF3;}

/* ⛔ IT NEVER GETS A ROW OF ITS OWN, AND THE RIG IS WHAT SETTLED THAT. The first
   cut put it under the words on every card; two checks went red within the hour
   — a long prompt was given 41px of air where the page promises 38, and a short
   one was padded out by 11px it should not have had. Both were measuring the
   promise this control was made under: THE CARD DOES NOT CHANGE SHAPE. So it
   rides a row that already exists — beside Copy on the picture benches, in the
   foot beside the tokens on the film bench, on the «You asked» line on the words
   bench, and beside the character count on every composer. */
.psheet-inline{margin-left:8px;vertical-align:middle;}
.turnhead{display:flex;align-items:center;gap:8px;}
.turnhead .psheet-go{margin-left:auto;}

/* THE ⤢ ITSELF — small, quiet, and the same control on a composer heading and
   on a card. 44px of tap area from a 24px button, bought with an invisible
   ::after so neither row changes height to accommodate it. */
.psheet-go{display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;flex:0 0 auto;border:1px solid var(--line-strong);
  border-radius:7px;background:transparent;color:var(--bo-dim);cursor:pointer;
  padding:0;position:relative;}
.psheet-go::after{content:"";position:absolute;top:-10px;bottom:-10px;left:-10px;right:-10px;}
.psheet-go svg{width:12px;height:12px;display:block;}
.psheet-go:hover{color:#0C0F14;border-color:var(--bo-dim);}
:root[data-theme="dark"] .psheet-go:hover{color:#E9EDF3;}
.psheet-go:focus-visible{outline:2px solid var(--pow-ink);outline-offset:2px;}

/* ══ THE SAME ROOM WITH THE LIGHTS OFF ═════════════════════════════════════
   Arbiter, 2026-09-15: "add this on top find a place so we can switch the dark
   and light … simple 2 icon only", then "go for P1".

   ⛔ IT IS GATED ON AN ATTRIBUTE, NOT ON prefers-color-scheme, AND THAT IS THE
   WHOLE OF ITS SAFETY. /backadmin links this file too and is NOT going dark —
   it never sets data-theme, so not one of these declarations reaches it. The
   four Test Mode benches stamp `data-theme` on <html> before the first paint
   and are the only pages in the building that do. A media query would have
   turned his back office dark the moment his Mac did, which nobody asked for.

   NOT AN INVERSION — A SECOND PALETTE WITH THE SAME JOBS. Flipping the light
   values through 255 gives muddy washes and signal inks that fall under 4.5:1
   on their own grounds. Each family keeps its MEANING and is re-picked for a
   dark ground: the ink brightens until it carries on the wash, the wash sinks
   to a tint of the same hue, and the edge lands between them so a chip still
   has an outline. The order green → amber → violet → lavender → grey is the
   order the light set reads in, and it is preserved: `--off` stays the
   quietest, because a row of chips must still be read in that order.

   THE SHADOW STOPS BEING THE LIFT. On white paper a card lifts with a shadow;
   on a dark ground a shadow is invisible and the SURFACE is what lifts, so
   `--surface` and `--panel` sit above `--bg` in value and the shadow is kept
   only deep enough to hold an overlay off the page behind it. */
:root[data-theme="dark"]{
  --bg:#0B0E13; --surface:#151A21; --panel:#1C222B;
  --line:#252C36; --line-strong:#39434F;
  --ink:#E9EDF3; --bo-dim:#98A2B1;
  --lift:0 1px 2px rgba(0,0,0,.34), 0 6px 16px rgba(0,0,0,.30);
  --lift-hi:0 2px 4px rgba(0,0,0,.40), 0 12px 28px rgba(0,0,0,.44);
  --go:#2E9E6B; --go-ink:#5FD3A0; --go-wash:#10251C; --go-edge:#1E5540;
  --warn-ink:#E3A94A; --warn-wash:#2A1F0C; --warn-edge:#5C4415;
  /* THE RED IS LIGHTER HERE THAN THE OBVIOUS TRANSLATION, AND IT WAS MEASURED
     RATHER THAN CHOSEN. #D9534A came out at 4.40:1 against `--surface` in this
     room — under the floor, on the one line whose whole job is to be read when
     something has gone wrong. 5.5:1 at this value. */
  --stop:#E8695F; --stop-wash:#2C1412; --stop-edge:#6E2A24;
  --pow:#6F51DF; --pow-ink:#A78BFF; --pow-wash:#1C1435; --pow-edge:#453596;
  --own:#9B86E8; --own-wash:#1B1533; --own-edge:#40358A;
  --off:#A2ABB8; --off-wash:#1B212A;
}

/* ── THE DROP PANEL WHEN A FILE IS OVER IT ────────────────────────────────
   Arbiter, 2026-09-11: "the file box will be green". Here rather than in four
   page files because all four benches wear this palette and a state declared
   four times is a state that drifts one page at a time — the disease this file
   exists to cure. `.drop` itself stays with the pages, which size it
   differently; only the lit state is shared. Higher specificity than a page's
   own `.drop`, so it wins wherever it is set without overriding anything. */
.drop.armed{
  background:var(--go-wash);
  /* THE DARK GREEN, NOT THE MID ONE, AND NOT BY TASTE. tests/brand-palette.mjs
     refuses a fallback-less token reference in a shared asset — a shared file
     has to be self-sufficient — and it matches only names with no hyphen in
     them, which here is `--go` alone. (Written without the surrounding call
     syntax on purpose. This file's own header records the same trap one rung
     along: a tool that scans prose it has not stripped reads the example as
     the thing. It read this comment's first draft.) `--go-ink` is the right colour
     anyway: this border has to read as "let go HERE" against its own wash.
     The inset shadow thickens it without the 1px layout shift a wider border
     would cause, and costs no literal. */
  border-color:var(--go-ink);
  border-style:solid;
  box-shadow:inset 0 0 0 1px var(--go-ink);
}
.drop.armed b,.drop.armed small{color:var(--go-ink);}

/* ── AND IT USES NO SINGLE-WORD COLOUR TOKEN, WHICH TOOK TWO GOES ─────────
   tests/brand-palette.mjs §A refuses a fallback-less `var()` in a SHARED asset
   and matches names with NO HYPHEN in them; §B then requires every such
   fallback to name a BRAND colour and carry the guide's hex. Those two rules
   together mean a shared asset may not reach for `--ink`, `--panel` or
   `--line` at all: this file declares its own — the back office's ink is
   #0C0F14 where the brand's is #191410 — so a fallback here is either absent
   (§A red) or disagrees with the guide (§B red). Both were measured on
   2026-09-14, in that order.
   SO THE HYPHENATED TOKENS DO THE WORK. `--line-strong` and `--off-wash` are
   this palette's own and the check ignores them, and `--mono` is not a colour,
   so §B has nothing to say about it.
   ONE LITERAL SURVIVES, AND IT IS NAMED HERE SO IT CANNOT DRIFT SILENTLY: the
   figures need this palette's strong ink and there is no hyphenated token for
   it. It must track `--ink` in the :root block above — if that value ever
   moves, this moves with it. */
/* ══ THE PICKER'S OWN CHROME — ONE COPY, FOR ALL FOUR BENCHES ══════════════
   Arbiter, 2026-09-15, with a photograph of 04's model list rendered as bare
   divs down the page: *"fix this UI, so ugly"*.

   ⛔ IT WAS NOT A BROKEN RULE. IT WAS A MISSING COPY. /shared/picker.js has
   drawn these menus since 2026-09-14 and every bench loads it — but the CSS
   that makes a picker LOOK like a menu lived in three page files, and 04 was
   never given one. So its model list built correctly, opened correctly, and
   painted as unstyled text in the document flow: names and subtitles run
   together with no space, a tick on every row, the panel pushing the rest of
   the rail down the page. THE SECOND TIME THIS EXACT ABSENCE HAS BITTEN on
   this bench — the calculator's window menu did the same thing on 2026-09-14
   and was cured by moving its chrome here, scoped to `.calc`. Scoping it was
   the mistake; the base belonged here from the start.

   AND MOVING IT COSTS THE SINGLE-WORD TOKENS. tests/brand-palette.mjs §A
   refuses a fallback-less `var()` in a shared asset and §B matches names with
   no hyphen — so `--surface`, `--ink`, `--panel` and `--own` cannot be called
   by name from this file at all. Each becomes a literal with the dark room's
   value written under it, which is the pattern the prompt sheet above already
   follows. `--own` is the exception rather than a translation: the focus ring
   on everything else in this file is `--pow-ink`, and one room having two
   focus colours is a difference nobody chose. */
.arkpick{position:relative;}
.arkpick-go{appearance:none;width:100%;display:flex;align-items:center;gap:9px;
  font:inherit;font-size:13.5px;text-align:left;cursor:pointer;
  border:1px solid var(--line-strong);border-radius:10px;
  background:#FFFFFF;color:#0C0F14;   /* = --surface / --ink */
  padding:9px 11px;min-height:42px;}
:root[data-theme="dark"] .arkpick-go{background:#151A21;color:#E9EDF3;}
.arkpick-go:hover{border-color:var(--bo-dim);}
/* THE TRIGGER CLIPS ITSELF RATHER THAN ITS CHEVRON. Without this the face
   pushed the arrow off the end of a half-width control and the ellipsis never
   fired, because there was nothing constraining the thing that had to shrink. */
.arkpick-go{overflow:hidden;}
.arkpick-face{overflow:hidden;}
.arkpick-go:focus-visible{outline:2px solid var(--pow-ink);outline-offset:2px;}
.arkpick-face{display:flex;align-items:center;gap:9px;min-width:0;flex:1 1 auto;}
.arkpick-tx{font-weight:600;white-space:nowrap;}
.arkpick-sub{color:var(--bo-dim);font-size:12px;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;min-width:0;}
.arkpick-cv{flex:0 0 auto;color:var(--bo-dim);}
/* THE RECTANGLE. Its size is set per row from the ratio; only the ink and the
   corner live here, so the two cannot disagree about which is which. */
.arkpick-ic{flex:0 0 auto;border:1.7px solid currentColor;border-radius:3px;display:block;}
.arkpick-ic-auto{border-style:dashed;opacity:.75;}
/* ⛔ AS WIDE AS ITS OWN LONGEST ROW, NOT AS WIDE AS THE TRIGGER. `left:0;right:0`
   pinned the panel to the button, and the button is a narrow rail control.
   Measured on /app/test 2026-09-15: the panel came out 102px, every row 92px,
   and the word «adaptive» was drawn as «adaptiv» — clipped at the panel's edge,
   with the tick on the chosen row pressed flat against its label. That is the
   screenshot the Arbiter sent captioned "fix adaptive UI".
   `min-width:100%` keeps it at least as wide as the trigger it belongs to,
   `width:max-content` lets it grow to its longest row, and the cap stops a long
   label from running off the side of a phone. */
.arkpick-menu{position:absolute;z-index:40;top:calc(100% + 5px);left:0;right:auto;
  min-width:100%;width:max-content;max-width:min(320px,86vw);
  background:#FFFFFF;   /* = --surface */
  border:1px solid var(--line-strong);border-radius:12px;
  box-shadow:0 14px 34px rgba(15,23,36,.16);padding:5px;max-height:340px;overflow-y:auto;}
:root[data-theme="dark"] .arkpick-menu{background:#151A21;
  box-shadow:0 14px 34px rgba(0,0,0,.46);}
.arkpick-menu[hidden]{display:none;}
.arkpick-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:8px;
  cursor:pointer;min-height:38px;}
/* THE ICON COLUMN IS THE SAME WIDTH ON EVERY ROW, so seven rectangles of seven
   different shapes still read as one column rather than a ragged edge — and the
   COLUMN holds that width now, not the rectangle.
   ⛔ WHY THAT DISTINCTION IS THE WHOLE FIX. The rules this replaces put
   `flex:0 0 21px` on the rectangle itself, and a flex-basis beats the per-ratio
   inline width the picker sets. So every icon was drawn 21px across and only its
   HEIGHT varied: 9:16 and 3:4 came out square and were indistinguishable from
   1:1, in a list whose icons exist for nothing else but telling the shapes
   apart. Measured on /app/test 2026-09-15 — seven rows, every icon 21px wide. */
.arkpick-slot{flex:0 0 21px;display:flex;align-items:center;justify-content:center;}
.arkpick-slot>.arkpick-ic{flex:0 0 auto;}
.arkpick-txt{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1 1 auto;}
.arkpick-t1{font-size:13.5px;font-weight:600;color:#0C0F14;   /* = --ink */}
:root[data-theme="dark"] .arkpick-t1{color:#E9EDF3;}
.arkpick-t2{font-size:11.5px;color:var(--bo-dim);}
.arkpick-row:hover{background:#F3F5F8;   /* = --panel */}
.arkpick-row[aria-selected="true"]{background:#F3F5F8;}
.arkpick-row:focus-visible{outline:2px solid var(--pow-ink);outline-offset:-2px;background:#F3F5F8;}
:root[data-theme="dark"] .arkpick-row:hover,
:root[data-theme="dark"] .arkpick-row[aria-selected="true"],
:root[data-theme="dark"] .arkpick-row:focus-visible{background:#1C222B;}   /* = --panel, dark */
/* PINNED RIGHT, AND RESERVED ON EVERY ROW. `visibility` rather than `display`
   because the unchosen rows must still SPEND the width — hiding it outright is
   what made the panel resize when he picked a different shape. */
.arkpick-tick{flex:0 0 auto;margin-left:auto;color:var(--go-ink);}
.arkpick-tick-off{visibility:hidden;}

/* ══ THE SPEND CALCULATOR — ONE ROW, ON ALL FOUR BENCHES ═══════════════════
   Arbiter, 2026-09-14: *"for all 1 2 3 4 add a calculator on top right with
   1. total spend of all the page 2. total spend of the page"*.

   HERE RATHER THAN IN FOUR PAGE FILES, for the reason `.drop.armed` above gives
   about itself: four benches wear this palette, and a component declared four
   times is a component that drifts one page at a time. /shared/testcalc.js draws
   the markup; this is its only skin.

   ONE ROW, AT THE HEIGHT OF WHAT STANDS BESIDE IT. Arbiter, same day: "this
   need to be 1 line". The first draft stacked the two sums and stood a head
   taller than every control in the bar, and a bar is a row of things of one
   height. `nowrap` is the proof rather than the fix — with it the row can no
   longer hide a regression by quietly folding.

   IT WEARS THE MONEY COLOUR. `--warn-wash` is already what a spend warning is
   painted in on these pages, and a second money readout in a different skin
   would teach him the two are about different things. The amber is the edge and
   the label; the FIGURES stay `--ink`, because a number tinted amber reads as a
   warning rather than as a fact.

   AND THE FIGURES ARE TABULAR. Two sums are compared by their columns — the
   bottom one is a part of the top one — and proportional digits put the decimal
   points in different places, which is where the comparison stops working. */
.calc{display:inline-flex;align-items:center;gap:10px;padding:5px 12px 5px 10px;
  border:1px solid var(--warn-edge);border-left:3px solid var(--warn-ink);
  border-radius:10px;background:var(--warn-wash);white-space:nowrap;}
.calc .calct{font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:9px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--warn-ink);opacity:.85;}
.calc .cpair{display:inline-flex;align-items:center;gap:6px;}
.calc .cpair img{width:14px;height:14px;border-radius:4px;display:block;}
.calc .cl{font-size:11.5px;color:var(--warn-ink);}
.calc .cl.off{font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:10px;opacity:.85;}
.calc .cpair b{font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:13px;font-weight:700;color:#0C0F14;   /* = --ink above; see the note at the head of this block */
  font-variant-numeric:tabular-nums;letter-spacing:-.01em;}
/* ⛔ AND THE DARK GROUND NEEDS ITS OWN, WHICH IS THE COST OF THAT LITERAL.
   Arbiter, 2026-09-15, with a photograph of his own calculator: *"change the
   black word to white"*. The figures were the light palette's ink, typed as a
   hex because §B will not let a shared file call `--ink` by name — so when the
   room went dark they stayed #0C0F14 and the two sums he reads most went
   near-black on a near-black bar. A token would have followed the ground on its
   own; a literal has to be followed BY HAND, in both rooms, every time. */
:root[data-theme="dark"] .calc .cpair b{color:#E9EDF3;}   /* = --ink, dark */
.calc .cpair.self .cl{font-weight:700;}
.calc .cbar{width:1px;height:17px;background:var(--warn-edge);}
/* ══ THE WINDOW, AS AN ARROW BUTTON ON THE PILL HE ALREADY HAS ══════════════
   Arbiter, 2026-09-14: "follow image 1 UI but add the arrow button". The amber
   readout keeps its shape; the trigger is a compact chip at the head of it,
   drawn in the same ink as the label beside it so the row still reads as one
   object rather than as a control pasted onto a readout.
   IT IS /shared/picker.js's TRIGGER, RESTYLED — not a second menu. The panel
   that opens keeps the picker's own light surface, because a menu tinted amber
   would read as four warnings. */
.calc .crangebox{display:inline-flex;align-items:center;}
.calc .crangebox .arkpick{position:relative;}
.calc .crangebox .arkpick-go{min-height:0;padding:3px 7px 3px 9px;gap:5px;
  font-size:11.5px;font-weight:700;border-radius:999px;
  border:1px solid var(--warn-edge);background:transparent;color:var(--warn-ink);}
.calc .crangebox .arkpick-go:hover{background:rgba(255,255,255,.55);border-color:var(--warn-ink);}
.calc .crangebox .arkpick-tx{font-weight:700;}
.calc .crangebox .arkpick-cv{color:var(--warn-ink);width:11px;height:11px;}
/* ⛔ THE PANEL'S OWN CHROME LIVES HERE NOW, AND IT DID NOT BEFORE.
   /shared/picker.js is loaded by all four benches, but only three of them carry
   the base .arkpick rules in their own <style> — /app/test/dolaseed has none, so
   the calculator's window menu opened there as unstyled divs in the document
   flow, shoving the bar apart. Measured 2026-09-15. A shared control whose looks
   live in three page files is a control that is broken on the fourth.
   SCOPED UNDER .calc SO IT CHANGES NOTHING ELSE: the three benches keep their own
   rules for the Shape and Quality rails, and these only reach the window chip. */
.calc .crangebox .arkpick-menu{position:absolute;z-index:40;top:calc(100% + 5px);
  left:auto;right:0;min-width:170px;width:max-content;max-width:min(260px,86vw);
  background:#FFFFFF;   /* = --surface above; a shared asset states its own colours */
  border:1px solid var(--line-strong);border-radius:12px;
  box-shadow:0 14px 34px rgba(15,23,36,.16);padding:5px;max-height:320px;overflow-y:auto;
  white-space:normal;}
.calc .crangebox .arkpick-menu[hidden]{display:none;}
.calc .crangebox .arkpick-row{display:flex;align-items:center;gap:10px;
  padding:7px 10px;border-radius:8px;cursor:pointer;min-height:32px;
  font-size:12.5px;color:#0C0F14;   /* = --ink above */}
/* THE SAME LITERAL, THE SAME DEBT — found in the same sweep as the figures
   above and fixed in the same breath, because the window menu opens ONTO the
   dark bar and its rows were the same near-black. */
:root[data-theme="dark"] .calc .crangebox .arkpick-row{color:#E9EDF3;}   /* = --ink, dark */
.calc .crangebox .arkpick-row:hover,
.calc .crangebox .arkpick-row[aria-selected="true"]{background:var(--off-wash);}
.calc .crangebox .arkpick-row:focus-visible{outline:2px solid var(--warn-ink);outline-offset:-2px;}
.calc .crangebox .arkpick-txt{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1 1 auto;}
.calc .crangebox .arkpick-t1{font-weight:600;}
.calc .crangebox .arkpick-t2{font-size:11px;color:var(--bo-dim);}
/* RESERVED ON EVERY ROW, HIDDEN ON ALL BUT ONE — `visibility`, never `display`,
   or the panel changes width when he picks a different window. */
.calc .crangebox .arkpick-tick{flex:0 0 auto;margin-left:auto;color:var(--warn-ink);}
.calc .crangebox .arkpick-tick-off{visibility:hidden;}
/* AND WITHOUT THE PICKER IT IS STILL A MENU. A page that has not loaded
   /shared/picker.js shows the browser's own select rather than nothing — the
   property that makes this safe to put in a file four pages share. */
.calc select.crange{font:inherit;font-size:11.5px;font-weight:700;color:var(--warn-ink);
  background:transparent;border:1px solid var(--warn-edge);border-radius:999px;padding:2px 6px;}
/* A READOUT THAT COULD NOT BE READ IS A SENTENCE, NOT A ZERO — so it drops the
   money colour entirely rather than showing an amber USD 0.00. */
.calc.calc-off{background:var(--off-wash);border-color:var(--line-strong);border-left-color:var(--line-strong);}
.calc.calc-off .calct,.calc.calc-off .cl{color:var(--bo-dim);}

/* ── AND ON A PHONE IT WRAPS, BECAUSE `nowrap` IS A PROMISE ABOUT A BAR ────
   MEASURED, 2026-09-14: qa/browser-app-test.mjs asserts /app/test still fits a
   390px viewport, and the calculator made the document 408px wide — eighteen
   pixels of sideways scroll on every phone, on a page that had none.
   `nowrap` exists to stop the readout hiding a regression by folding INSIDE a
   desktop bar; it was never a claim that two sums and a logo fit across a
   phone. Below the width where a bar is a bar, it is allowed to become two
   lines — which is what every other control on these pages already does. */
@media (max-width:640px){
  .calc{white-space:normal;flex-wrap:wrap;row-gap:4px;min-width:0;}
  .calc .cbar{display:none;}
  .calc .cpair{flex:1 1 auto;min-width:0;}
}

/* ══ THE UPLOAD PANEL — ROUND MARKS, THEN THE WORDS ════════════════════════
   Arbiter, 2026-09-15, approving a sheet whose fifth picture is a dashed panel
   carrying round icon orbs above the call to action: "Do it push to main when
   done".

   THE MARKS ARE THE SENTENCE, NOT THE DECORATION, so the set is per bench and
   lives in the page rather than here. 01, 02 and 03 read photographs and
   nothing else and carry ONE mark; only 04 reads films and sound as well and
   carries three. A film orb over a box that refuses films is a promise the page
   cannot keep, and a shared rule that drew a fixed set would have made that
   promise on three pages at once.

   ⛔ AND THE NATIVE FILE BUTTON IS GONE FROM THE FLOW WITHOUT BEING GONE FROM
   THE PAGE. It was the one piece of unstyled chrome left on the rail — a grey
   system button under a panel every other pixel of which this palette drew.
   `display:none` and `visibility:hidden` would have taken it out of the tab
   order and out of Playwright's reach with it; four suites drive this control
   by `setInputFiles("#photo", …)`. So it is taken out of FLOW instead, at its
   own static position with no offsets set, which means it needs no positioned
   ancestor and cannot land anywhere unexpected if one is missing. It keeps its
   focus, and the panel wears the ring for it through `:has`. The <label>
   wrapping the words is what makes a click anywhere in the box open the
   picker — window.dropZone() answers the DRAG, never the click. */
/* ⛔ IT IS A <label>, AND ON THESE FOUR PAGES A <label> IS A FORM LABEL: every
   bench declares `label{font-size:11px;font-weight:700;letter-spacing:.07em;
   text-transform:uppercase;color:…}` for the names above its inputs. MEASURED
   2026-09-15, in a browser, before this block existed: the panel came out
   reading "CHOOSE SEVERAL PHOTOS AT ONCE" in bold grey caps, because
   text-transform, letter-spacing, weight and colour all INHERIT past `.drop b`
   and `.drop small` — those two set a size and, for `small`, a colour, and
   nothing else. So this resets what it inherits rather than trusting that a
   class beats an element: specificity decides the properties a rule DECLARES,
   and the four that broke it were the four it did not. */
.dropcall{display:flex;flex-direction:column;align-items:center;gap:3px;cursor:pointer;
  text-transform:none;letter-spacing:normal;font-weight:400;font-size:inherit;
  color:inherit;margin-bottom:0;}
/* A WIDOW IS A CRAFT DEFECT, AND THIS TITLE MAKES ONE. 04's line is the longest
   of the four and wrapped to leave "once" alone on the second row at every
   width the rail takes. `balance` splits it evenly instead; a browser without
   it wraps the way it always did, so there is nothing to fall back to. */
.dropcall b{text-wrap:balance;}
.orbs{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px;
  margin-bottom:9px;}
/* 40px OF DISC AROUND 20px OF DRAWING, AND NO RING AROUND THE DISC. Arbiter,
   2026-09-15, with four panels drawn side by side: a soft tinted disc, no
   outline, the glyph grey inside it. The first cut gave it a 1px border and he
   sent the drawing back — a ring inside a dashed box is two outlines arguing
   about where the edge of this thing is, and the dashes already won.
   ⛔ THE TINT IS A LITERAL, AND IT HAS TO BE. §B refuses a fallback-less
   `var()` in a shared asset and matches token names with no hyphen, so
   `--line`, `--panel` and `--surface` may not be called by name from this file
   at all. `--off-wash` CAN be, and is the obvious reach — but it is #EEF1F5 on
   a #F3F5F8 panel, five values apart, and the disc simply disappeared. These
   two track `--line` in each palette; if that value ever moves, these move
   with it. */
.orb{display:inline-flex;align-items:center;justify-content:center;
  width:40px;height:40px;flex:0 0 auto;border-radius:999px;
  background:#E3E8F0;color:var(--bo-dim);   /* ≈ --line, light */
  transition:background .12s,color .12s;}
.orb svg{width:20px;height:20px;display:block;}
:root[data-theme="dark"] .orb{background:#242C38;}   /* ≈ --line, dark */
/* THE PANEL ANSWERS THE POINTER AS ONE THING, because it now IS one control. */
.drop:hover .orb{color:var(--go-ink);}
/* .drop.armed already turns the words green further up this file; the mark
   belongs to the same sentence and turns with it. The EDGE colour is the disc
   here, not an outline — on the armed wash a #E3E8F0 disc reads as a hole. */
.drop.armed .orb{background:var(--go-edge);color:var(--go-ink);}
/* ⛔ TWO CLASSES, AND THAT IS THE POINT. Every bench styles `.drop
   input[type=file]` in its own <style> — one class and one element, which a
   bare `.dropin` would lose to. Two classes wins it without any page needing to
   be edited to make room. */
.drop .dropin{position:absolute;width:1px;height:1px;opacity:0;
  margin:0;padding:0;border:0;pointer-events:none;}
/* KEYBOARD GETS THE RING THE MOUSE NEVER NEEDED. The input it is drawn for is
   a pixel wide, so the ring goes on the panel; a browser without `:has` simply
   does not draw it, which is the one failure mode here that costs nothing. */
.drop:has(.dropin:focus-visible){outline:2px solid var(--pow-ink);outline-offset:2px;}
