/*
  P6 stylesheet — Organic retheme, v0.5.0.

  Two halves. The retheme from the design handback comes first: tokens, base
  type, shell, trip navigation, panels, the list row, forms, sheets and the
  utilities. Everything the retheme does not restyle follows it, carried over
  from v0.4.0 — the threshold dial, chip filters, notices, sort bar, meters,
  flashes, the meals tables, the item detail page, the food sub-tabs, and the
  utility classes the mechanical pass introduced that organic's shorter set
  does not cover.

  One file rather than two stylesheets. Two would mean every future change
  beginning with "which sheet wins", which is the same problem the mechanical
  pass just removed from the templates.

  The carry-over was done rule by rule, not section by section. A first
  attempt dropped whole sections that organic appeared to replace and lost 54
  classes — `.tags`, `.tick-cell`, `.rownote` and the wider utility set all
  live inside sections whose *other* rules organic does redefine. A rule is
  dropped here only when every selector in it is one organic also defines.

  Two renames applied on the way through:
    #fff         -> var(--surface)   the retheme's own point: a token, so a
                                     dark mode stays possible
    var(--serif) -> var(--display)   the token changed name
*/

/*
  P6 — Organic retheme, v0.5.0.

  Drop-in replacement for the token block and the shell/list/form layers of
  static/css/p6.css. Written against v0.4.0's class names, so nothing in the
  templates has to move for the colours and type to land. Where it asks for a
  template change, the comment says so and names the file.

  Three things the handoff asked for are done here:
    1. --surface exists, so the fourteen hardcoded #fff go through a token
       and a dark mode becomes possible later.
    2. There is a spacing scale. Twenty-one ad-hoc rem values collapse to six
       steps; the utility classes at the bottom are what the ~125 non-dynamic
       inline styles convert into.
    3. The two iOS zoom offenders are fixed: .assignee goes to 1rem, and the
       dead `td input, td select` rule is simply absent — delete it from the
       old file rather than porting it.

  Contrast, measured on the new palette (WCAG AA needs 4.5 for body text):
    --ink on --paper            #201e1d on #f5ead8   14.9  AAA
    --ink on --surface          #201e1d on #f9f4ed   16.0  AAA
    --ink-soft on --paper       #645c50 on #f5ead8    5.6  AA
    --heather-deep on --paper   #8c491a on #f5ead8    5.9  AA   ← links, body-size accent text
    white on --heather          #fff on #c67139       3.2        LARGE TEXT AND CHROME ONLY
    white on --heather-deep     #fff on #8c491a       6.4  AA   ← primary button label
    --moss-deep on --paper      #56633f on #f5ead8    6.3  AA

  The one palette rule worth carrying forward, restated for this palette:
  --heather (#c67139) and --moss (#8fa073) are 3:1 colours. Fills, borders,
  meters, icons and large type only. Body-size text in either accent uses the
  -deep step.
*/


/* ── Fonts ──────────────────────────────────────────────────────────── */

/*
  Written here rather than taken from the handback: the spec says "the CSS
  self-hosts them from static/fonts", and the comment referring to "the
  @font-face blocks" survived, but the blocks themselves were never in the
  file. The stacks named two families nothing loaded, so every page would
  have quietly rendered in Georgia and system-ui.

  Subset to Latin, woff2, 37.6 KB for both — see static/fonts/README.md.
  `swap` because a packing list is readable in the fallback: showing nothing
  while a font arrives is worse than showing the old look for 200ms.
*/

