/* Mise design system — Console direction, faithful to mockups/2-console.html.
   Fonts self-hosted (vendor/fonts, OFL) — no CDN, strict CSP. */

@font-face {
  font-family: "Archivo";
  src: url("../vendor/fonts/archivo-var.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../vendor/fonts/jetbrains-mono-var.woff2") format("woff2");
  font-weight: 100 800;
  font-display: swap;
}

:root {
  --bg: #13271c;
  --panel: #1a3224;
  --panel-2: #213c2c;
  --line: #2f4d3b;
  --text: #e8edef;
  --dim: #93a59c;
  --signal: #3ddc84;
  --signal-dark: #22b866;
  --amber: #ffb224;
  --warn: #e0a34a;
  --recover: #4cc3ff;
  --preact: #ff7849;
  --satiety: #d2a8ff;
  --red: #f85149;
  --red-bg: #2d1216;
  --on-signal: #06130b;
  --signal-08: rgba(61, 220, 132, 0.08);
  --line-strong: #3a454d;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --sans: "Archivo", -apple-system, "Segoe UI", system-ui, sans-serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

body {
  padding: calc(10px + env(safe-area-inset-top)) 16px calc(92px + env(safe-area-inset-bottom));
  max-width: 640px;
  margin: 0 auto;
}

.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* ---- statusline ---- */

.statusline {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--dim);
  letter-spacing: 0.08em;
  padding: 4px 4px 14px;
}

.statusline .sync {
  color: var(--signal);
}

.statusline .sync::before {
  content: "●";
  margin-right: 5px;
  font-size: 8px;
}

.statusline .sync.off {
  color: var(--amber);
}

.statusline .sync.off::before {
  content: "○";
}

.statusline .sync.warn {
  color: var(--amber);
}

.statusline .sync.warn::before {
  content: "◐";
}

/* ---- hero + primary CTA ---- */

.hero {
  padding: 2px 4px 18px;
}

.hero h1 {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0;
}

.hero h1 span {
  color: var(--dim);
  font-weight: 600;
}

.hero .sub {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  margin-top: 6px;
  letter-spacing: 0.04em;
}

.hero .sub b {
  color: var(--amber);
  font-weight: 600;
}

.ask {
  width: 100%;
  min-height: 60px;
  padding: 16px;
  border: none;
  border-radius: 12px;
  cursor: pointer;
  background: linear-gradient(135deg, var(--signal) 0%, var(--signal-dark) 100%);
  color: var(--on-signal);
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.01em;
  box-shadow: 0 0 24px rgba(61, 220, 132, 0.25);
}

.ask small {
  display: block;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 10px;
  margin-top: 3px;
  opacity: 0.8;
}

.ask:active {
  transform: scale(0.98);
}

/* ---- tiles ---- */

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 14px;
}

.tile {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 13px 14px;
}

a.tile {
  text-decoration: none;
  color: inherit;
  display: block;
}

.view > .tile + .tile {
  margin-top: 10px;
}

.batch > div + div {
  margin-top: 8px;
}

.ing .note {
  color: var(--dim);
  font-size: 12px;
}

.tile .k {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 8px;
}

.tile .v {
  font-family: var(--mono);
  font-size: 22px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.tile .v small {
  font-size: 11px;
  font-weight: 400;
  color: var(--dim);
}

.tile .d {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--dim);
  margin-top: 7px;
}

.tile .d b {
  color: var(--signal);
  font-weight: 600;
}

.tile.warn .d b {
  color: var(--amber);
}

/* status rows (system view) */

.row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  font-size: 14px;
}

.row + .row {
  border-top: 1px solid var(--line);
}

.row .k {
  color: var(--dim);
}

.status {
  font-family: var(--mono);
  font-size: 12px;
}

.status.ok {
  color: var(--signal);
}

.status.bad {
  color: var(--red);
}

.status.warn {
  color: var(--amber);
}

.status.dim {
  color: var(--dim);
}

/* ---- section titles ---- */

.block-title {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400; /* also used on h2 elements for a11y heading structure */
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 20px 4px 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.block-title::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--line);
}

/* Sunday batch-prep block: native <details> is the toggle, Sunday just
 * opens it by default (app/views/today.js) */
summary.block-title {
  cursor: pointer;
  min-height: 44px;
}

/* ---- recipe rows ---- */

.slots {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.slot {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 6px 6px 6px 13px;
  min-height: 56px;
}

.slot .slotlink {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  padding: 7px 0;
}

.slot:active {
  background: var(--panel-2);
}

.slot .plus {
  min-width: 44px;
  min-height: 44px;
  flex-shrink: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--signal);
  font-size: 18px;
  cursor: pointer;
}

.slot .plus.done {
  border-color: var(--signal);
}

.slot .plus:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.daypick {
  display: flex;
  align-items: center;
  gap: 6px;
  overflow-x: auto;
  padding: 6px 2px 2px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* right-edge fade: cue that more chips are off-screen */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}

.daypick .wklabel {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--dim);
  flex-shrink: 0;
  padding: 0 2px;
}

.added-note {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--signal);
  padding: 4px 2px 0;
}

.daypick::-webkit-scrollbar {
  display: none;
}

.rowwrap {
  display: flex;
  flex-direction: column;
}

.slot .name {
  flex: 1;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.slot .m {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--dim);
  text-align: right;
  line-height: 1.5;
  flex-shrink: 0;
}

.slot .m b {
  color: var(--text);
  font-weight: 600;
}

.slot .why {
  display: block;
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--dim);
  font-weight: 400;
  margin-top: 3px;
}

/* purpose tag pills */

.tag {
  display: inline-block;
  font-family: var(--mono);
  font-size: 8.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 20px;
  margin-left: 7px;
  vertical-align: 2px;
  background: var(--panel-2);
  color: var(--dim);
}

.tag.recovery {
  background: rgba(76, 195, 255, 0.14);
  color: var(--recover);
}

.tag.pre-activity {
  background: rgba(255, 120, 73, 0.14);
  color: var(--preact);
}

.tag.long-satiety {
  background: rgba(210, 168, 255, 0.14);
  color: var(--satiety);
}

.tag.sick-day {
  background: rgba(255, 178, 36, 0.14);
  color: var(--amber);
}

/* ---- filter chips ---- */

.chips {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 2px 4px 10px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* right-edge fade: cue that more chips are off-screen */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}

.chips::-webkit-scrollbar {
  display: none;
}

