/*
 * app.css -- the app shell's look. Binding palette (the owner's ruling,
 * her Case Manager's look) -- do not invent new colors elsewhere.
 *
 * Dark is the DEFAULT (no media query needed for it); light kicks in via
 * prefers-color-scheme. Macro colors are fixed app-wide from this file on:
 * calories = --accent, protein = --blue, carbs = --amber, fat = --green.
 * Over-target always turns --over (yellow) -- calm, never red-alarm, never
 * any shame copy anywhere near it. --over is deliberately its own color,
 * distinct from --amber (carbs) and --accent (calories), so a carbs bar
 * past its target is visibly different from its own normal fill.
 */

:root {
  --bg: #12141a;
  --panel: #1c1f27;
  --line: #2c303b;
  --txt: #eef0f5;
  --muted: #a2aaba;
  /* v1.5 (accessibility review): was #7b8493, which measured 4.37:1 on
     the panel -- just under the 4.5:1 ordinary text needs -- and it sits
     on real controls ("No target set", "Copy from...", "Weigh-in"). This
     shade measures 5.3:1. Still the quietest color in the app. */
  --faint: #8a93a3;
  --blue: #5b9bff;
  --green: #37c98a;
  --amber: #ffb020;
  --red: #ff5a5a;
  --accent: #c9f24d;
  --over: #ffd60a;
  /* v1.12 Task 9 (bug-patterns 8z10b): a primary button's own fill and
     text, always this lime + dark pair in BOTH themes -- separate from
     --accent, which light mode deliberately darkens for use as TEXT (the
     active tab, the hearted heart). Keeping the button fill off --accent
     means there is no override to order against; it is simply always
     this value. */
  --btn-bg: #c9f24d;
  --btn-text: #12141a;
  /* v1.12 Task 8c: the weekly report's cell shades -- on target, under
     (from 2/3), low (under 2/3), over, and no data / not logged -- plus
     the paler blue of an "under" bar. Never red. --txt and --muted on
     each measure 4.5:1 or better (verify_accessibility.py). */
  --tint-good: #193d2d;
  --tint-under: #1f2f47;
  --tint-low: #1d3a6b;
  --tint-over: #453a0c;
  --tint-none: #262a33;
  --bar-under: #a9c6f5;

  --nav-height: 64px;
  --header-height: 56px;
  --tap-min: 48px;

  --font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #eef0f4;
    --panel: #ffffff;
    /* v1.5: was #e4e7ec, a 1.24:1 line on white -- a row was a white box
       on a near-white page with an edge nobody could see. */
    --line: #c7ccd6;
    --txt: #1b1e26;
    --muted: #59616f;
    /* v1.5: was #8b93a1 (3.09:1 on white). 5.0:1 on the page now. */
    --faint: #5f6775;
    /* v1.5 (accessibility review): the six color roles used to be left at
       their dark-mode values here, which were picked to sit on near-black.
       On white the active tab label measured 1.29:1, UNDO 2.77:1, every
       error line 1.83:1, and the macro bar fills about 1:1 against their
       track. Each of these was checked: 4.5:1 or better as text on white,
       3:1 or better as a bar fill against --line. Same roles, same
       meanings, darker shades. --accent is used as TEXT here (the active
       tab, the hearted heart), which this shade covers; a primary
       button's own fill reads --btn-bg instead (see :root, bug-patterns
       8z10b), never this darker --accent. */
    --blue: #1f5fc4;
    --green: #1b7a4e;
    --amber: #9a5b00;
    --red: #c62828;
    --accent: #5f7a00;
    --over: #7d6000;
    /* v1.12 Task 8c: the weekly report's shades, the picture's own. */
    --tint-good: #dff1e6;
    --tint-under: #e3edf9;
    --tint-low: #cfe0f7;
    --tint-over: #fff1b8;
    --tint-none: #eef0f4;
    --bar-under: #4f86d0;
  }

  /* v1.12 Task 9 (bug-patterns 8z10b): this override used to redeclare
     the primary-button fill here, at the SAME specificity as the plain
     component rules 1,000+ lines below -- and the later rule always won,
     so every primary button painted the darker --accent above (about
     3.3:1) instead of lime. Fixed at the root: those rules now read
     --btn-bg/--btn-text (defined once in :root, never overridden), so
     there is nothing left here to lose the order fight. */
}

/* v1.5 (accessibility review): the app never set a focus style of its
   own, so the browser's thin default ring was all a keyboard or switch
   user had. This is drawn only for keyboard focus (:focus-visible), never
   for a tap, so a thumb sees nothing new. The ring is never switched
   off anywhere in this file -- Tests\verify_accessibility.py scans for
   that, and the scan reads comments too (bug-patterns 8z6), which is why
   this sentence does not spell the rule out in CSS. */
:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 2px;
}

* {
  box-sizing: border-box;
}

/* [hidden] loses to any display rule with higher specificity, silently --
   a known trap here (Met Tac Ops, 2026-08-20). Force it everywhere; the
   two places that need to override [hidden] with content already do it
   through :not([hidden]), which this never touches. */
[hidden] {
  display: none !important;
}

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--txt);
  font-family: var(--font-stack);
  -webkit-text-size-adjust: 100%;
}

button, input, select, textarea {
  font-family: inherit;
  /* 16px minimum on inputs -- a smaller input makes the phone zoom the
     page on focus. This is a known trap; never shrink this. */
  font-size: 16px;
  color: var(--txt);
}

a {
  color: inherit;
}

h1, h2, h3, p {
  margin: 0;
}

/* --- app shell layout --------------------------------------------------- */

#app {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

.app-header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--header-height);
  padding: 8px max(12px, env(safe-area-inset-left)) 8px max(16px, env(safe-area-inset-left));
  padding-top: calc(8px + env(safe-area-inset-top));
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

/* v1.3 Task 1: the title takes whatever room the arrow, the meal button
   and the gear leave, and a long one (a food's own name on the amount
   screen, a recipe's name) trails off rather than pushing the buttons out
   of the header. min-width: 0 is what actually lets a flex child shrink
   below its own text width -- without it the ellipsis never happens. */
.app-title {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 1.1em;
  font-weight: 600;
}

/* v1.5: an <h1> now (accessibility review) -- the one heading a screen
   reader's "jump to heading" can land on, and it already holds the
   screen's own name. Sized by its parent, not by the browser's h1
   default. */
#hdr-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: inherit;
  font-weight: inherit;
  margin: 0;
}

/* The back arrow sits left of the title; it is an .icon-btn like the gear,
   so it already carries the 48dp floor. */
.hdr-back {
  margin-left: -8px;
}

/* The meal button: the meal name plus a small "open me" chevron. Sized to
   the same 48dp floor every other tap target in this app clears. */
.hdr-meal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0 8px;
  border: none;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font-size: 0.95em;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

.hdr-meal:hover, .hdr-meal:active {
  background: var(--line);
}

/* The picker drops out from under the header, in ordinary flow, right
   where it belongs. It used to be sticky at top: var(--header-height),
   which is a GUESS at the header's height and a wrong one -- the header
   renders 48dp of buttons plus 8px of padding top and bottom, plus the
   safe-area inset, so the picker's top sat behind it. router.js scrolls
   the page to the top when the picker opens instead, so the header and
   the four meals under it are both fully on screen at whatever height
   they really are (fix round 1, Finding 2). */
.hdr-meal-picker {
  margin-bottom: 0;
  padding: 8px max(12px, env(safe-area-inset-left));
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

.app-version {
  font-size: 0.65em;
  font-weight: 400;
  color: var(--faint);
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  border-radius: 10px;
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.3em;
  text-decoration: none;
  cursor: pointer;
}

.icon-btn:hover, .icon-btn:active {
  background: var(--line);
}

.screens {
  flex: 1 1 auto;
  padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom) + 16px);
}

/* A .screen defaults to hidden (display: none). We key visibility off
   :not([hidden]) rather than relying on the UA's [hidden] rule, so an
   author display rule here can never accidentally out-rank it. */
.screen {
  display: none;
}

.screen:not([hidden]) {
  display: block;
  padding: 16px max(16px, env(safe-area-inset-left)) 16px max(16px, env(safe-area-inset-right));
}

.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  display: flex;
  min-height: var(--nav-height);
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--panel);
  border-top: 1px solid var(--line);
}

.nav-btn {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-min);
  color: var(--muted);
  text-decoration: none;
  font-size: 0.95em;
}

.nav-btn.active {
  color: var(--accent);
  font-weight: 600;
}

/* v1.19: the sync line in the nav. Painted on every change; only the wide
   layout reveals it (Task 7). The phone layout never shows it. */
.nav-sync {
  display: none;
}

/* The Settings screen's Sync row: a plain row (not a link) with the status
   words and a "Sync now" button under them. */
.settings-row.settings-sync {
  display: block;
  padding: 12px 16px;
}

.settings-sync-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}

.settings-sync .backup-secondary-btn {
  margin-bottom: 0;
}

/* --- toast --------------------------------------------------------------- */

#toast-root {
  position: fixed;
  left: 16px;
  right: 16px;
  /* Sits ABOVE the bottom nav with a clear gap -- a toast painting over
     the nav's tap area is a known trap in these apps. */
  bottom: calc(var(--nav-height) + env(safe-area-inset-bottom) + 12px);
  z-index: 20;
  display: flex;
  justify-content: center;
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 16px;
  max-width: 480px;
  width: 100%;
  padding: 12px 16px;
  border-radius: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
}

.toast-text {
  flex: 1 1 auto;
  font-size: 0.95em;
}

.toast-undo {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  padding: 0 12px;
  background: transparent;
  border: none;
  color: var(--blue);
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
}

/* --- overlays (Task 9: the "+ Add" chooser, the browser scan dialog, and
   the quiet "Looking it up..." state -- ALL of them share this chrome, her
   "same overlay style" instruction). Plain fixed-position panels, never
   window.prompt/confirm. Removed from the DOM entirely on close (never
   left behind hidden), so there is nothing stale to cover a control later
   -- see bug-patterns.md #1 on hidden-but-present overlays. */

.app-overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  padding: 16px;
  padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom) + 16px);
}

.app-sheet {
  width: 100%;
  max-width: 420px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 16px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);
}

.app-sheet-title {
  font-weight: 600;
  margin-bottom: 4px;
}

.app-sheet-hint {
  color: var(--muted);
  font-size: 0.85em;
  margin-bottom: 14px;
}

.app-sheet-btn {
  display: block;
  width: 100%;
  min-height: var(--tap-min);
  margin-top: 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  font-size: 0.95em;
  cursor: pointer;
}

.app-sheet-btn:first-child {
  margin-top: 0;
}

.app-sheet-btn.primary {
  background: var(--btn-bg);
  border-color: var(--btn-bg);
  color: var(--btn-text);
}

.app-sheet-actions {
  display: flex;
  gap: 10px;
}

