/* Recipe Book — design system: a calm "kitchen notebook" (app/dev/UI-STANDARD.md).
   Warm paper, editorial serif titles, crisp small UI type, food photos as the hero,
   hairlines instead of boxes, one restrained accent.
   Tokens and every shared component live here; css/<view>.css holds only that view's layout.
   Text sizes are in rem (Settings › Text size sets the root size); palettes change colours only, never geometry. */

/* ============================================================== tokens == */
:root {
  /* ---- Paper (the default palette; Auto uses it by day) ---- */
  --bg: #F6F1E9;
  --surface: #FFFCF7;
  --surface-2: #F0E9DE;
  --ink: #1F1A15;
  --ink-2: #4A4239;
  --muted: #6E6357;            /* ≥ 4.5:1 on bg, surface and surface-2 */
  --line: #E4DACB;
  --line-soft: #ECE4D8;
  --line-strong: #D3C5B1;
  --field-line: #968672;       /* field bottom edge, checkbox borders: ≥ 3:1 */
  --accent: #B5461F;
  --accent-hover: #9C3A17;
  --accent-text: #A23F1B;
  --accent-soft: #F6DED2;
  --accent-ink: #FFFFFF;
  --herb: #3E7B4F;
  --olive: #7A8A2B;
  --saffron: #C9901C;
  --terracotta: #B2735C;
  --danger: #B3261E;
  --danger-ink: #FFFFFF;
  --tier-ok: #A87513;          /* the 5–6.9 score ring: saffron, dark enough to show on paper */
  --hover: rgb(74 66 57 / .07);
  --press: rgb(74 66 57 / .12);
  --topbar-bg: rgb(246 241 233 / .84);
  --search-bg: rgb(74 66 57 / .065);
  --backdrop: rgb(40 28 18 / .30);
  --toast-bg: #2A241F;
  --toast-ink: #F6F1E9;
  --check-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.4 4.3L19 7.2'/%3E%3C/svg%3E");
  --ph-sat: 46%; --ph-l1: 84%; --ph-l2: 72%; --ph-glow: 95%; --ph-glow-a: .9; --ph-ink: 28%;
  /* Categorical chart colours (validated for colour-blind separation on --bg). */
  --chart-1: #B5461F; --chart-2: #3A6EA5; --chart-3: #C9901C; --chart-4: #8E4F8F; --chart-5: #2E8B57;
  --shadow: 0 1px 2px rgba(60, 40, 20, .06), 0 4px 16px rgba(60, 40, 20, .06);
  --shadow-photo: 0 1px 2px rgba(60, 40, 20, .08), 0 8px 22px -12px rgba(60, 40, 20, .30);
  --shadow-lift: 0 2px 4px rgba(60, 40, 20, .07), 0 18px 36px -14px rgba(60, 40, 20, .38);
  --shadow-lg: 0 2px 6px rgba(60, 40, 20, .08), 0 24px 60px -12px rgba(60, 40, 20, .28);
  --shadow-float: 0 1px 4px rgb(40 28 18 / .16), 0 6px 16px -8px rgb(40 28 18 / .28);   /* a button on a photo */
  --shadow-knob: 0 1px 2px rgb(60 40 20 / .12), 0 0 0 1px var(--line-soft);           /* the raised part of a control */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .35 0 0 0 0 .24 0 0 0 0 .13 0 0 0 .09 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  color-scheme: light;

  /* ---- Geometry: identical in every palette ---- */
  /* ---- Fonts ---- */
  --font-ui: "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
  --font-display: "Sitka Display", "Sitka Heading", Georgia, serif;
  --font-serif: "Sitka Subheading", "Sitka Text", Georgia, serif;
  --font-num: "Bahnschrift", "Segoe UI Variable Display", sans-serif;
  --font-mono: "Cascadia Mono", Consolas, ui-monospace, monospace;          /* file paths only */

  /* ---- Type scale (rem: follows Settings › Text size). Values of 2xs…h1 unchanged. ---- */
  --fs-2xs: .72rem;    /* 11.5 — UPPERCASE eyebrows, glyph counts (nav badge, kbd, help ?), chart ticks. Never running words. */
  --fs-xs: .78rem;     /* 12.5 — meta, labels, hints, errors, badges, .score.sm digits */
  --fs-sm: .845rem;    /* 13.5 — controls, secondary text, .score digits */
  --fs-md: .94rem;     /* 15   — body at every width, fields, item titles, .score.lg digits */
  --fs-read: 1.03rem;  /* 16.5 — serif reading; phone card titles and day numbers */
  --fs-h3: 1.19rem;    /* 19   — group/card titles, wordmark */
  --fs-h2: 1.44rem;    /* 23   — section, dialog, empty-state titles */
  --fs-h1: clamp(1.9rem, 2.4vw + 1rem, 2.6rem);          /* 30–42 — KPI values, title fields, welcome/boot titles */
  --fs-display: clamp(1.9rem, 3vw + 1.1rem, 3.0625rem);  /* 30–49 — the recipe page title only (new) */
  /* Cook mode, the large-type exception (only step, ingredients and tips are multiplied by --cook-scale) */
  --fs-cook-xs: .875rem;     /* 14 — eyebrows incl. ingredient groups, timer labels, tip meta, A− */
  --fs-cook-sm: 1.125rem;    /* 18 — bar title, meta row, stepper, Back/Next, done actions */
  --fs-cook-md: 1.25rem;     /* 20 — ingredients, tips, done subtitle, score picks, A+ */
  --fs-cook-timer: 1.75rem;  /* 28 — running timer digits */
  --fs-cook-step: clamp(1.75rem, 1.5vw + 1.1875rem, 3.125rem);  /* 28–50, × --len (1/.94/.86 per recipe); ≥ 30 px at ≥ 1000 px */
  --fs-cook-title: clamp(2.25rem, 2.8vw + 1.125rem, 3.75rem);   /* 36–60 — mise and done titles */

  /* ---- Line height ---- */
  --lh-none: 1;     /* controls, badges, scores, steppers, toolbar titles */
  --lh-tight: 1.1;  /* display ≥ --fs-h1 */
  --lh-snug: 1.25;  /* titles --fs-md … --fs-h2 */
  --lh-ui: 1.35;    /* UI text that can wrap: messages, rows, toasts, banners */
  --lh-body: 1.5;   /* body, help, notes */
  --lh-read: 1.6;   /* serif reading and every multi-line field */

  /* ---- Tracking (otherwise 0; never on small numbers) ---- */
  --ls-display: -.02em;  /* ≥ --fs-h1 */
  --ls-heading: -.01em;  /* display-face titles, KPI, cook step */
  --ls-eyebrow: .09em;   /* uppercase */

  /* ---- Type roles: use as `font: var(--t-…)`; a view never re-declares a title's size/line-height ---- */
  --t-section: 400 var(--fs-h2)/var(--lh-snug) var(--font-display);  /* h2, dialog, empty state */
  --t-group: 400 var(--fs-h3)/var(--lh-snug) var(--font-serif);      /* list section, strip, card title */
  --t-item: 400 var(--fs-md)/var(--lh-snug) var(--font-serif);       /* row / item title */
  --t-label: 600 var(--fs-md)/var(--lh-ui) var(--font-ui);           /* h3 label heading */
  --t-eyebrow: 600 var(--fs-2xs)/var(--lh-ui) var(--font-ui);        /* + --ls-eyebrow, uppercase */

  /* ---- Controls: one ladder 24 · 32 · 38 · 44 · 56 ---- */
  --control-h-xs: 1.5rem;      /* 24 — chip-sm, badge, tag chip, Bought label, help ?, × (new) */
  --control-h-sm: 2rem;        /* 32 — btn-sm, chip, search, menu item, toast/banner action, day + */
  --control-h: 2.375rem;       /* 38 — field, btn, seg, tabs */
  --control-h-lg: 2.75rem;     /* 44 — was 46; = --touch, phone Cook */
  --control-h-hero: 3.5rem;    /* 56 — was 54; = --touch-cook, cook bar and nav */
  --row-min: 2.75rem;          /* 44 */
  --textarea-min: 6rem;        /* 96 */
  --touch: 2.75rem;            /* 44 */
  --touch-cook: 3.5rem;        /* 56 */
  --toolbar-h: 48px;           /* view toolbar (+ hairline), same as --bar-h (new) */
  --page-form: 1100px;         /* editor + importer column; a form toolbar aligns to it (new) */
  --field-w-num: 5.125rem;     /* 82 px */
  --field-w-unit: 8.25rem;     /* 132 px */
  --field-w-cuisine: 13.75rem; /* 220 px */

  /* ---- Radii: 6 · 8 · 10 · 12 · 16 · pill (nested radius = outer − padding) ---- */
  --radius-xs: 6px;                   /* checkbox, tick, focus ring, kbd, tiny marks */
  --radius-sm: 8px;                   /* 32 px controls, rows, thumbs ≤ 40, seg option */
  --radius-field: 10px;               /* field, button, seg track, thumbs 44–72 */
  --radius: 12px;                     /* card, menu, popover, strip, row hover surface */
  --radius-lg: 16px;                  /* photo, panel, dialog */
  --radius-photo: var(--radius-lg);   /* alias (was 14px) */
  --radius-dialog: var(--radius-lg);  /* alias (was 18px) */
  --radius-pill: 999px;               /* chips, bars, underline ends */

  /* ---- Rings (palette-free: they take palette colours) ---- */
  --ring-halo: 0 0 0 3px var(--accent-soft);       /* drag-over / chosen card; never the only focus sign */
  --ring-well: inset 0 0 0 1px var(--line-soft);   /* wells, empty icons */
  --ring-line: inset 0 0 0 1px var(--line);        /* strips, lasting notes */
  --ring-edge: inset 0 0 0 1px var(--line-strong); /* seg track, outline badge, control edges */

  /* ---- Interaction states ---- */
  --surface-hover: color-mix(in srgb, var(--surface), var(--ink) 4%);    /* filled controls: hover */
  --surface-press: color-mix(in srgb, var(--surface), var(--ink) 8%);    /* filled controls: pressed */
  --ink-disabled: color-mix(in srgb, var(--muted) 78%, var(--surface-2)); /* disabled labels: ≥ 3:1 on bg/surface/surface-2 */
  --knob: var(--surface);      /* raised part of a control (seg option); dark palettes override below */
  --press-y: 1px;              /* raised controls sink */
  --press-scale: .92;          /* marks shrink (check, score pick, help ?) */

  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 48px;
  --page-top: 20px;

  /* --topbar-h is the whole sticky header: the 48 px bar plus the not-saved banner while it shows
     (main.js sets --banner-h), so toolbars that stick below it move down with it. */
  --bar-h: 48px;
  --banner-h: 0px;
  --topbar-h: calc(var(--bar-h) + var(--banner-h));
  --page-max: 1180px;
  --page-pad: 24px;
  --page-narrow: 760px;
  --dialog-w: 520px;      /* messages */
  --dialog-w-form: 580px; /* forms */
  --dialog-w-wide: 780px; /* wide */

  /* ---- Motion ---- */
  --dur-fast: 120ms;   /* hover, press, every exit, small popovers (new) */
  --dur: 160ms;        /* tints, fades */
  --dur-slow: 220ms;   /* overlays enter, lifts, ticks, photo fade */
  --dur-page: 240ms;   /* view entrance, week/cook turn, list moves (new) */
  --ease: cubic-bezier(.2, .7, .2, 1);     /* enter / standard */
  --ease-in: cubic-bezier(.4, 0, 1, 1);    /* exits (new) */
  --ease-move: cubic-bezier(.3, 0, .2, 1); /* A → B moves (new) */
  --tr-tint: color var(--dur) var(--ease), background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), opacity var(--dur) var(--ease);
  --tr-press: var(--tr-tint), transform var(--dur-fast) var(--ease);
  --tr-lift: transform var(--dur-slow) var(--ease), box-shadow var(--dur-slow) var(--ease);
}