@font-face {
  font-family: "Caprasimo";
  src: url("../fonts/caprasimo-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Figtree";
  src: url("../fonts/figtree-latin.woff2") format("woff2");
  /* One variable file covers the whole range, so 400, 600 and 700 are one
     request between them rather than three. */
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

/* ── Tokens ─────────────────────────────────────────────────────────── */

:root {
  /* Ground and ink */
  --paper:        #f5ead8;
  --paper-raised: #ebddc5;   /* the masthead, the tripbar, the bottom nav */
  --surface:      #f9f4ed;   /* cards, rows, inputs — was fourteen #fff */
  --ink:          #201e1d;
  --ink-soft:     #645c50;
  --grid:         #dcd3c4;
  --grid-faint:   #eee7db;

  /* Accents. -deep is the body-text-safe step of each. */
  --heather:       #c67139;  /* primary, links, focus ring */
  --heather-deep:  #8c491a;
  --heather-soft:  #fff2eb;
  --heather-press: #b2622d;
  --moss:          #8fa073;  /* the second voice: packed, meters, cooks */
  --moss-deep:     #56633f;
  --moss-soft:     #e1eecc;
  --contour:       #a19786;  /* rules and the wordmark */
  --water:         #728157;
  --warn:          #8c491a;
  --warn-soft:     #ffe1d0;

  /* Tick states — the ordered pair, nothing → got → got + packed */
  --got:       #ffe1d0;
  --got-edge:  #d67f48;
  --done:      #e1eecc;
  --done-edge: #728157;

  /* Type. Two webfonts, which is a change: the old file forbade them because
     a font request is a network request in a field with no signal. Both are
     self-hosted from static/fonts and preloaded, and every stack falls back
     to system-ui, so a cold cache in a glen degrades to the old look rather
     than to nothing. If that trade is unwanted, drop the @font-face blocks
     and the stacks resolve to system-ui on their own. */
  --display: "Caprasimo", Georgia, serif;
  --sans:    "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono:    ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Spacing scale — the missing system. 1.10x density, matching the type. */
  --space-1: 0.275rem;  /*  4.4px */
  --space-2: 0.55rem;   /*  8.8px */
  --space-3: 0.825rem;  /* 13.2px */
  --space-4: 1.1rem;    /* 17.6px */
  --space-6: 1.65rem;   /* 26.4px */
  --space-8: 2.2rem;    /* 35.2px */

  --radius-sm: 8px;
  --radius:    16px;
  --radius-lg: 28px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(46, 43, 37, .14);
  --shadow-md: 0 3px 10px rgba(46, 43, 37, .16);
  --shadow-lg: 0 12px 32px rgba(46, 43, 37, .22);

  --tap: 44px;
  --nav-h: 76px;        /* bottom bar + safe area; content pads past it */
}

/* ── Base ───────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  /* The contour wash goes. Organic's ground is a flat warm field and the
     hatching fights the rounded shapes. If it is missed, the two gradients
     from the old file still work — derive them from --contour, not from a
     literal rgba, which was one of the five hardcoded colours flagged. */
  background-image: none;
}

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;               /* Caprasimo ships one weight */
  line-height: 1.12;
  letter-spacing: -.015em;
  margin: 0 0 var(--space-2);
}
h1 { font-size: 1.7rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.05rem; }

/* .group-head h2 keeps carrying its own size, so the heading level and the
   look stay decoupled — the handoff's point, unchanged. */
.group-head h2 { font-size: 1rem; }

a { color: var(--heather-deep); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--heather-press); }

:focus-visible { outline: 2px solid var(--heather); outline-offset: 2px; }
::selection { background: color-mix(in srgb, var(--heather) 30%, transparent); }

.eyebrow {
  font-size: .69rem; letter-spacing: .11em; text-transform: uppercase;
  color: var(--heather-deep); font-weight: 600;
}
.count { font-size: .78rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-soft); }
.small { font-size: .85rem; }

/* ── Shell ──────────────────────────────────────────────────────────── */

.masthead {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--paper) 94%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--grid);
}
.masthead-inner {
  max-width: 62rem; margin: 0 auto;
  padding: var(--space-2) var(--space-4);
  display: flex; align-items: center; gap: var(--space-3);
}
.wordmark {
  font-family: var(--display); font-size: 1.15rem; letter-spacing: .02em;
  color: var(--ink); text-decoration: none;
}
.wordmark span { color: var(--heather); }
.masthead-spacer { flex: 1; }

.whoami { display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: var(--tap); font-size: .9rem; text-decoration: none; color: var(--ink); }

.dot {
  width: 1.75rem; height: 1.75rem; border-radius: var(--radius-pill);
  display: inline-grid; place-items: center; flex: none;
  color: #fff; font-size: .68rem; font-weight: 700;
}

main {
  max-width: 62rem; margin: 0 auto;
  padding: var(--space-4) var(--space-4) calc(var(--nav-h) + var(--space-8));
}

/* ── Trip navigation ────────────────────────────────────────────────── */