.app-sheet-actions .app-sheet-btn {
  margin-top: 0;
  flex: 1 1 0;
}

.app-sheet-input {
  width: 100%;
  min-height: var(--tap-min);
  padding: 6px 10px;
  margin-bottom: 14px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.app-sheet-loading {
  text-align: center;
  color: var(--muted);
}

/* Task 10: the label-photo browser dialog's paste-it-here textarea --
   layers on top of .app-sheet-input (same background/border/radius/
   margin), just taller and resizable since label text runs to many
   lines, where the barcode dialog's single-line input never needed
   either. font-size stays the global 16px (see the button/input/select/
   textarea rule near the top of this file) -- never shrunk here. */
.app-sheet-textarea {
  min-height: 120px;
  resize: vertical;
  font-family: inherit;
  line-height: 1.4;
}

/* --- date strip (Today) ----------------------------------------------------- */

.date-strip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 16px;
}

.date-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  border-radius: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--txt);
  font-size: 1.2em;
  cursor: pointer;
}

.date-label {
  min-width: 120px;
  text-align: center;
  font-weight: 600;
}

/* --- workout/rest day toggle chip (Today) ------------------------------- */

.daytype-chip-row {
  display: flex;
  justify-content: center;
  margin-bottom: 16px;
}

.daytype-chip {
  min-height: var(--tap-min);
  padding: 0 20px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--txt);
  font-size: 0.9em;
  font-weight: 600;
  cursor: pointer;
}

.daytype-chip.is-rest {
  border-color: var(--blue);
}

/* --- Task 13: Today's actions row ("Copy day from...", Task 23's
   "Weigh-in") ------------------------------------------------------------ */

.today-actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-bottom: 16px;
}

.today-action-btn {
  min-height: var(--tap-min);
  padding: 0 20px;
  border-radius: 999px;
  background: transparent;
  border: 1px dashed var(--line);
  color: var(--faint);
  font-size: 0.85em;
  font-weight: 600;
  cursor: pointer;
}

/* --- macro bars --------------------------------------------------------- */

.macro-bars {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 24px;
}

.macro-bar {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
}

.macro-bar-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 8px;
}

.macro-bar-name {
  font-weight: 600;
}

.macro-bar-value {
  color: var(--muted);
  font-size: 0.9em;
}

.macro-bar-track {
  height: 10px;
  border-radius: 6px;
  background: var(--line);
  overflow: hidden;
}

.macro-bar-fill {
  height: 100%;
  border-radius: 6px;
  transition: width 0.2s ease;
}

.macro-hint {
  /* Task 28's own 48dp audit caught this one measuring 79x18px -- a real
     standalone tap target (it is the only way to reach Targets for a
     macro with none set, not a decorative caption inside a longer
     sentence), just rendered as bare inline text with no room around it.
     inline-flex + min-height keeps the small underlined-link look while
     giving it the same tap-min height every other control in this app
     gets; align-items centers the text inside that taller box instead of
     leaving it pinned to the top. */
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  margin-top: 8px;
  color: var(--faint);
  font-size: 0.85em;
  text-decoration: underline;
}

/* --- Task 25 part 1: Trends' weight chart, weekly average intake ------- */
/* Same panel look .micro-bar already established (background/border/
   radius/padding) -- one shared class so this and Part 2's burn panel read
   as one family of boxes, not ad hoc looks. NEUTRAL palette only: the
   chart's line is --blue, its dots/gridlines/axis text are --muted --
   never a direction color (green/red), ever -- a weight trend going up or
   down is a fact, not a verdict. */

.trends-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 14px;
  margin-bottom: 14px;
}

.trends-weight-svg {
  width: 100%;
  height: auto;
  display: block;
}

.trends-week-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 6px 0;
  border-bottom: 1px solid var(--line);
}

.trends-week-row:last-child {
  border-bottom: none;
}

.trends-week-label {
  color: var(--txt);
}

.trends-week-value {
  color: var(--muted);
}

/* --- Task 25 part 2: Trends' burn panel ---------------------------------- */
/* The answer itself (or the honest "not yet" wording), then -- ONLY
   alongside a real rough/stable answer -- a muted line naming the days/
   dates the numbers actually used, then the signed weekly projection.
   Observational-only, never advice; no color grading by direction here
   either. */

.trends-burn-main {
  margin: 0 0 4px;
  font-weight: 600;
}

.trends-burn-sub {
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.85em;
}

.trends-burn-projection {
  margin: 0;
  color: var(--muted);
  font-size: 0.9em;
}

/* --- Task 20: Trends' "Today's micronutrients" fullness bars ----------- */
/* Same shape as .macro-bar above, but every bar fills with the SAME
   --blue (no per-nutrient color coding) -- over-target turns --over,
   exactly like a macro bar. .is-empty is the "no data yet" state: muted
   text, no fill, no percent -- never a full/red 0%. */

.micro-bars {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.micro-bar {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 14px;
  min-height: var(--tap-min);
  /* Task 22: every bar is a tap target now (ui/trends.js's own gap-fixer
     wiring) -- the pointer affordance is the only visual change this rule
     gets; no color grading, no border change, nothing that would make a
     low bar read as an alarm. */
  cursor: pointer;
  /* v1.5: the bar is a <button> now (accessibility review), so it has to
     be told to fill its row and keep its text left, which a div did on
     its own. Everything else about its look is unchanged. */
  display: block;
  width: 100%;
  text-align: left;
  color: var(--txt);
}

.micro-bar-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 8px;
}

.micro-bar-track {
  display: block;
}

.micro-bar-fill {
  display: block;
}

.micro-bar-name {
  font-weight: 600;
}

.micro-bar-value {
  color: var(--muted);
  font-size: 0.9em;
}

.micro-bar-track {
  height: 8px;
  border-radius: 6px;
  background: var(--line);
  overflow: hidden;
}

.micro-bar-fill {
  height: 100%;
  border-radius: 6px;
  transition: width 0.2s ease;
}

.micro-bar.is-empty .micro-bar-name,
.micro-bar.is-empty .micro-bar-value {
  color: var(--faint);
}

/* --- meals list --------------------------------------------------------- */

.meal-section {
  margin-bottom: 20px;
}

/* v1.16: "Copy from" and "Save meal" beside the meal's name, not two
   full-width links under + Add (her pick, 2026-09-29: the gaps). 48 px tall
   for a thumb, quiet like the links they replace. */
.meal-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.meal-header {
  min-width: 0;
  padding-top: 13px;
}

.meal-tools {
  display: flex;
  flex: 0 0 auto;
  gap: 6px;
}

.meal-tool-btn {
  min-height: var(--tap-min);
  padding: 0 10px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.85em;
  cursor: pointer;
}

.meal-header h3 {
  font-size: 1em;
  color: var(--muted);
  margin-bottom: 8px;
}

/* v1.7: the meal's three macros against its own target, under the heading.
   The same muted text as the heading, one step smaller; no color of its
   own, whichever way the numbers fall. */
.meal-header-macros {
  margin: -4px 0 8px;
  color: var(--muted);
  font-size: 0.85em;
}

.addfood-meal-macros {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 0.85em;
}

#add-food.is-searching > .addfood-meal > .addfood-meal-macros {
  display: none;
}

/* v1.7: the split-the-day rows on Daily targets. A percent box beside the
   meal's name, and the worked-out numbers under it. */
.targets-split-line {
  margin: -8px 0 0;
  padding: 0 14px 8px;
  color: var(--faint);
  font-size: 0.85em;
}

.targets-split-note {
  margin: 0;
  color: var(--muted);
  font-size: 0.85em;
}

.targets-typed-btn {
  min-height: var(--tap-min);
  padding: 0 14px;
  background: transparent;
  border: none;
  color: var(--blue);
  font-size: 0.85em;
  text-decoration: underline;
  cursor: pointer;
}

.meal-entries {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
}

.log-entry {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}

.log-entry-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--tap-min);
  padding: 8px 14px;
  background: transparent;
  border: none;
  color: var(--txt);
  text-align: left;
  cursor: pointer;
}

.log-entry-name {
  flex: 1 1 auto;
}

.log-entry-grams, .log-entry-cal, .log-entry-basis, .log-entry-typed {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 0.9em;
}

/* Task 2 (v1.2): what she typed ("2 x 1 sachet (12 g)"), painted just
   before the grams it worked out to, with a middle dot between the two so
   they read as one amount rather than two competing numbers. */
.log-entry-typed::after {
  content: "\00B7";
  margin-left: 8px;
}

.log-entry-panel {
  padding: 4px 14px 14px;
  border-top: 1px solid var(--line);
}

.log-entry-macro {
  padding: 4px 0;
  color: var(--muted);
  font-size: 0.9em;
}

.log-entry-delete {
  margin-top: 10px;
  min-height: var(--tap-min);
  width: 100%;
  background: transparent;
  border: 1px solid var(--red);
  border-radius: 8px;
  color: var(--red);
  font-weight: 600;
  cursor: pointer;
}

/* v1.4: changing a logged amount without leaving Today. One box, the same
   unit chips the amount screen offers, and Save beside Delete -- the shape
   she picked off two drawn options. Deliberately built from the amount
   screen's own vocabulary rather than a new one: a chip is a chip on both
   screens. */
.log-entry-edit {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.log-entry-edit-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.log-entry-qty {
  flex: 0 0 auto;
  width: 86px;
  min-height: var(--tap-min);
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  /* 16px is the floor that stops Android/iOS zooming the page on focus --
     the same reason every other input in this app sets it. */
  font-size: 16px;
  text-align: center;
}

.log-entry-units {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  gap: 6px;
}

.log-entry-unit {
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  padding: 8px 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.9em;
  cursor: pointer;
}

.log-entry-unit[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--txt);
}

/* "= 60 g", only when the chip is not grams and the box holds a number.
   Empty the rest of the time, and it takes no room when it is. */
.log-entry-eq {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 0.85em;
}

.log-entry-eq:empty {
  margin: 0;
}

/* v1.16: a logged recipe -- the portion box's word, then one row per
   ingredient under a native fold. The recipe's editor sits ABOVE the
   macros, so the macros line gets its own gap. */
.log-entry-unit-word {
  color: var(--muted);
}

.log-entry-ings {
  margin-top: 12px;
}

/* A plain list-item summary keeps the browser's own fold arrow (a flex
   summary drops it). */
.log-entry-ings > summary {
  min-height: var(--tap-min);
  box-sizing: border-box;
  padding: 13px 0;
  color: var(--muted);
  cursor: pointer;
}

.log-entry-ing {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
}

.log-entry-ing-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.log-entry-ing-qty {
  flex: 0 0 auto;
  width: 76px;
  min-height: var(--tap-min);
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  font-size: 16px;
  text-align: center;
}

.log-entry-ing-unit {
  color: var(--muted);
}

.log-entry-edit + .log-entry-macros {
  margin-top: 12px;
}

.log-entry-actions {
  display: flex;
  gap: 8px;
}