.chip {
  flex-shrink: 0;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: 22px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.chip.on {
  border-color: var(--signal);
  color: var(--signal);
  background: var(--signal-08);
}

/* avoided-cuisine state (survey-v2 Q14: tap once = love/on, twice = avoid) */
.chip.off {
  border-color: var(--muted, #666);
  color: var(--muted, #888);
  opacity: 0.6;
  text-decoration: line-through;
}

/* ---- recipe detail ---- */

.backlink {
  display: inline-block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--dim);
  text-decoration: none;
  padding: 10px 4px;
  min-height: 44px;
}

.detail h1 {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 2px 0 8px;
}

.detail .meta {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.04em;
  margin-bottom: 12px;
}

.macros4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 12px 0;
}

.macros4 .tile {
  padding: 10px 8px;
  text-align: center;
}

.macros4 .v {
  font-size: 17px;
}

.ing {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 4px;
  font-size: 14px;
  border-bottom: 1px solid var(--line);
}

.ing .q {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--dim);
  white-space: nowrap;
}

.ing.staple {
  color: var(--dim);
}

.ing.staple .pantry-mark {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--signal);
  text-transform: uppercase;
}

.steps {
  margin: 0;
  padding: 0 0 0 4px;
  list-style: none;
  counter-reset: step;
}

.steps li {
  counter-increment: step;
  display: flex;
  gap: 12px;
  padding: 10px 0;
  font-size: 14px;
  line-height: 1.55;
  border-bottom: 1px solid var(--line);
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--signal);
  padding-top: 3px;
}

.batch {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--recover);
  border-radius: 12px;
  padding: 12px 14px;
  margin: 12px 0;
  font-size: 13px;
  line-height: 1.5;
}

.batch .k {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--recover);
  margin-bottom: 4px;
}

/* ---- the serve tile (Cook Mode removed 2026-08-19; the serve step lives
   on the recipe page now, spec §7.2's guarantee on one page). Names lead,
   bare noun phrases follow, no macros anywhere in this tile. */
.tile.serve {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.tile.serve .serve-title {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--dim);
}
.tile.serve .serve-sub {
  font-size: 14px;
  color: var(--dim);
  margin-bottom: 2px;
}
.tile.serve .serve-seat {
  border-left: 3px solid var(--line);
  padding-left: 10px;
}
.tile.serve .serve-seat.aside {
  border-left-color: var(--warn);
}
.tile.serve .serve-name {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.1em;
}
.tile.serve .serve-line {
  font-size: 18px;
  font-weight: 600;
  line-height: 1.3;
}

/* ---- planner ---- */

.weeknav {
  display: flex;
  align-items: center;
  gap: 12px;
}

.weeknav .wkmid {
  flex: 1;
  text-align: center;
}

.weeknav .sub {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--dim);
  margin-top: 2px;
}

.weeknav .wk {
  min-width: 44px;
  min-height: 44px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 20px;
  cursor: pointer;
}

.weeknav .wk:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.chipbody {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.chipbody .n {
  font-size: 12.5px;
  font-weight: 600;
  /* was nowrap + ellipsis, which is how a planned meal rendered as
     "matcha gree…" (David, 2026-07-27). A recipe name is the single most
     load-bearing string on this screen, so it gets two lines before it
     truncates, and the row grows to fit rather than the name shrinking. */
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.chipbody .m {
  font-size: 9.5px;
  color: var(--dim);
}

.ask:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.buildreport {
  margin-top: 10px;
}

.buildreport .d {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--dim);
  margin-top: 6px;
  line-height: 1.6;
}

.buildreport .d:first-of-type {
  color: var(--signal);
}

.day {
  margin-bottom: 6px;
}

/* a past day of the current week: already eaten, read-only, visually parked.
   0.65 not lower: recipe names must stay AA-readable through the opacity */
.day.past {
  opacity: 0.65;
  filter: saturate(0.4);
}

.dsum-whisper .eaten {
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 1px 5px;
}

.meter {
  height: 5px;
  background: var(--panel-2);
  border-radius: 3px;
  margin-top: 5px;
  overflow: hidden;
}

.meter i {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--signal);
}

.slotgrid {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.slotrow {
  display: flex;
  align-items: center;
  /* tightened 2026-07-27: the gap and padding here were sized for a drop
     target with two trailing buttons. Both buttons and the drop target are
     gone, so this space now belongs to the recipe name. */
  gap: 6px;
  min-height: 52px;
  padding: 5px 6px 5px 8px;
  background: var(--panel);
  border: 1px dashed var(--line-strong);
  border-radius: 12px;
}

.slotrow .t {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  color: var(--dim);
  width: 26px;
  flex-shrink: 0;
}

.slotrow .stack {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.stackline {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* the meal itself: a button, because tapping it opens the recipe */
.slotrow .fill {
  flex: 1;
  min-width: 0;
  max-width: none;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 6px 8px;
  text-align: left;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel-2);
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.slotrow .fill:disabled {
  cursor: default;
  opacity: 0.85;
}

.slotrow .fill:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

/* SWITCH: one tap swaps the meal for another that fits the slot */
.slotrow .switchbtn {
  min-width: 40px;
  min-height: 44px;
  flex-shrink: 0;
  border: none;
  background: none;
  color: var(--dim);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  border-radius: 10px;
}

.slotrow .switchbtn:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

/* COOKED: one tap on the plan row, valid after the fact, for today and any
   past day. The recipe page's COOKED IT sat two screens deep and was pressed
   twice in ten weeks (parts audit, 2026-09-21); the confirmation has to live
   where the plan is read. Once tapped the row shows the cooked chip instead. */
.slotrow .cooktap {
  min-width: 56px;
  min-height: 44px;
  padding: 0 8px;
  flex-shrink: 0;
  border: 1px solid var(--signal);
  background: none;
  color: var(--signal);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  line-height: 1;
  cursor: pointer;
  border-radius: 10px;
}

/* a swipe already marked eaten keeps its button, quiet, so it can be undone */
.slotrow .cooktap.on {
  border-color: var(--line-strong);
  color: var(--dim);
}

/* the meal swipe reads as a meal row (2026-10-16), not as a greyed-out slot */
.slotrow.isout:has(.swipecard) {
  border-style: dashed;
  opacity: 1;
}

.slotrow .swipecard {
  text-decoration: none;
  color: inherit;
}

/* one tap for the whole day (2026-10-17) */
.daymeals .ateall {
  width: 100%;
  min-height: 44px;
  margin: 4px 0 8px;
  border: 1px solid var(--signal);
  background: none;
  color: var(--signal);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  border-radius: 12px;
  cursor: pointer;
}

/* the engine's reports, folded under the week (2026-10-16) */
.engineinfo {
  margin: 18px 0 8px;
}

.engineinfo > summary {
  cursor: pointer;
  list-style: none;
  padding: 8px 0;
  min-height: 44px;
  display: flex;
  align-items: center;
}

.slotrow .cooktap:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.slotrow .emptyslot {
  flex: 1;
  color: var(--dim);
  text-align: center;
  font-family: var(--mono);
}

.slotrow .outbtn {
  min-width: 44px;
  min-height: 44px;
  flex-shrink: 0;
  border: none;
  background: none;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  cursor: pointer;
  border-radius: 10px;
}

.slotrow .outbtn.on {
  color: var(--signal);
}

.slotrow .outbtn:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.slotrow.isout {
  border-style: solid;
  opacity: 0.75;
}

.slotrow .outslot {
  flex: 1;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 11px;
}

.tface {
  text-align: center;
  padding: 18px 0 10px;
  border: 1px dashed var(--line-strong);
  border-radius: 14px;
}

.tface.work {
  border-color: var(--signal);
  border-style: solid;
}

.tface.rest {
  border-color: var(--recover);
  border-style: solid;
}

.tphase {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--dim);
}

.tface.work .tphase {
  color: var(--signal);
}

.tface.rest .tphase {
  color: var(--recover);
}

.tclock {
  font-size: 56px;
  font-weight: 700;
  line-height: 1.2;
}

.tactions {
  display: flex;
  gap: 10px;
  margin-top: 10px;
}

.tactions button {
  flex: 1;
}

/* ---- screen-awake reason line (2026-07-27; the chip went with Cook Mode
   2026-08-19) — the recipe page still says WHY when it cannot hold the
   screen, because that failure used to be silent. */
.awakewhy {
  color: var(--dim);
  line-height: 1.5;
}

.tunerow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 10px 0 4px;
}

/* ---- recipe peek: the card a planned meal opens into (2026-07-27) ----
   Registered in tests/overlays.test.js: a full-screen layer that takes taps
   must always render its own way out. Here that is the ✕, plus a backdrop
   tap and Escape, none of them behind a conditional. */
.peek-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.62);
  padding: 12px;
  padding-bottom: max(12px, env(safe-area-inset-bottom));
}