/* Desktop keeps the horizontal top bar. */
.tripbar { background: var(--paper-raised); border-bottom: 1px solid var(--grid); }
.tripbar-inner {
  max-width: 62rem; margin: 0 auto; display: flex; gap: var(--space-1);
  padding: var(--space-2) var(--space-3); overflow-x: auto;
}
.tripbar a {
  min-height: var(--tap); display: inline-flex; align-items: center;
  padding: 0 var(--space-3); border-radius: var(--radius-pill);
  font-size: .92rem; font-weight: 600; text-decoration: none;
  color: var(--ink); white-space: nowrap;
}
.tripbar a:hover { background: var(--heather-soft); }
.tripbar a[aria-current="page"] { background: var(--heather); color: #fff; }

/*
  Mobile gets a fixed bottom bar. Four destinations plus More; Crew, Shopping,
  Generator and the kit catalogue live in the sheet. This needs one template
  change — _tripbar.html grows a second <nav class="bottomnav"> with the four
  links and a <details class="morebar"> for the rest. Same hrefs, same
  aria-current logic, no JS.
*/
@media (max-width: 45rem) {
  .tripbar { display: none; }

  .bottomnav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    display: flex; align-items: stretch;
    padding: var(--space-2) var(--space-1) calc(var(--space-2) + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--paper-raised) 97%, transparent);
    backdrop-filter: blur(14px);
    border-top: 1px solid var(--grid);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
  .bottomnav a, .bottomnav button {
    flex: 1; min-height: 52px; border: none; background: none; cursor: pointer;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; font-size: .66rem; font-weight: 700; text-decoration: none;
    color: var(--ink-soft); font-family: inherit;
  }
  .bottomnav a[aria-current="page"] { color: var(--heather-deep); }
  .bottomnav svg { width: 23px; height: 23px; stroke-width: 2.75; }

  /* The add affordance sits clear of the bar, never on it. */
  .fab {
    position: fixed; right: var(--space-4); z-index: 29;
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--space-2));
    width: 58px; height: 58px; border-radius: var(--radius-pill); border: none;
    background: var(--heather); color: #fff; box-shadow: var(--shadow-lg);
    display: grid; place-items: center;
  }
  .fab:active { background: var(--heather-press); }
  /* The old inline add form becomes the sheet the FAB opens; .sticky-actions
     stops being sticky on mobile so the two never stack. */
  .sticky-actions { position: static; }
}

/* ── Panels and cards ───────────────────────────────────────────────── */

.panel, .card {
  background: var(--surface);
  border: none;
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-bottom: var(--space-3);
}
.panel-head { display: flex; align-items: baseline; gap: var(--space-2); margin-bottom: var(--space-2); }
.panel-head h1, .panel-head h2 { margin: 0; }
.panel-head .count { margin-left: auto; }

.group-head {
  display: flex; align-items: baseline; gap: var(--space-2);
  padding: 0 var(--space-2) var(--space-2);
  margin-top: var(--space-4);
}

.meter {
  height: 8px; border-radius: var(--radius-pill);
  background: var(--grid); overflow: hidden;
}
.meter span { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--moss-deep); }

.notice { border-radius: var(--radius); padding: var(--space-3) var(--space-4); }
.notice-urgent { background: var(--warn-soft); color: var(--warn); }
.notice-quiet  { background: var(--surface); color: var(--ink-soft); }

.empty {
  background: var(--surface); border-radius: var(--radius-lg);
  padding: var(--space-6) var(--space-4); text-align: center; color: var(--ink-soft);
}

/* ── The list row ───────────────────────────────────────────────────── */

/*
  Anatomy after the redesign: name (+ quantity), holder on communal or the
  privacy toggle on a personal page, the two ticks, the ellipsis. Notes and
  tags move into the ellipsis sheet — which is where the full name already
  was, so nothing becomes wide-screen-only.

  Both bug fixes from the old file survive and must stay:
    flex-wrap: nowrap  — wrapping cost three lines a row on a fifty-item list
    min-width: 0       — without it .item-name refuses to shrink and the row
                         overflows sideways instead
*/

.items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }

.item-row {
  display: flex; flex-wrap: nowrap; align-items: center; gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius);
  border: 1.5px solid transparent;
  background: var(--surface);
}
.item-name {
  flex: 1; min-width: 0;
  font-size: .95rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.item-name a { color: inherit; text-decoration: none; }

.item.is-owned  .item-row { background: var(--got);  border-color: var(--got-edge); }
.item.is-packed .item-row { background: var(--done); border-color: var(--done-edge); }

/* The handback had `.item-aside { display: none }` here, with the comment
   "it is gone from the row on every width". The intent is right and the
   selector was not: `.item-aside` is not the row's alone. Four meals
   templates — plan, sitting, supplies, suggested — use the same class inside
   the same `.item-row` parent, so an unscoped `display: none` hid `0.5 can
   each` on the recipe editor and the `explain()` line on the shopping list at
   every width. That is a harder version of the bug step 1 fixed.

   There is nothing to hide instead: `_row.html` no longer emits an aside, so
   the row's copy is gone from the markup rather than from the stylesheet.
   What the meals templates emit stays visible, and wraps to its own line on a
   phone — the rules for that are carried over below. */

.tick-pair { display: flex; gap: var(--space-1); flex: none; }
.tickbox {
  appearance: none; -webkit-appearance: none; margin: 0;
  width: 38px; height: 38px; border-radius: var(--radius-pill);
  border: 2px solid var(--contour); background: transparent; cursor: pointer;
  display: grid; place-items: center;
}
.tickbox::after {
  content: ""; width: 15px; height: 9px; margin-top: -3px;
  border-left: 3px solid transparent; border-bottom: 3px solid transparent;
  transform: rotate(-45deg);
}
.tickbox.owned:checked  { background: var(--got-edge);  border-color: var(--got-edge); }
.tickbox.packed:checked { background: var(--done-edge); border-color: var(--done-edge); }
.tickbox:checked::after { border-color: #fff; }

.holder, .assignee {
  height: 32px; border-radius: var(--radius-pill);
  border: none; background: var(--grid-faint); color: var(--ink);
  padding: 0 var(--space-2);
  font-family: inherit;
  font-size: 1rem;      /* 16px. THE iOS ZOOM FIX — was .8rem. Do not shrink. */
  max-width: 7rem;
  text-overflow: ellipsis;
}
.holder.unheld, .assignee:invalid { background: var(--heather-soft); color: var(--heather-deep); }

.rowmeta > summary {
  list-style: none; cursor: pointer;
  width: 30px; height: 38px; display: grid; place-items: center;
  color: var(--ink-soft); letter-spacing: .06em;
}
.rowmeta > summary::-webkit-details-marker { display: none; }
.rowmeta-body {
  background: var(--surface); border-radius: var(--radius);
  padding: var(--space-3); margin-top: var(--space-2);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.rowmeta-name { font-family: var(--display); font-size: 1.1rem; margin: 0; }

/* Batch selection — workstream 5. Same row, one box on the left. */
.item-select {
  appearance: none; -webkit-appearance: none; margin: 0;
  width: 26px; height: 26px; flex: none;
  border: 2px solid var(--contour); border-radius: var(--radius-sm);
  background: transparent; cursor: pointer;
}
.item-select:checked { background: var(--heather); border-color: var(--heather); }
.selectbar {
  position: fixed; left: var(--space-3); right: var(--space-3); z-index: 31;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--space-2));
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: #2e2b25; color: #fff;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
}

/* ── Forms and buttons ──────────────────────────────────────────────── */

input[type="text"], input[type="number"], input[type="date"], input[type="search"],
select, textarea {
  min-height: var(--tap);
  font-family: inherit;
  font-size: 1rem;                /* 16px is what stops iOS zooming on focus */
  color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--grid);
  border-radius: var(--radius-pill);
  padding: 0 var(--space-4);
}
textarea { border-radius: var(--radius); padding: var(--space-3) var(--space-4); }
.field { display: flex; flex-direction: column; gap: var(--space-1); }
.field label { font-size: .8rem; font-weight: 700; color: var(--ink-soft); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: var(--tap); padding: 0 var(--space-4);
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--heather);
  background: transparent; color: var(--heather-deep);
  font-family: var(--display); font-size: 1rem; line-height: 1;
  text-decoration: none; cursor: pointer;
}
.btn:hover { background: var(--heather-soft); }
.btn:active { background: var(--got); }
.btn-primary { background: var(--heather); border-color: var(--heather); color: #fff; }
.btn-primary:hover { background: var(--heather-press); border-color: var(--heather-press); }
.btn-primary:active { background: var(--heather-deep); }
.btn-quiet { border-color: transparent; color: var(--ink-soft); }
.btn-quiet:hover { background: var(--grid-faint); color: var(--warn); }
.btn-small { min-height: 38px; padding: 0 var(--space-3); font-size: .9rem; }
.btn[disabled] { opacity: .45; pointer-events: none; }

.tag {
  display: inline-flex; align-items: center; height: 30px;
  padding: 0 var(--space-3); border-radius: var(--radius-pill);
  background: var(--moss-soft); color: var(--moss-deep);
  font-size: .8rem; font-weight: 600;
}
.tag.mealtype { background: var(--heather-soft); color: var(--heather-deep); }

.code {
  font-family: var(--mono); font-size: 1.25rem; letter-spacing: .1em; font-weight: 700;
}

/* ── Sheets — the one surface, worn three ways ──────────────────────── */

/* Duplicate confirm, delete confirm and the add form are the same component.
   Workstream 5 says build them together; this is the shell they share. */
.sheet-backdrop { position: fixed; inset: 0; z-index: 40; background: rgba(46, 43, 37, .45); }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 41;
  background: var(--paper);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: var(--space-3) var(--space-4) calc(var(--space-6) + env(safe-area-inset-bottom));
  box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.sheet::before {
  content: ""; width: 44px; height: 5px; border-radius: var(--radius-pill);
  background: var(--grid); margin: 0 auto var(--space-2);
}
.sheet h2 { margin: 0; }

/* ── Utilities — what the ~125 inline styles become ─────────────────── */

/* Convert these first, as a mechanical step, before any visual work. The
   dynamic three stay inline: the meter width, current_user.colour, and
   member.swatch_style / holder.swatch_style. */
.row      { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.row-tight{ display: flex; align-items: center; gap: var(--space-1); }
.stack    { display: flex; flex-direction: column; gap: var(--space-3); }
.stack-sm { display: flex; flex-direction: column; gap: var(--space-2); }
.grow     { flex: 1; min-width: 0; }
.grid-2   { display: grid; gap: var(--space-3); }
@media (min-width: 40rem) { .grid-2 { grid-template-columns: 1fr 1fr; } }

.w-name  { flex: 1; min-width: 9rem; }   /* was flex:1;min-width:9rem  ×6  */
.w-short { max-width: 9rem; }            /* was max-width:9rem        ×5  */
.w-qty   { max-width: 6rem; }
/* The four inline widths that exceed a 375px viewport — 26/28/32/38rem —
   become this, which is the same on a desktop and safe on a phone. */
.w-prose { max-width: min(38rem, 100%); }

.mt-1 { margin-top: var(--space-1); } .mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); } .mt-4 { margin-top: var(--space-4); }
.mb-2 { margin-bottom: var(--space-2); } .mb-3 { margin-bottom: var(--space-3); }
.m-0  { margin: 0; }