.log-entry-actions > .log-entry-delete,
.log-entry-actions > .log-entry-save {
  flex: 1 1 0;
  width: auto;
}

.log-entry-save {
  margin-top: 10px;
  min-height: var(--tap-min);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  font-weight: 600;
  cursor: pointer;
}

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

.add-entry-btn {
  width: 100%;
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px dashed var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 0.95em;
  cursor: pointer;
}

/* Task 13: deliberately the quietest button on the screen -- a plain
   underlined link, not a bordered panel like "+ Add" above it, so it
   never competes for her attention. Still a full 48px tap target. */
.copy-meal-btn {
  width: 100%;
  min-height: var(--tap-min);
  background: transparent;
  border: none;
  color: var(--faint);
  font-size: 0.85em;
  text-decoration: underline;
  cursor: pointer;
}

/* v1.12 Task 4: planned rows from the meal plan (js/mealplan.js) --
   "Planned" recipe slots and "Daily extra" rows, painted between a meal's
   logged entries and its + Add row. A dashed border and the tag are the
   only visual difference from a logged entry -- no color for "not yet
   eaten," her no-guilt rule stands here too. */
.planned-row {
  border: 1px dashed var(--blue);
  border-radius: 10px;
  padding: 10px 12px;
  margin: 6px 0;
  opacity: .9;
}

.planned-tag {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--blue);
}

.planned-name {
  display: block;
  width: 100%;
  min-height: var(--tap-min);
  background: transparent;
  border: none;
  color: var(--txt);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  padding: 2px 0;
}

.planned-meta {
  display: block;
  color: var(--muted);
  font-size: 0.85em;
}

/* v1.18: "How to make it" -- a native fold on Today's planned recipe and on
   the recipe screen. Same summary shape as the logged recipe's Ingredients
   fold (the browser's own arrow stays). */
.howto > summary {
  min-height: var(--tap-min);
  box-sizing: border-box;
  padding: 13px 0;
  color: var(--muted);
  cursor: pointer;
}

.howto-ings, .howto-steps {
  margin: 4px 0 0;
  padding-left: 20px;
  color: var(--txt);
}

.howto-steps {
  margin-top: 10px;
}

.howto-ings li, .howto-steps li {
  padding: 2px 0;
}

.howto-none {
  color: var(--muted);
  font-size: 0.9em;
}

.planned-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  flex-wrap: wrap;
  margin-top: 8px;
}

.planned-log {
  width: auto;
  min-width: 96px;
  min-height: var(--tap-min);
  padding: 0 16px;
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
}

.planned-log:disabled {
  opacity: .6;
  cursor: default;
}

.planned-skip {
  width: auto;
  min-width: 72px;
  min-height: var(--tap-min);
  padding: 0 14px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  cursor: pointer;
}

.empty-hint {
  color: var(--faint);
}

/* --- v1.12 Task 5: the Plan tab -----------------------------------------
   Week/Shopping/Prep chips, then (Week only) a This week/Next week pair,
   both role=group buttons -- the same shape .daytype-picker-btns already
   uses on Today, reused here rather than a third variant. */

.plan-section-row, .plan-week-toggle-row {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
}

.plan-section-btn, .plan-week-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-weight: 600;
  cursor: pointer;
}

.plan-section-btn[aria-pressed="true"], .plan-week-btn[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--txt);
  background: var(--line);
}

.plan-day-block {
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 10px;
  overflow: hidden;
}

.plan-day-head {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: var(--tap-min);
  padding: 10px 14px;
  background: var(--panel);
  border: none;
  color: var(--txt);
  text-align: left;
  cursor: pointer;
}

.plan-day-name {
  font-weight: 600;
}

.plan-day-total {
  color: var(--muted);
  font-size: 0.9em;
}

.plan-day-body {
  padding: 4px 14px 12px;
  border-top: 1px solid var(--line);
}

.plan-slot-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}

.plan-slot-row:last-of-type {
  border-bottom: none;
}

.plan-slot-meal {
  display: block;
  color: var(--faint);
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.plan-slot-name {
  display: block;
  font-weight: 600;
}

.plan-slot-empty {
  color: var(--faint);
  font-weight: 400;
}

.plan-slot-meta {
  display: block;
  color: var(--muted);
  font-size: 0.85em;
}

.plan-slot-actions {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}

.plan-swap-btn {
  font-size: 1.1em;
}

.plan-away-btn {
  min-height: var(--tap-min);
  padding: 0 12px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.85em;
  cursor: pointer;
}

.plan-away-btn.is-on {
  border-color: var(--blue);
  color: var(--blue);
}

.plan-away-form, .plan-swap-picker {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
}

.plan-away-form-actions {
  display: flex;
  gap: 8px;
}

.plan-away-save-btn, .plan-away-cancel-btn {
  flex: 1 1 0;
  min-height: var(--tap-min);
  border-radius: 8px;
  cursor: pointer;
}

.plan-away-save-btn {
  background: var(--btn-bg);
  border: none;
  color: var(--btn-text);
  font-weight: 700;
}

.plan-away-cancel-btn {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
}

.plan-swap-picker {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.plan-pick-btn {
  min-height: var(--tap-min);
  padding: 0 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  text-align: left;
  cursor: pointer;
}

.plan-pick-none {
  color: var(--muted);
}

.plan-extras-line, .plan-from-line {
  color: var(--muted);
  font-size: 0.85em;
  margin: 10px 0;
}

.plan-prep-item {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
}

.plan-prep-name {
  display: block;
  font-weight: 600;
}

.plan-prep-makes, .plan-prep-amount, .plan-prep-meta {
  color: var(--muted);
  font-size: 0.9em;
  margin-top: 4px;
}

.plan-prep-steps {
  margin: 8px 0 0;
  padding-left: 20px;
  color: var(--txt);
}

.plan-prep-steps li {
  padding: 2px 0;
}

.plan-prep-add-btn {
  margin-top: 8px;
  min-height: var(--tap-min);
  padding: 0 16px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--blue);
  cursor: pointer;
}

.plan-slot-actions .plan-prep-add-btn {
  margin-top: 0;
}

.plan-notes-list {
  margin: 8px 0 0;
  padding-left: 20px;
  color: var(--muted);
}

.plan-notes-list li {
  padding: 2px 0;
}

/* v1.12 Task 7: the shopping list, and the prep portions. A tick box is a
   full 48px target (the whole row's label is tappable too). A ticked row
   just fades, like a planned meal she hasn't eaten. */
.tick-box {
  flex: 0 0 auto;
  width: var(--tap-min);
  height: var(--tap-min);
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.shop-heading {
  color: var(--muted);
  margin: 0 0 12px;
}

.shop-aisle-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 14px;
  margin-bottom: 10px;
}

.shop-aisle-name {
  margin: 4px 0;
  font-size: 0.8em;
  color: var(--faint);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.shop-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  border-bottom: 1px solid var(--line);
  padding: 2px 0;
}

.shop-row:last-of-type {
  border-bottom: none;
}

.shop-row-label {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--tap-min);
  cursor: pointer;
}

.shop-row-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.shop-row-note {
  color: var(--muted);
  font-size: 0.8em;
}

.shop-row.is-ticked .shop-row-text {
  color: var(--faint);
  text-decoration: line-through;
}

.shop-aisle-btn, .shop-extra-remove, .shop-aisle-pick, .shop-extra-add-btn {
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  padding: 0 10px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.85em;
  cursor: pointer;
}

.shop-aisle-group {
  flex: 1 0 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 6px 0 8px;
}

.shop-aisle-pick[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--txt);
}

.shop-extra-add {
  display: flex;
  gap: 8px;
  padding: 8px 0 4px;
}

.shop-extra-input {
  flex: 1 1 0;
  min-width: 0;
  min-height: var(--tap-min);
  padding: 0 12px;
  font-size: 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
}

.plan-prep-portions, .plan-prep-ings {
  margin: 6px 0 0;
  padding-left: 20px;
  color: var(--txt);
}

.recipe-ing-fixed-row {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: 0.85em;
  cursor: pointer;
}

/* --- Task 23: day-complete checkmark (Today) ---------------------------
   Her ruling: no color/commentary difference for an UNCHECKED day -- the
   plain panel/muted look below IS its unchecked state, same neutral look
   any other unpressed toggle in this app already has. Checked simply
   fills in the box and brightens the label text -- an ordinary pressed
   state, not praise. */

.daycomplete-row {
  margin-top: 8px;
}

.daycomplete-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: var(--tap-min);
  padding: 0 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 0.95em;
  font-weight: 600;
  cursor: pointer;
}

.daycomplete-box {
  position: relative;
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  border-radius: 6px;
  border: 2px solid var(--line);
}

.daycomplete-btn.is-complete {
  color: var(--txt);
  border-color: var(--accent);
}

.daycomplete-btn.is-complete .daycomplete-box {
  background: var(--btn-bg);
  border-color: var(--btn-bg);
}

.daycomplete-btn.is-complete .daycomplete-box::after {
  content: "\2713";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #12141a;
  font-size: 15px;
  font-weight: 700;
}

/* --- settings / targets forms -------------------------------------------- */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
}

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--tap-min);
  padding: 0 16px;
  text-decoration: none;
  color: var(--txt);
}

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

.settings-version {
  margin-top: 16px;
  color: var(--faint);
  font-size: 0.85em;
}

/* A settings row's own status text -- the Account row's "Signed in" /
   "Not signed in" (v1.15; it began as the old key rows' "Key set"). */
.settings-row-status {
  color: var(--faint);
  font-size: 0.85em;
}

/* Task 31 Part 4: the one plain line app.js paints at the top of #app
   when db.init() itself rejected at boot -- same honest-amber look every
   other failure sentence in this app already uses (.backup-error-line). */
.boot-storage-error {
  margin: 0;
  padding: 10px 16px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  color: var(--amber);
  font-size: 0.9em;
}

/* --- Task 26: the Backup screen ------------------------------------------
   .amount-add-btn (already defined) is reused verbatim for every primary
   action here (Back up now, Restore from a backup, Restore) -- same
   full-width accent 48px button every other screen's primary action
   already uses, not a new look invented for this one. */

.backup-section {
  padding: 16px;
}

.backup-section + .backup-section {
  margin-top: 16px;
}

.backup-line {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 0.9em;
}

.backup-stale-line {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 0.85em;
}

.backup-error-line {
  color: var(--amber);
  font-size: 0.9em;
  margin: 8px 0 0;
}

.backup-secondary-btn {
  width: 100%;
  min-height: var(--tap-min);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  cursor: pointer;
  margin-bottom: 16px;
}

.backup-summary-box {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px;
  margin-top: 12px;
}

.backup-summary-box p {
  margin: 0 0 14px;
}

.targets-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
}

.targets-tab {
  flex: 1 1 0;
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-weight: 600;
  cursor: pointer;
}

.targets-tab.active {
  border-color: var(--accent);
  color: var(--txt);
  background: var(--line);
}