/* ---- Per palette (values of --shadow, --shadow-float, --shadow-photo, --shadow-lift, --shadow-lg, --shadow-knob stay as they are) ----
   Elevation scale: --shadow (1 rest) · --shadow-float (small control on a photo) · --shadow-photo (2 raised photo)
                    · --shadow-lift (3 hover/drag) · --shadow-lg (4 menu, popover, tooltip, dialog, toast) · --shadow-knob.
   Paper and Delft: --knob = var(--surface) from the geometry block; print resolves it to #fff. */

/* ---- Delft: cool white-tile day, Delft-blue accent ---- */
:root[data-theme="delft"] {
  --bg: #F3F2EE; --surface: #FFFFFF; --surface-2: #E9ECF1;
  --ink: #141A26; --ink-2: #3B4352; --muted: #5B6372;
  --line: #DCE0E6; --line-soft: #E7E9ED; --line-strong: #C5CBD5; --field-line: #7F8796;
  --accent: #24508F; --accent-hover: #1C4176; --accent-text: #24508F; --accent-soft: #DCE6F4; --accent-ink: #FFFFFF;
  --herb: #3E7B4F; --olive: #7A8A2B; --saffron: #C9901C; --terracotta: #B2735C; --danger: #B3261E; --danger-ink: #FFFFFF;
  --tier-ok: #A87513;
  --hover: rgb(20 30 50 / .06); --press: rgb(20 30 50 / .11);
  --topbar-bg: rgb(243 242 238 / .86); --search-bg: rgb(20 30 50 / .06); --backdrop: rgb(14 22 40 / .32);
  --toast-bg: #1C2433; --toast-ink: #F3F2EE;
  --ph-sat: 30%; --ph-l1: 86%; --ph-l2: 76%; --ph-glow: 96%; --ph-glow-a: .9; --ph-ink: 30%;
  --chart-1: #24508F; --chart-2: #B5461F; --chart-3: #C9901C; --chart-4: #8E4F8F; --chart-5: #2E8B57;
  --shadow: 0 1px 2px rgba(20, 30, 50, .06), 0 4px 16px rgba(20, 30, 50, .06);
  --shadow-photo: 0 1px 2px rgba(20, 30, 50, .08), 0 8px 22px -12px rgba(20, 30, 50, .30);
  --shadow-lift: 0 2px 4px rgba(20, 30, 50, .07), 0 18px 36px -14px rgba(20, 30, 50, .36);
  --shadow-lg: 0 2px 6px rgba(20, 30, 50, .08), 0 24px 60px -12px rgba(20, 30, 50, .26);
  --shadow-float: 0 1px 4px rgb(14 22 40 / .16), 0 6px 16px -8px rgb(14 22 40 / .28);
  --shadow-knob: 0 1px 2px rgb(20 30 50 / .12), 0 0 0 1px var(--line-soft);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .2 0 0 0 0 .26 0 0 0 0 .38 0 0 0 .05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  color-scheme: light;
}

/* ---- Charcoal: warm dark (Auto uses it at night; 'dark' is its old name) ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]), :root[data-theme="auto"] {
    --bg: #161412; --surface: #1F1C19; --surface-2: #2A2622; --ink: #F3EDE4; --ink-2: #D2C8BB; --muted: #9C9184;
    --line: #352F29; --line-soft: #2B2622; --line-strong: #4A423A; --field-line: #756B60;
    --accent: #E2703F; --accent-hover: #EC8457; --accent-text: #EE8B60; --accent-soft: #3A2419; --accent-ink: #1A0F09;
    --herb: #7DBB8C; --olive: #B4C46A; --saffron: #E0B04A; --terracotta: #CF917A; --danger: #F2847B; --danger-ink: #1A0F09;
    --tier-ok: #E0B04A;
    --hover: rgb(243 237 228 / .07); --press: rgb(243 237 228 / .12);
    --topbar-bg: rgb(22 20 18 / .82); --search-bg: rgb(243 237 228 / .07); --backdrop: rgb(0 0 0 / .55);
    --toast-bg: #F3EDE4; --toast-ink: #1F1A15;
    --check-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231F1C19' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.4 4.3L19 7.2'/%3E%3C/svg%3E");
    --ph-sat: 20%; --ph-l1: 27%; --ph-l2: 19%; --ph-glow: 42%; --ph-glow-a: .16; --ph-ink: 80%;  /* calmer letter tiles (was 26% / .28) */
    --knob: color-mix(in srgb, var(--surface-2), var(--ink) 10%);  /* lighter than the track, never sunk */
    --chart-1: #DD6A39; --chart-2: #4F86C6; --chart-3: #B88A2A; --chart-4: #A872B3; --chart-5: #44996A;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 4px 16px rgba(0, 0, 0, .25);
    --shadow-photo: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 22px -12px rgba(0, 0, 0, .7);
    --shadow-lift: 0 2px 4px rgba(0, 0, 0, .4), 0 18px 36px -14px rgba(0, 0, 0, .8);
    --shadow-lg: 0 2px 6px rgba(0, 0, 0, .4), 0 24px 60px -12px rgba(0, 0, 0, .7);
    --shadow-float: 0 1px 4px rgb(0 0 0 / .45), 0 6px 16px -8px rgb(0 0 0 / .6);
    --shadow-knob: 0 1px 2px rgb(0 0 0 / .45), 0 0 0 1px var(--line-soft);
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 .94 0 0 0 0 .86 0 0 0 .05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
    color-scheme: dark;
  }
}
:root[data-theme="charcoal"], :root[data-theme="dark"] {
  --bg: #161412; --surface: #1F1C19; --surface-2: #2A2622; --ink: #F3EDE4; --ink-2: #D2C8BB; --muted: #9C9184;
  --line: #352F29; --line-soft: #2B2622; --line-strong: #4A423A; --field-line: #756B60;
  --accent: #E2703F; --accent-hover: #EC8457; --accent-text: #EE8B60; --accent-soft: #3A2419; --accent-ink: #1A0F09;
  --herb: #7DBB8C; --olive: #B4C46A; --saffron: #E0B04A; --terracotta: #CF917A; --danger: #F2847B; --danger-ink: #1A0F09;
  --tier-ok: #E0B04A;
  --hover: rgb(243 237 228 / .07); --press: rgb(243 237 228 / .12);
  --topbar-bg: rgb(22 20 18 / .82); --search-bg: rgb(243 237 228 / .07); --backdrop: rgb(0 0 0 / .55);
  --toast-bg: #F3EDE4; --toast-ink: #1F1A15;
  --check-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231F1C19' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.4 4.3L19 7.2'/%3E%3C/svg%3E");
  --ph-sat: 20%; --ph-l1: 27%; --ph-l2: 19%; --ph-glow: 42%; --ph-glow-a: .16; --ph-ink: 80%;
  --knob: color-mix(in srgb, var(--surface-2), var(--ink) 10%);
  --chart-1: #DD6A39; --chart-2: #4F86C6; --chart-3: #B88A2A; --chart-4: #A872B3; --chart-5: #44996A;
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 4px 16px rgba(0, 0, 0, .25);
  --shadow-photo: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 22px -12px rgba(0, 0, 0, .7);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, .4), 0 18px 36px -14px rgba(0, 0, 0, .8);
  --shadow-lg: 0 2px 6px rgba(0, 0, 0, .4), 0 24px 60px -12px rgba(0, 0, 0, .7);
  --shadow-float: 0 1px 4px rgb(0 0 0 / .45), 0 6px 16px -8px rgb(0 0 0 / .6);
  --shadow-knob: 0 1px 2px rgb(0 0 0 / .45), 0 0 0 1px var(--line-soft);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 .94 0 0 0 0 .86 0 0 0 .05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  color-scheme: dark;
}

/* ---- Night kitchen: low-light dark, amber accent ---- */
:root[data-theme="night"] {
  --bg: #110F0D; --surface: #191613; --surface-2: #221E1A; --ink: #EDE2D1; --ink-2: #C8BAA5; --muted: #9A8C7A;
  --line: #2C2722; --line-soft: #221E1A; --line-strong: #3D362F; --field-line: #6F6457;
  --accent: #D98A4A; --accent-hover: #E39A5E; --accent-text: #E29A5E; --accent-soft: #34230F; --accent-ink: #1A0F06;
  --herb: #76AE83; --olive: #A9B866; --saffron: #D6A64A; --terracotta: #C48A72; --danger: #E57D72; --danger-ink: #1A0F06;
  --tier-ok: #D6A64A;
  --hover: rgb(237 226 209 / .06); --press: rgb(237 226 209 / .10);
  --topbar-bg: rgb(17 15 13 / .86); --search-bg: rgb(237 226 209 / .06); --backdrop: rgb(0 0 0 / .6);
  --toast-bg: #EDE2D1; --toast-ink: #1A1613;
  --check-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23191613' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.4 4.3L19 7.2'/%3E%3C/svg%3E");
  --ph-sat: 16%; --ph-l1: 21%; --ph-l2: 14%; --ph-glow: 34%; --ph-glow-a: .12; --ph-ink: 74%;  /* was 22% / .22 */
  --knob: color-mix(in srgb, var(--surface-2), var(--ink) 10%);
  --chart-1: #CF7F45; --chart-2: #4F7FB8; --chart-3: #B08A35; --chart-4: #9C6FA6; --chart-5: #3F8F62;
  --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 4px 16px rgba(0, 0, 0, .3);
  --shadow-photo: 0 1px 2px rgba(0, 0, 0, .45), 0 8px 22px -12px rgba(0, 0, 0, .75);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, .45), 0 18px 36px -14px rgba(0, 0, 0, .85);
  --shadow-lg: 0 2px 6px rgba(0, 0, 0, .45), 0 24px 60px -12px rgba(0, 0, 0, .75);
  --shadow-float: 0 1px 4px rgb(0 0 0 / .5), 0 6px 16px -8px rgb(0 0 0 / .65);
  --shadow-knob: 0 1px 2px rgb(0 0 0 / .5), 0 0 0 1px var(--line-soft);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 .9 0 0 0 0 .75 0 0 0 .035 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  color-scheme: dark;
}

/* ---- Text size: Normal · Large · Larger (everything in rem follows) ---- */
:root[data-text="large"] { font-size: 112.5%; }
:root[data-text="larger"] { font-size: 125%; }

/* ================================================================ base == */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

/* The paper lives on <html> so the reserved scrollbar gutter is paper too. */
html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent; /* every control draws its own pressed state */
  scrollbar-gutter: stable;
  background-color: var(--bg);
  background-image: var(--grain);
}
html:has(dialog[open]) { overflow: hidden; }

body {
  margin: 0;
  min-height: 100vh;
  background: transparent;
  color: var(--ink);
  font: 400 var(--fs-md)/var(--lh-body) var(--font-ui);
  font-kerning: normal;
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
h1 { font: 400 var(--fs-h1)/var(--lh-tight) var(--font-display); letter-spacing: var(--ls-display); text-wrap: balance; }
/* The section role, declared once: h2, section, dialog and empty-state titles. */
h2, .section-title, .empty-title, .dialog-title { font: var(--t-section); letter-spacing: var(--ls-heading); text-wrap: balance; }
h3 { font: var(--t-label); }
/* The one eyebrow style (small caps line above or beside a title); views reuse it instead of a copy. */
h4, .eyebrow { font: var(--t-eyebrow); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--muted); }
p { text-wrap: pretty; }
small { font-size: var(--fs-xs); }
b, strong { font-weight: 600; }
hr { border: 0; border-top: 1px solid var(--line); margin: 20px 0; }
img, svg, video { display: block; max-width: 100%; }
svg.icon { display: inline-block; flex: none; vertical-align: -.22em; }
/* Icon steps in rem, so icons follow Text size (zero specificity: any view rule still wins; author CSS beats the
   width/height attributes). 12 in marks ≤ 24 px · 14 beside meta · 16 default · 20 bars and hero fields; 24–40 decorative. */