/* ── Classes the new templates reference ────────────────────────────── */

/* Selection is off until <main> says otherwise, so entering select mode is
   one class and no row has to be re-rendered. */
/* Selection, reconciling the plan with the handback.

   The handback hides the checkbox until select mode at every width. The plan
   settles it differently and later: "the separation is spatial rather than
   modal", with long-press summoning the column on a phone and "desktop keeps
   the always-visible column, since there is width for it and no long-press
   convention".

   So: modal on a phone, permanent on a desktop. The handback's mechanism is
   what makes both cheap — one class on <main>, no row aware of anything. */
.item-select { display: none; }
main.selecting .item-select { display: block; }

@media (min-width: 45.01rem) {
  .item-select { display: block; }
}
main.selecting .rowmeta { display: none; }
.selectbar button[disabled] { opacity: .4; }

/* The privacy toggle — the personal page's middle slot. */
.privacy {
  width: 32px; height: 32px; flex: none;
  border: none; border-radius: var(--radius-pill);
  background: var(--moss-soft); color: var(--moss-deep);
  font-size: .9rem; line-height: 1; cursor: pointer;
}
.privacy.is-private { background: var(--grid); color: var(--ink); }
.hidetoggle { display: flex; }

/* Button variants the sheets use. */
.btn-block  { width: 100%; }
.btn-danger { border-color: var(--warn); color: var(--warn); }
.btn-danger:hover { background: var(--warn-soft); }
.btn-moss   { border-color: var(--moss-deep); color: var(--moss-deep); }
.btn-moss:hover { background: var(--moss-soft); }

/* Sheet plumbing. Every sheet is a <details> or a [hidden] host, so the
   open/close state is the browser's and Escape works with no JS. */
.fab-sheet > summary, .morebar > summary { list-style: none; cursor: pointer; }
.fab-sheet > summary::-webkit-details-marker,
.morebar  > summary::-webkit-details-marker { display: none; }
.fab-sheet > summary { /* the FAB itself; .fab carries the position */ }
.morebar { display: contents; }
.morebar > summary {
  flex: 1; min-height: 52px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; font-size: .66rem; font-weight: 700; color: var(--ink-soft);
}
.morebar[open] > summary { color: var(--heather-deep); }
.morebar > summary svg { width: 23px; height: 23px; }

.sheet-host[hidden] { display: none; }
.sheet-row {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 52px; padding: 0 var(--space-4);
  border-radius: var(--radius); background: var(--surface);
  text-decoration: none; color: var(--ink); font-weight: 600;
}
.sheet-row:hover { background: var(--heather-soft); }

/* On desktop the row's details stays an ordinary disclosure; only below
   45rem does it present as the bottom sheet. */
@media (min-width: 45.01rem) {
  .rowmeta .sheet-backdrop { display: none; }
  .rowmeta-body.sheet { position: static; border-radius: var(--radius); box-shadow: none; }
  .rowmeta-body.sheet::before { display: none; }
  .fab, .bottomnav { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}


/* ═══ Carried over from v0.4.0 — rules the retheme does not restyle ═══ */


/* ---------- Type ---------- */

h1, h2, h3 { font-family: var(--display); font-weight: 600; line-height: 1.15; margin: 0 0 .4em; }

/* ---------- Shell ---------- */

.masthead {
  border-bottom: 1px solid var(--grid);
  background: var(--paper-raised);
  position: sticky;
  top: 0;
  z-index: 20;
}

/* ---------- Trip navigation ---------- */

.tripbar {
  border-bottom: 1px solid var(--grid);
  background: var(--paper-raised);
}
.tripbar-inner::-webkit-scrollbar { display: none; }

/* ---------- Panels ---------- */

.panel {
  background: var(--paper-raised);
  border: 1px solid var(--grid);
  border-radius: var(--radius);
  padding: .9rem;
  margin-bottom: 1rem;
}

.stack > * + * { margin-top: .75rem; }
@media (min-width: 40rem) { }

/* ---------- Forms ---------- */

label { display: block; font-size: .8rem; color: var(--ink-soft); margin-bottom: .2rem; }

input[type="text"], input[type="date"], input[type="number"],
input[type="search"], input[type="email"], select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: .5rem .6rem;
  font: inherit;
  font-size: 1rem; /* 16px stops iOS zooming on focus */
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--grid);
  border-radius: var(--radius);
}