/* v1.9: My week -- seven rows, four buttons each. */
.targets-week {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
}

.targets-week-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.targets-week-day {
  flex: 0 0 38px;
  color: var(--muted);
  font-weight: 600;
}

.targets-week-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-weight: 600;
  cursor: pointer;
}

.targets-week-btn.active {
  border-color: var(--accent);
  color: var(--txt);
  background: var(--line);
}

/* v1.9: the Today chip's four-button row. */
.daytype-picker {
  margin: -8px 0 16px;
}

.daytype-picker-btns {
  display: flex;
  gap: 8px;
}

.daytype-picker-note {
  color: var(--muted);
  font-size: 0.9em;
  margin: 8px 0 0;
}

.daytype-picker-back {
  min-height: var(--tap-min);
  background: none;
  border: 0;
  padding: 0;
  color: var(--blue);
  font: inherit;
  cursor: pointer;
}

.targets-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.targets-group-label {
  color: var(--faint);
  font-size: 0.85em;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 8px;
}

.targets-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--tap-min);
  padding: 4px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.targets-field label {
  flex: 1 1 auto;
}

.targets-field input {
  flex: 0 0 110px;
  width: 110px;
  min-height: var(--tap-min);
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  text-align: right;
}

/* Task 20: the Micronutrients section -- its own heading and one
   "Back to defaults" control for the whole section (not per-row). Rows
   themselves reuse .targets-field/.targets-form above unchanged. */
.targets-section-title {
  margin-top: 24px;
  margin-bottom: 4px;
  font-size: 1em;
  font-weight: 600;
}

.targets-section-actions {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 12px;
}

.targets-reset-btn {
  min-height: var(--tap-min);
  padding: 0 16px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 0.9em;
  cursor: pointer;
}

/* --- food form ------------------------------------------------------------ */

/* Task 9: the quiet one-line notice after a scan miss ("isn't in the
   databases yet..." / "couldn't reach the food databases..."). Muted, no
   alarm color -- an honest miss is calm, not an error. */
.foodform-notice {
  color: var(--muted);
  font-size: 0.9em;
  margin: 0 0 16px;
}

/* Task 21: the small ~ marker beside a nutrient field's label whose value
   came from a linked USDA generic (see ui/foodform.js's
   currentFilledFromGeneric) -- muted, not an error, same reasoning as
   ui.fmt.est's own tilde: a marker, not a warning. */
.foodform-filled-tag {
  color: var(--faint);
  font-weight: 400;
}

/* Task 10: "Fill it in from a label photo" -- above the nutrient fields,
   below name/brand/barcode (see paint() in ui/foodform.js). Styled like
   .foodform-more-toggle (a secondary action, not the primary Save), and
   the quiet status line under it that reports what the photo did or
   didn't find -- same calm, no-alarm treatment as .foodform-notice. */
.foodform-photo-btn {
  width: 100%;
  min-height: var(--tap-min);
  margin-bottom: 8px;
  background: var(--panel);
  border: 1px dashed var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  font-size: 0.95em;
  cursor: pointer;
}

.foodform-photo-status {
  color: var(--muted);
  font-size: 0.85em;
  margin: 0 0 16px;
}

.foodform-field-text {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

.foodform-field-text input {
  min-height: var(--tap-min);
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.foodform-basis {
  margin-bottom: 16px;
}

.foodform-basis-label {
  margin-bottom: 8px;
  color: var(--muted);
  font-size: 0.9em;
}

.foodform-basis-toggle {
  display: flex;
  gap: 8px;
}

.basis-btn {
  flex: 1 1 0;
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-weight: 600;
  cursor: pointer;
}

.basis-btn.active {
  border-color: var(--accent);
  color: var(--txt);
  background: var(--line);
}

.foodform-serving {
  margin-bottom: 2px;
}

/* The serving amount box plus its g/oz/ml/fl oz unit picker (Task 3) --
   the box reuses .foodform-field-text input's own look; the select needs
   its own rule because a <select> does not inherit the same defaults a
   text input does in every browser. */
.foodform-serving-amount-row {
  display: flex;
  gap: 8px;
}

.foodform-serving-amount-row input {
  flex: 1;
}

.foodform-serving-amount-row select {
  min-height: var(--tap-min);
  font-size: 16px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0 10px;
}

.foodform-main-nutrients {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 16px 0;
}

.foodform-more-toggle {
  width: 100%;
  min-height: var(--tap-min);
  margin-bottom: 14px;
  background: var(--panel);
  border: 1px dashed var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 0.95em;
  cursor: pointer;
}

.foodform-more {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 14px;
}

.foodform-error {
  color: var(--amber);
  font-size: 0.9em;
  margin: 4px 0 16px;
}

.foodform-save {
  width: 100%;
  min-height: var(--tap-min);
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
  margin-bottom: 24px;
}

/* --- amount screen ---------------------------------------------------------- */

.amount-food {
  margin-bottom: 20px;
}

/* Task 12: name + star toggle share the top row. */
.amount-food-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.amount-food-name {
  font-size: 1.15em;
  font-weight: 700;
}

.amount-star-btn {
  flex: 0 0 auto;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.5em;
  line-height: 1;
  cursor: pointer;
}

.amount-star-btn.is-favorite {
  color: var(--amber);
}

.amount-food-brand {
  color: var(--muted);
  font-size: 0.9em;
}

/* Task 9: source badge ("From Open Food Facts", "From USDA", "Typed from
   its label") -- small, muted, plain words, never a loud claim. */
.amount-food-badge {
  margin-top: 4px;
  color: var(--faint);
  font-size: 0.8em;
}

/* Task 16: the raw<->cooked toggle's inline search panel -- reuses
   .recipe-search-input/.recipe-search-results verbatim (same look as the
   builder's own search), just not living inside a sticky bar here. */
.amount-cooked-panel {
  margin-bottom: 14px;
}

/* v1.4: the two "these numbers could be better" ways out, side by side --
   Edit the numbers, and Fill from its website. Wraps rather than squeezes
   on a narrow phone, so neither ever loses its 48dp. */
.amount-fix-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}

/* v1.19: the "He will see" lines on the Sharing screen. */
.sharing-sees {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  color: var(--txt);
  font-size: 0.9em;
  line-height: 1.6;
}

/* v1.15: .signed-out-link is ui.SIGNED_OUT_TEXT's link to Settings ->
   Account (ui/fmt.js) -- the same link look, so it reads as a way to go
   somewhere and never as an error. */
.amount-edit-link,
.signed-out-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  margin-bottom: 8px;
  padding: 0;
  background: transparent;
  border: none;
  color: var(--blue);
  font-weight: 600;
  font-size: 0.9em;
  text-decoration: underline;
  cursor: pointer;
}

.amount-preview {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  margin: 16px 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.amount-preview-row {
  display: flex;
  justify-content: space-between;
  color: var(--muted);
}

/* Task 2 (v1.2): the unit chips under the amount box, and the "= N g" line
   that says what is really about to be stored. min-width matters as much as
   min-height here -- a chip whose whole label is "g" would otherwise measure
   about 38px across, under the 40dp short side every tap target has to
   clear. */
.amount-unit-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.amount-unit-chip { min-height: var(--tap-min); min-width: var(--tap-min); padding: 6px 14px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 999px; color: var(--txt); cursor: pointer; }
.amount-unit-chip.is-selected { border-color: var(--blue); color: var(--blue); }
.amount-eq { color: var(--muted); font-size: 0.85em; margin: 0 0 14px; }

/* Task 21: the generic-link (micronutrient fill) section, between the
   macro preview and the Add button. .amount-micro-line reuses
   .foodform-notice's own calm, muted treatment -- an honest "not on the
   label yet" is not an error. The Fill/Unlink/All-nutrients controls all
   reuse .foodform-more-toggle verbatim (already 48px, already this app's
   own "secondary action" look) -- no new button style needed. */
.amount-micro-line {
  color: var(--muted);
  font-size: 0.9em;
  margin: 0 0 8px;
}

.amount-allnutrients-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

.amount-allnutrients-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: var(--txt);
  font-size: 0.9em;
}

.amount-allnutrients-muted {
  color: var(--faint);
}

.amount-add-btn {
  width: 100%;
  min-height: var(--tap-min);
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
  margin-bottom: 24px;
}

/* --- add-food screen (Task 11) ---------------------------------------------- */
/* The search input itself reuses .foodform-field-text's input rule (48px,
   16px font, same panel/border look every other text field in the app
   has) -- nothing new to define there. */

/* Task 4 (v1.2), the fold. Her words: "when you are typing to search you
   don't know anything is popping up below the keyboard." The markup order
   inside #add-food is the Favorites line, its list, the search box, the
   results, the buttons, the recent rows -- and stays that way; the rules
   below are the only thing that moves anything. Not searching, the buttons
   sit above the (empty) results the way they always have and the recent
   rows sit under them; the moment the box has text, ui/addfood.js adds
   .is-searching, everything but the box and the results gets out of the
   way, and the buttons drop below the list so the first result is the next
   thing under her finger. */
#add-food {
  display: flex;
  flex-direction: column;
}

/* v1.3 Task 2: the top of this screen is now the Macrostax shape she
   picked (Option A on the design page) -- the Left today line, the search
   box with the scanner in it, one row of five small tiles, then the two
   closed drop-down lines, with the results last. Every child gets an
   explicit order so the markup can read top-to-bottom the way the screen
   does and the fold is still one class flip.

   The fold moves the tile row BELOW the results while she types -- exactly
   what v1.2 did with the six-button choice row this row replaced. Fix
   round 1: an earlier draft hid the row outright, and that broke the rule
   "Eating out stays reachable". Both Eating out and Describe it carry the
   words already in the search box, so with the row gone the only route to
   them WITH those words was the nothing-found line, which shows up only on
   a genuine miss. The two drop-down lines still fold away; the strip and
   the tiles stay on screen. */
#add-food > .left-strip {
  order: 1;
}

#add-food > .addfood-search-wrap {
  order: 2;
}

/* v1.4: the meal block sits directly under the search box, which is where
   she picked it off the drawn options. Every order below it moved down one
   to make room; the fold's own numbers moved with them. */
#add-food > .addfood-meal {
  order: 3;
}

#add-food > .addfood-tiles {
  order: 4;
}

#add-food > .addfood-fav-toggle {
  order: 5;
}

#add-food > .addfood-fav-list {
  order: 6;
}

#add-food > .addfood-recent {
  order: 8;
}

#add-food > .addfood-results {
  order: 9;
}

/* Searching: the results come straight up under the box, and the tile row
   drops below them -- still reachable, just no longer between her and the
   first result. */
/* v1.4: while she is typing, the meal block shrinks to its one summary
   line and the results come up under it, so the box -> results distance is
   one 48dp line rather than the block's full height. The line stays on
   purpose: the search words survive a log (she keeps typing for the next
   food), so a block that vanished while searching would be missing at
   exactly the moment a food lands. The count and the calories on that line
   move the instant it does, which is the proof she asked for. */