:where(svg.icon[width="12"]) { width: .75rem; height: .75rem; }
:where(svg.icon[width="14"]) { width: .875rem; height: .875rem; }
:where(svg.icon[width="16"]) { width: 1rem; height: 1rem; }
:where(svg.icon[width="20"]) { width: 1.25rem; height: 1.25rem; }
:where(svg.icon[width="24"]) { width: 1.5rem; height: 1.5rem; }
:where(svg.icon[width="32"]) { width: 2rem; height: 2rem; }
:where(svg.icon[width="40"]) { width: 2.5rem; height: 2.5rem; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
button { cursor: pointer; }
button:disabled { cursor: default; }
input[type="checkbox"], input[type="radio"], input[type="range"], progress { accent-color: var(--accent); }
::selection { background: var(--accent-soft); color: var(--ink); }
::placeholder { color: var(--muted); opacity: 1; }

:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-xs); }
/* Targets the app focuses for orientation (view heading, outlet, help text) don't wear a ring. */
h1[tabindex="-1"]:focus, .outlet:focus, .help-pop:focus { outline: none; }

/* Thin, warm scrollbars */
* { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--ink) 20%, transparent) transparent; }

/* Skip link: first Tab stop, visible only while focused. */
.skip-link {
  position: absolute; left: 12px; top: -64px; z-index: 300;
  padding: 9px 14px; border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm); font-weight: 600;
}
.skip-link:focus { top: 8px; }

/* ============================================================== layout == */
.outlet { display: block; }
.view { min-height: calc(100vh - var(--topbar-h)); }
body.no-chrome .view { min-height: 100vh; }

.page { max-width: var(--page-max); margin: 0 auto; padding: var(--page-top) var(--page-pad) var(--space-7); }
.page-narrow { max-width: var(--page-narrow); margin: 0 auto; padding: var(--page-top) var(--page-pad) var(--space-7); }
.page-head { display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--space-3) var(--space-4); margin: 0 0 var(--space-5); }
.page-head > :first-child { flex: 1 1 auto; min-width: 0; }
.lede { font: 400 var(--fs-read)/var(--lh-read) var(--font-serif); color: var(--ink-2); max-width: 62ch; }
.section { margin-top: var(--space-6); }
.section-head { display: flex; align-items: baseline; gap: var(--space-3); margin-bottom: var(--space-3); }
.section-head::after { content: ""; flex: 1; height: 1px; background: var(--line); transform: translateY(-4px); }

.row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.row.wrap { flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.stack.tight { gap: 6px; }
.stack.loose { gap: 20px; }
.spacer { flex: 1 1 auto; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--min, 228px), 1fr)); gap: var(--gap, var(--space-6) var(--space-5)); }
.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 32px; }

.muted { color: var(--muted); }
.ink-2 { color: var(--ink-2); }
.accent { color: var(--accent-text); }
.serif { font-family: var(--font-display); }
.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; }
.small { font-size: var(--fs-sm); }
.tiny { font-size: var(--fs-xs); }
.nowrap { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.center { text-align: center; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.link { color: var(--accent-text); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, currentColor 35%, transparent); }
.link:hover { text-decoration-color: currentColor; }
.prose { font: 400 var(--fs-read)/var(--lh-read) var(--font-serif); color: var(--ink); max-width: 66ch; }
.prose a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; }
.prose p + p { margin-top: .8em; }
.divider { height: 1px; background: var(--line); border: 0; margin: 18px 0; }

/* ============================================================== top bar == */
.topbar {
  position: sticky; top: 0; z-index: 50;
  min-height: var(--bar-h);
  background: var(--topbar-bg);
  -webkit-backdrop-filter: saturate(1.5) blur(14px);
  backdrop-filter: saturate(1.5) blur(14px);
  border-bottom: 1px solid var(--line);
}
body.no-chrome .topbar { display: none; }
.topbar-inner {
  height: var(--bar-h); max-width: var(--page-max); margin: 0 auto; padding: 0 var(--page-pad);
  display: flex; align-items: center; gap: 6px;
}

/* The wordmark wears a paprika ribbon, hanging from the top edge like a notebook bookmark. */
.wordmark {
  display: flex; align-items: center; gap: 11px; height: 100%; margin-right: 18px; flex: none;
  font: 400 var(--fs-h3)/var(--lh-none) var(--font-display); letter-spacing: var(--ls-heading); color: var(--ink); white-space: nowrap;
}
.wordmark-ribbon {
  align-self: flex-start; width: 12px; height: 27px; flex: none;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 82%, #000) 0, var(--accent) 5px);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 76%, 0 100%);
  transform-origin: top; transition: transform var(--dur) var(--ease);
}
@media (hover: hover) { .wordmark:hover .wordmark-ribbon { transform: scaleY(1.185); } } /* 27 → 32 px */
.wordmark:focus-visible { outline-offset: -2px; }

.nav { display: flex; align-items: stretch; height: 100%; gap: 2px; }
.nav-link {
  position: relative; display: flex; align-items: center; gap: 7px; padding: 0 11px;
  color: var(--ink-2); font-size: var(--fs-sm); font-weight: 500; white-space: nowrap;
  transition: var(--tr-tint);
}
.nav-link .icon { display: none; }
.nav-link::after {
  content: ""; position: absolute; left: 11px; right: 11px; bottom: -1px; height: 2px;
  border-radius: var(--radius-pill) var(--radius-pill) 0 0; background: var(--accent);
  transform: scaleX(0); transition: transform var(--dur-slow) var(--ease);
}
.nav-link:hover { color: var(--ink); }
.nav-link[aria-current="page"] { color: var(--ink); }
.nav-link[aria-current="page"]::after { transform: scaleX(1); }
.nav-link:focus-visible { outline-offset: -6px; border-radius: var(--radius-field); }
.nav-badge {
  min-width: 1.125rem; height: 1.125rem; padding: 0 5px; border-radius: var(--radius-pill);
  display: inline-grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-text);
  font: 600 var(--fs-2xs)/var(--lh-none) var(--font-num); font-variant-numeric: tabular-nums; letter-spacing: 0;
}

.search {
  position: relative; display: flex; align-items: center; flex: 0 1 230px; min-width: 0; height: var(--control-h-sm);
  margin-left: 6px; border-radius: var(--radius-pill); background: var(--search-bg); color: var(--muted);
  border: 1px solid transparent;
  transition: flex-basis var(--dur-slow) var(--ease), var(--tr-tint);
}
.search .icon { position: absolute; left: 11px; pointer-events: none; }
.search input {
  appearance: none; border: 0; outline: 0; background: transparent; width: 100%; height: 100%; min-width: 0;
  padding: 0 10px 0 34px; font-size: var(--fs-sm); color: var(--ink);
}
.search input::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none; width: 14px; height: 14px; cursor: pointer;
  background: var(--muted);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center / contain no-repeat;
}
.search:hover { background: color-mix(in srgb, var(--search-bg), var(--ink) 4%); }
/* Focus shows as an accent edge (≥ 3:1) plus the soft halo, not the halo alone. */
.search:focus-within {
  flex-basis: 320px; background: var(--surface); border-color: color-mix(in srgb, var(--accent) 70%, var(--line-strong));
  box-shadow: 0 0 0 3px var(--accent-soft); color: var(--ink-2);
}
.search:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Squeezed (a phone-wide window) the placeholder would show as "Se": the magnifier and the field's name say it.
   main.js measures the fit (a size container would change how the bar shares its width). */
.search.is-squeezed input::placeholder { color: transparent; }
/* A quiet "/" key chip while the field is empty, on pointer screens wide enough for it. */
.search-kbd { position: absolute; right: 7px; pointer-events: none; }
.search:has(.search-kbd) input { padding-right: 34px; }
.search:focus-within .search-kbd, .search:has(input:not(:placeholder-shown)) .search-kbd, .search.is-squeezed .search-kbd { display: none; }
@media (max-width: 920px), (pointer: coarse) { .search-kbd { display: none; } }
.topbar-inner > .btn { flex: none; } /* actions never shrink; the search field gives way */
.topbar-add { margin-left: 8px; }
.topbar-help { margin-left: 2px; }
/* The current page is a 2 px accent bar on the bar's bottom edge (like the nav underline), never a stuck hover fill. */
.topbar-add, .topbar-settings { position: relative; }
:is(.topbar-add, .topbar-settings)[aria-current="page"]::after {
  content: ""; position: absolute; left: var(--space-2); right: var(--space-2); bottom: calc((100% - var(--bar-h)) / 2 - 1px);
  height: 2px; border-radius: var(--radius-pill) var(--radius-pill) 0 0; background: var(--accent);
}

/* Save state in words: "Saving…", "Offline", "Not saved", then "Saved" for a moment. */
.save-state {
  display: inline-flex; align-items: center; gap: 6px; flex: none; margin: 0 6px;
  color: var(--ink-2); font-size: var(--fs-xs); font-weight: 500; white-space: nowrap;
}
.save-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--saffron); }
.save-state[data-state="saving"] .save-dot { animation: rb-pulse 1.4s var(--ease) infinite; }
.save-state[data-state="offline"] .save-dot { background: transparent; box-shadow: inset 0 0 0 2px var(--muted); }
.save-state[data-state="error"] .save-dot { background: var(--danger); }
.save-state[data-state="error"] { color: var(--danger); }
.save-state[data-state="saved"] .save-dot { background: var(--herb); }
html[data-banner="unsaved"] .save-state, html[data-banner="stopped"] .save-state, html[data-banner="foreign"] .save-state { display: none; }

/* Not saved yet / stopped / other folder / updated: one slim line inside the sticky header, never floating. */
.banner {
  display: flex; align-items: center; gap: var(--space-3); min-height: var(--row-min);
  padding: var(--space-1) max(var(--page-pad), calc((100% - var(--page-max)) / 2 + var(--page-pad)));
  border-top: 1px solid color-mix(in srgb, var(--danger) 24%, var(--line));
  background: color-mix(in srgb, var(--danger) 9%, var(--surface));
  color: var(--ink); font-size: var(--fs-sm); line-height: var(--lh-ui);
}
.banner-mark { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--danger); }
.banner[data-kind="stopped"] .banner-mark { background: transparent; box-shadow: inset 0 0 0 2px var(--danger); }
.banner-msg { flex: 1 1 auto; min-width: 0; }
.banner-btn { flex: none; height: var(--control-h-sm); padding: 0 12px; }
.banner[data-kind="updated"] {
  border-top-color: color-mix(in srgb, var(--herb) 26%, var(--line));
  background: color-mix(in srgb, var(--herb) 9%, var(--surface));
}
.banner[data-kind="updated"] .banner-mark { background: var(--herb); }
/* Views without the top bar (cook mode) still get the banner: the header then shows only that line. */
body.no-chrome .topbar:has(> .banner:not([hidden])) { display: block; min-height: 0; border-bottom: 0; }
body.no-chrome .topbar > .topbar-inner { display: none; }
body.no-chrome:has(.topbar > .banner:not([hidden])) .view { min-height: calc(100vh - var(--banner-h)); }
body.no-chrome:has(.topbar > .banner:not([hidden])) .view.cook { height: calc(100dvh - var(--banner-h)); min-height: 0; }

/* ============================================= the optional second bar == */
/* Put .toolbar as a direct child of the view element (outside .page): it spans
   the full width but its content lines up with the page column. */
