/* ==================================================================
   ROSA'S BIRRIA — LAYOUT LAYER.
   Identity (colour, type, shape, rhythm) lives in tokens.css; this
   file should survive a re-skin untouched.

   ------------------------------------------------------------------
   WHY THIS IS A FILE AND NOT A <style> BLOCK (2026-08-03)
   ------------------------------------------------------------------
   It was inline in index.html until the Spanish page landed. Two pages
   sharing one design cannot each carry their own copy of it: the next
   CSS edit lands on one page and silently misses the other, which is
   this project's most-repeated bug wearing a new coat (the deleted
   dish in a second copy of the menu; the colour literals that would
   have kept the old palette through a re-skin).

   The rule the project settled for CONTENT is the opposite — page copy
   is duplicated per language on purpose, because it changes rarely and
   two static pages beat a JS string-swap (blueprint §6b). CSS gets the
   other answer because a stylesheet is MACHINERY, not content: when it
   changes it must change everywhere at once.

   Same answer, same reason, for menu.render.js.

   ------------------------------------------------------------------
   ⚠ THIS PAGE HAS JAVASCRIPT, AND THAT IS THE OPPOSITE OF www/site.css
   ------------------------------------------------------------------
   The agency site asserts ZERO JavaScript, because static copy cannot
   fail to load. This page's menu is DATA (menu.data.js — a menu change
   is a 2-minute edit, which is the Base-tier economics), so it CAN fail
   to load, in at least three ways: JS off, the data file missing, or
   the renderer itself missing.

   All three land on ONE standing <p class="menu-fallback"> that is in
   the markup, visible by default, and REMOVED by menu.render.js only
   once it has real data. Present-unless-something-succeeds is the
   direction that matters: it covers failure modes nobody has enumerated,
   including the renderer being what broke. It NAMES NO DISH AND NO
   PRICE, so it is copy that cannot go stale — it once wasn't, and it
   advertised a deleted dish for a day. The pre-flight asserts all of
   this mechanically; don't relax it.
   ================================================================== */

  *, *::before, *::after { box-sizing: border-box; }
  html { scroll-behavior: smooth; }
  body {
    margin: 0;
    background: var(--ink);
    color: var(--cream);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
  }
  img { max-width: 100%; display: block; }
  a { color: inherit; }
  /* ⛔ MAKE `hidden` MEAN HIDDEN. The attribute is only a UA-stylesheet
     `display:none`, so ANY author display rule silently beats it — and the
     today band below carries one. Without this line the band would render
     empty on every page load, which is worse than not shipping it: an empty
     "Today" strip reads as a broken site rather than as a quiet one. The
     ops-app mockup shipped exactly this bug on 2026-08-11 (a back button on
     the home screen) and it is one line to never repeat. */
  [hidden] { display: none !important; }
  :focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
  .visually-hidden {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip-path: inset(50%); overflow: hidden; white-space: nowrap;
  }

  h1, h2, .display {
    font-family: var(--font-display);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    line-height: 1.05;
    margin: 0;
  }
  h2 { font-size: clamp(28px, 6vw, 44px); }
  p  { margin: 0; }

  .wrap { max-width: var(--w-page); margin: 0 auto; padding-inline: var(--sp-2); }
  section { padding-block: var(--sp-5); }

  /* buttons: pill controls, thumb-height */
  .btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 52px; padding: 12px 28px;
    border-radius: var(--r-pill);
    font-weight: 700; font-size: 17px; text-decoration: none;
    border: 2px solid transparent;
    transition: transform 120ms ease, background-color 120ms ease;
  }
  .btn:active { transform: scale(0.97); }
  .btn-primary { background: var(--accent); color: var(--accent-ink); }
  .btn-primary:hover { background: var(--accent-hot); }
  .btn-ghost { border-color: var(--cream); color: var(--cream); }
  /* was a raw rgba() of --cream at 12%: the ONE colour literal left outside
     tokens.css, which is sold as the whole re-skin surface. A colour hiding in
     the layout layer is a control that quietly keeps the old palette when a
     client is re-skinned — the seed build hit this exact defect in 2026-07-29. */
  .btn-ghost:hover { background: var(--cream-veil); }

  /* header */
  header {
    position: sticky; top: 0; z-index: 10;
    background: var(--header-veil);
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--line);
  }
  .bar {
    display: flex; align-items: center; justify-content: space-between;
    min-height: 62px; gap: var(--sp-2);
  }
  /* The wordmark is a link, so it owns a tap target: at 1280 the ink is only
     23px tall and nothing else was asserting a box around it. nowrap because
     a two-line brand in a 62px bar reads as a layout accident. */
  .wordmark {
    display: inline-flex; align-items: center;
    min-height: 44px;
    font-size: 22px; text-decoration: none; letter-spacing: 0.03em;
    white-space: nowrap;
  }
  .wordmark span { color: var(--accent); }
  /* 44, not 42: measured 42.0 and 43.0 against a 44 bar at three viewports. */
  .bar .btn { min-height: 44px; padding: 8px 20px; font-size: 15px; }

  /* language toggle + the CTA it sits beside */
  .bar-right { display: flex; align-items: center; gap: var(--sp-2); }
  .lang-toggle {
    display: inline-flex; align-items: center;
    /* 44px is the tap target, not the ink: the label is small type by design,
       so the box has to be asserted rather than inherited from the text. */
    min-height: 44px; padding-inline: 4px;
    font-size: 14px; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; text-decoration: none;
    color: var(--muted); white-space: nowrap;
  }
  .lang-toggle:hover { color: var(--cream); text-decoration: underline; }

  /* ------------------------------------------------------------------
     PHONE HEADER: TWO ROWS, AND ONLY FOR A BAR THAT ACTUALLY CARRIES
     THREE THINGS.

     ⚠ THE `.bar-3` CLASS IS THE WHOLE POINT OF THIS BLOCK'S SELECTOR.
     This stylesheet is shared by both language pages, and since
     2026-08-03 they no longer carry the same header: Sami ruled the
     English page ships WITHOUT the Español toggle (the Spanish page is
     kept and never deployed, so the toggle was a dead link on a live
     client page). Left ungated, this block would give the English page
     a two-row bar for two items — a full-width CTA under the brand,
     paying ~112px of sticky header for a row it no longer needs. The
     twin keeps `.bar-3` because it still has three.

     So: a page with three header items opts IN by class. If the toggle
     ever returns to the English page, the class returns with it, in the
     same edit — that coupling is stated on both files.

     The measurement that produced the two-row design stands unchanged:
     three do not fit on one phone row — measured, not guessed:
     at 375 the Spanish CTA wrapped to two lines AND squeezed the wordmark
     onto two more, and at 414 it still wrapped. Shortening labels was
     tried on paper first and does not close the gap either (at 320 the
     three intrinsic widths total ~358px against 288px of usable bar).

     So the second row is the honest fix, and it keeps all three things
     the page needs: the brand, a toggle a Spanish speaker can find on
     sight, and the sticky thumb CTA that is this design's whole
     conversion argument. Nothing is hidden and no label changes.

     `display: contents` on .bar-right promotes the toggle and the CTA to
     grid items so they can sit on different rows without restructuring
     the markup. It is safe HERE specifically because .bar-right is a
     presentational <div> with no role of its own — the old a11y-tree bug
     for display:contents removes the BOX, and there is no semantics to
     lose. Do not copy it onto an element that carries meaning.
     ------------------------------------------------------------------ */
  @media (max-width: 520px) {
    .bar-3 {
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      row-gap: 8px; column-gap: var(--sp-2);
      padding-block: 8px;
    }
    .bar-3 .bar-right { display: contents; }
    /* hug the text: as a 1fr grid item the wordmark's BOX spans the row, so
       without this a tap on empty space to its right jumps to #top. */
    .bar-3 .wordmark { justify-self: start; }
    .bar-3 .lang-toggle { grid-column: 2; justify-self: end; }
    .bar-3 .btn { grid-column: 1 / -1; width: 100%; }
  }
  @media (max-width: 400px) {
    .wordmark { font-size: 19px; }
  }

  /* hero */
  /* vh first: dvh is dropped whole by browsers that don't know it, and the hero's only
     other content is absolutely positioned, so the section would collapse to the text. */
  .hero { position: relative; min-height: 78vh; min-height: 78dvh; display: flex; align-items: flex-end; padding: 0; }
  .hero-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  .hero::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(to top, var(--ink) 4%, var(--scrim-strong) 38%, var(--scrim-soft) 70%);
  }
  .hero .wrap { position: relative; z-index: 1; width: 100%; padding-block: var(--sp-4) var(--sp-4); }
  .eyebrow {
    font-size: 13px; font-weight: 700; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--accent);
  }
  .hero h1 { font-size: clamp(42px, 11vw, 84px); margin-top: var(--sp-1); max-width: 14ch; }
  .hero p { margin-top: var(--sp-2); max-width: 44ch; font-size: 18px; color: var(--cream); }
  .cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }

  /* ---- today's band (the ops layer's own DOM) ----
     Between the hero and the menu because that is the reading order of the
     question it answers: "is she out today, and where." Quiet by design — it
     borrows the plate-frame accent as a left rule rather than becoming a
     second hero, since on most days it is not there at all and the page must
     not look like something is missing when it isn't. */
  .today-band { display: block; background: var(--surface); border-left: var(--frame) solid var(--accent); }
  .today-band .wrap { padding-block: var(--sp-2); }
  .today-label {
    font-size: 13px; font-weight: 700; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--accent);
  }
  .today-text { margin-top: 4px; font-size: 17px; font-weight: 600; color: var(--cream); max-width: 52ch; }

  /* menu */
  .menu-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap; }
  .menu-updated { color: var(--muted); font-size: 14px; }
  .menu-grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-2); margin-top: var(--sp-3); }
  .menu-fallback { grid-column: 1 / -1; color: var(--muted); font-size: 16px; max-width: 52ch; }
  .menu-fallback a { color: var(--cream); }
  .dish { background: var(--surface); border-radius: var(--r-card); overflow: hidden; display: flex; flex-direction: column; }
  .dish.featured { grid-column: 1 / -1; }
  .dish-photo { aspect-ratio: 4 / 3; width: 100%; object-fit: cover; background: var(--line); }
  .dish.featured .dish-photo { aspect-ratio: 16 / 9; }
  .dish-body { padding: var(--sp-2); display: flex; flex-direction: column; gap: 6px; flex: 1; }
  .dish-top { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-1); }
  /* an <h3> since 2026-08-03 (screen-reader navigation) — so it must declare
     the type and kill the UA margin, or it takes browser defaults silently */
  .dish-name { margin: 0; font-weight: 700; font-size: 17px; line-height: 1.25; }
  .dish-price { font-family: var(--font-display); font-size: 22px; color: var(--accent); white-space: nowrap; }
  .dish-desc { color: var(--muted); font-size: 14.5px; }
  .dish-tag { color: var(--accent); font-size: 13px; font-weight: 700; }

  /* ---- ops-layer state on a dish ----
     ⛔ NO `opacity` ON THE CARD, AND THAT IS AN INSTRUMENT DECISION, NOT A
     TASTE ONE. The pre-flight grades contrast from computed `color` composited
     against the first opaque ancestor background — it cannot see an ancestor's
     `opacity`, so a card dimmed that way would keep PASSING contrast while
     genuinely failing it on the phone. Dimming by naming the muted token keeps
     every text node's real colour visible to the gate. The photo is dimmed
     instead, because photos are not graded and a greyed plate reads "gone" at
     a glance without asking any text to get quieter. */
  .dish.is-sold-out .dish-name { color: var(--muted); }
  .dish.is-sold-out .dish-price { color: var(--muted); }
  .dish.is-sold-out .dish-photo { filter: grayscale(0.85); }
  .dish-status {
    align-self: flex-start;
    background: var(--line); color: var(--cream);
    border-radius: var(--r-pill); padding: 3px 12px;
    font-size: 12.5px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  }
  /* Rosa's own words for today ("last few", "cash only"). Accent, like a tag,
     because it is the one thing on the card that is true only right now. */
  .dish-note { color: var(--accent); font-size: 13.5px; font-weight: 700; }
  .menu-note { margin-top: var(--sp-3); color: var(--muted); font-size: 15px; max-width: 60ch; }
  .menu-note a { color: var(--cream); }

  /* the weekend-special slot: typographic card, no photo, wears the plate frame */
  .dish.special {
    grid-column: 1 / -1;
    background: none;
    border: var(--frame) solid var(--accent);
    justify-content: center;
    padding: var(--sp-3);
    text-align: center;
  }
  .dish.special .dish-name { font-family: var(--font-display); font-size: clamp(26px, 6vw, 38px); text-transform: uppercase; font-weight: 400; }
  .dish.special .dish-body { padding: 0; align-items: center; }
  .dish.special .dish-top { flex-direction: column; align-items: center; gap: 2px; }
  .dish.special .dish-desc { max-width: 42ch; }

  /* how it works */
  .steps { display: grid; gap: var(--sp-3); margin-top: var(--sp-3); }
  .step { border-left: 4px solid var(--accent); padding-left: var(--sp-2); }
  .step h3 { margin: 0 0 4px; font-size: 18px; }
  .step p { color: var(--muted); font-size: 15px; max-width: 44ch; }

  /* about the cook — the signature plate-frame photo */
  .about { display: grid; gap: var(--sp-3); align-items: center; }
  .frame {
    border: var(--frame) solid var(--accent);
    border-radius: var(--r-card);
    transform: rotate(-1.4deg);
    overflow: hidden;
    max-width: 420px;
  }
  .frame img { aspect-ratio: 4 / 5; object-fit: cover; width: 100%; }
  .about-text p { margin-top: var(--sp-2); color: var(--muted); max-width: 58ch; }
  .about-text .lead { color: var(--cream); font-size: 18px; }

  /* reviews */
  .quotes { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }
  .quote { background: var(--surface); border-radius: var(--r-card); padding: var(--sp-3); }
  .stars { color: var(--accent); font-size: 15px; letter-spacing: 2px; }
  .quote blockquote { margin: var(--sp-1) 0 0; font-size: 16px; }
  .quote cite { display: block; margin-top: var(--sp-2); color: var(--muted); font-style: normal; font-size: 14px; }

  /* hours + final CTA */
  .hours-grid { display: grid; gap: var(--sp-3); margin-top: var(--sp-3); }
  .hours table { border-collapse: collapse; width: 100%; max-width: 360px; }
  .hours th, .hours td { padding: 8px 0; border-bottom: 1px solid var(--line); font-size: 16px; }
  .hours th { text-align: left; font-weight: 400; }
  .hours td { text-align: right; color: var(--muted); }
  .pickup p { color: var(--muted); max-width: 44ch; }
  .pickup .big { color: var(--cream); font-size: 18px; }

  footer { border-top: 1px solid var(--line); padding-block: var(--sp-4); }
  footer .wrap { display: flex; flex-direction: column; gap: var(--sp-2); }
  .fineprint { color: var(--muted); font-size: 13.5px; }
  .fineprint a { color: var(--cream); }

  /* two-up only once there's room for it: at 320px a 2-col grid leaves 104px of card
     interior, which the dish name and the nowrap price then fight over. */
  @media (min-width: 480px) {
    .menu-grid { grid-template-columns: 1fr 1fr; }
  }

  /* desktop */
  @media (min-width: 760px) {
    .menu-grid { grid-template-columns: repeat(3, 1fr); }
    .dish.featured { grid-column: span 2; }
    /* equal-height rows: photos absorb the extra height, text hugs its content */
    .dish .dish-photo { aspect-ratio: auto; flex: 1 1 auto; min-height: 240px; }
    .dish .dish-body { flex: 0 0 auto; }
    .steps { grid-template-columns: repeat(3, 1fr); }
    .about { grid-template-columns: 420px 1fr; gap: var(--sp-5); }
    .quotes { grid-template-columns: repeat(3, 1fr); }
    .hours-grid { grid-template-columns: 1fr 1fr; align-items: start; }
  }

  /* motion is a button-press budget (see build state) — but the budget is still
     motion, and the OS-level preference outranks it. */
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .btn { transition: none; }
    .btn:active { transform: none; }
  }

  /* ═══════════════════════════════════════════════════════════════════════
     ORDER UI (ladder B2, direction A) — every class is `ord-`-prefixed.

     ⚠ THE PREFIX IS A RULE, NOT A STYLE CHOICE. The quantity stepper was
     first written as `.step`, which this stylesheet already owns for the
     "How ordering works" section (border-left: 4px accent) — so it silently
     grew an orange bar nobody wrote. This file ships to EVERY client build,
     so a collision would land per-client where nobody is looking.

     ⛔ Nothing here renders under file:// — order.js returns before it
     appends anything. These rules therefore style elements that only exist
     on a served page, which is the designed asymmetry, not dead CSS.
     ═══════════════════════════════════════════════════════════════════════ */
  .ord-step { display: flex; align-items: center; gap: 9px; margin-top: 10px; }
  .ord-btn {
    width: 44px; height: 44px;            /* access-warden's floor, not a look */
    border-radius: 10px; border: 1px solid var(--line);
    background: var(--ink); color: var(--cream);
    font-family: var(--font-body); font-size: 20px; line-height: 1;
    display: flex; align-items: center; justify-content: center;
  }
  .ord-btn:disabled { opacity: .38; }
  .ord-n { min-width: 20px; text-align: center; font-size: 17px; font-weight: 700; }

  /* The bar is `hidden` until something is chosen; `[hidden]` needs the
     explicit `display:none` because the flex rule below would otherwise win. */
  .ord-bar[hidden] { display: none; }
  .ord-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    display: flex; align-items: center; gap: 12px;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
    background: var(--surface); border-top: 1px solid var(--line);
  }
  .ord-bar-count { font-size: 14px; }
  .ord-bar-count b { font-family: var(--font-display); font-size: 20px; color: var(--accent); }
  .ord-review { margin-left: auto; min-height: 44px; }

  /* Scrim and sheet are one stacking context above the bar, so the bar cannot
     hit-test through an open sheet. ⛔ The ops panel shipped a toast sitting
     invisibly on top of Publish and ate every tap; a hidden control that still
     hit-tests is worse than a visible one in the way. */
  .ord-locked { overflow: hidden; }
  .ord-scrim { position: fixed; inset: 0; background: var(--scrim-strong); z-index: 50; }
  .ord-sheet {
    position: fixed; left: 0; right: 0; bottom: 0; top: 0; z-index: 51;
    background: var(--ink); overflow-y: auto; -webkit-overflow-scrolling: touch;
  }
  .ord-sheet-head {
    position: sticky; top: 0; z-index: 2;
    display: flex; align-items: center; gap: 12px;
    padding: 12px 14px; background: var(--header-veil);
    border-bottom: 1px solid var(--line);
  }
  .ord-sheet-head h2 { margin: 0; font-family: var(--font-display); font-size: 24px; text-transform: uppercase; }
  .ord-close {
    margin-left: auto; width: 44px; height: 44px; border-radius: 10px;
    border: 1px solid var(--line); background: var(--ink); color: var(--cream);
    font-size: 17px; line-height: 1;
  }
  .ord-sheet-body { padding: 14px calc(14px + env(safe-area-inset-right)) calc(28px + env(safe-area-inset-bottom)) 14px; }

  .ord-row { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
  .ord-row-name { font-size: 15px; font-weight: 700; line-height: 1.25; }
  .ord-row-calc { color: var(--muted); font-size: 13px; }
  .ord-row-total { margin-left: auto; font-family: var(--font-display); font-size: 19px; color: var(--accent); }
  .ord-total { display: flex; align-items: baseline; gap: 8px; margin: 12px 0 4px; font-size: 14px; }
  .ord-total-v { margin-left: auto; font-family: var(--font-display); font-size: 26px; color: var(--accent); }
  /* Not a checkout — she is paid at pickup, so this line is load-bearing copy
     rather than decoration (ORDERS_CONTRACT §3, and Sami's 08-16 question). */
  .ord-pay { color: var(--muted); font-size: 13.5px; margin: 0 0 16px; }

  .ord-field { margin-bottom: 12px; }
  .ord-field label { display: block; font-size: 13px; font-weight: 700; margin-bottom: 5px; }
  .ord-opt { color: var(--muted); font-weight: 400; }
  .ord-field input, .ord-field textarea {
    width: 100%; box-sizing: border-box; min-height: 46px; padding: 11px 12px;
    background: var(--surface); color: var(--cream); border: 1px solid var(--line);
    border-radius: 10px; font-family: var(--font-body);
    /* ⚠ 16px FLOOR IS FUNCTIONAL: iOS Safari zooms the page on focus for any
       smaller font, which on a one-handed phone reflows the form mid-typing. */
    font-size: 16px;
  }
  .ord-field textarea { min-height: 64px; resize: vertical; }
  .ord-field input:focus-visible, .ord-field textarea:focus-visible,
  .ord-btn:focus-visible, .ord-close:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
  }
  .ord-hint { color: var(--muted); font-size: 12.5px; margin: 4px 0 0; }
  .ord-turnstile { min-height: 65px; margin: 4px 0 12px; }
  .ord-send { width: 100%; justify-content: center; min-height: 48px; }
  /* Quieter than .ord-hint and never hidden: a notice nobody can read is not a
     notice. Kept above the 12px floor the rest of this sheet respects. */
  .ord-privacy { color: var(--muted); font-size: 12px; line-height: 1.5; margin: 10px 0 0; }

  .ord-sms { color: var(--muted); font-size: 13px; margin: 12px 0 0; }
  .ord-sms a { color: var(--accent); }

  /* The one exit from every failure. It is a primary-weight control on purpose:
     at this point the customer has chosen, typed, and been refused, and the
     text path is the thing that still works. */
  .ord-problem { color: var(--cream); font-size: 14px; line-height: 1.5; margin: 4px 0 12px; }
  .ord-degrade {
    display: block; margin-top: 10px; text-align: center;
    background: var(--accent); color: var(--accent-ink);
    border-radius: var(--r-pill); padding: 13px 18px;
    font-weight: 700; text-decoration: none; min-height: 48px; box-sizing: border-box;
  }
  .ord-ack { border: 1px solid var(--accent); border-radius: 12px; padding: 14px; margin-bottom: 14px; }
  .ord-ack-t { font-weight: 700; font-size: 16px; margin: 0 0 4px; }
  .ord-ack-s { color: var(--muted); font-size: 13.5px; margin: 0; }

  @media (min-width: 620px) {
    .ord-sheet { left: 50%; transform: translateX(-50%); max-width: 560px; border-left: 1px solid var(--line); border-right: 1px solid var(--line); }
  }

  /* ⛔ AFTER A REFUSAL THE RETRY STOPS BEING A PRIMARY. Two full-width accent
     buttons stacked is the "two green primaries on one sheet" defect the ops
     panel already paid for on 2026-08-15 — and it came straight back here,
     because that lesson lived in a build note instead of in this stylesheet.
     A rule recorded only in prose survives exactly one careless edit. */
  /* ⛔ THE :hover SELECTOR HAD TO BE NAMED, and leaving it out was a real
     defect rather than a test artifact. `.btn-primary:hover` is specificity
     (0,2,0); `.ord-send--quiet` alone is (0,1,0), so the moment a pointer sits
     on the demoted button it repainted itself accent-hot and the sheet was back
     to two competing oranges. On a phone a tap leaves exactly that sticky hover
     state, so this is the normal case after a failed submit, not an edge one.
     🔑 A demotion has to out-specify every state of the thing it demotes — the
     resting style is the easy half. */
  .ord-send--quiet,
  .ord-send--quiet:hover {
    background: transparent; color: var(--cream);
    border: 1px solid var(--line);
  }