#add-food.is-searching > .addfood-meal {
  order: 3;
}

#add-food.is-searching > .addfood-meal > .addfood-meal-rows {
  display: none;
}

#add-food.is-searching > .addfood-results {
  order: 4;
}

#add-food.is-searching > .addfood-tiles {
  order: 5;
}

#add-food.is-searching > .addfood-fav-toggle,
#add-food.is-searching > .addfood-fav-list,
#add-food.is-searching > .addfood-recent {
  display: none;
}

/* The Recent line and its list sit under Favorites. The line reuses the
   Favorites line's own look (.addfood-fav-toggle) -- they are the same
   control doing the same job, so they are the same rule, not two that can
   drift. */
#add-food > #addfood-recent-toggle {
  order: 6;
}

#add-food.is-searching > #addfood-recent-toggle {
  display: none;
}

/* v1.3 Task 2: the Left today line. Her rule for it is the whole design:
   observe, never instruct. One quiet label, one line of numbers, no color
   of its own, no icon, and the same text color whether the numbers are
   positive or negative. Shared with the amount screen's copy of the same
   strip, which is why it is not named for either screen. */
.left-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--tap-min);
  margin-bottom: 10px;
  padding: 0 2px;
}

.left-strip-label {
  color: var(--muted);
  font-size: 0.85em;
}

.left-strip-value {
  color: var(--txt);
  font-size: 0.9em;
  text-align: right;
}

/* The one case where the value is a control: with no targets typed there
   is nothing to count, so the line becomes the way to go and type them.
   Same 48dp treatment .macro-hint on Today already needed, and for the
   same reason -- a bare inline link is a real tap target rendered too
   small to hit. */
a.left-strip-value {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  color: var(--faint);
  text-decoration: underline;
}

/* v1.3 Task 2: the five tiles. One row, always -- flex: 1 1 0 shares the
   width evenly and the short words are allowed to wrap to a second line on
   a narrow phone rather than pushing a tile onto a row of its own. */
.addfood-tiles {
  display: flex;
  gap: 6px;
  margin-bottom: 14px;
}

.addfood-tile {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: var(--tap-min);
  padding: 6px 2px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-size: 0.78em;
  line-height: 1.15;
  text-align: center;
  cursor: pointer;
}

.addfood-tile-icon {
  display: flex;
  color: var(--muted);
}

/* v1.3 Task 2: the scanner glyph inside the search box, in the same spot
   the clear (x) uses -- exactly one of the two is ever showing. */
.addfood-scan {
  position: absolute;
  top: 0;
  right: 0;
  width: var(--tap-min);
  height: var(--tap-min);
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  color: var(--muted);
  cursor: pointer;
}

/* v1.3 Task 2: a row and its heart. The heart is a SIBLING of the row
   button, never a child -- a button may not contain another button -- so
   this wrapper is what the list actually lays out. */
.addfood-row-wrap {
  display: flex;
  align-items: stretch;
  gap: 6px;
}

.addfood-row-wrap > .addfood-row {
  flex: 1 1 auto;
  min-width: 0;
}

.row-heart {
  flex: 0 0 auto;
  width: var(--tap-min);
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.row-heart[aria-pressed="true"] {
  color: var(--accent);
}

/* v1.4: the pencil on a favorite row -- same 48dp square, same border and
   radius as the heart beside it on every other list, so the right edge of
   a row reads as one consistent column of small controls rather than two
   competing shapes. */
.row-edit {
  flex: 0 0 auto;
  width: var(--tap-min);
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

/* v1.7: swipe a row to add it (ui/swipe.js). The wrap holds the blue panel
   behind and the row in front; the row slides left over it. No cursor of
   its own, so the 48dp audit never counts the wrap as a control. pan-y is
   what keeps a vertical scroll a scroll: the browser handles up and down,
   the script watches for sideways. */
.swipe-wrap {
  position: relative;
  overflow: hidden;
  border-radius: 10px;
  touch-action: pan-y;
}

.swipe-front {
  position: relative;
  z-index: 1;
  will-change: transform;
}

.swipe-panel {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  padding: 0 18px;
  border-radius: 10px;
  background: var(--blue);
  color: #12141a;
  text-align: right;
}

.swipe-wrap.is-swiping .swipe-panel {
  display: flex;
}

.swipe-wrap.is-armed .swipe-panel {
  background: var(--btn-bg);
}

.swipe-panel-text {
  font-weight: 700;
  font-size: 0.95em;
}

.swipe-panel-sub {
  font-size: 0.8em;
}

/* Task 5: the Favorites line -- one full-width 48dp row with the count on
   the left and the arrow on the right, quiet enough that the search box is
   still the first thing she sees. */
.addfood-fav-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: var(--tap-min);
  margin-bottom: 10px;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.addfood-fav-chev {
  color: var(--muted);
}

.addfood-fav-toggle[aria-expanded="true"] .addfood-fav-chev {
  transform: rotate(180deg);
}

/* v1.4: what is already in this meal. Quiet on purpose -- it is a record,
   not a control: no border of its own beyond the panel it sits on, no
   color that means anything, nothing tappable. Same "observe, never
   instruct" rule as the Left today strip above it. */
.addfood-meal {
  margin-bottom: 12px;
  padding: 10px 12px;
  background: var(--panel);
  border-radius: 10px;
}

.addfood-meal-line {
  margin: 0;
  color: var(--muted);
  font-size: 0.85em;
}

.addfood-meal-rows {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 8px;
}

.addfood-meal-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 0.9em;
}

.addfood-meal-row-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.addfood-meal-row-grams,
.addfood-meal-row-cal {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 0.9em;
  white-space: nowrap;
}

.addfood-fav-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 14px;
}

.addfood-recent {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
}

/* Task 5: the clear button lives INSIDE the search box's own wrapper, so
   the box has to be the positioning context and leave room for it. */
.addfood-search-wrap {
  position: relative;
}

.addfood-search-wrap > input {
  padding-right: 52px;
}

.addfood-clear {
  position: absolute;
  top: 0;
  right: 0;
  width: var(--tap-min);
  height: var(--tap-min);
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.addfood-choice-btn {
  /* v1.3 Task 2: the choice ROW itself is gone (five tiles replaced it).
     This button style stays because the nothing-found line still uses it
     for its two ways forward -- full-width-ish buttons inside
     .addfood-empty-line, which brings its own flex container. */
  flex: 1 1 40%;
  min-height: var(--tap-min);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  cursor: pointer;
}

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

.addfood-row {
  width: 100%;
  min-height: var(--tap-min);
  display: flex;
  align-items: center;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  text-align: left;
  cursor: pointer;
}

.addfood-row-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Task 4: the pill now shares this row, so the text takes what is left
     rather than pushing the pill off the edge on a long food name. */
  flex: 1 1 auto;
  min-width: 0;
}

.addfood-row-brand {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.9em;
}

.addfood-row-meta {
  color: var(--muted);
  font-size: 0.85em;
}

/* Task 4: the macros for the serving the line above names, one step
   quieter again -- there to confirm a choice, not to be read first. */
.addfood-row-meta2 {
  color: var(--muted);
  font-size: 0.8em;
}

/* Task 4: the serving repeated on the right of a result row, so a glance
   down the list reads as servings rather than food names alone. */
.addfood-row-pill {
  flex: 0 0 auto;
  background: var(--bg);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 0.85em;
  color: var(--txt);
  align-self: center;
  white-space: nowrap;
}

/* Task 11: a small muted section label, same "quiet, not a claim" treatment
   as .amount-food-badge -- USDA generics are a second-class citizen under
   her own saved foods, not an equal, competing list. */
.addfood-usda-divider {
  margin: 4px 0 2px;
  color: var(--faint);
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.addfood-offline-line {
  color: var(--muted);
  font-size: 0.9em;
  margin: 4px 0 0;
}

/* v1.3 Task 3: the one quiet line under the Describe it box saying the
   keyboard's mic works here. Muted and small on purpose -- it is a hint
   about a control the phone already gives her, not a control of its own,
   so it must never read as something to tap. */
.describe-hint {
  color: var(--muted);
  font-size: 0.9em;
  margin: 4px 0 12px;
}

/* Task 5: the nothing-found line. It names what was searched (never a bare
   "no results") and puts the two ways forward right where she is looking,
   so a miss is a fork in the road rather than a dead end. */
.addfood-empty-line {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 0;
}

.addfood-empty-line p {
  flex: 1 1 100%;
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.9em;
}

/* v1.4: "None of these? Look it up online", under a list that found things
   but not the one she wanted. Same shape as the nothing-found line above,
   because it is the same offer -- reached from the other half of the same
   dead end. One button rather than four: the other three are already a tap
   away on the tile row. */
.addfood-online-line {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

.addfood-online-line p {
  flex: 1 1 100%;
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.9em;
}

/* Task 12: a horizontally scrollable chip row. The add-food screen's own
   favorites/recents chips became rows in v1.2 Task 5; the recipe builder's
   favorite-ingredient row (ui/recipeedit.js) still uses these, and the
   Eating out screen uses .addfood-chip below. Hidden entirely (see each
   screen file) rather than an empty-state line when there is nothing to
   show. */
.addfood-chip-row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  margin-bottom: 14px;
  -webkit-overflow-scrolling: touch;
}

.addfood-chip {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: 6px 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--txt);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.addfood-chip-name {
  font-weight: 600;
  font-size: 0.92em;
}

.addfood-chip-meta {
  color: var(--muted);
  font-size: 0.8em;
}

/* --- Eating out (ui/eatingout.js) ---------------------------------------- */
/* Chips wrap here (16 of them) instead of scrolling sideways like the
   favorites row -- she should see every dish shape at once. */
.eatout-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 14px;
}

.addfood-chip.is-selected {
  border-color: var(--blue);
  color: var(--blue);
}

.eatout-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
  margin: 10px 0;
  background: var(--panel);
}

.eatout-card-name {
  font-weight: 600;
}

.eatout-card-num {
  display: flex;
  justify-content: space-between;
  padding: 2px 0;
}

.eatout-card-note {
  color: var(--muted);
  font-size: 0.85em;
  margin-top: 6px;
}

.eatout-secondary-btn {
  width: 100%;
  min-height: var(--tap-min);
  margin-top: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  cursor: pointer;
}

/* --- Describe it (ui/describe.js, v1.2 Task 7) ---------------------------- */
/* The words box is a textarea rather than a one-line input because a whole
   meal is a sentence, not a search term -- three rows so she can see what
   she has written. The 16px font comes from the shared button/input/
   textarea rule at the top of this file; nothing here may shrink it. */
#describe-input {
  min-height: var(--tap-min);
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  font-family: inherit;
  resize: vertical;
}

.describe-rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
}