.toolbar {
  position: sticky; top: var(--topbar-h); z-index: 40;
  display: flex; align-items: center; gap: var(--space-2); min-height: var(--toolbar-h);
  padding: var(--space-2) max(var(--page-pad), calc((100% - var(--page-max)) / 2 + var(--page-pad)));
  background: var(--topbar-bg);
  -webkit-backdrop-filter: saturate(1.5) blur(14px);
  backdrop-filter: saturate(1.5) blur(14px);
  border-bottom: 1px solid var(--line-soft);
  overflow-x: auto; scrollbar-width: none;
}
.toolbar.is-form { padding-inline: max(var(--page-pad), calc((100% - var(--page-form)) / 2 + var(--page-pad))); }
.toolbar::-webkit-scrollbar { display: none; }
.toolbar > * { flex: none; }
.toolbar .spacer { flex: 1 1 auto; }
body.no-chrome .toolbar { top: 0; }

/* ============================================================= buttons == */
/* States (UI-STANDARD §12a): hover never overrides selected; pressed sinks by --press-y; disabled is flat
   (--surface-2 + --ink-disabled), never opacity; busy keeps its colour and shows the spinner (aria-busy). */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: var(--control-h); padding: 0 15px; border-radius: var(--radius-field);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
  font-size: var(--fs-sm); font-weight: 500; line-height: var(--lh-none); white-space: nowrap; text-decoration: none;
  cursor: pointer; user-select: none;
  transition: var(--tr-press);
}
.btn:hover { background: var(--surface-hover); border-color: color-mix(in srgb, var(--line-strong), var(--ink) 12%); }
.btn:active:where(:not(:disabled)) { transform: translateY(var(--press-y)); background: var(--surface-press); }
.btn > .icon:first-child:not(:only-child) { margin-left: -3px; }
.btn > .icon:last-child:not(:only-child) { margin-right: -3px; }

.btn-primary {
  background: var(--accent); border-color: transparent; color: var(--accent-ink);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .14), 0 1px 2px color-mix(in srgb, var(--accent) 35%, transparent);
}
.btn-primary:hover { background: var(--accent-hover); border-color: transparent; }
.btn-primary:active { background: var(--accent-hover); box-shadow: inset 0 1px 3px rgb(0 0 0 / .22); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: var(--hover); border-color: transparent; color: var(--ink); }
.btn-ghost:active { background: var(--press); }

/* White text on a light salmon fails in the dark palettes: --danger-ink is dark there. */
.btn-danger { background: var(--danger); border-color: transparent; color: var(--danger-ink); }
.btn-danger:hover { background: color-mix(in srgb, var(--danger), var(--ink) 12%); border-color: transparent; }
.btn-danger:active { background: color-mix(in srgb, var(--danger), var(--ink) 18%); box-shadow: inset 0 1px 3px rgb(0 0 0 / .22); }
.btn-ghost.btn-danger { background: transparent; color: var(--danger); }
.btn-ghost.btn-danger:hover { background: color-mix(in srgb, var(--danger) 9%, transparent); }
.btn-ghost.btn-danger:active { background: color-mix(in srgb, var(--danger) 15%, transparent); box-shadow: none; }

.btn-sm { height: var(--control-h-sm); padding: 0 12px; font-size: var(--fs-sm); border-radius: var(--radius-sm); gap: 6px; }
.btn-lg { height: var(--control-h-lg); padding: 0 20px; font-size: var(--fs-md); border-radius: var(--radius); }
.btn-icon { width: var(--control-h); padding: 0; }
.btn-icon.btn-sm { width: var(--control-h-sm); }
.btn-icon.btn-lg { width: var(--control-h-lg); }
.btn-block { display: flex; width: 100%; }

/* Disabled: flat and still readable (≥ 3:1). A closing dialog keeps its buttons disabled, but they don't flash flat
   while it fades; a busy button is disabled for clicks only. */
.btn:is(:disabled, [aria-disabled="true"]):not(.busy, [aria-busy="true"], .dialog.closing .btn) {
  background: var(--surface-2); border-color: transparent; color: var(--ink-disabled); box-shadow: none; pointer-events: none;
}
.btn-ghost:is(:disabled, [aria-disabled="true"]):not(.dialog.closing .btn) { background: transparent; }
/* Busy is not disabled: same colour, the spinner in place of its icon. */
.btn:is(.busy, [aria-busy="true"]) { pointer-events: none; cursor: progress; }
.btn:is(.busy, [aria-busy="true"])::before {
  content: ""; display: inline-block; flex: none; width: .875rem; height: .875rem; border-radius: 50%;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent); border-top-color: currentColor;
  animation: rb-spin .9s linear infinite;
}
.btn:is(.busy, [aria-busy="true"]) > .icon:first-child { display: none; }

/* =============================================================== chips == */
.chip {
  display: inline-flex; align-items: center; gap: 6px; height: var(--control-h-sm); padding: 0 12px;
  border-radius: var(--radius-pill); border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-2); font-size: var(--fs-sm); font-weight: 500; line-height: var(--lh-none); white-space: nowrap;
  cursor: pointer; user-select: none;
  transition: var(--tr-press);
}
.chip.on, .chip[aria-pressed="true"] {
  background: var(--accent-soft); color: var(--accent-text);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent);
}
/* Hover never takes the selected look away: selected + hover is one step deeper in the accent family. */
:is(button, a, label).chip:not(.on, [aria-pressed="true"]):hover { background: var(--surface-hover); border-color: var(--line-strong); color: var(--ink); }
:is(button, a, label).chip:is(.on, [aria-pressed="true"]):hover {
  background: color-mix(in srgb, var(--accent-soft), var(--accent) 8%); border-color: color-mix(in srgb, var(--accent) 50%, transparent);
}
:is(button, a, label).chip:active { transform: translateY(var(--press-y)); }
:is(button, a, label).chip:not(.on, [aria-pressed="true"]):active { background: var(--surface-press); }
.chip .n { color: var(--muted); font: 500 var(--fs-xs)/var(--lh-none) var(--font-num); font-variant-numeric: tabular-nums; }
.chip.on .n, .chip[aria-pressed="true"] .n { color: inherit; }
.chip-sm { height: var(--control-h-xs); padding: 0 9px; font-size: var(--fs-xs); }
/* A clickable small chip is drawn 24 px but takes a 32 px target. */
:is(a, button).chip-sm { position: relative; }
:is(a, button).chip-sm::after { content: ""; position: absolute; inset: -4px 0; }
/* The × is drawn 18 px but takes a 24 px target (the negative margins keep the chip's size). */
.chip-x {
  display: inline-grid; place-items: center; width: 24px; height: 24px; margin: -3px -9px -3px -3px;
  border: 0; border-radius: 50%; background: transparent; color: var(--muted); padding: 0;
  transition: var(--tr-tint);
}
.chip-x:hover { background: var(--hover); color: var(--ink); }
.chip-x:active { background: var(--press); }

/* =============================================================== cards == */
.card {
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: var(--space-4) var(--space-5);
}
.card.flush { padding: 0; overflow: hidden; }
a.card, button.card { display: block; text-align: left; color: inherit; transition: var(--tr-lift); }
@media (hover: hover) {
  a.card:hover, button.card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lift); }
}
a.card:active, button.card:active { transform: none; box-shadow: var(--shadow); }
.card-title { font: var(--t-group); letter-spacing: 0; }

/* Recipe card — image first, text on the paper:
   <a class="rcard" href="#/r/ID">
     ${photoHtml(r, {cls:'rcard-img'})}               (optionally wrapped in .rcard-media with a .rcard-badge)
     <div class="rcard-body"><h3 class="rcard-title">…</h3><div class="rcard-meta">…</div></div>
   </a> */
.rcard { display: block; min-width: 0; color: inherit; border-radius: var(--radius-lg); }
.rcard:focus-visible { outline-offset: 4px; }
.rcard-media { position: relative; }
.rcard-img, .rcard-media > .ph {
  width: 100%; aspect-ratio: 4 / 3; border-radius: var(--radius-photo);
  box-shadow: var(--shadow-photo);
  transition: var(--tr-lift);
}
.rcard-img img, .rcard-media > .ph img { transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease); }
.rcard-badge { position: absolute; top: 10px; right: 10px; z-index: 1; transition: transform var(--dur-slow) var(--ease); }
/* Hover lift only where there is a real hover (a tap on a phone must not leave a card lifted). */
@media (hover: hover) {
  .rcard:hover .rcard-img, .rcard:hover .rcard-media > .ph { transform: translateY(-2px); box-shadow: var(--shadow-lift); }
  .rcard:hover .rcard-img img, .rcard:hover .rcard-media > .ph img { transform: scale(1.02); }
  .rcard:hover .rcard-badge { transform: translateY(-2px); }
}
.rcard:active .rcard-img, .rcard:active .rcard-media > .ph {
  transform: scale(.985); box-shadow: var(--shadow-photo); transition-duration: var(--dur-fast);
}
.rcard-badge .score { --fill: var(--surface); box-shadow: var(--shadow-float); }
.rcard-body { padding: var(--space-3) 2px 0; }
.rcard-title {
  font: var(--t-group); letter-spacing: 0; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; text-wrap: balance;
  overflow-wrap: anywhere;
}
.rcard-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 12px; margin-top: 6px;
  color: var(--muted); font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
}
.rcard-meta > span { display: inline-flex; align-items: center; gap: 4px; }
.rcard-meta .icon { opacity: .8; }

/* Photo + placeholder tile (ui.photoHtml). The size comes from the class passed in. */
.ph {
  --ph-h: 24;
  position: relative; overflow: hidden; isolation: isolate;
  display: grid; place-items: center; container-type: inline-size;
  aspect-ratio: 4 / 3;
  background:
    radial-gradient(120% 95% at 20% 8%, hsl(var(--ph-h) 60% var(--ph-glow) / var(--ph-glow-a)), transparent 60%),
    linear-gradient(155deg, hsl(var(--ph-h) var(--ph-sat) var(--ph-l1)), hsl(calc(var(--ph-h) + 10) var(--ph-sat) var(--ph-l2)));
  color: hsl(var(--ph-h) 40% var(--ph-ink) / .42);
}
/* A faint plate under the initial */
.ph::before {
  content: ""; grid-area: 1 / 1; width: 58cqi; aspect-ratio: 1; border-radius: 50%;
  border: 1px solid hsl(var(--ph-h) 40% var(--ph-ink) / .12);
}
.ph-letter {
  grid-area: 1 / 1; font: italic 400 clamp(14px, 22cqi, 96px)/var(--lh-none) var(--font-display);
  letter-spacing: var(--ls-display); transform: translateY(-3%); user-select: none;
}
.ph img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; max-width: none; object-fit: cover; }
/* A photo cross-fades over its tile once it has loaded (ui.js marks it .is-in; html.ph-fade turns the rule on). */
.ph > img { transition: opacity var(--dur-slow) var(--ease); }
.ph-fade .ph > img:not(.is-in) { opacity: 0; }
/* No title yet (editor and import preview): a quiet neutral tile instead of a coloured one with an initial. */
.ph.ph-blank { background: var(--surface-2); }
.ph.ph-blank::before { border-color: var(--line); }

.thumb { width: 52px; height: 52px; aspect-ratio: 1; flex: none; border-radius: var(--radius-field); overflow: hidden; object-fit: cover; }
.thumb.sm { width: 40px; height: 40px; border-radius: var(--radius-sm); }
.thumb.lg { width: 72px; height: 72px; border-radius: var(--radius-field); }

