:root {
  --bg: #12121a;
  --surface: #1b1b26;
  --surface-2: #232331;
  --border: #33334a;
  --text: #f1f0f7;
  --text-muted: #a3a3b8;
  --violet: #8b5cf6;
  --green: #22c55e;
  --sky: #38bdf8;
  --danger: #f87171;
  --warning: #f59e0b;
  --radius: 14px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  min-height: 100dvh;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  padding-top: var(--safe-top);
  padding-bottom: var(--safe-bottom);
}

#app {
  flex: 1;
  display: flex;
  flex-direction: column;
  max-width: 640px;
  width: 100%;
  margin: 0 auto;
  padding: 20px 18px 40px;
  position: relative;
}

h1, h2, h3 { line-height: 1.2; margin: 0 0 6px; }
h1 { font-size: 1.9rem; }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.02rem; color: var(--text); margin-top: 22px; }
p { line-height: 1.5; }
a { color: var(--sky); }

.muted { color: var(--text-muted); font-weight: 400; }

/* ---------- Welcome ---------- */
.screen.welcome {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: 18px;
}

.brand-mark {
  width: 72px;
  height: 72px;
  border-radius: 20px;
  background: conic-gradient(from 180deg, var(--violet), var(--sky), var(--green), var(--violet));
  margin: 0 auto 14px;
}

.tagline { color: var(--sky); font-weight: 600; margin-top: 0; }
.lede { color: var(--text-muted); max-width: 420px; }

.actions { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 320px; }

/* ---------- Buttons ---------- */
.btn {
  border: none;
  border-radius: 999px;
  padding: 14px 22px;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.08s ease, opacity 0.15s ease;
}
.btn:active { transform: scale(0.97); }