/* Three lines per row, by wrapping rather than by nesting: the food's name
   (a full-width button -- tapping it opens the other foods it could be),
   then what it was worked out from, then the amount and what it costs with
   the x to drop it. */
.describe-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  padding: 8px 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.describe-name {
  flex: 1 1 100%;
  min-height: var(--tap-min);
  padding: 0;
  background: none;
  border: none;
  color: var(--txt);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

/* v1.7: a row's name with nothing to swap to is text, not a control. */
.describe-name-fixed {
  display: flex;
  align-items: center;
  cursor: default;
}

.describe-meta {
  flex: 1 1 100%;
  color: var(--muted);
  font-size: 0.85em;
}

.describe-grams {
  flex: 0 0 auto;
  width: 84px;
  min-height: var(--tap-min);
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  text-align: right;
}

.describe-unit {
  color: var(--muted);
}

.describe-kcal {
  flex: 1 1 auto;
  color: var(--muted);
  font-size: 0.9em;
}

.describe-drop {
  flex: 0 0 auto;
  width: var(--tap-min);
  height: var(--tap-min);
  background: none;
  border: none;
  color: var(--muted);
  font-size: 1.3em;
  cursor: pointer;
}

/* The other USDA foods that search found, opened under the row they belong
   to. Indented so they read as belonging to it, not as more rows. */
.describe-alts {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 6px 0 0 12px;
}

.describe-total {
  margin: 12px 0;
  color: var(--txt);
  font-weight: 600;
}

/* --- Task 13: copy-meal / copy-day flow (ui/copyflow.js) ------------------ */

.copy-heading {
  color: var(--muted);
  font-size: 0.95em;
  margin-bottom: 16px;
}

.copy-days-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.copy-day-row {
  width: 100%;
  min-height: var(--tap-min);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  text-align: left;
  cursor: pointer;
}

.copy-day-row-label {
  font-weight: 600;
}

.copy-day-row-meta {
  color: var(--muted);
  font-size: 0.9em;
}

.copy-group {
  margin-bottom: 20px;
}

.copy-group-title {
  font-size: 1em;
  color: var(--muted);
  margin-bottom: 8px;
}

.copy-item {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--tap-min);
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 8px;
}

.copy-item-name {
  flex: 1 1 auto;
}

.copy-item-grams {
  flex: 0 0 auto;
  width: 64px;
  min-height: var(--tap-min);
  padding: 4px 8px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  text-align: right;
}

.copy-item-cal {
  flex: 0 0 auto;
  min-width: 64px;
  color: var(--muted);
  font-size: 0.9em;
  text-align: right;
}

/* --- Task 15: recipes list (ui/recipeslist.js) ----------------------------- */
/* Rows reuse .copy-day-row's exact look (48px, name + muted meta, panel
   card) -- no new row chrome needed, same reasoning as reusing
   .addfood-row/.addfood-chip elsewhere in the builder below. */

/* Review fix (spec gap, round 1): the brief says this button is "pinned at
   the top" -- it shipped as an ordinary in-flow button that scrolled away
   with a long recipe list. `top` is set in JS (positionTopRow() in the JS
   file) from the app header's own rendered height, same reasoning as
   ui/recipeedit.js's pinned bar just below.
   Task 18: the sticky element is now the ROW (.recipes-top-row) that holds
   New recipe AND Import, so both stay pinned together -- the buttons
   themselves are plain flex children. */
.recipes-top-row {
  position: sticky;
  z-index: 5;
  display: flex;
  gap: 8px;
  background: var(--bg);
  padding: 2px 0;
  margin-bottom: 20px;
}

.recipes-new-btn {
  flex: 1 1 0;
  min-height: var(--tap-min);
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
}

.recipes-import-btn {
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--txt);
}

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

/* Task 16: the row itself (.recipes-row, reusing .copy-day-row) and its
   Edit control sit side by side -- never nested, HTML disallows a button
   inside a button, and it also keeps the two taps visually and physically
   distinct (log this vs. change this). */
.recipes-row-wrap {
  display: flex;
  align-items: stretch;
  gap: 8px;
}

.recipes-row-wrap .recipes-row {
  flex: 1 1 auto;
}

.recipes-edit-btn {
  flex: 0 0 auto;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--muted);
  font-weight: 600;
  cursor: pointer;
}


/* --- Task 15: recipe builder (ui/recipeedit.js) ---------------------------- */
/* Her named reason this screen exists: Macrostax's own recipe scan button
   scrolls out of reach on a long ingredient list. This bar is pinned
   (position: sticky) with its `top` offset measured in JS from the app
   header's own rendered height (see positionPinnedBar() in the JS file) --
   a guessed CSS offset here would risk the header painting over the top of
   it, exactly the "looks pinned, isn't actually hit-testable" failure
   Tests\verify_scan_pinned.py exists to catch. */

.recipe-pinned-bar {
  position: sticky;
  z-index: 5;
  background: var(--bg);
  padding: 10px 0;
  margin: 0 -16px 12px;
  padding-left: max(16px, env(safe-area-inset-left));
  padding-right: max(16px, env(safe-area-inset-right));
  border-bottom: 1px solid var(--line);
}

.recipe-pin-row {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}

/* v1.7: the paste-a-link row at the top of the builder. */
.re-import-row {
  margin-bottom: 14px;
}

.recipe-scan-btn {
  flex: 0 0 auto;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  cursor: pointer;
}

/* Reuses .foodform-field-text input's look (48px, 16px font) by hand,
   since this input does not sit inside that wrapper class here. */
.recipe-search-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--tap-min);
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
}

/* Review fix (Important, round 1): lives INSIDE .recipe-pinned-bar now
   (see ui/recipeedit.js's own comment at the markup site) so results stay
   reachable at any scroll position -- a sibling placed after the sticky
   bar just scrolled away with the rest of the page. Capped height + its
   own scroll keeps a long results list from growing the pinned bar past
   the point where the Favorites row (or the ingredient list under it)
   still gets any room at all. */
.recipe-search-results {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 40vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 0 10px;
}

.recipe-ingredients {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}

.recipe-ing-row {
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

/* Muted, not hidden -- an incomplete line stays visible and pickable, it
   just does not count toward the pot's totals yet (the WATCH ITEM in
   ui/recipeedit.js's own header). No guilt wording, just a plain note. */
.recipe-ing-row-incomplete {
  opacity: 0.7;
}

.recipe-ing-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.recipe-ing-name {
  font-weight: 600;
}

.recipe-ing-remove {
  flex: 0 0 auto;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.1em;
  cursor: pointer;
}

.recipe-ing-mid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.recipe-ing-grams {
  flex: 0 0 96px;
  min-height: var(--tap-min);
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.recipe-ing-basis {
  flex: 1 1 200px;
  margin-bottom: 0;
}

.recipe-ing-note {
  margin-top: 6px;
  color: var(--muted);
  font-size: 0.85em;
}

/* v1.13: the kitchen measure ("2 tsp") with its grams small and gray beside it. */
.recipe-ing-measure:not(:empty) {
  margin-top: 6px;
}

.measure-grams {
  margin-left: 4px;
  color: var(--faint);
  font-size: 0.85em;
}

.recipe-totals {
  margin-bottom: 16px;
}

/* Same fixed-above-the-nav placement as #toast-root -- established, tested
   spot in this app for a control that must survive any list length. */
.recipe-save-btn {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(var(--nav-height) + env(safe-area-inset-bottom) + 12px);
  z-index: 8;
  min-height: var(--tap-min);
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
}

/* v1.16: keyboard up (app.js markKeyboard) -- the nav and the builder's
   own Save step aside so the box she is typing in is not under them. */
.kb-open .bottom-nav,
.kb-open #re-save-btn {
  display: none;
}

/* Reserves room so the fixed Save button never covers the last field. */
.recipe-save-spacer {
  height: calc(var(--tap-min) + 24px);
}

/* Task 2 (v1.12): Steps, and the Makes picker beside it. .field-label is a
   plain label look shared by both (not tied to .foodform-field-text's own
   flex-column wrapper, since the steps textarea and the Makes row are not
   built the same shape as a foodform text field). */
.field-label {
  display: block;
  margin-bottom: 6px;
  color: var(--muted);
  font-size: 0.9em;
}

.recipe-steps {
  width: 100%;
  min-height: 120px;
  padding: 8px 10px;
  font: inherit;
  font-size: 16px; /* the 16px floor -- a smaller field zooms iOS/Android in on focus */
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  resize: vertical;
  margin-bottom: 6px;
}

/* Quiet, not a claim -- the same --muted treatment as every other honest
   status line in this app (bug-patterns' no-guilt rule: this only points
   at a gap, it never blocks Save, so it never reads as an error). */
.recipe-steps-check {
  min-height: 1.2em;
  color: var(--muted);
  font-size: 0.85em;
  margin: 0 0 16px;
}

.recipe-makes-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}

.recipe-makes-btn {
  min-height: var(--tap-min);
  padding: 0 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--txt);
  font-weight: 600;
  cursor: pointer;
}

.recipe-makes-picker {
  margin-bottom: 16px;
}

.recipe-makes-picker .recipe-search-input {
  margin-bottom: 8px;
}

/* --- Task 16: portion screen (ui/recipelog.js) ----------------------------- */
/* Header name reuses .amount-food-name (same weight/size treatment as the
   amount screen's own food name); the mode tabs reuse .foodform-basis-
   toggle/.basis-btn (the exact same look the builder already uses for
   dry/raw/cooked); the preview block reuses .amount-preview; the Add
   button reuses .recipe-save-btn/.recipe-save-spacer -- nothing new to
   define for any of those. */

.rl-pot-cal {
  color: var(--muted);
  font-size: 0.9em;
  margin: 2px 0 16px;
}

.rl-mode-row {
  margin-bottom: 16px;
}

.rl-remaining-line {
  color: var(--muted);
  font-size: 0.9em;
  margin: -8px 0 16px;
}

/* --- Task 19: the Fit panel (ui/recipelog.js) ------------------------------- */
/* The Fit button and Apply to a copy both reuse .foodform-more-toggle
   verbatim (already 48px, already the app's own "secondary action" look);
   the mode toggle reuses .foodform-basis-toggle/.basis-btn, the exact same
   pair the portion tabs above already use -- nothing new to define for
   either. */

/* v1.4: one quiet line under the Fit button saying what it will do.
   Observe, never instruct -- it describes the tool, it never tells her to
   use it or what to eat. */
.rl-fit-hint {
  margin: -4px 0 14px;
  color: var(--muted);
  font-size: 0.85em;
}

.rl-fit-panel {
  margin: -6px 0 16px;
  padding: 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.rl-fit-mode-row {
  margin-bottom: 16px;
}

.rl-fit-section {
  margin-bottom: 14px;
}

.rl-fit-section:last-child {
  margin-bottom: 0;
}

.rl-fit-heading {
  font-size: 0.95em;
  color: var(--muted);
  margin-bottom: 8px;
}

.rl-fit-portion-line {
  font-weight: 700;
  margin-bottom: 4px;
}

.rl-fit-skip-line {
  color: var(--muted);
  font-size: 0.85em;
  margin: 2px 0;
}

.rl-fit-note {
  color: var(--muted);
  font-size: 0.9em;
  margin-bottom: 8px;
}

.rl-fit-totals {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 10px;
}

.rl-fit-totals-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.9em;
}