/* Shared photo pieces: a button sitting on a photo, and the veil while a photo is being processed. */
.btn-on-photo, .rp-photo-add, .imp-pv-photo-actions .btn, .log-photo-actions .btn {
  background: color-mix(in srgb, var(--surface) 88%, transparent); border-color: transparent;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); box-shadow: var(--shadow-float);
}
.btn-on-photo:hover, .rp-photo-add:hover, .imp-pv-photo-actions .btn:hover, .log-photo-actions .btn:hover { background: var(--surface); }
/* The paper fill in the ring's 2 px offset keeps the focus ring at 3:1 on a dark photo. */
.btn-on-photo:focus-visible, .rp-photo-add:focus-visible, .imp-pv-photo-actions .btn:focus-visible, .log-photo-actions .btn:focus-visible {
  box-shadow: var(--shadow-float), 0 0 0 2px var(--surface);
}
.photo-busy {
  position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; border-radius: inherit;
  background: color-mix(in srgb, var(--surface) 55%, transparent); color: var(--ink-2);
}
.photo-busy .spinner { width: var(--control-h-xs); height: var(--control-h-xs); } /* 24 px on a photo */

/* ============================================================== inputs == */
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field > label, .field-label, .field-head > label { font-size: var(--fs-xs); font-weight: 600; color: var(--ink-2); }
.field-head { display: flex; align-items: center; gap: 4px; min-height: 1.1rem; }
.field-hint { font-size: var(--fs-xs); color: var(--muted); }
.field-error { margin: 0; color: var(--danger); font-size: var(--fs-xs); line-height: var(--lh-ui); }
.field-row { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.field-row > .field { flex: 1 1 160px; }
/* Field widths shared by the editor and the import preview. */
.ed-f-num, .f-num { width: var(--field-w-num); }
.ed-f-unit, .f-unit { width: var(--field-w-unit); }
.ed-f-cuisine, .f-cuisine { width: var(--field-w-cuisine); }
.ed-f-lang .seg { height: var(--control-h); }
/* Field groups (editor ↔ importer): related fields wrap as one unit; a message wraps inside its field, never widens it. */
.facts { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-4) var(--space-5); }
.facts-group { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3); }
.facts > .field, .facts-group > .field { flex: none; }
.facts .field-error, .facts .field-hint { width: 0; min-width: 100%; }

.input, .select, .textarea {
  width: 100%; min-width: 0; height: var(--control-h); padding: 0 12px;
  border: 1px solid var(--line-strong); border-bottom-color: var(--field-line);
  border-radius: var(--radius-field); background: var(--surface); color: var(--ink);
  font-size: var(--fs-md);
  transition: var(--tr-tint);
}
.input:hover, .select:hover, .textarea:hover { border-color: color-mix(in srgb, var(--line-strong), var(--ink) 14%); border-bottom-color: var(--field-line); }
/* Focus: the one 2 px accent ring (offset 2) plus an accent edge, like every other control. */
.input:focus, .select:focus, .textarea:focus, .tags:has(.tags-input:focus) {
  outline: 2px solid var(--accent); outline-offset: 2px;
  border-color: color-mix(in srgb, var(--accent) 70%, var(--line-strong)); box-shadow: none;
}
.input:disabled, .select:disabled, .textarea:disabled {
  background: var(--surface-2); color: var(--ink-disabled); border-color: var(--line); border-bottom-color: var(--line-strong);
}
/* Invalid: a danger outline and the message under the field (ui.setFieldError). */
.input[aria-invalid="true"], .select[aria-invalid="true"], .textarea[aria-invalid="true"], .is-invalid > .input, .tags.is-invalid {
  border-color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger);
}
.input[aria-invalid="true"]:focus, .textarea[aria-invalid="true"]:focus, .is-invalid > .input:focus, .tags.is-invalid:has(.tags-input:focus) {
  border-color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger);
}
.input.lg { height: var(--control-h-lg); font-size: var(--fs-read); padding: 0 14px; border-radius: var(--radius); }
.input.title-input { height: auto; padding: 6px 10px; font: 400 var(--fs-h1)/var(--lh-tight) var(--font-display); letter-spacing: var(--ls-display); }
.input.num { text-align: right; }
.textarea { height: auto; min-height: var(--textarea-min); padding: 10px 12px; line-height: var(--lh-read); resize: vertical; }
.select {
  appearance: none; padding-right: 34px; cursor: pointer;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.input-group { position: relative; display: flex; align-items: center; }
.input-group > .icon { position: absolute; left: 12px; color: var(--muted); pointer-events: none; }
.input-group > .input { padding-left: 38px; }

/* ui.numberField: [ 25 ] min — the unit beside the value, never only a placeholder. */
.numfield { display: inline-flex; align-items: center; gap: var(--space-2); max-width: 100%; min-width: 0; }
.numfield > .input { width: var(--field-w-num); flex: none; font-family: var(--font-num); font-variant-numeric: tabular-nums; }
.field > .numfield > .input, .numfield.wide > .input { flex: 1 1 auto; width: auto; min-width: 3.5rem; }
.numfield-unit, .field-unit { color: var(--ink-2); font-size: var(--fs-sm); white-space: nowrap; }
/* After the generic field rules on purpose (same specificity, the later one wins): */
/* A time: the narrow number field with "min" beside it (editor and import preview). */
.ed-f-time .numfield > .input { flex: none; width: var(--field-w-num); }
/* The ingredient and method text boxes (editor and import preview). */
.ed-code { min-height: 220px; resize: none; overflow: hidden; font: 400 var(--fs-md)/var(--lh-read) var(--font-ui); tab-size: 2; }
.ed-steps { min-height: 200px; resize: none; overflow: hidden; font: 400 var(--fs-read)/var(--lh-read) var(--font-serif); }
.field-with-unit { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }

/* The inline recipe title (editor, import preview): reads as the page title until touched; it has an aria-label.
   Hover is a 1 px rule, focus a 2 px accent underline (no ring), invalid a 2 px danger underline (UI-STANDARD §14). */
.input.title-inline, .ed .title-input, .input.title-input.imp-pv-title {
  margin-left: 0; width: 100%; padding: 4px 0;
  border-color: transparent; border-radius: 0; background: transparent;
  font-size: var(--fs-h1); line-height: var(--lh-tight);
}
:is(.input.title-inline, .ed .title-input, .input.title-input.imp-pv-title):hover {
  border-color: transparent; box-shadow: inset 0 -1px 0 var(--line-strong);
}
:is(.input.title-inline, .ed .title-input, .input.title-input.imp-pv-title):focus {
  outline: none; background: transparent; border-color: transparent; box-shadow: inset 0 -2px 0 var(--accent);
}
:is(.input.title-inline, .ed .title-input, .input.title-input.imp-pv-title)[aria-invalid="true"] {
  border-color: transparent; box-shadow: inset 0 -2px 0 var(--danger);
}

/* The source line above a recipe title (recipe page, import preview). */
.rp-source, .source-line {
  display: inline-flex; align-items: center; gap: 5px; color: var(--accent-text); /* + .eyebrow */
}
span.rp-source, span.source-line { color: var(--muted); }
a.rp-source:hover, a.source-line:hover { text-decoration: underline; text-underline-offset: 3px; }

/* "Send to Recipe Book": the bookmarklet you drag to the favourites bar (importer, Settings). */
.bookmarklet, .set-bookmarklet {
  cursor: grab; border-style: dashed; border-color: color-mix(in srgb, var(--accent) 45%, var(--line-strong));
  color: var(--accent-text); background: var(--accent-soft); font-weight: 600;
}
.bookmarklet:hover, .set-bookmarklet:hover { background: color-mix(in srgb, var(--accent-soft), var(--accent) 8%); border-color: var(--accent); }
.bookmarklet:active, .set-bookmarklet:active { cursor: grabbing; }

/* The one done/ticked mark: a rounded square with a 2 px ring and a herb fill; the tick grows in on a real change
   (a transition, so a re-render that draws it ticked never replays it). */
input[type="checkbox"].check {
  appearance: none; width: 1.25rem; height: 1.25rem; flex: none; margin: 0; border-radius: var(--radius-xs); cursor: pointer;
  border: 2px solid var(--field-line); background: var(--surface) var(--check-tick) center / 0 no-repeat;
  display: inline-grid; place-items: center;
  transition: var(--tr-press), background-size var(--dur) var(--ease);
}
input[type="checkbox"].check:hover { border-color: var(--herb); }
input[type="checkbox"].check:active { transform: scale(var(--press-scale)); }
input[type="checkbox"].check:checked { border-color: var(--herb); background-color: var(--herb); background-size: 70%; }
input[type="checkbox"].check:disabled:not(:checked) { background-color: var(--surface-2); border-color: var(--line-strong); }
input[type="checkbox"].check:disabled:checked { background-color: var(--ink-disabled); border-color: transparent; }

/* tagInput */
.tags {
  position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  min-height: var(--control-h); padding: 6px; cursor: text;
  border: 1px solid var(--line-strong); border-bottom-color: var(--field-line);
  border-radius: var(--radius-field); background: var(--surface);
  transition: var(--tr-tint);
}
.tags-chips { display: contents; }
.chip-tag { height: var(--control-h-xs); padding: 0 10px; cursor: default; background: var(--surface-2); border-color: transparent; color: var(--ink); }
.tags-input { flex: 1 1 90px; min-width: 90px; height: var(--control-h-xs); border: 0; outline: 0; background: transparent; padding: 0 6px; font-size: var(--fs-md); }
.tags-suggest {
  position: absolute; left: -1px; right: -1px; top: calc(100% + 4px); z-index: 30;
  max-height: 260px; overflow: auto; padding: 5px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.tags-option { padding: 7px 10px; border-radius: var(--radius-sm); font-size: var(--fs-sm); cursor: pointer; color: var(--ink-2); transition: var(--tr-tint); }
.tags-option:hover { background: var(--hover); color: var(--ink); }
.tags-option:active { background: var(--press); }
/* The keyboard position in the list: an inset ring, not just a darker row. */
.tags-option.on { background: var(--surface-2); color: var(--ink); box-shadow: inset 0 0 0 2px var(--accent); }

/* stepper  − 4 +  */
.stepper { display: inline-flex; align-items: center; gap: 4px; }
.stepper-btn { border-radius: 50%; }
.stepper-value {
  min-width: 2.2ch; text-align: center;
  font: 600 var(--fs-read)/var(--lh-none) var(--font-num); font-variant-numeric: tabular-nums; color: var(--ink);
}
.stepper-label { margin-left: 4px; color: var(--muted); font-size: var(--fs-sm); }

/* segmented: as tall as a field; the chosen option is the raised --knob (ui.segmented may slide one knob between options) */
.seg {
  position: relative; display: inline-flex; align-items: center; gap: 2px; padding: 2px;
  background: var(--surface-2); border-radius: var(--radius-field); box-shadow: var(--ring-edge);
}
.seg button {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 6px; height: calc(var(--control-h) - 4px); padding: 0 12px;
  border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--ink-2);
  font-size: var(--fs-sm); font-weight: 500; white-space: nowrap;
  transition: var(--tr-tint);
}
.seg button:not(.on, [aria-checked="true"]):hover { background: var(--hover); color: var(--ink); }
.seg button:not(.on, [aria-checked="true"]):active { background: var(--press); }
.seg button.on, .seg button[aria-checked="true"] { background: var(--knob); color: var(--ink); box-shadow: var(--shadow-knob); }
.seg button:focus-visible { outline-offset: 0; }
/* The sliding knob (ui.segmented measures the chosen option; y and height too, so a wrapping group works). */
.seg-knob {
  position: absolute; left: 0; top: 0; width: var(--seg-w, 0); height: var(--seg-h, 0);
  transform: translate(var(--seg-x, 0), var(--seg-y, 0));
  border-radius: var(--radius-sm); background: var(--knob); box-shadow: var(--shadow-knob); pointer-events: none;
}
.seg:not(.has-knob) .seg-knob { display: none; }
.seg.is-ready .seg-knob { transition: transform var(--dur-slow) var(--ease), width var(--dur-slow) var(--ease); }
.seg.has-knob button:is(.on, [aria-checked="true"]) { background: transparent; box-shadow: none; }

/* Help: a small "?" after a label opens a short popover (ui.help); the app bar's "?" opens the help sheet. */
.help-btn {
  position: relative; isolation: isolate; display: inline-grid; place-items: center; flex: none;
  width: 24px; height: 24px; margin: -4px 0; padding: 0; vertical-align: middle;
  border: 0; border-radius: 50%; background: transparent; color: var(--ink-2);
  font: 600 var(--fs-2xs)/var(--lh-none) var(--font-ui); letter-spacing: 0; /* never tracked, even inside a title */
}
.help-btn::before {
  content: ""; position: absolute; inset: 3px; z-index: -1; border-radius: 50%;
  border: 1px solid var(--field-line); transition: var(--tr-tint);
}
.help-btn { transition: transform var(--dur-fast) var(--ease); }
.help-btn:hover::before { background: var(--hover); border-color: var(--ink-2); }
.help-btn:active { transform: scale(var(--press-scale)); }
.help-btn[aria-expanded="true"] { color: var(--accent-text); }
.help-btn[aria-expanded="true"]::before { border-color: var(--accent); background: var(--accent-soft); }
.help-btn:focus-visible { outline-offset: 0; border-radius: 50%; }
.help-pop {
  position: fixed; inset: auto; margin: 0; z-index: 120;
  width: max-content; max-width: min(320px, calc(100vw - 16px)); padding: var(--space-3) var(--space-4);
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); font-size: var(--fs-sm); line-height: var(--lh-body); text-align: left; white-space: normal;
}
.help-pop p + p { margin-top: .5em; }
.help-sheet { width: min(var(--dialog-w-form), calc(100vw - 32px)); }
.help-sheet-body { display: flex; flex-direction: column; gap: 20px; }
.help-sec { display: flex; flex-direction: column; gap: 12px; }
.help-sec-title { margin-bottom: -4px; }
.help-q { font: var(--t-label); color: var(--ink); }
.help-a { margin-top: 2px; color: var(--ink-2); font-size: var(--fs-sm); line-height: var(--lh-body); }
.help-keys { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 14px; margin: 0; align-items: center; }
.help-keys dt { margin: 0; }
.help-keys dd { margin: 0; color: var(--ink-2); font-size: var(--fs-sm); }