.field + .field { margin-top: .7rem; }

/* ---------- The threshold dial (Pattern 3) ----------
   The signature element. An ordered dimension is not a dropdown: choosing a
   level means "this and everything below it", so the control shows the
   included levels filling up beneath the one you picked. The interface states
   the rule instead of hiding it. */

.threshold { display: flex; flex-direction: column; gap: 2px; }

.threshold input { position: absolute; opacity: 0; pointer-events: none; }

.threshold label {
  display: flex;
  align-items: center;
  gap: .6rem;
  min-height: var(--tap);
  margin: 0;
  padding: .35rem .7rem;
  font-size: .9rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--grid);
  border-left: 4px solid var(--grid-faint);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}

.threshold label::before {
  content: attr(data-level);
  font-family: var(--mono);
  font-size: .65rem;
  color: var(--ink-soft);
  min-width: 1.1rem;
}

/* Everything after the checked input is a level below it — see the template
   comment for why the values are written highest-first. Order matters here:
   the `+` rule must come after the `~` rule, since both have equal
   specificity and the selected label is matched by both. */
.threshold input:checked ~ label {
  background: var(--heather-soft);
  border-left-color: var(--contour);
}
.threshold input:checked + label {
  background: var(--heather);
  border-color: var(--heather);
  border-left-color: var(--ink);
  color: var(--surface);
  font-weight: 600;
}
.threshold input:checked + label::before { color: rgba(255,255,255,.7); }

.threshold-note {
  font-size: .75rem;
  color: var(--ink-soft);
  margin-top: .4rem;
  font-style: italic;
}

/* ---------- Chip filters ---------- */

.chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.chips input { position: absolute; opacity: 0; pointer-events: none; }