.rl-fit-totals-label {
  color: var(--muted);
  flex: 1 1 auto;
}

.rl-fit-totals-before {
  color: var(--muted);
}

.rl-fit-totals-after {
  color: var(--txt);
  font-weight: 600;
}

.rl-fit-changes {
  margin-bottom: 10px;
}

.rl-fit-change-line {
  font-size: 0.9em;
  margin: 4px 0;
}

/* --- Task 18: recipe import (ui/recipeimport.js) --------------------------- */
/* Rows/grams/remove/note reuse .recipe-ing-row and friends verbatim (same
   look as the builder's own ingredient list) -- the reason line ALWAYS
   uses plain .recipe-ing-note, whether needsAttention is true or false
   (the parse.js handoff rule: no separate "error" look for either). The
   Change picker reuses .recipe-search-input/.recipe-search-results/
   .addfood-row/.addfood-choice-btn/.addfood-usda-divider verbatim, same
   reasoning as everywhere else in this app that a search list appears. */

.recipe-import-textarea {
  min-height: 120px;
  padding: 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  resize: vertical;
}

.recipe-import-read-btn {
  width: 100%;
  min-height: var(--tap-min);
  margin-bottom: 14px;
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
}

.recipe-import-error {
  color: var(--amber);
  font-size: 0.9em;
  margin: 4px 0 16px;
}

.recipe-import-rows {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}

.recipe-import-raw {
  color: var(--muted);
  font-size: 0.9em;
}

.recipe-import-name {
  flex: 1 1 160px;
  min-height: var(--tap-min);
  padding: 6px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.recipe-import-match-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 8px;
}

.recipe-import-match-text {
  color: var(--txt);
  font-size: 0.9em;
}

.recipe-import-nomatch {
  color: var(--muted);
}

/* v1.13: a done row says "✓ Using <food>" in green with a quiet text
   Change; a row with no food gets one lime "Pick a food". */
.recipe-import-done {
  color: var(--green);
}

.recipe-import-change-btn {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  padding: 0 12px;
  background: none;
  border: none;
  color: var(--muted);
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.recipe-import-pick-btn {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  padding: 0 16px;
  background: var(--btn-bg);
  border: none;
  border-radius: 10px;
  color: var(--btn-text);
  font-weight: 700;
  cursor: pointer;
}

.recipe-import-picker {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

/* Plain, muted status text -- never amber/red, this is progress, not a
   warning ("no guilt wording" binds here too). */
.recipe-import-hint {
  color: var(--muted);
  font-size: 0.9em;
  margin: 4px 0 8px;
}

/* --- Task 22: the gap fixer (ui/gapfixer.js) --------------------------- */
/* The header's own two lines reuse .targets-section-title for the label
   (the exact same look every other section heading in this app already
   uses) plus this one small new rule for the "X / Y unit" line under it --
   everything else on this screen (rows, badge, panel, honest-miss line)
   reuses an existing class verbatim; see the file's own header for which. */
.gap-fixer-header-value {
  color: var(--muted);
  font-size: 0.95em;
  margin: 0 0 16px;
}

#gf-groups .targets-section-title {
  margin-top: 20px;
}

#gf-groups .targets-section-title:first-child {
  margin-top: 0;
}

/* --- Task 27: the Weekly report screen (ui/report.js) --------------------
   The week-nav row reuses .date-strip/.date-arrow/.date-label verbatim
   (the same 48px arrows and centered label Today's own date strip already
   established) -- .report-week-nav adds nothing but the name. Every panel
   below reuses .trends-panel (Task 25's own "one shared box" look). */

.report-header {
  margin: -6px 0 12px;
  text-align: center;
  color: var(--muted);
  font-size: 0.9em;
}

/* --- v1.12 Task 8c: the redesigned report (her approved picture) --------
   Tiles 2 by 2, the "What stands out" box, two grids that scroll sideways
   INSIDE their panels (first column sticky), two charts, one column of
   micro bars. Cell shades come from the --tint-* tokens only; the chart
   bars from the role colors. Never --red. */

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

.report-tile {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 8px 12px;
  min-width: 0;
}

.report-tile-label {
  color: var(--muted);
  font-size: 0.72em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.report-tile-value {
  font-size: 1.45em;
  font-weight: 700;
  line-height: 1.2;
}

.report-tile-sub {
  color: var(--muted);
  font-size: 0.8em;
}

.report-standout {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: 12px;
  padding: 8px 14px;
  margin-bottom: 4px;
}

.report-standout-title {
  margin: 0 0 4px;
  font-size: 0.78em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--accent);
}

.report-standout ul {
  margin: 0;
  padding-left: 18px;
}

.report-standout li {
  margin: 2px 0;
}

.report-grid-scroll {
  overflow-x: auto;
  max-width: 100%;
}

.report-grid {
  border-collapse: separate;
  border-spacing: 2px;
  font-size: 0.85em;
  white-space: nowrap;
}

.report-grid th {
  color: var(--muted);
  font-weight: 600;
  font-size: 0.9em;
  padding: 2px 4px;
}

.report-grid th.report-grid-name {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--panel);
  color: var(--txt);
  text-align: left;
  padding-right: 8px;
}

.report-grid td {
  text-align: center;
  padding: 5px 6px;
  border-radius: 4px;
  color: var(--txt);
}

.report-grid td[data-status="good"] { background: var(--tint-good); }
.report-grid td[data-status="under"] { background: var(--tint-under); }
.report-grid td[data-status="low"] { background: var(--tint-low); }
.report-grid td[data-status="over"] { background: var(--tint-over); }
.report-grid td[data-status="none"],
.report-grid td[data-status="empty"] { background: var(--tint-none); }

.report-grid td.report-grid-avg {
  font-weight: 700;
}

.report-grid .report-grid-daytype td,
.report-grid td.report-grid-target {
  color: var(--muted);
}

.report-cell-sub {
  color: var(--muted);
  font-size: 0.85em;
  font-weight: 400;
}

.report-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 0.75em;
}

.report-legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 4px;
  border-radius: 2px;
  vertical-align: -1px;
  border: 1px solid var(--line);
}

.report-legend i[data-status="good"] { background: var(--tint-good); }
.report-legend i[data-status="under"] { background: var(--tint-under); }
.report-legend i[data-status="low"] { background: var(--tint-low); }
.report-legend i[data-status="over"] { background: var(--tint-over); }
.report-legend i[data-status="none"],
.report-legend i[data-status="empty"] { background: var(--tint-none); }

.report-chart-svg {
  width: 100%;
  height: auto;
  display: block;
}

.report-chart-note,
.report-section-sub {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 0.8em;
}

.report-section-sub {
  margin: 0 0 6px;
}

/* v1.19: the coach portal -- "What she ate" on the report in coach mode,
   and the athlete cards (ui/coachhome.js). */
.report-ate-head,
.coach-card-name {
  margin: 0 0 6px;
  font-size: 1em;
}
.report-ate-meal {
  margin: 8px 0 2px;
  color: var(--muted);
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.report-ate-list {
  margin: 0;
  padding-left: 18px;
  line-height: 1.5;
}
.report-ate-day,
.coach-card {
  margin-bottom: 12px;
}

.report-chart-grid { stroke: var(--line); }
.report-chart-axis { fill: var(--muted); font-size: 9px; }
.report-chart-value { fill: var(--blue); font-size: 10px; font-weight: 700; }
.report-chart-week { fill: var(--blue); fill-opacity: 0.1; }
.report-chart-weeklabel { fill: var(--blue); font-size: 8.5px; }
.report-dot { fill: var(--muted); }
.report-trend-line { fill: none; stroke: var(--blue); stroke-width: 2.4; }
.report-bar-top { fill: var(--txt); font-size: 8.5px; }
.report-target-tick { stroke: var(--txt); stroke-width: 1.2; stroke-dasharray: 3 2; }
.report-bar[data-status="good"] { fill: var(--green); }
.report-bar[data-status="over"] { fill: var(--over); }
.report-bar[data-status="under"] { fill: var(--bar-under); }
.report-bar[data-status="none"] { fill: var(--faint); }
.report-bar.is-current { stroke: var(--txt); stroke-width: 1.5; }

.report-microbar {
  display: grid;
  grid-template-columns: 9em 1fr 3em;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
  font-size: 0.85em;
}

.report-microbar-track {
  position: relative;
  height: 9px;
  border-radius: 5px;
  background: var(--tint-none);
  overflow: hidden;
}

.report-microbar-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 5px;
}

.report-microbar[data-status="good"] .report-microbar-fill { background: var(--green); }
.report-microbar[data-status="under"] .report-microbar-fill { background: var(--bar-under); }
.report-microbar[data-status="low"] .report-microbar-fill { background: var(--blue); }

.report-microbar-tick {
  position: absolute;
  top: 0;
  bottom: 0;
  border-left: 1.5px solid var(--muted);
}

.report-microbar-pct {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.report-nodata {
  margin: 6px 0 0;
  font-size: 0.85em;
}

/* --- Task 6 (v1.2): saved meals ------------------------------------------
   Two small screens and nothing else new: the name screen (ui/savemeal.js)
   reuses .foodform-field-text for its one box and .amount-add-btn for its
   Save, so only the summary line below is genuinely new there. The Saved
   meals list (ui/savedmeals.js) is one row shape -- name and meta on the
   left, a pencil and an x on the right -- built on the same panel/border/
   radius look .addfood-row already established, rather than a second,
   slightly different card style. */

.savemeal-summary {
  margin: 0 0 20px;
  color: var(--muted);
  font-size: 0.9em;
}

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

.saved-meal-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--tap-min);
  padding: 6px 6px 6px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.saved-meal-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}

.saved-meal-name {
  color: var(--txt);
}

.saved-meal-meta {
  color: var(--muted);
  font-size: 0.85em;
}

/* The rename box sits in the row where the name was, so it drops the
   bottom margin .foodform-field-text carries on a form. */
.saved-meal-edit {
  margin-bottom: 0;
}

.saved-meal-icon {
  flex: 0 0 auto;
  width: var(--tap-min);
  min-height: var(--tap-min);
  background: transparent;
  border: none;
  border-radius: 8px;
  color: var(--muted);
  font-size: 1.1em;
  cursor: pointer;
}

.saved-meal-done {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  padding: 0 16px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--txt);
  font-weight: 600;
  cursor: pointer;
}