/* ======================================================== badges/score == */
.badge {
  display: inline-flex; align-items: center; gap: 4px; height: var(--control-h-xs); padding: 0 8px;
  border-radius: var(--radius-pill); background: var(--surface-2); color: var(--ink-2);
  font-size: var(--fs-xs); font-weight: 600; line-height: var(--lh-none); letter-spacing: 0; white-space: nowrap; vertical-align: middle;
}
.badge-accent { background: var(--accent-soft); color: var(--accent-text); }
.badge-herb { background: color-mix(in srgb, var(--herb) 15%, transparent); color: color-mix(in srgb, var(--herb) 80%, var(--ink)); }
.badge-saffron { background: color-mix(in srgb, var(--saffron) 18%, transparent); color: color-mix(in srgb, var(--saffron) 55%, var(--ink)); }
.badge-outline { background: transparent; box-shadow: var(--ring-edge); }

/* Score: a ring that fills to score/10, in the colour of its tier; the digits stay ≥ 4.5:1.
   Three sizes in rem (they follow Text size); the digits are a type step, never computed from the size:
   .score.sm 1.625rem / --fs-xs · .score 2rem / --fs-sm · .score.lg 2.5rem / --fs-md. */
.score {
  --c: var(--muted);
  --size: 2rem;
  --fill: color-mix(in srgb, var(--c) 9%, var(--surface));
  --ring: max(2px, calc(var(--size) * .075));
  display: inline-grid; place-items: center; flex: none;
  width: var(--size); height: var(--size); border-radius: 50%;
  font: 600 var(--fs-sm)/var(--lh-none) var(--font-num); font-variant-numeric: tabular-nums; letter-spacing: 0;
  color: color-mix(in srgb, var(--c) 62%, var(--ink));
  background:
    radial-gradient(closest-side, var(--fill) calc(100% - var(--ring)), transparent calc(100% - var(--ring) + .5px)),
    conic-gradient(var(--c) calc(var(--p, 0) * 1%), color-mix(in srgb, var(--c) 20%, transparent) 0);
}
.score-top { --c: var(--herb); }
.score-good { --c: var(--olive); }
.score-ok { --c: var(--tier-ok); }
.score-low { --c: var(--terracotta); }
.score-none { --c: var(--muted); font-weight: 400; }
.score.sm { --size: 1.625rem; font-size: var(--fs-xs); }
.score.lg { --size: 2.5rem; font-size: var(--fs-md); }

.meter { height: 6px; border-radius: var(--radius-pill); background: var(--surface-2); overflow: hidden; }
/* The bar grows once to its true length when it is first drawn; the number beside it never animates. */
.meter > span {
  display: block; height: 100%; width: calc(var(--v, 0) * 1%); border-radius: inherit; background: var(--accent);
  transform-origin: left; transition: transform var(--dur-page) var(--ease);
}
@starting-style { .meter > span { transform: scaleX(0); } }
.meter-herb > span { background: var(--herb); }

.kbd {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 5px;
  border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: var(--radius-xs);
  background: var(--surface); color: var(--ink-2);
  font: 600 var(--fs-2xs)/var(--lh-none) var(--font-num); letter-spacing: 0;
}

/* The 1–10 score row (log dialog, cook mode's done screen): ten round picks and the word for the chosen one. */
.score-row { display: flex; align-items: center; gap: 10px 16px; flex-wrap: wrap; }
.score-row-btns {
  display: grid; grid-template-columns: repeat(10, minmax(0, 1fr)); gap: 6px;
  flex: 1 1 auto; min-width: 0;
}
.score-pick {
  --c: var(--muted);
  display: grid; place-items: center; aspect-ratio: 1; width: 100%; min-width: 0; padding: 0;
  border: 1px solid var(--field-line); border-radius: 50%;
  background: var(--surface); color: var(--ink-2);
  font: 600 var(--fs-md)/var(--lh-none) var(--font-num); font-variant-numeric: tabular-nums;
  transition: var(--tr-press);
}
.score-pick.tier-top { --c: var(--herb); }
.score-pick.tier-good { --c: var(--olive); }
.score-pick.tier-ok { --c: var(--tier-ok); }
.score-pick.tier-low { --c: var(--terracotta); }
.score-pick:hover {
  border-color: var(--c);
  background: color-mix(in srgb, var(--c) 9%, var(--surface));
  color: color-mix(in srgb, var(--c) 62%, var(--ink));
}
.score-pick:active { transform: scale(var(--press-scale)); }
.score-pick.on {
  border-color: transparent;
  background: color-mix(in srgb, var(--c) 17%, var(--surface));
  box-shadow: inset 0 0 0 2.5px var(--c);
  color: color-mix(in srgb, var(--c) 62%, var(--ink));
  transform: scale(1.08);
}
.score-pick:focus-visible { outline-offset: 3px; border-radius: 50%; }
.score-row-btns.has-value .score-pick:not(.on):not(:hover) { color: var(--muted); }
.score-row-word { min-width: 5.5em; font: italic 400 var(--fs-read)/var(--lh-snug) var(--font-serif); color: var(--ink-2); }
.score-row-word:empty { visibility: hidden; }
.score-row-word.is-new { animation: rb-fade-in var(--dur) var(--ease); }
.score-row-lg .score-row-btns { gap: clamp(6px, 1vw, 12px); }
.score-row-lg .score-pick { font-size: var(--fs-cook-md); }
.score-row-lg .score-pick.on { box-shadow: inset 0 0 0 3px var(--c); }

/* ======================================================= tabs & lists == */
.tabs { display: flex; gap: var(--space-5); border-bottom: 1px solid var(--line); overflow-x: auto; scrollbar-width: none; }
.tabs > button, .tabs > a {
  position: relative; display: inline-flex; align-items: center; gap: 6px; height: var(--control-h); padding: 0 1px;
  border: 0; background: none; color: var(--muted); font-size: var(--fs-sm); font-weight: 500; white-space: nowrap;
  transition: var(--tr-tint);
}
.tabs > button::after, .tabs > a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; border-radius: var(--radius-pill);
  background: var(--accent); transform: scaleX(0); transition: transform var(--dur-slow) var(--ease);
}
.tabs > :hover { color: var(--ink); }
.tabs > .on, .tabs > [aria-selected="true"], .tabs > [aria-current="page"] { color: var(--ink); }
.tabs > .on::after, .tabs > [aria-selected="true"]::after, .tabs > [aria-current="page"]::after { transform: scaleX(1); }

.list { list-style: none; margin: 0; padding: 0; }
.list > li, .list-item {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 11px 2px; border-bottom: 1px solid var(--line-soft);
}
.list > li:last-child, .list-item:last-child { border-bottom: 0; }
a.list-item, button.list-item, .list-item.clickable {
  width: 100%; border-left: 0; border-right: 0; border-top: 0; background: none; text-align: left; color: inherit;
  margin: 0 -8px; padding-left: 10px; padding-right: 10px; width: calc(100% + 16px); border-radius: var(--radius-field);
  transition: var(--tr-tint);
}
a.list-item:hover, button.list-item:hover, .list-item.clickable:hover { background: var(--hover); }
a.list-item:active, button.list-item:active, .list-item.clickable:active { background: var(--press); }
.list-main { flex: 1 1 auto; min-width: 0; }
.list-title { font-weight: 500; color: var(--ink); }
.list-sub { font-size: var(--fs-xs); color: var(--muted); }

/* ===================================== day chips & the recipe picker == */
/* Shared by the planner, the recipe page and Stats ("Add to plan", "Move to…", the day's "+" picker). */
.atp { display: flex; flex-direction: column; gap: 18px; }
.atp-head { display: flex; align-items: center; gap: 14px; min-width: 0; }
.atp-head .thumb { width: 56px; height: 56px; border-radius: var(--radius-field); }
.atp-head-text { min-width: 0; }
.atp-title { font: var(--t-group); letter-spacing: 0; color: var(--ink); }
.atp-meta { font-size: var(--fs-xs); color: var(--muted); }
.atp .stepper { margin-left: -6px; }