.peek-card {
  width: 100%;
  max-width: 560px;
  max-height: 86vh;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  padding: 14px 14px 18px;
  -webkit-overflow-scrolling: touch;
}

.peek-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.peek-head h2 {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 19px;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.peek-close {
  min-width: 44px;
  min-height: 44px;
  flex-shrink: 0;
  border: none;
  background: none;
  color: var(--dim);
  font-size: 16px;
  cursor: pointer;
  border-radius: 10px;
}

.peek-close:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.peekmacros {
  margin-top: 2px;
  color: var(--dim);
}

.peekreceipt,
.receiptnote {
  border-left: 2px solid var(--line-strong);
  padding-left: 8px;
}

.peekactions {
  margin-top: 14px;
}

/* the moving parts. Each figure animates ONE group, because two moving
   groups on a 120x60 stick figure reads as noise rather than as a movement */
.fig-plank .f-limb {
  animation: fig-breathe 3.2s ease-in-out infinite;
}

.fig-sideplank .f-body {
  animation: fig-breathe 3.2s ease-in-out infinite;
  transform-origin: 30px 40px;
}

.fig-hollow .f-shake {
  animation: fig-breathe 2.4s ease-in-out infinite;
}

.fig-hipdip .f-hips {
  animation: fig-dip 2.4s ease-in-out infinite;
}

.fig-copenhagen .f-hips {
  animation: fig-dip 2.8s ease-in-out infinite;
}

.fig-crunch .f-fold {
  animation: fig-fold 2.6s ease-in-out infinite;
  transform-origin: 70px 48px;
}

.fig-reversecrunch .f-roll {
  animation: fig-roll 2.6s ease-in-out infinite;
  transform-origin: 66px 48px;
}

.fig-legraise .f-swing {
  animation: fig-swing 3.4s ease-in-out infinite;
  transform-origin: 64px 48px;
}

.fig-twist .f-rotate {
  animation: fig-twist 3s ease-in-out infinite;
  transform-origin: 60px 50px;
}

.fig-deadbug .f-alt-a,
.fig-flutter .f-alt-a,
.fig-bicycle .f-alt-a {
  animation: fig-alt 2.2s ease-in-out infinite;
}

.fig-deadbug .f-alt-b,
.fig-flutter .f-alt-b,
.fig-bicycle .f-alt-b {
  animation: fig-alt 2.2s ease-in-out infinite reverse;
}

@keyframes fig-breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.62;
  }
}

@keyframes fig-dip {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(7px);
  }
}

@keyframes fig-fold {
  0%,
  100% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(-22deg);
  }
}

@keyframes fig-roll {
  0%,
  100% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(-28deg);
  }
}

@keyframes fig-swing {
  0%,
  100% {
    transform: rotate(-58deg);
  }
  50% {
    transform: rotate(-4deg);
  }
}

@keyframes fig-twist {
  0%,
  100% {
    transform: rotate(-12deg);
  }
  50% {
    transform: rotate(12deg);
  }
}

@keyframes fig-alt {
  0%,
  100% {
    transform: translateY(-5px);
  }
  50% {
    transform: translateY(5px);
  }
}

/* a phone set to reduce motion gets the pose, not the movement */
@media (prefers-reduced-motion: reduce) {
  .corefig * {
    animation: none !important;
  }
}

/* the lead-in: the cue arrives BEFORE you are in position, which is the
   whole fix. Reading it mid-plank was the complaint. */
.tface.ready {
  border-color: var(--dim);
  border-style: solid;
}

.tface.ready .tphase {
  color: var(--dim);
}

/* ---- food safety guide (D3) ---- */

.foodsafety {
  margin-top: 18px;
}

.foodsafety summary {
  cursor: pointer;
}

.foodsafety .tablewrap {
  overflow-x: auto;
}

.safetytable {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.safetytable th,
.safetytable td {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line-strong);
  vertical-align: top;
}

.safetytable th {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  color: var(--dim);
}

.dangerlist {
  margin: 6px 0 10px;
  padding-left: 18px;
  font-size: 12px;
  color: var(--dim);
}

.dangerlist li {
  margin-bottom: 4px;
}

/* ---- undo toast (G3) ---- */

.toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  transform: translateX(-50%);
  z-index: 90;
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  padding: 10px 16px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
}

.toast-undo {
  min-height: 44px;
  border: none;
  background: none;
  color: var(--signal);
  font-family: var(--mono);
  letter-spacing: 0.1em;
  cursor: pointer;
}