/* --- Fill from its website (ui/webfill.js, v1.3 Task 4) ------------------- */
/* The notice a named-but-numberless food gets on the amount screen, above
   the amount box: the honest sentence (.foodform-notice's own calm, muted
   treatment) and the two ways out of it, both full-width 48dp buttons
   (.foodform-photo-btn, reused verbatim -- the same "a second way to fill
   this in" shape the food form's own camera button already has). */
.amount-no-numbers {
  margin-bottom: 8px;
}

/* The screen itself reuses .foodform-field-text for the link box,
   .amount-add-btn for its two primary actions, .eatout-secondary-btn for
   the two secondary ones, .eatout-card/.eatout-card-num/.eatout-card-note
   for the result card and .amount-food-badge for the site badge -- so all
   that is left here is the product line at the top and the screen's own
   breathing room. */
.webfill-product {
  margin-bottom: 12px;
}

.webfill-product-name {
  font-weight: 600;
}

#wf-line {
  margin: 10px 0;
}

#wf-read-btn {
  margin-bottom: 8px;
}

/* ==========================================================================
   v1.19 wide layout. Only body.wide (a computer, window 1000 px or more).
   The phone layout never reaches any of this.
   ========================================================================== */
.nav-brand { display: none; }
.today-add-box { display: none; }
/* The column wrappers add no box on the phone: their children stay direct
   layout children of the screen, so the builder's sticky pinned bar keeps
   the whole screen as its containing block. */
.re-cols, .re-left, .re-right, .today-cols, .today-main, .today-side { display: contents; }

body.wide { --side: 200px; }
body.wide .bottom-nav { top:0; bottom:0; right:auto; width:var(--side); flex-direction:column;
  align-items:stretch; border-top:0; border-right:1px solid var(--line); padding:16px 10px; gap:4px; }
body.wide .nav-btn { flex:0 0 auto; justify-content:flex-start; padding:10px 12px; border-radius:8px; }
body.wide .nav-btn.active { background:var(--tint-good); }
body.wide .nav-brand, body.wide .nav-sync { display:block; }
body.wide .nav-brand { padding:4px 12px 16px; font-weight:700; font-size:1.05em; }
body.wide .nav-sync { margin-top:auto; padding:8px 12px; color:var(--muted); font-size:0.85em; }
body.wide .app-header, body.wide .hdr-meal-picker, body.wide .screens { margin-left:var(--side); }
body.wide .screens { padding-bottom:24px; }
body.wide .screen:not([hidden]) { max-width:760px; margin:0 auto; }
body.wide #screen-today:not([hidden]), body.wide #screen-plan:not([hidden]),
body.wide #screen-recipe-edit:not([hidden]), body.wide #screen-report:not([hidden]),
body.wide [id^="screen-coach"]:not([hidden]) { max-width:1280px; }
body.wide #toast-root { left:calc(var(--side) + 16px); bottom:24px; }
body.wide .app-overlay { align-items:center; padding-bottom:16px; overflow:auto; }
body.wide .today-cols { display:grid; grid-template-columns:1fr 340px; gap:16px; align-items:start; }
body.wide .today-main, body.wide .today-side, body.wide .re-left, body.wide .re-right { display:block; }
body.wide .today-main { grid-column:1; grid-row:1; }
body.wide .today-side { grid-column:2; grid-row:1; position:sticky; top:calc(var(--header-height) + 12px);
  max-height:calc(100vh - var(--header-height) - 56px); overflow:auto; }
body.wide .today-add-box { display:block; width:100%; min-height:var(--tap-min); margin-top:12px; padding:0 14px;
  text-align:left; background:var(--bg); border:1px solid var(--line); border-radius:10px;
  color:var(--muted); font:inherit; cursor:pointer; }
body.wide .re-cols { display:grid; grid-template-columns:1fr 1fr; gap:16px; align-items:start; }
/* 56 px, not 24: a sticky column also has to fit above the screen's own
   bottom padding, or it gets pushed up under the header at the end of the page. */
body.wide .re-right { position:sticky; top:calc(var(--header-height) + 12px);
  max-height:calc(100vh - var(--header-height) - 56px); overflow:auto; }
body.wide .recipe-save-btn { position:static; width:100%; }
body.wide .recipe-save-spacer { display:none; }
/* The side menu already says "Macro Tracker": on a tab the header keeps the
   version badge and drops the repeated name (still there for a screen reader). */
body.wide #hdr-back[hidden] + .app-title #hdr-title { position:absolute; width:1px; height:1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }

/* Plan on a computer: the week grid, with Shopping and Prep beside it (Task 8).
   Everything hangs off body.wide; the phone's Week/Shopping/Prep never changes. */
body.wide .plan-wide-cols { display:grid; grid-template-columns:minmax(0, 1fr) 290px; gap:16px; align-items:start; }
body.wide .plan-wide .plan-week-toggle-row { max-width:360px; }
body.wide .plan-grid-wrap { min-width:0; overflow-x:auto; }
body.wide .plan-grid { min-width:640px; border:1px solid var(--line); border-radius:10px; overflow:hidden; background:var(--panel); }
body.wide .plan-grow { display:grid; grid-template-columns:84px repeat(7, minmax(0, 1fr)); border-top:1px solid var(--line); }
body.wide .plan-ghead { border-top:0; }
body.wide .plan-row-label { padding:8px 8px; color:var(--muted); font-size:0.85em; font-weight:600; align-self:center; }
body.wide .plan-col-head { padding:8px 6px; text-align:center; display:flex; flex-direction:column; border-left:1px solid var(--line); }
body.wide .plan-col-head.is-today { background:var(--tint-good); }
body.wide .plan-col-day { font-weight:700; }
body.wide .plan-col-type { color:var(--muted); font-size:0.8em; }
body.wide .plan-gcell { border-left:1px solid var(--line); min-width:0; display:flex; }
body.wide .plan-cell { flex:1 1 auto; min-width:0; min-height:56px; padding:6px 6px; display:flex; flex-direction:column;
  gap:2px; align-items:flex-start; justify-content:center; text-align:left; background:transparent; border:0;
  color:var(--txt); font:inherit; font-size:0.85em; cursor:pointer; }
body.wide .plan-cell:hover:not(:disabled) { background:var(--line); }
body.wide .plan-cell:disabled { cursor:default; color:var(--muted); }
body.wide .plan-cell-name { font-weight:600; overflow-wrap:anywhere; }
body.wide .plan-cell-kcal { color:var(--muted); font-size:0.9em; }
body.wide .plan-cell-plus { color:var(--muted); font-size:1.2em; }
body.wide .plan-cell.is-away { border:1px dashed var(--muted); margin:3px; border-radius:6px; }
body.wide .plan-extras-cell, body.wide .plan-total-cell { padding:8px 6px; font-size:0.85em; color:var(--muted); align-items:center; }
body.wide .plan-total-cell { flex-direction:column; align-items:flex-start; color:var(--txt); }
body.wide .plan-total-num { font-weight:700; }
body.wide .plan-total-target { color:var(--muted); font-size:0.9em; }
body.wide .plan-total-cell[data-status="good"] { background:var(--tint-good); }
body.wide .plan-total-cell[data-status="under"] { background:var(--tint-under); }
body.wide .plan-total-cell[data-status="over"] { background:var(--tint-over); }
body.wide .plan-total-cell[data-status="none"] { background:var(--tint-none); }
body.wide .plan-aside { position:sticky; top:calc(var(--header-height) + 12px); width:290px;
  max-height:calc(100vh - var(--header-height) - 56px); overflow:auto; }
body.wide .plan-aside-sec { margin-bottom:16px; }
body.wide .plan-aside-h { margin:0 0 8px; font-size:1em; }
body.wide .plan-pop { position:fixed; z-index:60; width:300px; max-height:calc(100vh - 16px); overflow:auto; padding:12px;
  background:var(--panel); border:1px solid var(--line); border-radius:12px; box-shadow:0 8px 28px rgba(0, 0, 0, 0.35); }
body.wide .plan-pop-title { margin:0 0 8px; font-size:1em; }
body.wide .plan-pop-list { display:flex; flex-direction:column; gap:4px; max-height:240px; overflow:auto; }
body.wide .plan-pop-recipe { display:flex; justify-content:space-between; gap:8px; min-height:40px; padding:6px 10px;
  background:var(--bg); border:1px solid var(--line); border-radius:8px; color:var(--txt); font:inherit; text-align:left; cursor:pointer; }
body.wide .plan-pop-recipe.is-current { border-color:var(--accent); }
body.wide .plan-pop-kcal { color:var(--muted); font-size:0.85em; white-space:nowrap; }
body.wide .plan-pop-scope { display:flex; flex-direction:column; gap:6px; margin:12px 0; }
body.wide .plan-pop-away { width:100%; min-height:40px; background:var(--bg); border:1px dashed var(--muted); border-radius:8px;
  color:var(--txt); font:inherit; cursor:pointer; }

/* v1.19 Task 11: the coach's Targets screen (ui/coachtargets.js) and her
   one-time "<coach> updated your targets" card on Today (ui/today.js).
   A changed box is outlined blue; nothing here is red. */
.coach-card-btns { display:flex; gap:8px; }
.coach-card-btns .amount-add-btn { flex:1 1 0; margin-bottom:0; }
.ct-cols { display:block; }
.ct-grid-wrap { overflow-x:auto; padding:8px; margin-bottom:12px; }
.ct-grid { width:100%; border-collapse:collapse; }
.ct-grid th, .ct-grid td { padding:4px; text-align:right; font-size:0.85em; font-weight:600; }
.ct-grid thead th { color:var(--muted); vertical-align:bottom; }
.ct-grid .ct-daycol { text-align:left; font-size:0.95em; white-space:nowrap; }
.ct-grid tbody th { color:var(--txt); }
.ct-box { width:88px; min-height:var(--tap-min); padding:6px 8px; text-align:right; background:var(--bg);
  border:1px solid var(--line); border-radius:8px; color:var(--txt); font:inherit; }
.ct-box.ct-changed { border:2px solid var(--blue); padding:5px 7px; }
.ct-sum { color:var(--muted); font-weight:400; white-space:nowrap; }
.ct-cancel { margin-bottom:24px; }
.ct-history { margin-top:8px; }
body.wide .ct-cols { display:grid; grid-template-columns:minmax(0, 1fr) 340px; gap:24px; align-items:start; }
body.wide .ct-history { margin-top:0; }

.coach-update-card { margin:8px 0 12px; padding:12px 14px; background:var(--tint-under); border-radius:10px; color:var(--txt); }
.coach-update-title { margin:0 0 6px; font-size:1em; }
.coach-update-days, .coach-update-same, .coach-update-note { margin:0 0 4px; }
.coach-update-list { margin:0 0 6px; padding-left:20px; }
.coach-update-new { font-weight:700; }
.coach-update-old { color:var(--muted); }
.coach-update-same { color:var(--muted); font-size:0.9em; }
.coach-update-note { margin:6px 0 10px; font-style:italic; }
.coach-update-got { margin:8px 0 0; }
.sr-only { position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