.daychips { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.daychip {
  display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; padding: 8px 2px 7px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); color: var(--ink-2);
  transition: var(--tr-press);
}
.daychip:hover { border-color: var(--line-strong); background: var(--surface-hover); }
.daychip:active:not(:disabled) { transform: translateY(var(--press-y)); }
.daychip:disabled { background: var(--surface-2); border-color: transparent; cursor: default; }
.daychip:disabled :is(.daychip-dow, .daychip-num, .daychip-num small) { color: var(--ink-disabled); }
.daychip-dow { font: 600 var(--fs-2xs)/var(--lh-none) var(--font-ui); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--muted); }
.daychip-num { font: 400 var(--fs-h3)/var(--lh-none) var(--font-serif); color: var(--ink); white-space: nowrap; }
.daychip-num small { font: 500 var(--fs-xs)/var(--lh-none) var(--font-ui); color: var(--muted); }
.daychip-dots { display: flex; gap: 3px; height: 5px; }
.daychip-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--saffron); }
.daychip.is-past .daychip-num { color: var(--muted); }
.daychip.is-today:not(.on) { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.daychip.is-today .daychip-dow { color: var(--accent-text); }
.daychip.on { background: var(--accent); border-color: transparent; }
.daychip.on .daychip-dow, .daychip.on .daychip-num, .daychip.on .daychip-num small { color: var(--accent-ink); }
.daychip.on .daychip-dots i { background: color-mix(in srgb, var(--accent-ink) 75%, transparent); }
/* The meal's own day in "Move to…" is selected but can't be picked: the flat disabled chip with an accent outline. */
.daychip.on:disabled { background: var(--surface-2); border-color: var(--accent); }
.daychip.on:disabled :is(.daychip-dow, .daychip-num, .daychip-num small) { color: var(--ink-disabled); }
.daychip.on:disabled .daychip-dots i { background: var(--saffron); }

.pick-dialog { width: min(var(--dialog-w-form), calc(100vw - 32px)); }
.pick { display: flex; flex-direction: column; gap: 10px; }
.pick-results { max-height: min(54vh, 500px); overflow: auto; margin: 0 -12px; padding: 0 12px 4px; overscroll-behavior: contain; }
.pick-group + .pick-group { margin-top: 12px; }
.pick-label { padding: 8px 0 6px; } /* + .eyebrow */
.pick-label-row {
  position: sticky; top: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: var(--surface);
}
.pick-row {
  display: flex; align-items: center; gap: 12px; width: calc(100% + 16px); margin: 0 -8px; padding: 7px 8px;
  border: 0; border-radius: var(--radius-field); background: none; color: inherit; text-align: left;
  transition: var(--tr-tint);
}
.pick-row:hover { background: var(--hover); }
.pick-row:focus-visible { background: var(--surface-2); }
.pick-row:active { background: var(--press); }
/* Inset ring: the scrolling results box would clip an outer one on the first and last row. */
.pick-row:focus-visible { outline-offset: -2px; }
.pick-row .thumb { width: 44px; height: 44px; border-radius: var(--radius-field); }
.pick-main { display: flex; flex-direction: column; gap: 3px; flex: 1 1 auto; min-width: 0; }
.pick-name { font: var(--t-item); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-meta { font-size: var(--fs-xs); color: var(--muted); }
.pick-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.pick-chips .chip { height: var(--control-h-xs); padding: 0 8px; font-size: var(--fs-xs); cursor: inherit; background: var(--surface-2); border-color: transparent; color: var(--ink-2); }
.pick-row:hover .pick-chips .chip { background: var(--surface); }
.pick-more { padding: 8px 0; font-size: var(--fs-xs); color: var(--muted); }
.pick-note-icon { display: grid; place-items: center; width: 44px; flex: none; color: var(--muted); }
.pick-as-note .pick-name { font-style: italic; }
.pick-reason { overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.pick-empty .pick-name { font-family: var(--font-ui); font-size: var(--fs-md); color: var(--ink-2); }
.pick-empty-add { color: var(--accent-text); font-weight: 600; }
.pick-empty:hover .pick-empty-add { text-decoration: underline; text-underline-offset: 3px; }
.pick-other { display: flex; align-items: center; gap: 10px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.pick-other .input { flex: 1 1 auto; }

/* ====================================== parsed-ingredient preview == */
/* Shared by the editor and the import preview: amount · unit · name · note, lined up in one grid. */
.ed-pv-empty { color: var(--muted); font-size: var(--fs-sm); padding: 6px 2px; }
.ed-pv-head {
  display: flex; justify-content: space-between; gap: 10px; margin-bottom: 6px; /* + .eyebrow */
}
.ed-pv-unknown-n { display: inline-flex; align-items: center; gap: 2px; color: color-mix(in srgb, var(--saffron) 55%, var(--ink)); }
.ed-pv-grid {
  display: grid; column-gap: 10px; font-size: var(--fs-sm); line-height: var(--lh-ui);
  grid-template-columns: minmax(1.6em, max-content) minmax(0, max-content) minmax(0, 1fr) minmax(0, .85fr);
}
.ed-pv-row {
  display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: baseline;
  padding: 5px 0; border-bottom: 1px solid var(--line-soft);
}
.ed-pv-row:last-child { border-bottom: 0; }
.ed-pv-q { text-align: right; font: 600 var(--fs-sm)/var(--lh-ui) var(--font-num); font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }
.ed-pv-u { color: var(--ink-2); white-space: nowrap; }
.ed-pv-n { color: var(--ink); min-width: 0; }
.ed-pv-o { color: var(--muted); min-width: 0; font-size: var(--fs-xs); }
.ed-pv-row.ed-pv-unknown .ed-pv-n {
  text-decoration: underline dotted; text-decoration-color: color-mix(in srgb, var(--saffron) 80%, transparent);
  text-decoration-thickness: 1.5px; text-underline-offset: 3px;
}
.ed-pv-group {
  grid-column: 1 / -1; margin: 10px 0 2px; color: var(--accent-text); /* + .eyebrow */
}
.ed-pv-group:first-child { margin-top: 2px; }

/* ========================================================= empty state == */
.empty {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px;
  padding: 64px 16px; color: var(--muted);
}
.empty-icon {
  width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center; margin-bottom: 6px;
  background: var(--surface-2); color: var(--accent-text);
  box-shadow: var(--ring-well), 0 0 0 8px color-mix(in srgb, var(--surface-2) 45%, transparent);
}
.empty-title { color: var(--ink); } /* font: the section role (h2 rule above) */
.empty p { max-width: 38ch; font-size: var(--fs-sm); text-wrap: balance; }
.empty-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 10px; }
.empty.compact { padding: 28px 12px; }

/* ============================================================ dialogs == */
/* Enter at --dur-slow, leave faster (--dur-fast, --ease-in). close() closes the <dialog> at once (focus returns in
   the same task); the overlay/display allow-discrete transitions keep the closed, inert dialog drawn while it fades. */
.dialog {
  width: min(var(--dialog-w), calc(100vw - 32px)); max-height: min(88vh, 900px);
  padding: 0; border: 0; border-radius: var(--radius-dialog);
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow-lg);
  overflow: hidden; flex-direction: column;
  opacity: 1; transform: none;
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease),
    overlay var(--dur-slow) var(--ease) allow-discrete, display var(--dur-slow) var(--ease) allow-discrete;
}
.dialog[open] { display: flex; }
.dialog-form { width: min(var(--dialog-w-form), calc(100vw - 32px)); }
.dialog-wide { width: min(var(--dialog-w-wide), calc(100vw - 32px)); }
@starting-style { .dialog[open] { opacity: 0; transform: translateY(8px) scale(.985); } }
.dialog.closing {
  opacity: 0; transform: translateY(4px) scale(.99);
  transition-duration: var(--dur-fast); transition-timing-function: var(--ease-in);
}
.dialog::backdrop {
  background: var(--backdrop);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  transition: opacity var(--dur-slow) var(--ease),
    overlay var(--dur-slow) var(--ease) allow-discrete, display var(--dur-slow) var(--ease) allow-discrete;
}
@starting-style { .dialog[open]::backdrop { opacity: 0; } }
.dialog.closing::backdrop { opacity: 0; transition-duration: var(--dur-fast); transition-timing-function: var(--ease-in); }
/* One horizontal inset for head, body and foot. */
.dialog-head { display: flex; align-items: flex-start; gap: 12px; padding: var(--space-5) var(--space-4) var(--space-1) var(--space-5); flex: none; }
.dialog-head-bare { position: absolute; top: 0; right: 0; padding: 12px; z-index: 1; }
.dialog-title { flex: 1; min-width: 0; padding-top: 3px; } /* font: the section role (h2 rule above) */
.dialog-x { margin-top: -2px; color: var(--muted); }
.dialog-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: var(--space-2) var(--space-5) var(--space-5); }
.dialog-head-bare + .dialog-body { padding-top: var(--space-5); }
.dialog-msg { font-size: var(--fs-md); color: var(--ink-2); padding-right: var(--space-5); }
.dialog-foot {
  display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; flex: none;
  padding: var(--space-4) var(--space-5); border-top: 1px solid var(--line-soft); background: color-mix(in srgb, var(--surface-2) 35%, var(--surface));
}

/* ============================================================== toasts == */
.toasts {
  position: fixed; inset: auto 0 22px 0; margin: 0 auto; padding: 0; border: 0; background: none; overflow: visible;
  width: max-content; max-width: calc(100vw - 32px);
  flex-direction: column; align-items: center; gap: 8px; pointer-events: none;
}
.toasts:popover-open, .toasts:not([popover]) { display: flex; }
.toast {
  display: flex; align-items: center; gap: 14px; max-width: 520px;
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4); min-height: 40px; border-radius: var(--radius);
  background: var(--toast-bg); color: var(--toast-ink); box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm); line-height: var(--lh-ui); pointer-events: auto;
  opacity: 0; transform: translateY(10px) scale(.98);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
.toast:not(:has(.toast-action)) { padding-right: var(--space-4); }
.toast.in { opacity: 1; transform: none; }
.toast.out { opacity: 0; transform: translateY(6px); transition-duration: var(--dur-fast); transition-timing-function: var(--ease-in); }
.toast-action {
  flex: none; height: var(--control-h-sm); padding: 0 10px; border: 0; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--toast-ink) 12%, transparent); color: var(--toast-ink);
  font-size: var(--fs-sm); font-weight: 600;
  transition: var(--tr-tint);
}
.toast-action:hover { background: color-mix(in srgb, var(--toast-ink) 20%, transparent); }
.toast-action:active { background: color-mix(in srgb, var(--toast-ink) 26%, transparent); }
/* On the dark (or, in dark palettes, light) toast the accent ring would be too faint. */
.toast-action:focus-visible { outline-color: var(--toast-ink); }

/* =============================================================== menus == */
.menu {
  position: fixed; inset: auto; margin: 0; z-index: 100;
  min-width: 190px; max-width: 300px; padding: 5px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  max-height: calc(100vh - 16px); overflow-y: auto; overscroll-behavior: contain;
}
/* Menus and help popovers grow from their anchor side (ui.js sets data-side / data-align) and close instantly. */
.menu, .help-pop { animation: rb-pop var(--dur-fast) var(--ease); transform-origin: top left; }
.menu[data-align="end"] { transform-origin: top right; }
.menu[data-side="top"], .help-pop[data-side="top"] { animation-name: rb-pop-up; transform-origin: bottom left; }
.menu[data-side="top"][data-align="end"] { transform-origin: bottom right; }
.menu hr { margin: 5px 6px; border-top-color: var(--line-soft); }
.menu-item {
  display: flex; align-items: center; gap: 10px; width: 100%; height: var(--control-h-sm); padding: 0 10px;
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--ink-2); text-align: left;
  font-size: var(--fs-sm); white-space: nowrap;
  transition: var(--tr-tint);
}
.menu-item .icon { color: var(--muted); }
.menu-noicon { width: 16px; flex: none; }
.menu-item:hover { background: var(--hover); color: var(--ink); }
.menu-item:active { background: var(--press); }
/* A visible ring (inset: the menu scrolls), not just a slightly darker row. */
.menu-item:focus-visible { background: var(--surface-2); color: var(--ink); outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--radius-sm); }
.menu-item.checked, .menu-item[aria-checked="true"] { color: var(--ink); font-weight: 600; }
.menu-item.checked .icon, .menu-item[aria-checked="true"] .icon { color: var(--accent-text); }
.menu-item.danger, .menu-item.danger .icon { color: var(--danger); }
.menu-item:disabled, .menu-item:disabled .icon { color: var(--ink-disabled); }

/* ================================================================ boot == */
.boot { position: fixed; inset: 0; display: grid; place-items: center; padding: 24px; z-index: 10; pointer-events: none; }
.boot:empty { display: none; }
.boot-card { max-width: 440px; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; pointer-events: auto; }
.boot-mark {
  width: 64px; height: 64px; border-radius: 50%; display: grid; place-items: center; margin-bottom: 8px;
  background: var(--surface); color: var(--accent); box-shadow: var(--shadow), var(--ring-well);
}
.boot-loading .boot-mark { animation: rb-breathe 1.8s var(--ease) infinite; }
.boot-title { font: 400 var(--fs-h1)/var(--lh-tight) var(--font-display); letter-spacing: var(--ls-display); }
.boot-text { color: var(--ink-2); font-size: var(--fs-md); }
.boot-retry { display: flex; align-items: center; gap: 10px; margin-top: 14px; color: var(--muted); font-size: var(--fs-sm); }
.boot-pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--saffron); animation: rb-pulse 1.4s var(--ease) infinite; }