.chips label {
  margin: 0;
  padding: .45rem .7rem;
  min-height: 2.4rem;
  display: inline-flex;
  align-items: center;
  font-size: .85rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--grid);
  border-radius: 999px;
  cursor: pointer;
}
.chips input:checked + label,
.chips label.on {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* ---------- Notices ---------- */

.notices { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .4rem; }
.notice a { color: inherit; }
.notice-normal { border-left-color: var(--contour); }
.notice-good   { border-left-color: var(--moss); background: var(--done); }

/* ---------- Row detail (quantity, notes, type) ---------- */

.rowmeta { flex: none; }
.rowmeta summary {
  list-style: none;
  cursor: pointer;
  min-width: 2rem;
  min-height: 2rem;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  color: var(--ink-soft);
  font-family: var(--mono);
}
.rowmeta summary::-webkit-details-marker { display: none; }
.rowmeta summary:hover { background: var(--paper); color: var(--ink); }
.rowmeta[open] summary { background: var(--paper); color: var(--ink); }
.rowmeta-body label { margin: 0; white-space: nowrap; }
.rowmeta-body .row { gap: .4rem; }
/* Restored: the merge dropped this as "superseded" because organic declared
   `.item-aside` too — but the declaration it was superseded by has itself
   been removed above. Without the base rule the meals asides render as plain
   inline content and lose their alignment with the row. */
.item-aside {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex: none;
  max-width: 45%;
  overflow: hidden;
}
.item-aside .tags { margin-top: 0; flex-wrap: nowrap; }

@media (max-width: 45rem) {
  /* Wrap rather than hide. This is step 1's fix and it has to survive the
     retheme: on a phone these lines are the per-person amount and the
     "6 cans — chilli x6 @ 0.5, plus 2 spare" explanation, and neither has
     anywhere else to be read. */
  .item-aside {
    flex-basis: 100%;
    max-width: 100%;
    overflow: visible;
    order: 10;
  }
  .item-aside .tags { flex-wrap: wrap; }
  .item-aside .rownote { white-space: normal; }
}

.rownote {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: .78rem;
  color: var(--ink-soft);
  font-style: italic;
  margin-top: .1rem;
}

/* ---------- Spacing scale ---------- */

/*
  Six steps, identical to the values in p6-organic.css. They land here at the
  mechanical pass rather than with the retheme on purpose: the utility classes
  below are defined in terms of them, so if the scale arrived later, every
  margin in the app would shift at the same moment as every colour and every
  typeface, and a spacing regression would be invisible inside a retheme.

  This way the retheme is the test the build order says it should be — swap
  the sheet, and only colour and type move.
*/
:root {
  --space-1: 0.275rem;
  --space-2: 0.55rem;
  --space-3: 0.825rem;
  --space-4: 1.1rem;
  --space-6: 1.65rem;
  --space-8: 2.2rem;
}

/* ---------- Layout utilities ---------- */

/*
  What the inline styles become. Two rules held to while writing these:

  - A utility earns its place by appearing more than once, or by encoding a
    layout decision worth naming. Fifty classes for fifty unique values would
    be inline styles with extra steps.
  - Ad-hoc margins snap to the scale. .5rem and .6rem both become --space-2,
    .8rem and 1rem become --space-3 and --space-4. This is a real change of
    up to about 10% on individual gaps, and it is the point: twenty-one
    hand-picked values collapsing to six is what makes the spacing legible.
*/

.d-inline { display: inline; }
.wrap     { flex-wrap: wrap; }
.push     { margin-left: auto; }
.mono     { font-family: var(--mono); }
.prewrap  { white-space: pre-line; }
.no-grow  { flex: none; }
.pointer  { cursor: pointer; }

/* Flexible fields: grow to fill, wrap at their own minimum. */
.w-field  { flex: 1; min-width: 8rem; }
.w-wide   { flex: 1; min-width: 10rem; }
.w-widest { flex: 1; min-width: 12rem; }

/* Fixed caps. */
.w-tiny   { max-width: 5rem; }
.w-holder { max-width: 7rem; }
.w-date   { max-width: 11rem; }
.w-auto   { width: auto; }
.w-free   { width: auto; max-width: none; }
.mt-6 { margin-top: var(--space-6); }
.mb-1 { margin-bottom: var(--space-1); }
.my-2 { margin: var(--space-2) 0; }

.h-note { min-height: 4rem; }

/* Two classes the templates have used since 0.4.0 with nothing defining
   them. Found by the "every class is defined" test rather than by eye, which
   is the case for the test: an undefined class renders fine and is wrong only
   on screen. p6-organic.css styles both, so these match its declarations —
   the retheme then changes their colour, not their existence. */
.hidetoggle { display: flex; }

/* Tighter than .row, for controls that belong to each other rather than
   merely sharing a line. */
.row-tight { display: flex; align-items: center; gap: var(--space-1); }
.row-gap   { gap: var(--space-1); }

/* An eyebrow that is a code rather than a word — the invite code above the
   join field. Letterspaced because a code is read character by character. */
.code-eyebrow {
  font-family: var(--mono);
  letter-spacing: .3em;
  text-transform: uppercase;
}

/* A claim URL printed in full: it must break anywhere, because it has no
   spaces and is longer than a phone is wide. */
.claim-link { font-size: .75rem; overflow-wrap: anywhere; }

/* A label sitting inline with its control instead of above it. Keeps the
   pointer cursor a label earns by being clickable. */
.label-inline {
  font-size: .95rem;
  color: var(--ink);
  margin: 0;
  cursor: pointer;
}
.img-fit { max-width: 100%; border-radius: var(--radius); }
.rule {
  border: none;
  border-top: 1px solid var(--grid-faint);
  margin: var(--space-6) 0;
}
.checkline {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  margin: var(--space-2) 0;
}

/* ---------- Width utilities ---------- */

.w-prose {
  /* The `100%` is the whole point: a bare `max-width: 38rem` is 608px and
     overflows every phone, because max-width only caps, it never yields.
     Five templates had a fixed rem width over the 23.4rem a 375px screen
     gives you. This is the first of the utility classes the mechanical pass
     will bring the rest of the inline styles into. */
  max-width: min(38rem, 100%);
}

/* ---------- Sort bar ---------- */

.sortbar {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
  margin: .7rem 0 .2rem;
}
.sortlink {
  font-size: .8rem;
  padding: .3rem .6rem;
  min-height: 2rem;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--grid);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
}
.sortlink.on { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* ---------- Lists ---------- */

.group-head {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  margin: 1.2rem 0 .4rem;
  padding-bottom: .2rem;
  border-bottom: 1px solid var(--grid);
}
/* h2, not h3: these group headings sit directly under the page's h1, and
   jumping a level made a screen reader's heading outline read as though a
   section were missing. The size is set here rather than inherited, so the
   change is semantic only — nothing moves on screen. */
.group-head h2 { margin: 0; font-family: var(--sans); font-size: .9rem; font-weight: 700; }

.item {
  border-bottom: 1px solid var(--grid-faint);
}
.item-name a:hover { text-decoration: underline; }

/* Ticking highlights the row; it does not strike anything out. Striking the
   name made it harder to read the thing you had just found, and dragged the
   dimension tags along with it. Yellow = got, green = packed; packed wins
   because it is the later state. */
.item.is-owned  { background: var(--got); box-shadow: inset 3px 0 0 var(--got-edge); }
.item.is-packed { background: var(--done); box-shadow: inset 3px 0 0 var(--done-edge); }
.item.is-owned .item-name,
.item.is-packed .item-name { color: var(--ink); text-decoration: none; }
.item.is-owned .tag,
.item.is-packed .tag { text-decoration: none; }

.tags { display: flex; gap: .3rem; flex-wrap: wrap; margin-top: .1rem; }

/* Tick boxes big enough for cold fingers */
.tickbox {
  appearance: none;
  width: 1.5rem; height: 1.5rem;
  flex: none;
  border: 1.5px solid var(--ink-soft);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  display: grid;
  place-items: center;
}
/* --moss-deep, not --moss. Both of these are v0.4.0 rules that were correct
   until the retheme changed what --moss means: it was #4E7A3A, a dark green,
   and is now #8fa073, a pale sage. The rules did not change; the token they
   point at did.

   The tick mark inside a checked box is white. On the old moss that was 5.0:1
   and legible. On the new one it is 2.8:1 — under the 3:1 WCAG asks of a
   graphical object, so the tick would be hard to see in daylight, on the one
   control the whole app exists to press. --moss-deep restores it to 6.5:1.

   This is the failure mode a token swap creates and a test cannot see by
   reading either sheet alone: nothing is wrong with the rule or with the
   palette, only with their combination. */
.tickbox:checked { background: var(--moss-deep); border-color: var(--moss-deep); }
.tick-pair .stack-label {
  font-family: var(--mono);
  font-size: .55rem;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: .08em;
}
.tick-cell { display: flex; flex-direction: column; align-items: center; gap: .1rem; }

/* ---------- Progress ---------- */

.meter {
  height: 5px;
  background: var(--grid-faint);
  border-radius: 999px;
  overflow: hidden;
}
/* Same cause: the fill has to be distinguishable from the track it sits in.
   Pale sage on the grid colour is 1.9:1; moss-deep is 4.4:1. */
.meter > span { display: block; height: 100%; background: var(--moss-deep); }

/* ---------- Cards ---------- */

.card {
  display: block;
  border: 1px solid var(--grid);
  border-left: 4px solid var(--contour);
  border-radius: var(--radius);
  background: var(--paper-raised);
  padding: .8rem .9rem;
  text-decoration: none;
  color: inherit;
}
.card:hover { border-color: var(--heather); border-left-color: var(--heather); }
.card h2 { margin: .1rem 0 .2rem; }

/* ---------- Flashes ---------- */

.flash {
  border: 1px solid var(--contour);
  border-left: 4px solid var(--contour);
  background: var(--surface);
  padding: .6rem .8rem;
  border-radius: var(--radius);
  margin-bottom: .9rem;
  font-size: .9rem;
}

/* ---------- Tables (meals) ---------- */

.table-scroll { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: .88rem; }
th {
  text-align: left;
  font-family: var(--mono);
  font-size: .65rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 500;
  padding: .4rem .5rem;
  border-bottom: 1px solid var(--grid);
  white-space: nowrap;
}
td { padding: .3rem .5rem; border-bottom: 1px solid var(--grid-faint); vertical-align: middle; }
/* `td input, td select` lived here and was deleted in 0.5.0: there is no
   <table>, <tr> or <td> in any template, so it styled nothing. It was also
   the second of the two iOS zoom offenders, which is how it got noticed. */

/* ---------- Detail ---------- */

.prose { font-family: var(--display); font-size: 1.02rem; line-height: 1.6; max-width: 38rem; }
.prose p { margin: 0 0 .8rem; }

.linklist { list-style: none; padding: 0; margin: 0; }
.linklist li { padding: .35rem 0; border-bottom: 1px solid var(--grid-faint); }

footer {
  border-top: 1px solid var(--grid);
  margin-top: 2rem;
  padding: 1rem .9rem 2rem;
  font-size: .75rem;
  color: var(--ink-soft);
  max-width: 62rem;
  margin-inline: auto;
}

@media (prefers-reduced-motion: reduce) {
}


/* ---------- The sitting: recipe lines ---------- */

/* The per-person amount sits under the name; the scaled total sits right and
   heavier. They answer different questions — one is what you edit, the other
   is what you buy — so they should not read as a pair. */
.per-mouth {
  display: block;
  font-size: .72rem;
  color: var(--ink-soft);
  margin-top: .1rem;
}
.scaled {
  flex: none;
  font-size: .85rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  min-width: 4.5rem;
  color: var(--ink);
}

/* ---------- Food sub-tabs ---------- */

.subtabs {
  display: flex;
  gap: .1rem;
  overflow-x: auto;
  border-bottom: 1px solid var(--grid);
  margin: 0 0 .9rem;
  -webkit-overflow-scrolling: touch;
}
.subtabs a {
  flex: none;
  padding: .45rem .7rem;
  font-size: .85rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.subtabs a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--contour);
  font-weight: 600;
}

/* The meal type sits before the name and must never be squeezed. */
.tag.mealtype {
  flex: none;
  min-width: 4.4rem;
  text-align: center;
  background: var(--paper-raised);
}