/* ---- pantry freshness (D1) ---- */

.usesoon {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--recover);
  border: 1px solid var(--recover);
  border-radius: 6px;
  padding: 1px 5px;
  vertical-align: middle;
}

.q.expiring {
  color: var(--recover);
}

.usesoontile .d {
  color: var(--recover);
}

/* ---- in-app confirm modal (A2: replaces window.confirm) ---- */

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.modal {
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  padding: 18px;
  max-width: 420px;
  width: 100%;
}

.modal-msg {
  margin: 0 0 14px;
  line-height: 1.45;
}

.modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.modal-btn {
  min-height: 44px;
  padding: 0 18px;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: none;
  color: var(--dim);
  font-family: var(--mono);
  letter-spacing: 0.1em;
  cursor: pointer;
}

.modal-btn.ok {
  color: var(--signal);
  border-color: var(--signal);
}

.modal-btn:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

/* ---- weekly buffer snack ---- */

.buffer .bufferrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
  flex-wrap: wrap;
}

.buffer .bufcount {
  min-width: 24px;
  text-align: center;
  font-size: 16px;
}

/* ---- shopping list ---- */

.checkrow {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 8px 13px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}

.checkrow .tickarea {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 12px;
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  text-align: left;
  padding: 0;
  cursor: pointer;
}

.checkrow .tickarea:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.ownbtn {
  min-width: 44px;
  min-height: 44px;
  flex-shrink: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--recover);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  cursor: pointer;
}

.ownbtn:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.checkrow .box {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border: 1.5px solid var(--line-strong);
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--on-signal);
  font-size: 15px;
}

.checkrow.done .box {
  background: var(--signal);
  border-color: var(--signal);
}

.checkrow.done .food {
  color: var(--dim);
  text-decoration: line-through;
}

.checkrow .food {
  flex: 1;
  min-width: 0;
  font-weight: 600;
}

.checkrow .q {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  flex-shrink: 1;
  max-width: 38%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.checkrow.static {
  cursor: default;
}

/* STRICT LIST COLUMNS (David 2026-08-19: "literally make columns"). Line 1
   is box + food + the action buttons; line 2 is four fixed tracks — NEED
   (the recipes' summation) · BUY (packs × the store's pack) · $/unit ·
   TOTAL. The same tracks repeat in .colhead and in every row, and the
   action area is a FIXED 92px column, which is what keeps the tracks
   aligned when a row has one button and its neighbor has two. */
.colhead {
  display: grid;
  grid-template-columns: 1.35fr 1.5fr 0.85fr 0.75fr;
  gap: 6px;
  margin: 10px 13px 0 52px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  color: var(--dim);
}
.colhead .c {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.checkrow.listcols {
  display: grid;
  grid-template-columns: 1fr 92px;
  gap: 6px;
  align-items: center;
}
.checkrow.listcols .tickarea {
  display: grid;
  grid-template-columns: 26px 1fr;
  column-gap: 12px;
  align-items: center;
}
.checkrow.listcols .food {
  grid-column: 2;
}
/* the columns line spans the FULL row (ui-review F1: inside the tickarea it
   inherited the 92px button carve-out and 1fr collapsed to ~42px at 390px,
   truncating every TOTAL with cents; full-width gives each track ~66px) */
.checkrow.listcols .cols {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1.35fr 1.5fr 0.85fr 0.75fr;
  gap: 6px;
  padding-left: 39px;
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
}
.checkrow.listcols .cols .c {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.checkrow.listcols .rowbtns {
  display: flex;
  gap: 4px;
  justify-content: flex-end;
  flex-wrap: wrap;
}

.lowbtn {
  min-width: 64px;
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  cursor: pointer;
}

.lowbtn.on {
  border-color: var(--amber);
  color: var(--amber);
  background: rgba(255, 178, 36, 0.1);
}

.lowbtn:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.lockbtn.on {
  border-color: var(--amber);
  color: var(--amber);
  background: rgba(255, 178, 36, 0.1);
}

label.tile .k {
  display: block;
}

.dailynum {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  font-size: 18px;
  font-weight: 700;
  min-height: 44px;
  padding: 6px 10px;
}

.dailynum:focus {
  outline: none;
  border-color: var(--recover);
}

/* ---- forms ---- */

.token-form,
.actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.actions.wrap {
  flex-wrap: wrap;
}

.actions.wrap .primary {
  min-width: 0;
}

.tag.premium {
  background: rgba(255, 178, 36, 0.14);
  color: var(--amber);
}

.token-form input {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  font-family: var(--mono);
  /* never below 16px on an input — iOS Safari auto-zooms the viewport on focus */
  font-size: 16px;
  padding: 12px 10px;
}

.token-form input:focus {
  outline: none;
  border-color: var(--recover);
}

button.primary {
  min-height: 44px;
  background: rgba(61, 220, 132, 0.1);
  border: 1px solid var(--signal);
  color: var(--signal);
  font-family: var(--mono);
  font-size: 13px;
  border-radius: 8px;
  padding: 12px 16px;
  cursor: pointer;
}

button.primary:active {
  transform: scale(0.97);
}

button.primary:disabled,
button.secondary:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* secondary action: visually demoted next to .primary (e.g. FINISH SESSION
   beside REST — ending a workout must not look like the routine tap).
   Element-agnostic: anchors styled as buttons (FEELING OFF?) use it too. */
a.secondary,
button.secondary {
  min-height: 44px;
  background: var(--panel-2);
  border: 1px solid var(--line-strong);
  color: var(--text);
  font-family: var(--mono);
  font-size: 13px;
  border-radius: 8px;
  padding: 12px 16px;
  cursor: pointer;
}

button.secondary.arm {
  border-color: var(--amber);
  color: var(--amber);
}

button.secondary:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

/* daily counters: −/+ steppers flank the count (mis-tap recovery) */
.checkrow .tickarea:active {
  background: var(--panel-2);
}

.stepbtn {
  min-width: 52px;
  min-height: 44px;
  flex-shrink: 0;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: var(--panel-2);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 13px;
  cursor: pointer;
}

.stepbtn.plus {
  border-color: var(--signal);
  color: var(--signal);
  background: var(--signal-08);
}

.stepbtn:active {
  transform: scale(0.94);
}

.stepbtn:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

.checkrow.counter {
  cursor: default; /* only the flanking stepbtns are interactive */
}

.checkrow.counter .food {
  text-align: left;
}

.buildreport .redflag {
  color: var(--red);
}

.todaylist {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}

a.todayrow {
  text-decoration: none;
  color: var(--text);
}

.todayrow {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 8px 13px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
}

.todayrow .t {
  flex-shrink: 0;
  width: 34px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--dim);
}

.todayrow .n {
  flex: 1;
  font-size: 14px;
}

.todayrow .m {
  flex-shrink: 0;
  font-size: 12px;
  color: var(--dim);
}

/* camera-pantry scan (Task 12) */
.visuallyhidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.scanbtn {
  margin-bottom: 12px;
}

.scanerr {
  color: var(--red);
}

.scanreview {
  margin-bottom: 14px;
}

.scanreview .checkrow {
  min-height: 48px;
}

.scanreview input[type="checkbox"] {
  accent-color: var(--signal);
  width: 20px;
  height: 20px;
}

.scanreview .q {
  color: var(--dim);
  font-size: 12px;
}

.scanreview .actions {
  display: flex;
  gap: 10px;
  margin-top: 10px;
}

.checkrow.counter .countnum {
  margin-left: auto;
}

.countnum {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.02em;
  flex-shrink: 0;
}

.countnum small {
  font-size: 11px;
  font-weight: 400;
  color: var(--dim);
}

.counters {
  margin-top: 10px;
}

/* ---- remedies ---- */

.wrapchips {
  flex-wrap: wrap;
  overflow-x: visible;
  -webkit-mask-image: none;
  mask-image: none;
}

.protolist {
  margin: 0;
  padding: 0 4px;
  list-style: none;
}

.protolist li {
  padding: 8px 0;
  font-size: 14px;
  line-height: 1.5;
  border-bottom: 1px solid var(--line);
}

.protolist li::before {
  content: "· ";
  color: var(--signal);
}

a.secondary.linkbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  flex: 1;
}

a.linkbtn.remedy {
  border-color: var(--recover);
  color: var(--recover);
  background: rgba(76, 195, 255, 0.08);
  font-weight: 600;
}

a.linkbtn.remedy:active {
  transform: scale(0.98);
}

button.primary:focus-visible,
.chip:focus-visible,
.ask:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
}