/* ======================================================= small helpers == */
.spin { animation: rb-spin .9s linear infinite; }
/* The shared busy mark (a pressed button shows it in place of its icon; see .btn.busy). */
.spinner {
  display: inline-block; flex: none; width: 1rem; height: 1rem; border-radius: 50%;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent); border-top-color: currentColor;
  animation: rb-spin .9s linear infinite;
}
/* A row on its way to a new place (ui.flip): above its neighbours, on its own paper. */
.is-moving { position: relative; z-index: 1; background: var(--surface); box-shadow: var(--shadow); border-radius: var(--radius-sm); }
/* The slim lasting-note row (list "Sent to phone", cookbook Today): page content, not a bar. */
.strip {
  display: flex; align-items: center; gap: var(--space-3); min-height: var(--row-min);
  padding: 6px 6px 6px var(--space-3); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--ring-line);
  font-size: var(--fs-sm); color: var(--ink-2);
}

/* Save state: "Saving…" fades in once; "Saved" settles with a bump, then fades out (main.js adds .is-leaving). */
.save-state:not([hidden]) { animation: rb-fade-in var(--dur) var(--ease) backwards; }
.save-state.is-leaving { opacity: 0; transition: opacity var(--dur-slow) var(--ease-in); }
.save-state[data-state="saved"] .save-dot, .nav-badge.bump { animation: rb-bump var(--dur-slow) var(--ease); }

/* ---- Motion vocabulary (UI-STANDARD §10): feedback or orientation only, transform and opacity only. ---- */
/* A route brings its content in with a short rise (router.js sets data-enter once per navigation); the toolbar never moves.
   Fill mode backwards only: a kept transform would break fixed and sticky elements inside. */
.view[data-enter]:not(.cook) > :not(.toolbar) { animation: rb-rise var(--dur-page) var(--ease) backwards; }
.view[data-enter="next"]:not(.cook) > :not(.toolbar) { animation-name: rb-turn-next; }
.view[data-enter="prev"]:not(.cook) > :not(.toolbar) { animation-name: rb-turn-prev; }
/* Changing the palette cross-fades the page (ui.morph → View Transition). */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--dur-slow); animation-timing-function: var(--ease); }

@keyframes rb-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.8); } }
@keyframes rb-breathe { 0%, 100% { transform: scale(1); opacity: .9; } 50% { transform: scale(.94); opacity: .55; } }
@keyframes rb-spin { to { transform: rotate(360deg); } }
@keyframes rb-pop { from { opacity: 0; transform: translateY(-4px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes rb-pop-up { from { opacity: 0; transform: translateY(4px) scale(.98); } }
@keyframes rb-rise { from { opacity: 0; transform: translateY(6px); } }
@keyframes rb-turn-next { from { opacity: 0; transform: translateX(24px); } }
@keyframes rb-turn-prev { from { opacity: 0; transform: translateX(-24px); } }
@keyframes rb-pop-in { from { opacity: 0; transform: scale(.9); } }
@keyframes rb-tick { 0% { transform: scale(.8); } 60% { transform: scale(1.1); } 100% { transform: none; } }
@keyframes rb-draw { from { stroke-dashoffset: 20; } to { stroke-dashoffset: 0; } }
@keyframes rb-value { from { opacity: .35; transform: translateY(-3px); } }
@keyframes rb-fade-in { from { opacity: 0; } }
@keyframes rb-bump { 40% { transform: scale(1.25); } }

/* ========================================================== responsive == */
@media (max-width: 920px) {
  .nav-link .icon { display: inline-block; }
  /* Icons only, but the words stay the links' accessible names ("List 2 meals to shop for"). */
  .nav-link .nav-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .nav-link { padding: 0 10px; gap: 4px; }
  .nav-link::after { left: 8px; right: 8px; }
  .wordmark { margin-right: 8px; }
  .search { flex-basis: 200px; }
  .search:focus-within { flex-basis: 260px; }
  .split { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 640px) {
  :root { --page-pad: 16px; --page-top: 16px; }
  /* Phone width never lowers a text size: body stays --fs-md; a title may take a smaller token. */
  .topbar-inner { padding: 0 12px; gap: 2px; }
  /* The ribbon keeps a 44 px target when the words hide. */
  .wordmark { margin-right: 4px; min-width: 44px; justify-content: center; }
  .wordmark-text { display: none; }
  /* Icons follow Text size: tighter links keep the bar on one line at Large and Larger (targets stay ≥ 24 × 48). */
  .nav-link { padding: 0 5px; }
  .nav-badge { position: absolute; top: 6px; right: 1px; min-width: 1rem; height: 1rem; padding: 0 4px; }
  .search { flex: 1 1 auto; margin-left: 4px; }
  .search:focus-within { flex-basis: auto; }
  .search input { padding-left: 30px; }
  .search .icon { left: 9px; }
  .save-state { margin: 0 2px; }
  .topbar-add { width: var(--control-h-sm); padding: 0; margin-left: 4px; }
  .topbar-add-label { display: none; }
  .topbar-add > .icon:first-child:not(:only-child) { margin: 0; }
  .grid { --min: 150px; --gap: 22px 14px; }
  .rcard-title { font-size: var(--fs-read); }
  .dialog-head { padding: var(--space-4) var(--space-3) var(--space-1) var(--space-4); }
  .dialog-body { padding: var(--space-2) var(--space-4) var(--space-4); }
  .dialog-foot { padding: var(--space-3) var(--space-4) var(--space-4); }
  .empty { padding: 44px 12px; }
  .ed-f-num, .f-num { width: calc(33% - 7px); min-width: 74px; }
  .ed-f-unit, .f-unit { width: calc(66% - 3px); }
  .ed-f-cuisine, .f-cuisine { width: 100%; }
  .daychips { gap: 4px; }
  .daychip { padding: 7px 0 6px; border-radius: var(--radius-field); }
  .daychip-num { font-size: var(--fs-read); }
  .ed-pv-grid { grid-template-columns: minmax(1.6em, max-content) minmax(0, max-content) minmax(0, 1fr); }
  .ed-pv-o { grid-column: 3; }
}

@media (max-width: 520px) {
  .score-row-btns { grid-template-columns: repeat(5, minmax(0, 1fr)); max-width: 320px; }
  .score-pick { font-size: var(--fs-read); }
}

@media (max-width: 400px) {
  .nav-link { padding: 0 4px; }
  .topbar-settings, .topbar-help { width: 30px; }
}

/* Touch screens: primary controls get a 44 px target. */
@media (pointer: coarse) {
  .btn-sm, .btn-icon { min-height: var(--touch); }
  .btn-icon, .btn-icon.btn-sm { min-width: var(--touch); }
  .stepper-btn { width: var(--touch); height: var(--touch); }
  .menu-item { height: var(--touch); }
  .tags-option { padding-block: 11px; }
  .help-btn { width: 32px; height: 32px; margin: -8px -4px; }
  .chip-x { width: 32px; height: 32px; margin: -7px -13px -7px -7px; }
  .seg button { min-height: calc(var(--touch) - 4px); }
  .topbar-add { min-width: var(--touch); }
}

/* ===================================================== motion & print == */
/* Off switches: the system setting, and data-motion="off" on <html> (tests). JS animations check ui.motionOk(). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
:root[data-motion="off"] *, :root[data-motion="off"] *::before, :root[data-motion="off"] *::after {
  animation-duration: .01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important;
  transition-duration: .01ms !important; scroll-behavior: auto !important;
}
:root[data-motion="off"]::view-transition-group(*), :root[data-motion="off"]::view-transition-old(*),
:root[data-motion="off"]::view-transition-new(*) { animation: none !important; }

/* Windows contrast themes: system colours; a state is never shown by colour or transparency alone,
   and only ticked boxes show a tick. */
@media (forced-colors: active) {
  :focus-visible { outline: 2px solid Highlight; }
  [aria-pressed="true"], [aria-checked="true"], [aria-selected="true"]:not([role="tab"]), .chip.on, .daychip.on,
  .score-pick.on, .seg button.on, .tags-option.on, .menu-item.checked, .meal-shop.on, .sect-opt.on {
    outline: 2px solid Highlight; outline-offset: -2px;
  }
  .nav-link[aria-current="page"]::after, .tabs > .on::after, .tabs > [aria-selected="true"]::after, .tabs > [aria-current="page"]::after,
  :is(.topbar-add, .topbar-settings)[aria-current="page"]::after {
    forced-color-adjust: none; background: Highlight;
  }
  input[type="checkbox"].check { appearance: auto; width: 18px; height: 18px; background: none; border: 0; }
  .save-dot, .banner-mark { forced-color-adjust: none; background: CanvasText; box-shadow: none; }
  .save-state[data-state="offline"] .save-dot, .banner[data-kind="stopped"] .banner-mark { background: Canvas; box-shadow: inset 0 0 0 2px CanvasText; }
  .score { forced-color-adjust: none; background: Canvas; color: CanvasText; box-shadow: inset 0 0 0 2px CanvasText; }
  .toast, .menu, .help-pop, .dialog { border: 1px solid CanvasText; }
  .help-btn::before { border-color: ButtonText; }
  .btn:is(:disabled, [aria-disabled="true"]):not(.busy, [aria-busy="true"], .dialog.closing .btn) { color: GrayText; opacity: 1; }
  .input:disabled, .menu-item:disabled, .daychip:disabled { color: GrayText; }
  /* The inline title's underline is a box-shadow, which forced colours drop: a system ring instead. */
  :is(.input.title-inline, .ed .title-input, .input.title-input.imp-pv-title):focus { outline: 2px solid Highlight; outline-offset: 2px; }
  .seg-knob { display: none; }
  .spinner, .btn:is(.busy, [aria-busy="true"])::before { forced-color-adjust: none; border-color: Canvas; border-top-color: CanvasText; }
  .ph::before, .ph-letter { forced-color-adjust: auto; }
  .ph > img { opacity: 1 !important; }
}

@media print {
  /* Paper is always light: these selectors match (and so beat) every palette block above. */
  :root, :root[data-theme], :root:not([data-theme]) {
    --bg: #fff; --surface: #fff; --surface-2: #f4f4f4; --ink: #000; --ink-2: #222; --muted: #555;
    --line: #ccc; --line-soft: #ddd; --line-strong: #bbb; --field-line: #888;
    --accent: #B5461F; --accent-hover: #9C3A17; --accent-text: #A23F1B; --accent-soft: #F6DED2; --accent-ink: #FFFFFF; --herb: #3E7B4F;
    --olive: #7A8A2B; --saffron: #C9901C; --terracotta: #B2735C; --danger: #B3261E; --danger-ink: #FFFFFF; --tier-ok: #A87513;
    --chart-1: #B5461F; --chart-2: #3A6EA5; --chart-3: #C9901C; --chart-4: #8E4F8F; --chart-5: #2E8B57;
    --shadow: none; --shadow-photo: none; --shadow-lift: none; --shadow-lg: none; --shadow-float: none; --shadow-knob: none; --grain: none;
    --knob: var(--surface);
    color-scheme: light;
  }
  html, body { background: #fff !important; }
  body { font-size: 11pt; color: var(--ink); }
  .topbar, .toolbar, .toasts, .menu, .boot, .no-print, .btn, .seg, .stepper-btn, .help-btn, .help-pop, .skip-link, .save-state, dialog { display: none !important; }
  .page, .page-narrow { max-width: none; padding: 0; }
  .card { box-shadow: none; border-color: #ccc; break-inside: avoid; }
  .list > li, .list-item { break-inside: avoid; }
  a { text-decoration: none; }
  .ph::before, .ph-letter { display: none; }
  .ph > img { opacity: 1 !important; }
  ::placeholder { color: transparent; }
  .clamp-2, .rcard-title { display: block; -webkit-line-clamp: unset; overflow: visible; }
}