.btn-primary { background: linear-gradient(135deg, var(--violet), var(--sky)); color: #fff; }
.btn-secondary { background: var(--surface-2); color: var(--text); }
.btn-outline { background: transparent; color: var(--sky); border: 1px solid var(--border); }

.btn-icon {
  background: var(--surface-2);
  border: none;
  color: var(--text-muted);
  border-radius: 50%;
  width: 34px;
  height: 34px;
  cursor: pointer;
  font-size: 1rem;
}

/* ---------- Intake wizard ---------- */
.screen.intake { display: flex; flex-direction: column; flex: 1; }

.progress {
  display: flex;
  justify-content: space-between;
  margin-bottom: 24px;
  gap: 4px;
}
.progress-step {
  flex: 1;
  text-align: center;
  font-size: 0.72rem;
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.progress-step span {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--text-muted);
}
.progress-step.done span { background: var(--green); color: #062b13; }
.progress-step.current span { background: var(--violet); color: #fff; }
.progress-step.current { color: var(--text); }

.step-body { flex: 1; }
.hint { color: var(--text-muted); font-size: 0.92rem; margin-top: -2px; }

/* Round 14 fix: min-width: 0 overrides a flex item's default min-width:auto,
   which otherwise refuses to shrink below its content's own min-content
   size. Found while visually verifying this round's new calorie-override
   row on a real mobile viewport: a <select> with a long option string (e.g.
   member-satiety's "Strongly prefer the most filling meals, even over small
   price differences", or member-activity's longest option) was forcing
   itself — and every ancestor up through .field and .member-row-fields —
   wider than the actual 390px phone viewport, silently pushing later
   content off the right edge instead of wrapping or truncating. This was
   already present before this round (those long select options date back
   to Round 9/10/13); it just hadn't been visually caught on a real narrow
   viewport until this round's own new field-inline row made the resulting
   clipping obvious in a screenshot. width: 100% + min-width: 0 on every
   .field input/select/textarea, plus min-width: 0 on .field and
   .member-row-fields below, is the standard fix: it lets these controls
   (and the long text inside a <select>, which the browser already
   ellipsizes on overflow) shrink to fit their real container instead of
   forcing that container wider than the viewport. */
.field { display: flex; flex-direction: column; gap: 6px; margin: 14px 0; font-size: 0.9rem; color: var(--text-muted); min-width: 0; }
.field input, .field textarea, .field select {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  color: var(--text);
  font-size: 1rem;
  width: 100%;
  min-width: 0;
}
.field textarea { resize: vertical; font-family: inherit; }
.field select { appearance: auto; }

.link-btn {
  background: none;
  border: none;
  color: var(--sky);
  font-size: 0.8rem;
  padding: 0;
  margin: -4px 0 4px;
  text-align: left;
  cursor: pointer;
  text-decoration: underline;
  align-self: flex-start;
}

.member-list { display: flex; flex-direction: column; gap: 8px; }
.member-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 4px 14px;
  background: var(--surface);
}
.member-row-fields { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.member-row .field { margin: 8px 0; }
.member-row .btn-icon { margin-top: 12px; }

/* Round 10: per-person dietary needs (restrictions/allergies/dislikes) —
   each person's block keeps its own two check-grids (a CSS grid) and two
   free-text fields as SIBLINGS rather than mixed together inside one grid
   fieldset, since a <p>/<label class="field"> dropped in among check-grid's
   grid-item children got auto-placed into the 2-column grid track right
   alongside a checkbox, which could visually overlap adjacent rows. */
.member-dietary-block {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  background: var(--surface);
}
.member-dietary-block h3 { margin-top: 0; }
.member-dietary-block .field { margin: 10px 0; }

.check-grid {
  border: none;
  padding: 0;
  margin: 16px 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.check-grid legend { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 8px; grid-column: 1 / -1; }
.check-item {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 0.9rem;
}
.check-item input { accent-color: var(--violet); width: 18px; height: 18px; }
.check-item-disabled { opacity: 0.45; }

/* Round 11: the "blacklist" block on the dietary step — see app.js's
   renderBlacklistBlock. Its own bordered box (like .member-dietary-block)
   so it reads as a distinct sub-section within a member's card rather than
   blurring into the restrictions/allergies fieldsets above it; the two
   <details> panels keep the long ingredient/product checkbox lists out of
   the way until opened. */
.blacklist-block {
  border: 1px dashed var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  margin: 14px 0 0;
}
.blacklist-block legend { font-weight: 600; padding: 0 4px; }
.blacklist-block .hint { margin-top: 4px; }
.blacklist-block details { margin: 10px 0; }
.blacklist-block summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.88rem;
  padding: 8px 4px;
}
/* Round 12: redesigned on direct request — single column (rather than the
   2-3 column grid every other checklist on this step uses) reads better
   once a search box narrows the list to a handful of matches, and scoping
   the override to .blacklist-block specifically leaves the restrictions/
   allergies/cuisine grids elsewhere on this step untouched. */
.blacklist-block .check-grid { max-height: 260px; overflow-y: auto; margin: 8px 0; grid-template-columns: 1fr; }
.blacklist-search {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 0.88rem;
  margin: 0 0 8px;
}
.blacklist-block .check-item-hidden { display: none; }
.blacklist-block .check-grid-empty {
  color: var(--text-muted);
  font-size: 0.85rem;
  padding: 8px 4px;
}
.blacklist-selected-summary {
  color: var(--text-muted);
  font-size: 0.8rem;
  margin: 6px 0 0;
}
.check-item-disabled input { cursor: not-allowed; }

/* Round 11: a prominent, always-visible selected/remaining counter for a
   capped multi-select (currently just the cuisine step) — previously this
   count was buried in a paragraph of hint text, which a user found easy to
   miss until they'd already hit the cap. */
.selection-counter {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 0.85rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  margin: 10px 0;
}
.selection-counter strong { color: var(--violet); font-size: 0.95rem; }
.selection-counter span { color: var(--text-muted); }
.selection-counter-full strong { color: var(--sky); }

/* Round 11: a prominent callout box, used to make sure a fact that matters
   a lot (e.g. "this applies to your whole household, not just this person")
   doesn't get lost as just another sentence inside a long paragraph of hint
   text — a user asked for this specifically after the household-wide-effect
   note nearly went unnoticed inside the dietary-needs hint text. */
.callout {
  background: rgba(139, 92, 246, 0.12);
  border: 1px solid rgba(139, 92, 246, 0.4);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 10px 0 16px;
  font-size: 0.82rem;
  line-height: 1.5;
}
.callout strong { color: var(--violet); }

/* Round 11: "Add your own constraint" form on the Health conditions step. */
.custom-constraint-form { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
.custom-constraint-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.custom-constraint-row .field { flex: 1 1 160px; min-width: 140px; }
.custom-constraint-list { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
/* Round 11: export/import links on the welcome screen. */
.data-actions { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-top: 14px; }

.custom-constraint-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 0.82rem;
}

.conditions-suggestions { margin-top: 20px; display: flex; flex-direction: column; gap: 10px; }
.adjustment-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 0.9rem;
}
.adjustment-item .check-item { background: none; border: none; padding: 0; align-items: flex-start; }
.adjustment-item-accepted { border-color: var(--violet); }
.adjustment-item-none { color: var(--text-muted); }
.adjustment-value-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 8px 0 0 26px;
  flex-wrap: wrap;
}
.adjustment-value-input {
  width: 80px;
  padding: 6px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 0.9rem;
}
/* Round 12: the long sourced explanation for each suggested adjustment is
   tucked behind a "Why?" toggle so the short summary sentence above it is
   what's visible at a glance (screenshot 3). */
.adjustment-why { margin-top: 4px; }
.adjustment-why summary {
  cursor: pointer;
  color: var(--violet);
  font-size: 0.82rem;
  font-weight: 600;
}
.adjustment-why .muted { display: block; margin-top: 4px; }
.btn-link {
  background: none;
  border: none;
  color: var(--sky);
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0;
  text-decoration: underline;
}

.step-nav { display: flex; justify-content: space-between; gap: 12px; margin-top: 24px; }
.step-nav .btn { flex: 1; }

/* ---------- Results ---------- */
.screen.results { display: flex; flex-direction: column; gap: 4px; }
.results-header { display: flex; justify-content: space-between; align-items: center; }

.supermarket-tabs { display: flex; gap: 8px; overflow-x: auto; padding: 10px 0 4px; }
.chip {
  flex: none;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: 999px;
  padding: 8px 14px;
  font-size: 0.85rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
}
.chip-active { background: var(--violet); color: #fff; border-color: var(--violet); }
.chip-disabled { opacity: 0.55; }
.chip .soon { font-size: 0.65rem; text-transform: uppercase; background: rgba(255,255,255,0.15); padding: 2px 6px; border-radius: 999px; }

.cost-line { margin: 10px 0 6px; }
.cost-bar { height: 8px; background: var(--surface-2); border-radius: 999px; overflow: hidden; margin-bottom: 14px; }
.cost-bar-fill { height: 100%; background: linear-gradient(90deg, var(--green), var(--sky)); }
.cost-bar-fill.over { background: linear-gradient(90deg, #f59e0b, var(--danger)); }

.guideline-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; margin: 10px 0 16px; }
.guideline-badge {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  text-align: center;
}
.guideline-badge .pct { display: block; font-size: 1.1rem; font-weight: 700; }
.guideline-badge .label { display: block; font-size: 0.72rem; color: var(--text-muted); margin-top: 2px; }
.guideline-badge.met .pct { color: var(--green); }
.guideline-badge.under .pct { color: #f59e0b; }

/* Round 16: "compliance-badge pills made clickable to the nutrient-detail
   popup" — a real hover/focus affordance so a badge reads as something you
   can act on, not just a static number. */
.guideline-badge-clickable { cursor: pointer; }
.guideline-badge-clickable:hover, .guideline-badge-clickable:focus-visible { border-color: var(--violet); outline: none; }

/* Brief highlight flash on a Detailed Nutrient Targets card jumped to from
   a compliance badge above, so it's obvious which card just got scrolled
   into view. */
.nt-highlight-flash { animation: nt-flash 1.8s ease-out; }
@keyframes nt-flash {
  0% { box-shadow: 0 0 0 3px var(--violet); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.warnings { background: var(--surface); border: 1px solid var(--border); border-left: 3px solid #f59e0b; border-radius: 10px; padding: 12px 14px; font-size: 0.85rem; color: var(--text-muted); margin: 10px 0; }
.warnings li { margin-bottom: 4px; }

/* Round 12: the local-only nutrition history log (see app.js's
   renderHistorySection / state.js's saveHistorySnapshot). */
.history-section {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 14px;
  margin: 10px 0;
  font-size: 0.85rem;
}
.history-section summary { cursor: pointer; font-weight: 600; }
.history-section .hint { margin: 8px 0; }
.table-scroll { overflow-x: auto; margin: 8px 0; }
.history-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; white-space: nowrap; }
.history-table th, .history-table td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
.history-table td:last-child, .history-table th:last-child { white-space: normal; }

/* Round 12: batch-cooking — the recipe-picker on the intake step, and the
   "your batch-cook recipes this week" group on the results screen. */
.recipe-sections { margin: 14px 0; }
.recipe-section { margin-bottom: 14px; }
.recipe-section h4 { margin: 0 0 6px; }
.recipe-picker { margin-top: 14px; }
.recipe-candidate-list { list-style: none; padding: 0; margin: 10px 0 0; display: flex; flex-direction: column; gap: 8px; }
.recipe-candidate {
  display: flex;
  justify-content: space-between;
  /* Round 14: candidates now carry ingredient chips + a deliciousness line
     beneath the recipe name, so the row is taller and can wrap on narrow
     screens — align-items switched from center to flex-start so the
     "Choose this recipe" button sits at the top instead of vertically
     centering against the now-much-taller text column. */
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
}
.chosen-recipes { margin-top: 16px; font-size: 0.9rem; }
.chosen-recipes ul { list-style: none; padding: 0; margin: 8px 0 0; display: flex; flex-direction: column; gap: 4px; }

.list-section h3 { border-top: 1px solid var(--border); padding-top: 14px; }
.item-list { list-style: none; padding: 0; margin: 8px 0 0; display: flex; flex-direction: column; gap: 6px; }
.item-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 10px;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 0.88rem;
}
.item-name { font-weight: 600; }
.item-pack, .item-qty { color: var(--text-muted); font-size: 0.78rem; }
.item-price { font-weight: 700; color: var(--sky); }

/* Round 16: "Add to basket" tick-off checklist on the Shopping List tab's
   own item rows — a 5th leading column just for the checkbox, kept as its
   own class rather than changing the shared .item-row grid (Meal Plan/
   Supplements rows reuse .item-row with only 2-3 children and rely on the
   base 4-column layout). */
.item-row-shopping { grid-template-columns: auto 1fr auto auto auto; }
.basket-check { display: flex; align-items: center; cursor: pointer; }
.basket-check input { width: 18px; height: 18px; cursor: pointer; }
.item-row-added { opacity: 0.6; }
.item-row-added .item-name { text-decoration: line-through; }
.basket-progress-line { display: flex; align-items: center; gap: 10px; font-size: 0.85rem; margin: 4px 0 8px; }

.error-note { color: var(--danger); }
.disclaimer { font-size: 0.75rem; color: var(--text-muted); margin-top: 18px; }
.sources { font-size: 0.75rem; color: var(--text-muted); }
.sources a { margin: 0 2px; }

.nutrient-detail {
  margin-top: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 14px;
}
.nutrient-detail summary { cursor: pointer; font-size: 0.82rem; font-weight: 600; }
.nt-category { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin: 16px 0 8px; }
.nt-category:first-of-type { margin-top: 12px; }
.nutrient-target-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.nutrient-target-item { font-size: 0.78rem; border-top: 1px solid var(--border); padding-top: 8px; }
.nutrient-target-item:first-child { border-top: none; padding-top: 0; }
.nutrient-target-item.met,
.nutrient-target-item.fail {
  border-top: none;
  border-radius: 8px;
  padding: 8px 10px;
}
.nutrient-target-item.met { background: rgba(34, 197, 94, 0.12); }
.nutrient-target-item.fail { background: rgba(248, 113, 113, 0.12); }
.nt-status-icon { display: inline-block; width: 16px; font-weight: 700; }
.nutrient-target-item.met .nt-status-icon { color: var(--green); }
.nutrient-target-item.fail .nt-status-icon { color: var(--danger); }
/* Round 11: the "Met/Not met this week" sentence now carries its OWN
   met/fail/na class, independent of the card's overall .met/.fail (which
   since this round reflects BOTH the minimum AND the safe-upper-limit
   check — see app.js overallNutrientOk) — a basket can meet its minimum
   (this sentence: green ✓) while the card overall still reads red because
   the upper limit was exceeded (a different sentence below, its own ✗).
   Selectors here target .nt-status-text directly rather than via a
   .nutrient-target-item.met ancestor, so the two can disagree. */
.nt-status-text { margin: 4px 0; font-size: 0.78rem; font-weight: 700; }
.nt-status-text.met { color: var(--green); }
.nt-status-text.fail { color: var(--danger); }
.nt-status-text.met .nt-status-icon { color: var(--green); }
.nt-status-text.fail .nt-status-icon { color: var(--danger); }
.nt-detail { margin: 3px 0; color: var(--text-muted); }
.nt-sources { font-size: 0.72rem; }

/* Round 11: the always-visible tick/cross summary strip above the
   collapsible "Detailed nutrient targets" <details> — see
   renderNutrientSummaryStrip in app.js. */
.nutrient-summary-strip { display: flex; flex-wrap: wrap; gap: 6px 8px; margin: 10px 0; }
.nt-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.nt-chip.met { color: var(--green); border-color: rgba(34, 197, 94, 0.4); }
.nt-chip.fail { color: var(--danger); border-color: rgba(248, 113, 113, 0.4); }
.nt-chip.na { color: var(--text-muted); }
.nt-chip-icon { font-weight: 700; }

.toast {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 16px;
  font-size: 0.82rem;
  z-index: 10;
  box-shadow: 0 6px 20px rgba(0,0,0,0.4);
}

/* ---------- Clickable basket items (open the nutrient-breakdown popup) ---------- */
.item-row-clickable {
  cursor: pointer;
  transition: border-color 0.12s ease, background 0.12s ease;
}
.item-row-clickable:hover,
.item-row-clickable:focus-visible {
  border-color: var(--violet);
  background: var(--surface-2);
  outline: none;
}
.item-row-clickable .item-name::after {
  content: "›";
  display: inline-block;
  margin-left: 6px;
  color: var(--text-muted);
  font-weight: 700;
}

/* ---------- Upper-limit sub-block inside a nutrient-target-item ---------- */
.nt-upper-limit { margin: 6px 0; font-size: 0.78rem; font-weight: 600; }
.nt-upper-limit .nt-status-icon { width: 16px; }
/* Round 11: recoloured from an amber warning to red — exceeding a published
   safe upper limit is a genuine failure against that limit, not a softer
   "just worth a look" state, so it should read exactly as seriously as any
   other red ✗ on this card rather than a different, milder-looking colour. */
.nt-upper-limit.exceeds { color: var(--danger); }
.nt-upper-limit.exceeds .nt-status-icon { color: var(--danger); }
.nt-upper-limit.within { color: var(--green); }
.nt-upper-limit.within .nt-status-icon { color: var(--green); }
.nt-upper-limit-reference { color: var(--text-muted); font-weight: 400; }
.nt-upper-limit-detail { font-size: 0.76rem; }
.nutrient-target-item.exceeds-limit {
  border-radius: 8px;
  padding: 8px 10px;
  box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.35);
}

/* ---------- Round 19: per-person blocks inside a nutrient-target-item ----------
   Each nutrient card now shows one block (status sentences + its own stacked
   bar) per household member, instead of a single pooled household bar. The
   left border carries the per-person pass/fail colour so a failing person is
   findable at a glance inside an expanded card. */
.nt-person-rollup { margin: 6px 0 10px; font-size: 0.78rem; font-weight: 600; }
.nt-person-rollup.met { color: var(--green); }
.nt-person-rollup.fail { color: var(--danger); }
.nt-person-block {
  margin: 10px 0;
  padding: 8px 10px;
  border-radius: 8px;
  border-left: 3px solid var(--border);
  background: rgba(255, 255, 255, 0.02);
}
.nt-person-block.met { border-left-color: var(--green); }
.nt-person-block.fail { border-left-color: var(--danger); }
.nt-person-block.na { border-left-color: var(--border); }
.nt-person-name { margin: 0 0 4px; font-size: 0.8rem; }
.nt-household-note { margin: 6px 0; font-size: 0.76rem; }

/* ---------- Ingredient nutrient-breakdown modal ---------- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(8, 8, 14, 0.72);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 50;
  padding: 0;
}
.modal-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px 18px 0 0;
  width: 100%;
  max-width: 640px;
  max-height: 86dvh;
  overflow-y: auto;
  padding: 18px 18px calc(24px + var(--safe-bottom));
  box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.5);
}
@media (min-width: 480px) {
  .modal-overlay { align-items: center; padding: 20px; }
  .modal-box { border-radius: 18px; max-height: 80dvh; }
}
.modal-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.modal-header h3 { margin: 0; }

.nbar-row { margin: 16px 0; }
.nbar-heading { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 0.82rem; }
.nbar-label { font-weight: 700; }
.nbar-value { color: var(--text-muted); font-size: 0.74rem; text-align: right; white-space: nowrap; }
.nbar-track {
  position: relative;
  height: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  margin-top: 6px;
  overflow: visible;
}
.nbar-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 999px 0 0 999px;
  background: linear-gradient(90deg, var(--violet), var(--sky));
}
.nbar-fill[style*="width:100%"] { border-radius: 999px; }
.nbar-tick {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 2px;
  background: var(--text);
  transform: translateX(-1px);
}
/* Round 9: weekly target ticks/swatches are green, safe-upper-limit ones are
   red — previously the target rode the base .nbar-tick/.nbar-swatch white
   and the upper limit was amber, which read as too similar/low-contrast per
   user feedback. */
.nbar-tick-target { background: var(--green); }
.nbar-tick-upper { background: var(--danger); }
/* Round 10: a MAX-direction nutrient's own weekly-target tick (e.g.
   saturated fat, total fat, salt) used to share the same green
   .nbar-tick-target styling as a MIN-direction target — which reads as "on
   track" when in fact the tick marks a ceiling, not a floor. Given red for
   a maximum. No nutrient in this app carries both a max-direction target AND
   a separate safe-upper-limit tick (see guidelines.js's note above
   NUTRIENT_TARGETS: upperLimit is only ever added to min-direction entries),
   so this never collides with .nbar-tick-upper's red on the same bar. */
.nbar-tick-target-max { background: var(--danger); }
.nbar-legend { display: flex; gap: 14px; margin-top: 6px; font-size: 0.7rem; color: var(--text-muted); }
.nbar-legend span { display: inline-flex; align-items: center; gap: 5px; }
.nbar-swatch { display: inline-block; width: 8px; height: 8px; border-radius: 2px; background: var(--text); }
.nbar-swatch-target { background: var(--green); }
.nbar-swatch-target-max { background: var(--danger); }
.nbar-swatch-upper { background: var(--danger); }

/* ---- Round 8: full stacked-bar charts (replaces the old single-segment fill) ---- */
/* .nsbar-track needs taller than the plain .nbar-track above to fit inline
   segment name labels; ticks live OUTSIDE .nsbar-segments so they can still
   overflow the track vertically (per .nbar-tick above) while the segments
   themselves stay clipped to the pill shape. */
.nsbar-track { height: 26px; overflow: visible; }
.nsbar-segments {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  overflow: hidden;
  display: flex; /* fallback box so an empty state never collapses to 0 height */
}
.nsbar-seg {
  position: absolute;
  top: 0;
  bottom: 0;
  /* 1px inset + border-right creates the "2px surface gap between fills"
     look between adjacent stacked segments without the widths needing to
     account for it themselves. */
  border-right: 2px solid var(--surface-2);
  display: flex;
  align-items: center;
  overflow: hidden;
  cursor: default;
}
.nsbar-seg:last-child { border-right: none; }
/* Round 11: no longer forces a fixed grey — app.js now supplies the same
   compliance-status colour as the other segments via inline style (see
   renderNutrientStackedBar's otherHtml). Kept as a fallback only for the
   rare case a caller doesn't pass one. */
.nsbar-seg-other { background: var(--border); }
.nsbar-seg-label {
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.65);
  font-size: 0.66rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 8px;
}
/* A bright ring + glow around the highlighted segment (this popup's own
   item) — the "you are here" marker within the whole week's stacked total.
   Round 9: made more prominent (green instead of white, thicker, with a
   soft glow) per user feedback that the previous white outline was too easy
   to miss. Round 10: switched from green to sky blue — every bar's fill is
   now itself green-or-red for target compliance (see
   stackedBarSegmentColor), so a green highlight ring risked reading as "this
   one's good" rather than "this is the selected item", especially sitting
   on top of a RED (non-compliant) bar. Sky blue carries no compliance
   meaning of its own and stays legible against both fills. */
/* Round 16: restyled from an inset OUTLINE ring to a solid FILL, per direct
   feedback — the segment's own compliance colour (green/red) is replaced
   outright with solid sky blue rather than just ringed, so "this is the
   selected item" reads as unambiguously as the fill colour itself does for
   compliance, not as a thin line easy to miss on a narrow segment. The
   `!important` is needed because the segment's compliance colour is set as
   an inline style in app.js (computed per-segment, so it can't live in this
   stylesheet) — this class deliberately overrides it only for the
   highlighted segment. See the fix above (listGenerator.js
   nutrientContributorsByKey) for the companion "dual highlight" bug this
   was found alongside — two segments for the same product used to both
   match `highlightProductId` and both get this treatment at once. */
.nsbar-seg-highlight {
  background: var(--sky) !important;
  box-shadow: 0 0 0 1px var(--bg), 0 0 8px 1px rgba(56, 189, 248, 0.85);
  z-index: 1;
}
.nsbar-empty { margin-top: 6px; }

/* ---------- Round 14 additions ---------- */

/* Calorie range display + override row on the household step (screenshot 1:
   "add the calories range to this view... but over-ridable"). */
.calorie-range-display {
  margin-top: 6px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.calorie-override-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
/* Round 15: "please highlight in bold red the estimated calorie range" —
   the figure was previously styled with an ordinary <strong> (bold, but no
   colour). Bold is already the tag default; --danger is this app's one
   established red token (used everywhere else a figure needs to stand out
   as significant — see e.g. .nt-status-text.fail above), reused here rather
   than introducing a second, one-off red. */
.calorie-range-value { color: var(--danger); font-weight: 700; }
/* A narrower variant of .field for the two side-by-side override inputs —
   the base .field already sets width via its flex-column layout, so this
   just caps how wide each one grows within the row. */
.field-inline { flex: 1 1 200px; min-width: 160px; margin: 0; }

/* The 5 breakfast + 2 brunch direct-pick <select> slots (screenshot 6: "For
   breakfasts you will just tell the family what to eat") — reuses
   .member-list's column layout for the surrounding wrapper. */
.direct-recipe-slots { margin-bottom: 18px; }
.direct-recipe-slots .member-list { gap: 4px; }

/* Ingredient chips on a recipe candidate, each with a red-✕ "hide every
   recipe with this ingredient" button (screenshot 8). */
.ingredient-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 4px 2px 10px;
  margin: 3px 4px 0 0;
  font-size: 0.76rem;
  color: var(--text-muted);
}
.ingredient-exclude-btn {
  border: none;
  background: rgba(248, 113, 113, 0.18);
  color: var(--danger);
  width: 18px;
  height: 18px;
  line-height: 18px;
  border-radius: 50%;
  font-size: 0.7rem;
  cursor: pointer;
  padding: 0;
}
.ingredient-exclude-btn:hover { background: rgba(248, 113, 113, 0.35); }

/* Round 16: a user-friendly (not raw-gram) quantity shown alongside a
   recipe-picker ingredient chip's name, per direct feedback. */
.ingredient-qty { font-size: 0.72rem; }

/* Round 16: clearer whose-turn-it-is messaging on the batch-cook picker —
   a distinct bordered/tinted panel (not just plain .hint text) so the
   current turn reads as a status, not incidental copy, plus a one-off
   transition line the moment the picker actually moves to a new person
   (direct feedback: unclear when a turn had genuinely changed hands). */
.turn-banner {
  background: var(--surface-2);
  border: 1px solid var(--violet);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 10px;
}
.turn-banner .hint { margin-top: 0; }
.turn-transition {
  color: var(--green);
  font-weight: 600;
  margin: 0 0 6px;
  font-size: 0.9rem;
}

/* Deliciousness score + its small-text formula explanation (screenshot 4:
   "give each item a deliciousness % score, and a brief explanation of the
   score in small text"). */
.deliciousness-score { font-weight: 600; color: var(--warning); }
.deliciousness-explanation { display: block; font-size: 0.72rem; margin-top: 2px; }

/* Meal Plan tab: one heading + card group per meal category (breakfasts /
   brunches / batch-cook), plus the Supplements group — replaces the old
   flat per-food-group sections. */
.meal-category-group { margin-bottom: 20px; }
.meal-category-group h4 { margin: 0 0 8px; }
.meal-category-group h5 { margin: 10px 0 4px; font-size: 0.92rem; }

/* Round 16: the Meal Plan / Shopping List tab switcher used to reuse the
   exact same rounded-pill .chip/.chip-active styling as the supermarket
   row directly above it, per direct feedback that the two rows read as one
   continuous set of pills rather than two unrelated controls (pick a
   supermarket vs. pick which results view to see). Now deliberately
   different in shape (underline tabs, not pills) AND set apart in its own
   bordered/tinted panel with a small "Viewing" label, so it reads as its
   own section. */
.results-tabs-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 16px;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.results-tabs-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); flex: none; }
.results-tabs { display: flex; gap: 4px; }
.results-tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  padding: 6px 10px 4px;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}
.results-tab-active { color: var(--text); border-bottom-color: var(--violet); }

@media (min-width: 480px) {
  .check-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Round 47: sequential one-slot-at-a-time meal-plan picker (see app.js
   renderMealFlowCard / renderMealFlowReview and mealFlow.js). */
.meal-flow-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; }
.meal-flow-progress { font-size: 0.85rem; margin: 0 0 4px; }
.meal-flow-slot-label { margin: 0 0 16px; font-size: 1.1rem; }
.meal-flow-recipe { background: var(--surface-2); border-radius: var(--radius); padding: 16px; margin-bottom: 12px; }
.meal-flow-stepper { display: flex; align-items: stretch; gap: 10px; }
.meal-flow-step { min-width: 48px; font-size: 1.2rem; display: flex; align-items: center; justify-content: center; }
.meal-flow-step:disabled { opacity: 0.35; cursor: not-allowed; }
.meal-flow-recipe-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; text-align: center; justify-content: center; }
.meal-flow-position-tag { font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.meal-flow-position-tag.top-pick { color: var(--green); font-weight: 600; }
.meal-flow-recipe-name { font-size: 1.15rem; line-height: 1.3; }
.meal-flow-ingredients { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.meal-flow-nav { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.meal-flow-nav .btn-primary { flex: 1 1 auto; }
/* Review summary */
.meal-flow-review-group { margin-bottom: 20px; }
.meal-flow-review-group h4 { margin: 0 0 8px; }
.meal-flow-review-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.meal-flow-review-item { width: 100%; display: grid; grid-template-columns: 1fr auto; grid-template-areas: "label recipe" "pos edit"; gap: 2px 12px; align-items: center; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 14px; cursor: pointer; text-align: left; color: var(--text); }
.meal-flow-review-item:hover { border-color: var(--violet); }
.meal-flow-review-label { grid-area: label; font-size: 0.85rem; color: var(--text-muted); }
.meal-flow-review-recipe { grid-area: recipe; font-weight: 600; text-align: right; }
.meal-flow-review-pos { grid-area: pos; font-size: 0.78rem; }
.meal-flow-review-edit { grid-area: edit; justify-self: end; color: var(--violet); font-size: 0.85rem; font-weight: 600; }

/* Round 52: badge on a nutrient card whose total includes a mixed/processed
   product with estimated (not label-measured) micronutrients. */
.nt-estimated-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 10px;
  font-size: 0.72em;
  font-weight: 600;
  color: #b8860b;
  background: rgba(184, 134, 11, 0.14);
  border: 1px solid rgba(184, 134, 11, 0.35);
  vertical-align: middle;
  cursor: help;
}
.callout-field {
  background: rgba(120, 120, 160, 0.08);
  border: 1px solid rgba(120, 120, 160, 0.25);
  border-radius: 8px;
  padding: 10px 12px;
  margin-top: 14px;
}
.callout-field .check-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-weight: 600;
}

/* Round 53: debug appendix at the bottom of the Shopping List tab — small,
   muted, collapsed by default. A diagnostic surface, not part of the UI. */
.debug-appendix {
  margin-top: 28px;
  padding-top: 12px;
  border-top: 1px dashed rgba(120, 120, 160, 0.3);
  font-size: 0.78em;
  opacity: 0.72;
}
.debug-appendix summary {
  cursor: pointer;
  color: var(--muted, #888);
  font-weight: 600;
}
.debug-hint {
  margin: 8px 0;
  color: var(--muted, #888);
}
.debug-dump {
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.92em;
  line-height: 1.4;
  background: rgba(120, 120, 160, 0.08);
  border: 1px solid rgba(120, 120, 160, 0.2);
  border-radius: 6px;
  padding: 10px 12px;
  overflow-x: auto;
  color: var(--text, inherit);
}

/* Round 53: recipe blacklist chips (managed in the dietary/blacklist block)
   and the meal-picker's "Blacklist & next" button. */
.blacklist-recipes { margin-top: 8px; }
.blacklist-recipe-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.blacklist-recipe-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px 2px 10px;
  border-radius: 12px;
  font-size: 0.85em;
  background: rgba(200, 80, 80, 0.14);
  border: 1px solid rgba(200, 80, 80, 0.35);
}
.blacklist-recipe-remove {
  border: none;
  background: transparent;
  color: inherit;
  font-size: 1.1em;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
  opacity: 0.7;
}
.blacklist-recipe-remove:hover { opacity: 1; }


/* Round 54: the "blacklist" control now sits under the right stepper arrow
   (▶), where "show me the next candidate for this meal" semantics live — a
   blacklisted recipe is skipped and the next option shown, staying on the same
   meal slot (a dish must still be chosen for it). It reads as a lighter action
   than Select, so it's a small link-style button, not a primary. */
.meal-flow-step-right {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.meal-flow-blacklist-step {
  font-size: 0.8em;
  padding: 2px 6px;
  color: rgba(200, 100, 100, 0.9);
  white-space: nowrap;
}
.meal-flow-blacklist-step:hover { color: rgba(220, 90, 90, 1); text-decoration: underline; }

/* Round 55: per-person food-group appetite controls (household step). */
.portion-multipliers {
  margin-top: 10px;
  border: 1px solid rgba(120, 120, 160, 0.25);
  border-radius: 8px;
  padding: 8px 10px;
}
.portion-multipliers legend { font-size: 0.85em; font-weight: 600; padding: 0 4px; }
.portion-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.portion-field { flex: 1 1 100px; min-width: 90px; }
.portion-field span { font-size: 0.82em; }

/* Round 87: satiation / satiety per-meal targets */
.satiety-grid { width: 100%; border-collapse: collapse; margin: 0.4rem 0; }
.satiety-grid th, .satiety-grid td { padding: 0.25rem 0.35rem; text-align: left; font-size: 0.9rem; }
.satiety-grid th { font-weight: 600; }
/* Round 102: fullness grid is dropdowns now — one per meal per dimension. */
.satiety-grid { width: 100%; border-collapse: collapse; table-layout: fixed; }
.satiety-grid th, .satiety-grid td { padding: 0.25rem; text-align: left; font-size: 0.85rem; vertical-align: middle; }
.satiety-grid th:first-child { width: auto; font-weight: 600; }
.satiety-grid tr.satiety-section th { text-align: left; padding-top: 0.5rem; font-size: 0.9rem; font-weight: 600; }
.satiety-grid select { width: 100%; min-width: 0; font-size: 0.8rem; padding: 0.3rem 0.2rem; }
@media (max-width: 620px) {
  .satiety-grid th, .satiety-grid td { padding: 0.15rem; font-size: 0.75rem; }

  .satiety-grid select { font-size: 0.7rem; }
}

/* Round 117: per-meal fullness chart (satiation / satiety) */
.fullness-chart { margin: 0.5rem 0; }
.fullness-chart h5 { margin: 0 0 0.35rem; font-size: 0.95rem; }
.fullness-group { margin: 0.4rem 0; }
.fullness-group h6 { margin: 0 0 0.2rem; font-size: 0.82rem; font-weight: 600; }
.fullness-row { display: flex; align-items: center; gap: 0.4rem; margin: 0.12rem 0; }
.fullness-track { position: relative; flex: 1 1 auto; height: 0.85rem; border-radius: 0.45rem; background: rgba(255,255,255,0.07); overflow: hidden; }
.fullness-band { position: absolute; top: 0; bottom: 0; background: rgba(74,222,128,0.20); border-left: 1px solid rgba(74,222,128,0.75); border-right: 1px solid rgba(74,222,128,0.75); }
.fullness-fill { position: absolute; top: 0; bottom: 0; left: 0; border-radius: 0.45rem; }
.fullness-ok { background: #4ade80; }
.fullness-under { background: #fbbf24; }
.fullness-over { background: #f87171; }
.fullness-val { flex: 0 0 2.4rem; text-align: right; font-size: 0.78rem; opacity: 0.85; font-variant-numeric: tabular-nums; }

/* Round 124: account bar */
.account-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.9rem; padding: 0.5rem 0.9rem; margin: 0 0 0.75rem; border-bottom: 1px solid rgba(255,255,255,0.08); font-size: 0.88rem; }
.account-bar-form { display: block; }
.account-who { opacity: 0.85; }
.account-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-left: auto; }
.account-msg { flex-basis: 100%; opacity: 0.9; }
.account-tabs { display: flex; gap: 0.75rem; margin-bottom: 0.4rem; }
.account-tabs .is-active { text-decoration: underline; font-weight: 600; }
.account-fields { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.6rem; }
.account-fields .field { flex: 1 1 14rem; min-width: 0; }
@media (max-width: 620px) { .account-actions { margin-left: 0; } .account-fields .field { flex-basis: 100%; } }

/* Round 128: working indicator on the optimise button */
.spinner { display: inline-block; width: 0.9em; height: 0.9em; margin-right: 0.45em; vertical-align: -0.1em;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: op-spin 0.7s linear infinite; }
@keyframes op-spin { to { transform: rotate(360deg); } }

/* Round 129: meal-flow stage bar — whose meals we are on, and what is left */
.meal-flow-stages { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0 0 0.5rem; }
.meal-flow-stage { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.2rem 0.55rem; border-radius: 999px;
  background: rgba(255,255,255,0.06); font-size: 0.8rem; opacity: 0.7; }
.meal-flow-stage.is-now { background: rgba(139,92,246,0.28); opacity: 1; font-weight: 600; }
.meal-flow-stage.is-done { opacity: 0.45; }
/* Round 129: keep the picker compact enough to sit above the fold */
.meal-flow-card { padding: 0.75rem 0.9rem; }
.meal-flow-slot-label { margin: 0 0 0.5rem; font-size: 1.05rem; }
.meal-flow-card .hint { font-size: 0.82rem; margin: 0.4rem 0; }

/* Round 129: recipe blacklist search on the dietary step */
.blacklist-recipe-search { margin: 0.4rem 0 0.6rem; }
.blacklist-hits { display: flex; flex-direction: column; gap: 0.1rem; max-height: 11rem; overflow-y: auto; }
.blacklist-hit { text-align: left; padding: 0.2rem 0; font-size: 0.88rem; }

/* Round 132: per-person colour coding (traffic light across the household) */
.person-tinted { border-left: 4px solid hsl(var(--person-hue, 140) var(--person-sat, 65%) var(--person-light, 55%)); padding-left: 0.7rem;
  background: linear-gradient(90deg, hsl(var(--person-hue, 140) var(--person-sat, 65%) var(--person-light, 55%) / 0.10), transparent 40%); }
.person-tinted .member-name, .person-tinted > p:first-child strong { color: hsl(var(--person-hue, 140) var(--person-sat, 70%) calc(var(--person-light, 55%) + 12%)); }
/* Round 132: blacklisted items, one per line with a remove cross */
.blacklist-line { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  padding: 0.22rem 0.1rem; border-bottom: 1px solid rgba(255,255,255,0.06); font-size: 0.88rem; }
.blacklist-line:last-child { border-bottom: 0; }
.blacklist-recipe-remove { background: none; border: 0; color: #f87171; cursor: pointer; font-size: 0.95rem; padding: 0 0.25rem; }
.blacklist-subhead { margin: 0.5rem 0 0.2rem; }

/* Round 132: on-the-fly exclusions in the picker */
.picker-exclude { margin: 0.4rem 0; font-size: 0.88rem; }
.picker-exclude summary { cursor: pointer; opacity: 0.85; }

/* Round 133: meal-plan history */
.history { padding: 0.5rem 0; }
.history-week { border: 1px solid rgba(255,255,255,0.10); border-radius: 0.6rem; margin: 0.4rem 0; overflow: hidden; }
.history-head { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; width: 100%;
  padding: 0.6rem 0.8rem; background: none; border: 0; color: inherit; cursor: pointer; text-align: left; font-size: 0.92rem; }
.history-detail { padding: 0 0.8rem 0.8rem; }
.history-person h4 { margin: 0.6rem 0 0.2rem; }
.history-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.history-table th { text-align: left; opacity: 0.7; font-weight: 600; padding: 0.2rem 0.3rem; }
.history-table td { padding: 0.18rem 0.3rem; border-top: 1px solid rgba(255,255,255,0.06); }
.history-table tr.is-fail td { color: #f87171; }
.picker-exclude-who { display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center; margin: 0.3rem 0; }
.picker-exclude-who .chip { padding: 0.15rem 0.55rem; border-radius: 999px; border: 1px solid hsl(var(--person-hue,140) var(--person-sat, 60%) var(--person-light, 50%));
  background: none; color: inherit; cursor: pointer; font-size: 0.8rem; opacity: 0.55; }
.picker-exclude-who .chip.is-on { background: hsl(var(--person-hue,140) var(--person-sat, 60%) var(--person-light, 50%) / 0.25); opacity: 1; font-weight: 600; }

/* Round 138: basket items not tied to a specific meal */
.unattached { margin: 1rem 0 0.5rem; padding-top: 0.6rem; border-top: 1px solid rgba(255,255,255,0.10); }
.unattached h3 { margin: 0 0 0.2rem; font-size: 1rem; }
.unattached-group { margin: 0.5rem 0; }
.unattached-group h4 { margin: 0 0 0.1rem; font-size: 0.9rem; }
.unattached-list { margin: 0.2rem 0 0; padding-left: 1.1rem; font-size: 0.88rem; }

/* Round 145: print. The app is dark-themed and full of controls; a printed
   shopping list wants ink on white with the chrome gone. */
.print-row { margin: 0.8rem 0; }
.daily-supplements { margin: 0.8rem 0; padding-top: 0.6rem; border-top: 1px solid rgba(255,255,255,0.10); }
.daily-supplements h3 { margin: 0 0 0.2rem; font-size: 1rem; }
.daily-sup { margin: 0.35rem 0; }
.daily-sup h4 { margin: 0 0 0.1rem; font-size: 0.9rem; }
.daily-sup ul { margin: 0; padding-left: 1.1rem; font-size: 0.9rem; }
.use-up { margin: 0.6rem 0; }
@media print {
  :root, body { background: #fff !important; color: #000 !important; }
  .account-bar, .steps, .results-tabs, .supermarket-tabs, .btn, button, .print-row,
  .picker-exclude, .meal-flow-stages, details:not([open]) { display: none !important; }
  a { color: #000 !important; text-decoration: none; }
  .card, .recipe-sections, .history-week { border-color: #bbb !important; box-shadow: none !important; }
  h1, h2, h3, h4 { page-break-after: avoid; }
  li, tr, .recipe-section, .daily-sup { page-break-inside: avoid; }
  .hint, .muted { color: #444 !important; }
}

/* Round 156: the week-structure table. */
.week-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin: 0.5rem 0; }
.week-table th, .week-table td { text-align: left; padding: 0.3rem 0.35rem; border-bottom: 1px solid rgba(255,255,255,0.08); }
.week-table thead th { font-size: 0.75rem; opacity: 0.7; font-weight: 600; }
.daymeal { display: inline-flex; align-items: center; gap: 0.2rem; margin-right: 0.5rem; white-space: nowrap; }
.wildcard-num { width: 3.2rem; }
.week-structure { margin: 0.8rem 0; }
@media (max-width: 480px) { .week-table { font-size: 0.78rem; } .daymeal { margin-right: 0.3rem; } }

/* Round 179 */
.supplement-note { margin: 0.2rem 0 0.4rem; padding: 0.3rem 0.6rem; border-left: 3px solid var(--accent-sky, #38bdf8); }
.portion-grid .member-row { margin-top: 0.6rem; }
.person-swatch { display: inline-block; width: 0.8em; height: 0.8em; border-radius: 50%; margin-right: 0.4em; vertical-align: -0.05em;
  background: var(--person-colour, hsl(var(--person-hue,140) 65% 55%)); }
.nt-person-block .nt-person-name strong { color: var(--person-colour, inherit); }
.portion-person { margin-top: 0.6rem; }
.portion-person .portion-grid > div { flex: 1 1 160px; min-width: 150px; }
.portion-person .check-row { margin-bottom: 0.25rem; }

/* Round 180: carbohydrate breakdown on the wholegrain card */
.carb-breakdown { margin: 0.4rem 0 0.2rem; font-size: 0.88rem; }
.carb-breakdown summary { cursor: pointer; }
.carb-kind { margin: 0.5rem 0 0.15rem; }
.carb-table { width: 100%; border-collapse: collapse; }
.carb-table th, .carb-table td { text-align: left; padding: 0.15rem 0.4rem; border-top: 1px solid rgba(255,255,255,0.06); font-size: 0.85rem; }
.carb-table th { font-weight: 600; opacity: 0.8; }

/* Round 180: portioning instructions on shared / two-sitting dishes */
.portioning { margin: 0.4rem 0; font-size: 0.88rem; }
.portioning summary { cursor: pointer; font-weight: 600; }
.portioning-scroll { overflow-x: auto; max-width: 100%; }
.portioning-table { border-collapse: collapse; min-width: 100%; margin: 0.3rem 0; }
.portioning-table th, .portioning-table td { text-align: left; padding: 0.2rem 0.45rem; border-top: 1px solid rgba(255,255,255,0.07); white-space: nowrap; font-size: 0.85rem; }
.portioning-table thead th { opacity: 0.8; }

/* Round 183: meal-plan rotation */
.cycle-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.cycle-row .field { flex: 1 1 180px; min-width: 0; }
.cycle-tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.5rem 0; }
.cycle-tab { padding: 0.35rem 0.8rem; border-radius: 999px; border: 1px solid rgba(255,255,255,0.18); background: transparent; color: inherit; cursor: pointer; font: inherit; }
.cycle-tab.is-active { background: rgba(139, 92, 246, 0.25); border-color: rgba(139, 92, 246, 0.8); font-weight: 600; }
.cycle-banner { border: 1px solid rgba(139, 92, 246, 0.45); border-radius: 12px; padding: 0.6rem 0.9rem; margin-bottom: 0.8rem; }

/* Round 185: price flags and the report button on shopping-list lines */
.price-flag { font-size: 0.75rem; opacity: 0.8; margin-left: 0.3rem; white-space: nowrap; }
.price-flag-offer { color: #f59e0b; opacity: 1; }
.link-btn.report-price { background: none; border: 0; padding: 0 0.3rem; color: inherit; opacity: 0.6; font-size: 0.75rem; text-decoration: underline; cursor: pointer; }
.link-btn.report-price:hover { opacity: 1; }

/* Round 186: where each meal comes from */
.outside-meals { margin: 0.8rem 0; }
.outside-meals summary { cursor: pointer; font-weight: 600; }
.src-cells { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.src-cell { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; }
.src-meal { font-weight: 600; min-width: 4.5rem; }
.src-opt { font-size: 0.85rem; white-space: nowrap; }
.outside-pick { border-top: 1px solid rgba(255,255,255,0.08); padding-top: 0.5rem; margin-top: 0.5rem; }

/* Round 187: one-pot ingredient flags */
.dump-flags summary { cursor: pointer; font-size: 0.9rem; }
.dump-list { columns: 2 16rem; font-size: 0.82rem; margin: 0.2rem 0 0.6rem; padding-left: 1.1rem; }
.dump-list li { break-inside: avoid; }

/* Round 191: per-allergen risk level */
.allergy-level { font-size: 0.8rem; margin: 0 0 0.4rem 1.6rem; max-width: calc(100% - 1.6rem); }

/* Round 196 */
.portion-sub { margin: 0.25rem 0 0.75rem 1.75rem; }

/* Round 203 */
.adjustment-kind { font-size: 0.85rem; margin-right: 0.5rem; max-width: 100%; }