/* the peek's COOK IT is an <a>, not a <button>: without this it renders
   left-aligned with the underline running through its <small> subline
   (ui-review F12) */
a.ask.linkbtn {
  text-align: center;
  text-decoration: none;
}

.hint {
  color: var(--dim);
  font-size: 12px;
  line-height: 1.5;
  margin: 8px 0 0;
}

.banner {
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 14px;
  font-family: var(--mono);
  font-size: 13px;
  border: 1px solid var(--line);
}

.banner.red {
  background: var(--red-bg);
  border-color: var(--red);
  color: var(--red);
}

.empty {
  text-align: center;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.7;
  padding: 40px 16px;
}

/* ---- tab bar ---- */

.tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(12, 15, 17, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--line);
  display: flex;
  padding: 10px 6px calc(10px + env(safe-area-inset-bottom));
  z-index: 40;
}

.tabbar a {
  flex: 1;
  text-align: center;
  text-decoration: none;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.tabbar a .i {
  display: block;
  font-size: 16px;
  margin-bottom: 4px;
}

.tabbar a.active {
  color: var(--signal);
}

/* staggered console boot for view content */

@media (prefers-reduced-motion: no-preference) {
  .view > * {
    animation: rise 0.28s ease-out both;
  }

  .view > *:nth-child(2) {
    animation-delay: 0.04s;
  }

  .view > *:nth-child(3) {
    animation-delay: 0.08s;
  }

  .view > *:nth-child(4) {
    animation-delay: 0.12s;
  }

  .view > *:nth-child(5) {
    animation-delay: 0.16s;
  }

  @keyframes rise {
    from {
      opacity: 0;
      transform: translateY(6px);
    }

    to {
      opacity: 1;
      transform: none;
    }
  }
}

/* Chat onboarder */
.chat-scroll {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 8px 0;
}
.bubble {
  max-width: 82%;
  padding: 10px 12px;
  border-radius: 14px;
  line-height: 1.35;
  white-space: pre-wrap;
}
.bubble.assistant {
  align-self: flex-start;
  background: var(--panel, #16181d);
  border: 1px solid var(--line, #262a31);
  border-bottom-left-radius: 4px;
}
.bubble.user {
  align-self: flex-end;
  background: var(--accent, #6fcf7f);
  color: #0c0e12;
  border-bottom-right-radius: 4px;
}
.bubble.dim {
  opacity: 0.5;
}
.chat-input {
  margin-top: 8px;
}

/* Portion-aware cooking banners */
.tile.portion .d {
  margin-top: 2px;
  line-height: 1.35;
}
.tile.portion.batch {
  border-left: 3px solid var(--warn, #e0a34a);
}
.tile.portion.single {
  border-left: 3px solid var(--accent, #6fcf7f);
}
.tile.portion.bowl {
  border-left: 3px solid var(--accent, #6fcf7f);
}
.rotation .offshelf {
  margin-top: 8px;
}
/* COOK FOR N (Mise 2.0, D-03): the count and its buttons, thumb-sized */
.tile.cookfor {
  margin-top: 10px;
}
.cookfor-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.cookfor-btn {
  min-width: 44px;
  min-height: 44px;
  border-radius: 22px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: inherit;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}
.cookfor-btn:disabled {
  opacity: 0.4;
}
.cookfor-n {
  min-width: 2.5em;
  text-align: center;
  font-size: 22px;
  font-weight: 600;
}
/* List/pantry additions */
.q.num.nopr {
  opacity: 0.4;
  font-style: italic;
}
.rmbtn {
  background: none;
  border: none;
  color: var(--muted, #7a8290);
  font-size: 1rem;
  padding: 4px 8px;
  cursor: pointer;
}
.rmbtn:hover {
  color: var(--bad, #e06a6a);
}
button.linktext {
  background: none;
  border: none;
  color: var(--accent, #6fcf7f);
  padding: 0;
  font: inherit;
  cursor: pointer;
  text-align: left;
}

/* ---- guided tour (docs/tutorial-design.md v3) ---- */

/* full-screen layer; children carry the visuals. touch/wheel are blocked in
   the component so the page behind never scrolls out from under a cutout */
.tour {
  position: fixed;
  inset: 0;
  z-index: 120;
}

/* uniform dim while a step's target is still being located: keeps the
   backdrop steady so an invisible auto-skip never flashes the page bright */
.tour-dim {
  position: fixed;
  inset: 0;
  background: rgba(4, 6, 7, 0.78);
  pointer-events: none;
}

/* the spotlight: one element whose oversized shadow dims everything else */
.tour-cutout {
  position: fixed;
  border-radius: 14px;
  box-shadow: 0 0 0 9999px rgba(4, 6, 7, 0.78);
  border: 1px solid var(--signal);
  pointer-events: none;
  transition:
    top 0.25s ease,
    left 0.25s ease,
    width 0.25s ease,
    height 0.25s ease;
}

.tour-card {
  position: fixed;
  left: 16px;
  right: 16px;
  max-width: 480px;
  margin: 0 auto;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  padding: 14px 16px 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
  max-height: min(60vh, 420px);
  overflow-y: auto;
}

/* tall target with no room above or below: card sits on the bottom edge
   (the cutout is clipped in the component so they never intersect) */
.tour-card.pinned {
  bottom: calc(16px + env(safe-area-inset-bottom));
}

.tour-card:focus {
  outline: none;
}

.tour-dots {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--dim);
  letter-spacing: 0.16em;
}

.tour-title {
  font-size: 16px;
  font-weight: 800;
  margin-top: 4px;
}

.tour-text {
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  margin-top: 6px;
}

.tour-btns {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
}

.tour-btns button {
  min-height: 44px;
  min-width: 64px;
}

/* END TOUR is destructive: parked far left, away from BACK/NEXT thumbs */
.tour-btns .endbtn {
  margin-right: auto;
}

.tour-offer {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(96px + env(safe-area-inset-bottom));
  max-width: 480px;
  margin: 0 auto;
  z-index: 110;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  padding: 14px 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
}

/* the flex block-title suppresses the native disclosure triangle, so the
   summary needs its own open/closed cue or it reads as a dead header */
.whatlist > summary::before {
  content: "▸";
  color: var(--signal);
}

.whatlist[open] > summary::before {
  content: "▾";
}

.whatlist .whatitem {
  font-size: 12.5px;
  line-height: 1.45;
  margin-top: 6px;
}

.whatlist .whatitem b {
  font-weight: 700;
}

/* ---- tables (shared meals, docs/tables-design.md) ---- */

.tablecard.skipped {
  opacity: 0.6;
}

.tableform input[type="text"],
.tableform input:not([type]),
.tableform select {
  width: 100%;
  margin: 6px 0;
  min-height: 44px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 0 10px;
  font-family: var(--sans);
  font-size: 16px;
}

.tableform .row {
  gap: 8px;
}

.tableform .row select {
  flex: 1;
}

.tableform .row {
  flex-wrap: wrap;
  gap: 8px;
}

.tableform .row .tickarea {
  flex: 1 1 160px;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  cursor: pointer;
}

.tableform .row .tickarea:focus-within {
  outline: 2px solid var(--recover);
  outline-offset: 2px;
  border-radius: 8px;
}

.seatservings {
  width: 72px;
  min-height: 44px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  text-align: center;
}

/* AI features (menu scan, plate tailoring, dinner discussion) */
.plateline {
  display: block;
  margin-top: 2px;
}

/* redflag was only styled inside .buildreport; table cards use it too
   (conflicts, collisions, tailoring errors) */
.tablecard .redflag {
  color: var(--red);
}

/* Plan scoreboard (David's layout pick, 2026-07-23): the week as seven
   one-line days, meters always visible, native <details> accordion */
details.dayrow {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  margin-bottom: 8px;
  overflow: hidden;
}

details.dayrow summary {
  list-style: none;
  display: grid;
  grid-template-columns: 46px 1fr 52px;
  gap: 10px;
  align-items: center;
  padding: 10px 12px;
  min-height: 56px;
  cursor: pointer;
}

details.dayrow summary::-webkit-details-marker {
  display: none;
}

details.dayrow summary:focus-visible {
  outline: 2px solid var(--recover);
  outline-offset: -2px;
  border-radius: 14px;
}

.dsum-day {
  font-weight: 700;
  font-size: 13px;
  line-height: 1.25;
}

.dsum-day small {
  display: block;
  color: var(--dim);
  font-weight: 400;
}

.dsum-meters {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.dsum-meters .mline {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dsum-meters .mline b {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 600;
  color: var(--dim);
  min-width: 84px;
  text-align: right;
  white-space: nowrap;
}

.dsum-meters .meter {
  flex: 1;
  margin-top: 0;
}

.dsum-meters .mline.warn .meter i {
  background: var(--amber);
}

.dsum-whisper {
  display: block;
  color: var(--dim);
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dsum-status {
  text-align: right;
  font-size: 13px;
  font-family: var(--mono);
}

.dsum-status.ok {
  color: var(--signal);
}

.dsum-status.shortfall {
  color: var(--amber);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.daymeals {
  border-top: 1px solid var(--line);
  padding: 8px 10px 10px;
}

.saylabel {
  align-self: center;
  min-width: 64px;
}

/* Receipt review states (David, 2026-07-26: "i am unable to check any of the
   boxes ... i cannot tell"). The rows were toggling correctly, but a kept line
   drew its ✓ in --on-signal on an UNFILLED box, i.e. dark on dark, and an
   excluded line drew nothing: both states looked identical. A kept line now
   fills its box like every other checked control in the app, and an excluded
   line visibly drops out. */
.checkrow.picked .box {
  background: var(--signal);
  border-color: var(--signal);
}
.checkrow.off {
  opacity: 0.4;
}
.checkrow.off .food {
  text-decoration: line-through;
}

/* The tour's unconditional way out. .tour is fixed inset:0 and eats every
   tap, and its card only renders once a step's target is measured, so a step
   that never resolves left an invisible full-screen blocker with nothing to
   press (David, 2026-07-26: "none of the buttons work ... i can scroll"). */
.tour-escape {
  position: fixed;
  top: calc(10px + env(safe-area-inset-top));
  right: 12px;
  z-index: 130;
  padding: 10px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--panel);
  color: var(--fg);
  font: 600 12px/1 var(--mono);
}

/* Occasions: a dated override the generator hands off to. The disclaimer box
   is deliberately loud — a colonoscopy prep that gets half-read is a wasted
   procedure, and the clinic's own letter always outranks this app. */
.warnbox {
  margin: 10px 0;
  padding: 10px 12px;
  border-left: 3px solid var(--warn, #e0a34a);
  border-radius: 10px;
  background: rgba(224, 163, 74, 0.09);
  line-height: 1.4;
}
.warnbox p {
  margin: 0 0 8px;
}
.slot.muted {
  opacity: 0.55;
}
/* the running-occasion banner on Plan: it must be impossible to miss on the
   day it matters, and invisible every other day */
.occbanner {
  margin: 8px 0 12px;
  padding: 10px 12px;
  border-left: 3px solid var(--warn, #e0a34a);
  border-radius: 10px;
  background: rgba(224, 163, 74, 0.12);
  line-height: 1.4;
}
.occbanner b {
  display: block;
  font: 600 12px/1.4 var(--mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Multi-shot receipt capture: a long till roll needs several overlapping
   photos, and nothing is read until the whole strip is collected. */
.shotstrip {
  margin: 8px 0;
}
.shotstrip .actions {
  margin-top: 6px;
}

/* Kitchen equipment picker (SYS). Big touch targets: this gets tapped once,
   standing in a dorm room, on a phone. */
.gear-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.15rem;
  margin: 0.5rem 0;
}
@media (min-width: 30rem) {
  .gear-grid {
    grid-template-columns: 1fr 1fr;
  }
}
.gear-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.55rem 0.4rem;
  border-radius: 0.4rem;
  cursor: pointer;
  min-height: 2.75rem;
}
.gear-item:active {
  background: rgba(127, 127, 127, 0.12);
}
.gear-item input {
  width: 1.15rem;
  height: 1.15rem;
  flex: 0 0 auto;
  margin-top: 0.1rem;
}
.gear-item small {
  display: block;
}

/* KROGER PUSH LOG (David, 2026-08-25: "I'm logged in to my account on the Pay
   Less app, but I see nothing"). Kroger's cart cannot be read back, so this is
   the only record of what was sent. Collapsed by default — it is a diagnostic,
   not something to read every shop. */
.pushlog {
  margin-top: 0.6rem;
  border-top: 1px solid var(--line);
  padding-top: 0.5rem;
}
.pushlog > summary {
  cursor: pointer;
  font-size: 0.85rem;
  color: var(--dim);
  padding: 0.35rem 0;
}
.pushrow {
  border-left: 2px solid var(--line);
  padding-left: 0.6rem;
  margin: 0.4rem 0;
}
.pushlog .mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.72rem;
  word-break: break-all;
}

/* WHO'S EATING (Plan tab, brigade days; 2026-09-05) */
.whoeats {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 8px;
  margin: 0 0 8px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
}

.whoeats .t {
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.whoeats .names {
  flex: 1;
  min-width: 0;
  color: var(--text);
}

.whoeats .guestchip .linktext {
  padding: 0 6px;
  min-height: 28px;
}

.whoeats .guestpanel {
  flex-basis: 100%;
  border: 1px dashed var(--line-strong);
  border-radius: 12px;
  padding: 8px 10px;
}

.whoeats .guestpanel .chips {
  padding-bottom: 6px;
}

/* named-recipe pickers in the brigade form: wrap instead of scrolling one row */
.slotonly summary {
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.chips.wrapchips {
  flex-wrap: wrap;
  overflow: visible;
  -webkit-mask-image: none;
  mask-image: none;
}

/* SAY WHAT YOU HAVE (pantry dictation, 2026-09-06) */
.saywhat summary {
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.saywhat textarea {
  width: 100%;
  box-sizing: border-box;
  min-height: 96px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  resize: vertical;
}

/* THE SHELF CHECK card (planner) and the USE WHAT'S LEFT picks (2026-09-07) */
.shelfcheck .shelfrows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
}
.shelfrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.shelfrow.done {
  opacity: 0.6;
}
.shelfrow .rowbtns {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.shelfrow .qtyin {
  min-width: 12ch;
  font: inherit;
  padding: 6px 8px;
}
/* the release train's sandbox strip: on every screen of the Mise NEXT build */
.banner.sandbox {
  background: #ff9500;
  color: #0c0f11;
  font-weight: 600;
}

/* house money forms (zermatt, 2026-10-05): stacked fields, thumb-sized */
.money-form {
  display: grid;
  gap: 8px;
  margin-top: 8px;
}
.money-form label {
  display: grid;
  gap: 4px;
  font-size: 0.9rem;
}
.money-form input,
.money-form select {
  width: 100%;
  min-height: 44px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 0 10px;
  font-family: var(--sans);
  font-size: 16px;
  color-scheme: dark;
}
.money-recent .row {
  align-items: center;
}

/* release changelog in SYS (zermatt, 2026-10-05) */
.changelog ul {
  margin: 4px 0 10px 18px;
  padding: 0;
}

/* WALK THE FRIDGE (2026-10-18): the frames a walk scanned, small and in a row */
.thumbs {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  margin: 6px 0;
}
.thumbs .thumb {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: 6px;
  flex: none;
}

/* the passkey box (David, 2026-10-18): full width so the digits show, OPEN
   underneath instead of beside it squeezing the box to nothing */
.pin-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pin-input {
  width: 100%;
  min-height: 52px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  font-family: var(--mono);
  font-size: 24px;
  letter-spacing: 0.3em;
  text-align: center;
  padding: 10px;
}

.pin-input:focus {
  outline: none;
  border-color: var(--recover);
}

/* ---- phone audit fixes (2026-10-18) ---- */
/* a wrapping chip row lets a long recipe name break instead of pushing the
   page wider than the phone (the kitchen-rule form scrolled sideways and hid
   the Fri and Sat cook nights) */
.wrapchips .chip {
  flex-shrink: 1;
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: left;
}

/* a named recipe someone at the table cannot eat, or that is not checked
   yet (2.0, I-08): greyed with the reason under the name */
.chip.blocked {
  opacity: 0.55;
  border-style: dashed;
}
.chip.blocked .why {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  text-transform: none;
  letter-spacing: 0;
}

/* list cells wrap instead of cutting the amount or price to "1.04 lb weig…" */
.checkrow.listcols .cols .c {
  white-space: normal;
  overflow: visible;
  overflow-wrap: anywhere;
}

/* a button's second line sits under its label ("PICK DIFFERENT MEALS" then
   "swaps meals you have not bought or cooked yet"), never run into it */
button.secondary small,
button.primary small,
.actions button small {
  display: block;
  font-weight: 400;
  margin-top: 3px;
  opacity: 0.8;
}

/* never below 16px in a text box: iOS Safari zooms the page on focus */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]),
:root select,
:root textarea {
  font-size: 16px;
}

/* the pantry's ENOUGH FOR THE WEEK rows: name above its detail, HOW MUCH? on
   its own line, nothing past the right edge */
.shelfrow {
  min-width: 0;
  overflow-wrap: anywhere;
}
.shelfrow > * {
  min-width: 0;
}

/* a person row on People and on a guest's meals: label left, detail right */
.personrow {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  padding: 8px 0;
  cursor: pointer;
}
.personpanel {
  padding: 8px 0 12px;
}

/* the Settings rows' dropdowns: styled, so the 16px floor holds (an unstyled
   WebKit dropdown keeps its own 13px system font) */
.row select {
  font-size: 16px;
  min-height: 44px;
  max-width: 60%;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 6px 8px;
}

/* three boxes in one row (family, house, state) wrap instead of squeezing
   each to 84px */
.token-form {
  flex-wrap: wrap;
}
.token-form input {
  flex: 1 1 120px;
}

/* the buffer snack's minus and plus: a thumb-sized target, like the week
   arrows (they were 23x18) */
button.wk:not(.weeknav .wk) {
  min-width: 44px;
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
}
.pin-input::placeholder {
  letter-spacing: normal;
  font-size: 16px;
}

/* after the 16px floor above, which outranks .pin-input on specificity: the
   passkey digits stay big (Tribunal Engineer, loop 1) */
input.pin-input {
  font-size: 24px;
}
/* the kitchen-rule form's slot dropdown sits beside a date: no 60% cap */
.tableform .row select {
  max-width: none;
}

/* room under the last control for the floating suggest button (it covered
   the List's ADD) */
.view {
  padding-bottom: calc(140px + env(safe-area-inset-bottom));
}
/* a unit price reads whole ("$0.49/lb"), and the stale-price mark stays on
   its total */
.checkrow.listcols .cols .c:nth-child(3),
.checkrow.listcols .cols .c:nth-child(4) {
  white-space: nowrap;
}

/* the kitchen rule's CANCEL / SAVE stay on screen above the tab bar while
   the form scrolls (Mise 2.0, A-13: SAVE sat 1,300 px down on an 844 px phone) */
.sticky-save {
  position: sticky;
  bottom: calc(80px + env(safe-area-inset-bottom));
  z-index: 30;
  margin: 12px -12px -12px;
  padding: 10px 12px;
  background: rgba(12, 15, 17, 0.92);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--line);
}

/* the comma-separated boxes (anything else to avoid, eaten too much,
   dislikes, stores) are full-width, thumb-height fields, never a bare
   203 x 24 box: the avoid box is the one that matters most for safety
   (Mise 2.0, A-04 / A-21) */
input[aria-label$="comma separated"] {
  display: block;
  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
  min-height: 44px;
  margin: 8px 0;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.06);
  color: inherit;
}

/* the guest's login name sits in the passkey column at full width
   (Mise 2.0, A-05: "your name, e.g" was cut in a 160 px box) */
.pin-form input:not(.pin-input) {
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  padding: 12px 10px;
}

/* .token-form's display: flex outranks the hidden attribute, so a hidden
   form row still showed (Mise 2.0, A-12: a guest was asked family, house
   and state) */
.token-form[hidden] {
  display: none;
}

/* Plan's three actions stack full width at phone size: side by side, SET MY
   WEEK's subtitle ran one word a line and ADD A RECIPE's label ran into its
   own subtitle (Mise 2.0, I-25, Tribunal Usability) */
.actions.planacts {
  flex-direction: column;
  align-items: stretch;
}
.actions.planacts > * {
  width: 100%;
  box-sizing: border-box;
}
.linkbtn small {
  display: block;
  font-weight: 400;
  margin-top: 3px;
  opacity: 0.8;
}

/* THE $15 FLAG (Mise 2.0, I-09): its own full-width line under the row's
   columns, in words, so it reads at 390 px without a tap */
.checkrow.listcols .priceflag {
  grid-column: 1 / -1;
  margin: 4px 0 0 39px;
  padding: 4px 8px;
  border-left: 3px solid var(--warn, #e0a34a);
  border-radius: 6px;
  background: rgba(224, 163, 74, 0.09);
  color: var(--text);
  font-size: 12px;
  line-height: 1.4;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* CHECK YOU HAVE THESE (Mise 2.0, I-10): two answer buttons side by side,
   each a full 44 px target */
.checkfirst {
  margin-bottom: 12px;
}
.checkrow.listcols.checkfirstrow {
  grid-template-columns: 1fr auto;
  cursor: default;
}
.checkrow.listcols.checkfirstrow .rowbtns {
  flex-wrap: nowrap;
}
.checkrow.listcols.checkfirstrow .ownbtn {
  padding: 0 10px;
}

/* meal B's lines under the meal (Mise 1.96): what Sunday preps, and the
   night's meat; outside the meal button, which clamps to two lines */
.mealbline {
  margin: 0 0 0 4px;
  font-size: 11.5px;
}

/* a warning chip and the result of SET MY WEEK on the Plan tab (shrike 2026-10-25) */
.seatclash {
  color: var(--amber);
}

/* tap targets under 44px, found at phone width (shrike 2026-10-25): People
   rows, the folded Settings and Plan summaries, the kitchen rule's own
   selects and fields, the weekly budget box */
.personrow {
  min-height: 44px;
}
details.tile > summary.k,
.engineinfo > summary {
  min-height: 44px;
  display: flex;
  align-items: center;
}
.tableform select,
.tableform input[type="date"],
.tableform input[type="number"],
label.row input[type="number"],
label.row select,
.tile select,
.tile input[type="number"] {
  min-height: 44px;
  box-sizing: border-box;
  font-size: 16px;
}
.tableform input[type="number"],
label.row input[type="number"],
.tile input[type="number"] {
  width: 84px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--text);
  padding: 0 10px;
}
:root select {
  min-height: 44px;
  height: 44px;
}

/* shrike item 19 (10/25), the rest */
/* the peek's amounts wrap instead of cutting off ("4.82 lb (2187.5 ...") */
.checkrow.static .q {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  text-align: right;
  max-width: 48%;
  overflow-wrap: anywhere;
}
/* who cooks, on its own line under the meal name, never clipped by the
   name's two-line clamp */
.chipbody .cookchip {
  font-size: 10.5px;
  align-self: flex-start;
  white-space: normal;
}
/* a plain text box in a row (Settings: Family) is a 44px target */
.row > input:not([type="checkbox"]):not([type="radio"]):not([type="date"]):not([type="number"]) {
  min-height: 44px;
  box-sizing: border-box;
  font-size: 16px;
}
/* a checkbox's whole label is the target */
label.checkline {
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
label.checkline input[type="checkbox"] {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
/* "scan the receipt" is a button, not a 14px link */
.receiptbtn {
  margin-top: 6px;
}
/* a guest's own requested nights on the Add to a dinner chips (shrike item 20) */
.chip.asked {
  border-style: dashed;
  border-color: var(--signal);
}
