/* Design tokens lifted from the Claude Design import ("Coop App Screens").
 *
 * The design owns layout, type scale, colour, spacing, component shape and
 * motion. Everything in this file is measured from that import so the UI reads
 * as the same product; behaviour and copy rules come from the product spec.
 */

:root {
  /* type */
  --font: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;
  /* LA TIPOGRAFIA DE MILAM'S, y sale de los frames 17a/17b y de la etiqueta de
   * tienda de 16a — los tres la piden por nombre. NO sustituye a `--font`: 16a
   * sigue dibujando su titular y su boton en Plus Jakarta Sans, asi que las dos
   * conviven en la misma pantalla exactamente como en el frame.
   *
   * CON PILA DE RESPALDO DE VERDAD y no `sans-serif` a secas: esta fuente llega por
   * red, y en el pasillo de una tienda con cobertura mala la primera pintada se hace
   * con lo que haya. `system-ui` en un iPhone es San Francisco, que a 10.5pt con
   * 1.6px de tracking se comporta parecido; `sans-serif` a secas puede ser Times en
   * algun sitio. */
  --font-brand: 'Outfit', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* colour — ink */
  --ink: #0a2540; /* headings, body, the one dark colour */
  --ink-muted: #68737d; /* secondary values, sizes, units */
  --ink-faint: #9aa4af; /* echoed query, hints, labels */
  --ink-kicker: #60656b;

  /* The black of the frames' filled controls (2b's two answer buttons, 2m/2n's
   * "Add to list" pill, the listening screen's "Type instead"). NOT `--ink`:
   * that is the navy #0a2540 and reads visibly blue at fill size beside this.
   *
   * The frames disagree with themselves — 2b paints #0A0A0C and 2m/2n paint
   * #090909, 11/255 apart summed across channels — which is one colour drawn
   * twice rather than two decisions. #0a0a0c wins because app.css already
   * hardcoded it twice (`.btn--primary`, `.rx-btn--primary`) before this token
   * existed, so adopting the other value would have made the codebase carry
   * both. */
  --ink-black: #0a0a0c;

  /* colour — accent */
  /* EL VERDE DE MILAM'S. Frames 17a y 17b, y la etiqueta de tienda de 16a.
   *
   * NO ES `--accent`. El naranja es el color de COUPR —el cursor, la mira, el orbe— y
   * este es el de la TIENDA. Las dos pantallas de entrada llevan el logo de Milam's y
   * pintan su boton principal con este verde; el resto de la aplicacion sigue siendo
   * naranja. Colapsarlos habria hecho que la marca de la tienda desapareciera de la
   * unica pantalla que existe para decir de quien es la tienda.
   *
   * MEDIDO: #007934 sobre blanco da 5.31:1, que pasa AA para texto normal — asi que
   * vale tambien para la etiqueta de 10.5pt de 16a y no solo como relleno. */
  --milams: #007934;

  --accent: #ff5a00;
  /* Accent-coloured TEXT on a tinted ground, dark enough to read at 15px — the
   * unselected preference chips of design 3k. `--accent` itself is a fill colour and
   * MEASURED 2.95:1 on `--paper-warmer`, below AA for body text; this measures
   * 4.65:1 on the same ground. Text only: never used as a fill. */
  --accent-ink: #b4551f;
  --accent-hot: #ff4d00;
  --accent-warm: #ffae5c;
  --accent-tint: #fff1e7;
  --accent-line: #ffe3d0;
  --accent-bg: #fffaf6;

  /* colour — semantic (values only; never a grade or a score) */
  --good: #18ab0a;
  --good-tint: #eaf7ea;

  /* LA CANASTA, frames 13b. UN VERDE DISTINTO DE `--good` Y NO POR DESCUIDO.
   * `--good` (#18ab0a) significa «hecho»: es el verde del «Got it». Este significa
   * «llevas una canasta», que no es un exito ni un estado de nada — es un hecho
   * sobre el objeto que el comprador tiene en la mano. Pintarlos iguales seria
   * decir que escanear una canasta es completar algo.
   * Valores literales del diseno (turno 13); no son un ajuste de `--good`. */
  --vessel-basket: #1da05b;
  --vessel-basket-tint: #eff8f2;
  --vessel-basket-line: #d5ebdd;

  /* FRAMES 19a-19e, THE UP NEXT CARDS. Frame values, taken from the design's own
   * style attributes — not derived, and not to be moved without a ruling.
   *
   * `--marker-green` IS NOT `--good` (#18ab0a). The frame draws #1da05b, which is
   * measurably cooler, and the two are used for different things: `--good` is the
   * app's success colour, this is the colour of an EARNED nutrition marker on line
   * 5. Collapsing them would make a design change look like a refactor.
   *
   * `--card-line` (#f1f1f4) is likewise a shade off `--line-faint` (#efeff1). Kept
   * separate for the same reason: the frame is the source and the near-miss is not
   * evidence they are the same value.
   *
   * THERE IS NO `--shot-line`. It existed for a border on the packshot, which the
   * standing product ruling forbids on every surface — see the note in app.css. */
  /* FRAME 13a, THE COMPLETION SCREEN. Frame literals, as everywhere else here.
   *
   * `--basket-green` SHARES ITS HEX WITH `--vessel-basket` AND `--marker-green` AND
   * IS STILL NAMED SEPARATELY — the same decision `--budget-ok` records two blocks
   * down. The three mean different things: a basket in the hand, an earned nutrition
   * marker, and (here) the check that says the list is finished plus the `+` that
   * adds one more thing. One name per meaning is what lets a design change to any
   * one of them stay a one-line change.
   *
   * `--basket-btn-line` is the View list outline and `--basket-muted` is the card's
   * brand line and the subheading. Both are NEAR-MISSES of existing tokens —
   * `--strip-line` #dcdee3 is 7 away, `--rec-x` #8a9199 is 1 away — and per the note
   * above, a near-miss is not evidence they are the same value. Named rather than
   * rounded, so nobody later "tidies" the frame into a different colour.
   *
   * The ✕ and the chevron discs take `--sheet-chip` (#f4f4f6) and the header
   * hairline takes `--card-line` (#f1f1f4): those hexes are IDENTICAL to the
   * frame's, so a new name would be a parallel set for nothing. */
  --basket-green: #1da05b;
  --basket-btn-line: #dde1e6;
  --basket-muted: #8a9099;

  --marker-green: #1da05b;
  --marker-sep: #c6ccd3;

  /* FRAMES 29a / 29b, THE CONFIRM-LIST BUDGET LINE. Two states and no third.
   *
   * NAMED SEPARATELY DESPITE SHARING A HEX WITH `--marker-green` AND `--accent`,
   * for exactly the reason recorded above: this file names greens by MEANING, and
   * a near-miss is not evidence two values are the same one. `--marker-green` is
   * an EARNED nutrition marker, `--good` is "done", and this is a BUDGET STATUS —
   * three different facts that happen to share a colour today. Pointing this at
   * `--marker-green` would make the next budget-colour ruling look like a change
   * to nutrition markers, which is how a design change gets mistaken for a
   * refactor.
   *
   * `--budget-over` IS THE BRAND ORANGE'S HEX AND NOT THE BRAND ORANGE. The frame
   * draws #ff5a00 here as a WARNING; `--accent` is the same value as an identity.
   * They diverge the moment either is tuned. */
  --budget-ok: #1da05b;
  --budget-over: #ff5a00;

  /* FRAME 26a, the add control on a result card. A FOURTH NAME ON THIS HEX, and
   * the file's own rule is why: greens are named by MEANING. `--good` is "done",
   * `--marker-green` is an EARNED nutrition marker, `--budget-ok` is a basket
   * within budget, and this is "on your list". They share a value today and
   * answer four different questions; pointing any of them at another is how a
   * change to one silently becomes a change to all four. */
  --added-green: #1da05b;
  /* 25j's "on deal" marker. THE FIFTH GREEN NAMED BY MEANING and the fourth to
   * carry this hex, which is deliberate and documented: `--good` is #18ab0a and
   * a DIFFERENT colour, `--budget-ok` is about a budget and `--added-green` is
   * about the add control. A marker on an ingredient row is none of those, and
   * borrowing one would make a change to that one silently a change to this. */
  --deal-green: #1da05b;
  --rec-chip: #ffd84d;

  /* FRAME 3k, THE LIST READ-BACK'S PREFERENCE ROW. Frame literals, as everywhere
   * else in this file — read off `Latest Trimmer.dc.html`'s own style attributes.
   *
   * `--pref-pill-green` IS THE SIXTH GREEN NAMED BY MEANING, and the first NOT to
   * carry #1da05b. The frame draws **#15a05a**, which is a near-miss of the other
   * five — 8 off on red, equal on green, 1 off on blue — and this file's standing
   * rule is that a near-miss is not evidence two values are the same one. It is
   * also the rule that matters most here: rounding this to `--marker-green` would
   * make the next change to an EARNED NUTRITION MARKER silently restyle the
   * preference row, which is the exact confusion the other five notes exist to
   * prevent. This green means "this preference is applied to your list".
   *
   * `--make-list-yellow` IS NOT `--rec-chip` (#ffd84d) for the same reason: the
   * frame draws #ffe94d here, 17 off on green. One is a recommendation chip and
   * this is the row's own label pill.
   *
   * THE UNSELECTED BORDER IS NOT A FRAME LITERAL AND IS MARKED AS SUCH. 3k draws
   * `1px solid #0A2540` — the ink navy — and the brief that ordered this work says
   * "unselected is white fill with a GREY border". The product owner's wording
   * supersedes the drawing, the same way `SWAP_AXES`'s order does; `--line-strong`
   * is the app's existing border grey and is used rather than inventing a seventh
   * near-miss. Recorded here so the next person to open 3k does not read the navy
   * as a regression and "fix" it back. */
  --pref-pill-green: #15a05a;
  --make-list-yellow: #ffe94d;
  --card-line: #f1f1f4;

  /* FRAME 19c, the no-photo tile. IT KEEPS ITS BORDER, and the product ruling
   * against frames does not reach it: that ruling is about a PRODUCT IMAGE reading
   * as a floating object, and this is not an image — it is the designed slot that
   * stands in for one when there is none. The border and fill are what make it read
   * as a slot rather than as a grey blob, and frame 19c draws both. ~38% of records
   * have no image, so this is the common case, not an error state.
   *
   * FLAGGED rather than assumed: if the ruling is meant to cover the tile too, this
   * is the line to change, and the tile should then lose its border and keep its
   * fill (a `background` "STAYS and is not part of the frame", per 28801fb). */
  --tile-bg: #f1f4f8;
  --tile-line: #e4e9ef;
  --tile-ink: #b3becc;

  /* The Buy-1-Get-1 badge of design 3n. THE ONLY YELLOW IN THIS PALETTE, and it
   * cannot be derived from anything already here — `--good` is green and `--accent`
   * is orange — so it is a token rather than a near-miss reuse.
   *
   * The frame paints #fff on it. MEASURED in the browser: 1.48:1, which fails WCAG
   * AA outright and is close to invisible. It is used with `--ink` instead, measured
   * 10.49:1 on the same yellow — a legibility decision rather
   * than a design change: the colour is the brand's, the contrast is not optional in
   * the retail lighting §14 is written for. */
  --promo-bogo: #ffcf0c;

  /* colour — the walking screen's location strip and progress bar (design 2j).
   * Both were near-misses against existing tokens rather than reuses:
   * #dcdee3 is darker than --line-strong (#e6e6ea) because the two strip lines
   * have to read as fixtures at 16px tall, and #ffc9a8 is more saturated than
   * --accent-line (#ffe3d0) because it marks the CURRENT item against both a
   * full --accent bar and an empty --line-faint one, so it needs to sit visibly
   * between them. */
  --strip-line: #dcdee3;

  /* ── THE PRODUCT PAGE'S CARDS (frames 2m/2w/2v) ─────────────────────────
   *
   * THE DIETARY CHIP'S GREEN IS ITS OWN MEANING, and this file's rule is why:
   * greens are named by what they mean, never by hue. `--good` (#18ab0a) is
   * "done" — the Got it green — and `--deal-green` (#1da05b) is the (+) that
   * adds. This one means "the LABEL declares this", which is a claim about the
   * packet and not about anything the shopper did. The frames draw #eaf7f0 on
   * #127346, measurably cooler and deeper than `--good-tint`/`--good`, and
   * reusing those would say "done" on a row of dietary facts. */
  --claim-tint: #eaf7f0;
  --claim-ink: #127346;

  /* The nutrition markers' 12.5px labels. DELIBERATELY DARKER than
   * `--ink-faint` (#9aa4af) and not a careless near-duplicate: this sits at
   * 12.5px over `--sheet-field`, where MEASURED contrast is ~3.0:1 against
   * ~2.4:1 for `--ink-faint`. Neither reaches AA for normal text, which is a
   * known gap on a designer-set value rather than something this token
   * introduced — recorded so the next reader does not "simplify" it back up to
   * `--ink-faint` and lose the 0.6 that is there. */
  --metric-label: #8a9099;

  /* The image dots' OFF state. An affordance, not a control — see
   * `.pdp-dots`. Lighter than `--line-strong` because it sits on `--paper`
   * and has to read as "another image exists" without inviting a tap. */
  --dot-off: #d5d8de;
  --progress-now: #ffc9a8;

  /* colour — surface */
  --paper: #ffffff;
  --paper-warm: #fffaf5;
  --paper-warmer: #fff7ef;
  --line: #ededef;
  --line-strong: #e6e6ea;
  /* THE PAGER RAIL, in the answer screen's right gutter (2026-09-01).
   *
   * THERE WAS A `--rail-track` HERE AND IT IS GONE. A 2px rule behind the dots was
   * added to group them into one object once the rail left the card; on the device
   * it simply read as a visible line nobody had asked for, and the dots do the
   * grouping on their own. Removed by product ruling, 2026-09-01. Recorded rather
   * than deleted silently, because "add a track" is the obvious next idea for
   * anyone who thinks the rail looks loose — it was tried and it looked worse.
   *
   * `--rail-dot` is a NON-TEXT GRAPHICAL OBJECT and WCAG 1.4.11 asks 3:1 of it.
   * MEASURED on `--paper` #ffffff: this is **3.04:1**, where the `#e1e4e8` the
   * rail was still using is **1.28:1** and `--ink-faint` is **2.53:1** — neither
   * reaches the bar, and the first is very nearly invisible.
   *
   * IT WAS #8c96a3 FOR ONE COMMIT AND THAT IS **2.9972:1** — under the bar by
   * three ten-thousandths, and it read as "3.00" in every place I rounded to two
   * decimals, including the browser. `tests/test_rail_contrast.py` computed the
   * ratio rather than the rounded string and refused it. A bar checked by eye
   * against a rounded number is not a bar.
   *
   * The dot's contrast is now entirely its own: with no track behind it, every
   * ground under every dot is `--paper` #ffffff and the 3.04:1 below is the whole
   * of the measurement rather than a figure a second layer was propping up. */
  --rail-dot: #8b95a2;
  --line-faint: #efeff1;
  --skeleton-a: #efeff2;
  --skeleton-b: #e7e7eb;
  --chip-bg: #f1f1f3;

  /* shape */
  --r-card: 22px;
  --r-tile: 20px;
  --r-control: 18px;
  --r-thumb: 14px;
  --r-chip: 24px;
  --r-pill: 999px;

  /* elevation */
  --shadow-card: 0 3px 14px rgba(0, 0, 0, 0.05);
  --shadow-tile: 0 2px 10px rgba(0, 0, 0, 0.04);
  --shadow-float: 0 4px 18px rgba(0, 0, 0, 0.09);
  --shadow-accent: 0 8px 24px rgba(255, 90, 0, 0.34);

  /* spacing — the design's rhythm */
  --pad-screen: 26px;
  --pad-card: 15px;
  --gap-s: 8px;
  --gap-m: 12px;
  --gap-l: 18px;

  /* ergonomics (§14): comfortably above platform minimums */
  --touch-min: 56px;

  /* ── the bottom band ──────────────────────────────────────────────────────
   * BOTH OF THESE ARE FIRST-PAINT FALLBACKS. `layout.js` measures the rendered
   * surface and the whole bottom-anchored band on load, on resize, on
   * orientationchange and on every navigation, and publishes both as inline
   * custom properties on `<html>` — which outrank these.
   *
   * 104 -> 98, AND THE OLD VALUE WAS NEVER THE SURFACE'S HEIGHT. MEASURED at
   * 393x646: `.surface` renders 98px, so every rule reserving
   * `calc(var(--surface-h) + 16px)` was holding 120 for a 98px object and every
   * rule pinning something at `calc(var(--surface-h) - 2px)` was 6px out. 98 is
   * the browser reading, where `env(safe-area-inset-bottom)` is 0; on a handset
   * the inset is real and the surface is taller, which is exactly why the number
   * has to be measured rather than written down.
   *
   * `--bottom-h` DEFAULTS TO THE SURFACE ALONE. On first paint the only thing
   * anchored to the bottom is the surface, and the list pill and the walking CTA
   * are both painted later — so the fallback is right for the moment it covers,
   * and every rule reads `--bottom-h` with `--surface-h` as its own fallback so a
   * page with JS disabled still reserves the surface. */
  --surface-h: 98px;
  --bottom-h: var(--surface-h);

  /* ── the nav-bar recorder (design 11c/11g) ────────────────────────────────
   * Five colours the palette genuinely did not have. Each is checked against
   * the nearest existing token rather than assumed new:
   *   --rec-bg   #fbf8f3 vs --paper-warm  #fffaf5 — warmer and a shade darker,
   *              because the recorder sits ON --paper-warm and has to read as a
   *              raised object against it, not blend into it;
   *   --rec-line #efeae1 vs --line        #ededef — the warm counterpart of the
   *              neutral hairline, to match the warm ground above;
   *   --rec-idle #b9bcc1 is the waveform slot that holds no sample yet, and
   *   --rec-live #5c6169 the slot that does. They are one step either side of
   *              --ink-muted #68737d and the CONTRAST BETWEEN THEM is the whole
   *              signal — written vs not-yet-written — so neither can collapse
   *              onto the token in the middle.
   *   --rec-x    #8a9199 sits between --ink-muted and --ink-faint; it is the
   *              dismiss glyph, deliberately quieter than the stop control it
   *              shares a bar with. */
  --rec-bg: #fbf8f3;
  --rec-line: #efeae1;
  --rec-idle: #b9bcc1;
  --rec-live: #5c6169;
  --rec-x: #8a9199;

  /* The modals' two greys (11b/11d/11e). --sheet-chip is the round close button
   * and --sheet-field the typing field's ground; --chip-bg #f1f1f3 is a third
   * value between them and reusing it for either would have moved the design. */
  --sheet-chip: #f4f4f6;
  /* 25j — the hollow check's glyph on a dropped ingredient. NOTHING IN THIS
   * FILE IS WITHIN 23/255 of it, which is why it is a token of its own rather
   * than the nearest thing rounded: the near-miss rule cuts both ways, and
   * collapsing a genuinely new colour onto an unrelated one is the same defect
   * from the other side. */
  --check-off: #d3d7dc;
  --sheet-field: #f7f7f9;
  --sheet-rule: #f0f0f2;

  /* How far the home screen's lower cards and the nav bar travel DOWNWARD when
   * the listening surface takes over (11a). INFERRED, not taken: the frames bind
   * this to `{{ spkTilesT }}` / `{{ spkNavT }}` and no binding VALUES exist
   * anywhere in the design document, so the only resolved downward travel in the
   * whole turn is 11c's hidden "Type instead" at translateY(46px). That is the
   * number, reused, rather than one invented next to it. */
  --vs-slide: 46px;
}

/* High contrast is a requirement, not a preference: retail lighting, arm's
 * length, possibly cold hands in a freezer aisle (§14 rule 7). The palette is
 * already high-contrast; this keeps it that way if the OS asks for more. */
@media (prefers-contrast: more) {
  :root {
    --ink-muted: #4a545d;
    --ink-faint: #6b7681;
    --line: #d5d5d9;
    --line-strong: #c9c9d0;
    /* 4.62:1 on white — the rail follows the rest of the palette up when the OS
     * asks for more contrast, rather than staying at its 3:1 floor. */
    --rail-dot: #6b7684;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
