/* ------------------------------------------------------------ tokens */

:root {
  /* spacing scale */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;

  /* type scale: 14px is the smallest for anything to read; only the
     labels drawn inside a chart are smaller */
  --fs-chart: 12px;
  --fs-sm: 14px;
  --fs-md: 16px;
  --fs-lg: 20px;
  --fs-xl: 32px;

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-pill: 999px;

  --tap: 44px;

  /* light theme */
  color-scheme: light;
  --bg: #f1f5f9;
  --card: #ffffff;
  --card-2: #f1f5f9;
  --card-hover: #e2e8f0;
  --text: #0f172a;
  --muted: #475569;
  --border: #cbd5e1;
  --accent: #15803d;
  --accent-hover: #166534;
  --accent-soft: #dcfce7;
  --on-accent: #ffffff;
  --accent-text: #15803d;
  --danger: #b91c1c;
  --on-danger: #ffffff;
  --danger-soft: #fee2e2;
  --warning-soft: #fef3c7;
  --warning-text: #78350f;
  --warning-border: #f59e0b;
  --focus: #2563eb;
  --chart-calories: #15803d;
  --chart-weight: #1d4ed8;
  --bar-muted: #94a3b8;
  --bar-today: #334155;
  --segment-on: #ffffff;
  --shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
  --scrim: rgba(15, 23, 42, 0.6);
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.2);
  --toast-bg: #0f172a;
  --toast-text: #f8fafc;
  --toast-error-bg: #991b1b;
  --toast-error-text: #ffffff;
  --toast-action-hover: rgba(255, 255, 255, 0.15);
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --bg: #0f172a;
  --card: #1e293b;
  --card-2: #273449;
  --card-hover: #334155;
  --text: #f1f5f9;
  --muted: #94a3b8;
  --border: #334155;
  --accent: #22c55e;
  --accent-hover: #16a34a;
  --accent-soft: #14532d;
  --on-accent: #052e16;
  --accent-text: #4ade80;
  --danger: #f87171;
  --on-danger: #450a0a;
  --danger-soft: #450a0a;
  --warning-soft: #422006;
  --warning-text: #fde68a;
  --warning-border: #92400e;
  --focus: #60a5fa;
  --chart-calories: #22c55e;
  --chart-weight: #60a5fa;
  --bar-muted: #64748b;
  --bar-today: #e2e8f0;
  --segment-on: #475569;
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  --scrim: rgba(0, 0, 0, 0.85);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
  --toast-bg: #f1f5f9;
  --toast-text: #0f172a;
  --toast-error-bg: #fecaca;
  --toast-error-text: #450a0a;
  --toast-action-hover: rgba(15, 23, 42, 0.1);
}

/* ------------------------------------------------------------ base */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: var(--fs-md);
  line-height: 1.4;
  background: var(--bg);
  color: var(--text);
}

a { color: var(--accent-text); }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

h2[tabindex='-1']:focus { outline: none; }

/* An element marked hidden is never shown, whatever its classes say
   (.btn and others set their own display). */
[hidden] { display: none !important; }

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.app {
  max-width: 520px;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

/* ------------------------------------------------------------ header + tabs */

/* On a phone the brand and Settings share the first row and the tabs fill
   the second; on a wide screen all three share one row (see the end). */
.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  row-gap: var(--s2);
  padding: var(--s3) var(--s4);
}

.brand-block { flex: 1; order: 1; }
.topbar > .settings-link { order: 2; }

.brand {
  font-size: var(--fs-lg);
  line-height: 1.2;
  margin: 0;
}

.tagline {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
}

.tabs {
  order: 3;
  flex: 1 0 100%;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s1);
  margin: 0;
  padding: var(--s1);
  background: var(--card);
  border-radius: var(--r-md);
}

.tab {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  border-radius: var(--r-sm);
  color: var(--muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
}

.tab[aria-current='page'] {
  background: var(--accent);
  color: var(--on-accent);
}

.main {
  flex: 1;
  padding: 0 var(--s4) var(--s6);
}

.screen-stack { display: flex; flex-direction: column; gap: var(--s4); }

.storage-note {
  text-align: center;
  color: var(--muted);
  font-size: var(--fs-sm);
  padding: 0 var(--s4) var(--s4);
  margin: 0;
}

/* ------------------------------------------------------------ cards */

.card {
  background: var(--card);
  border-radius: var(--r-lg);
  padding: var(--s4);
}

.card-quiet { background: transparent; border: 1px solid var(--border); }

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
}

.card-title {
  font-size: var(--fs-lg);
  font-weight: 700;
  margin: 0 0 var(--s1);
}

.card-sub {
  color: var(--muted);
  font-size: var(--fs-sm);
  margin: 0 0 var(--s3);
}

.card-foot {
  margin: var(--s2) 0 0;
  text-align: center;
}

.section-title {
  font-size: var(--fs-md);
  font-weight: 600;
  margin: var(--s2) 0 var(--s2);
}

.empty-hint {
  color: var(--muted);
  font-size: var(--fs-sm);
  margin: var(--s3) 0;
  text-align: center;
}

.inline-note {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding: 0 0 0 var(--s3);
  margin-bottom: var(--s3);
  background: var(--warning-soft);
  color: var(--warning-text);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
}

.inline-note .btn-text { color: inherit; text-decoration: underline; }

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

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s3);
  margin-bottom: var(--s4);
}

.field { min-width: 0; margin-bottom: var(--s3); }
.field-row .field { margin-bottom: 0; }

label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
  margin: 0 0 var(--s1);
}

input[type='text'],
input[type='date'] {
  width: 100%;
  min-height: 48px;
  padding: var(--s3);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--card-2);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
}

input[type='date'] { -webkit-appearance: none; appearance: none; }

input:focus-visible { outline: 3px solid var(--focus); outline-offset: 0; border-color: var(--focus); }

input[aria-invalid='true'] { border-color: var(--danger); }

.field-status {
  min-height: 0;
  margin: var(--s1) 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2);
}

.field-status:empty { margin: 0; }
.field-status.is-saved { color: var(--accent-text); }
.field-status.is-saved::before { content: '✓'; font-weight: 700; }
.field-status.is-error { color: var(--danger); }
.field-hint { margin: var(--s1) 0 0; font-size: var(--fs-sm); color: var(--muted); }
.field-status:not(:empty) + .field-hint { display: none; }
.field-note { display: grid; }
.field-note > * { grid-area: 1 / 1; }
.field-note > .field-status:not(:empty) + .field-hint { display: block; visibility: hidden; }

/* ------------------------------------------------------------ buttons */

.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 48px;
  padding: var(--s3) var(--s4);
  margin-top: var(--s3);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  font: inherit;
  font-size: var(--fs-md);
  font-weight: 600;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}

.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-secondary { background: var(--card-2); color: var(--text); border-color: var(--border); }
.btn-danger { background: var(--danger); color: var(--on-danger); }
.btn-danger-outline { background: transparent; color: var(--danger); border-color: var(--danger); }

.btn:disabled,
.btn.is-disabled { opacity: 0.5; cursor: not-allowed; }

.btn-text {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 var(--s3);
  background: none;
  border: none;
  border-radius: var(--r-sm);
  color: var(--accent-text);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

/* A secondary way to do what a primary button on the same card does. */
.btn-text.btn-quiet { color: var(--muted); font-weight: 500; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: none;
  border-radius: var(--r-pill);
  background: none;
  color: var(--muted);
  font-size: var(--fs-lg);
  line-height: 1;
  cursor: pointer;
}

.icon-btn[aria-current='page'] { color: var(--accent-text); background: var(--card); }

/* Settings (backup, theme) in the header: the gear with its name. */
.settings-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 0 var(--s3) 0 var(--s2);
  border-radius: var(--r-pill);
  color: var(--muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.settings-link svg { flex: none; }
.settings-link[aria-current='page'] { color: var(--accent-text); background: var(--card); }
.icon-btn-danger { color: var(--danger); }

.file-btn { position: relative; }
.file-btn:focus-within,
input.visually-hidden:focus-visible + .file-btn { outline: 3px solid var(--focus); outline-offset: 2px; }

@media (hover: hover) {
  .tab:hover:not([aria-current='page']) { background: var(--card-2); color: var(--text); }
  .btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
  .btn-secondary:hover:not(:disabled):not(.is-disabled) { background: var(--card-hover); }
  .btn-danger:hover { filter: brightness(0.9); }
  .btn-danger-outline:hover { background: var(--danger-soft); }
  .btn-text:hover { background: var(--card-2); text-decoration: underline; }
  .icon-btn:hover { background: var(--card-2); color: var(--text); }
  .settings-link:hover:not([aria-current='page']) { background: var(--card-2); color: var(--text); }
  .icon-btn-danger:hover { background: var(--danger-soft); color: var(--danger); }
  .meal-pill:hover:not(.active) { border-color: var(--accent); color: var(--text); }
  .segment:hover { color: var(--text); }
  .history-item:hover { background: var(--card-hover); }
  .photo-thumb:hover img { opacity: 0.85; }
  .toast-action:hover { background: var(--toast-action-hover); }
}

.btn-primary:active:not(:disabled) { background: var(--accent-hover); }
.btn-secondary:active:not(:disabled) { background: var(--card-hover); }

/* ------------------------------------------------------------ today */

.total-box {
  background: var(--card-2);
  border-radius: var(--r-md);
  padding: var(--s4);
  text-align: center;
  margin: 0;
}

.total-box + .btn { margin: var(--s3) 0 var(--s2); }

.total-num {
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}

.total-label { color: var(--muted); font-size: var(--fs-sm); }
.total-goal { margin-top: var(--s2); font-size: var(--fs-sm); font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.set-goal-link { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; margin-top: var(--s1, 4px); font-size: var(--fs-sm); color: var(--muted); text-decoration: underline; }
.set-goal-link[hidden] { display: none; }
.total-goal.is-over { color: var(--danger); }

.meal-list { list-style: none; margin: 0; padding: 0; }

.meal-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  min-height: 52px;
  border-bottom: 1px solid var(--border);
}

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

/* The whole row, apart from its Undo and Remove buttons, opens Log Meal. */
.meal-link {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  min-width: 0;
  min-height: 52px;
  color: inherit;
  text-decoration: none;
  border-radius: var(--r-sm);
}

@media (hover: hover) {
  .meal-link:hover .meal-go { text-decoration: underline; }
}

.meal-info { display: flex; flex-direction: column; min-width: 0; }
.meal-name { font-size: var(--fs-sm); font-weight: 600; color: var(--text); }
.meal-value { font-size: var(--fs-md); font-weight: 700; font-variant-numeric: tabular-nums; }
.meal-empty { font-size: var(--fs-sm); color: var(--muted); }

.meal-actions { display: flex; align-items: center; gap: var(--s3); }

/* ------------------------------------------------------------ log meal */

.meal-picker {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s2);
  margin: var(--s2) 0 var(--s4);
}

.meal-pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: var(--s1) var(--s2);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--card-2);
  color: var(--muted);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
}

.meal-pill .pill-value { font-size: var(--fs-sm); font-weight: 500; font-variant-numeric: tabular-nums; }
.meal-pill .pill-value:empty { display: none; }
.meal-pill.filled { border-color: var(--accent); color: var(--text); }
.meal-pill.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Back (secondary) beside Save and close, or, when both labels don't fit
   on one line side by side, Save and close above Back, each full width. */
.log-actions { display: flex; flex-wrap: wrap-reverse; gap: 0 var(--s3); }
.log-actions > .btn { flex: 1 1 0; min-width: max-content; white-space: nowrap; }

.running-total {
  margin: 0 0 var(--s2);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
}

/* Type the total, or add foods one at a time. */
.log-mode { margin: 0 0 var(--s3); }

.foods-panel { margin-bottom: var(--s3); }
.food-list { list-style: none; margin: 0 0 var(--s2); padding: 0; }
.food-row {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: var(--tap);
  border-bottom: 1px solid var(--border);
}
.food-name { flex: 1; min-width: 0; overflow-wrap: anywhere; font-size: var(--fs-md); }
.food-cal { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.food-sum { margin: 0 0 var(--s3); font-size: var(--fs-sm); font-weight: 600; color: var(--muted); }
.food-add .field-row { grid-template-columns: 3fr 2fr; margin-bottom: 0; }
.food-add .field-status { margin-bottom: var(--s2); }
.food-add-btn { width: 100%; margin-top: var(--s2); }

/* Today: a meal logged food by food names its foods under its total. */
.meal-foods {
  font-size: var(--fs-sm);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ------------------------------------------------------------ history */

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

.history-month + .history-month { margin-top: var(--s5); }
.months-overview { display: none; }
.months-overview .meal-table thead th { position: sticky; top: 0; background: var(--card); }
.month-link { min-height: 32px; min-width: 0; padding: 0 var(--s1); margin-left: calc(-1 * var(--s1)); }
.history-month-title { font-size: var(--fs-md); font-weight: 700; margin: var(--s2) 0 0; }
.history-month-title:focus { outline: none; }
.history-month-title:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.history-month-sub { font-size: var(--fs-sm); color: var(--muted); margin: 0 0 var(--s2); font-variant-numeric: tabular-nums; }

select {
  width: 100%;
  min-height: 48px;
  padding: var(--s3);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--card-2);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
}
select:focus-visible { outline: 3px solid var(--focus); outline-offset: 0; border-color: var(--focus); }

.history-item {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 56px;
  padding: var(--s2) var(--s3) var(--s2) var(--s4);
  border-radius: var(--r-md);
  background: var(--card-2);
  color: var(--text);
  text-decoration: none;
}

.history-date { font-weight: 600; flex: 1; }
.history-stats { color: var(--text); font-size: var(--fs-sm); text-align: right; font-variant-numeric: tabular-nums; }
.history-stats.is-muted { color: var(--muted); }
.chevron { color: var(--muted); font-size: var(--fs-lg); }

/* ------------------------------------------------------------ compare */

.compare-answers { display: flex; flex-direction: column; gap: var(--s3); }

.compare-answer {
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--card-2);
}

.compare-answer-label {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.compare-answer-text { margin: var(--s1) 0 0; font-size: var(--fs-md); font-weight: 600; line-height: 1.35; }
.compare-answer-text strong { font-size: var(--fs-lg); font-variant-numeric: tabular-nums; }
.compare-answer-detail { margin: var(--s1) 0 0; font-size: var(--fs-sm); color: var(--muted); font-variant-numeric: tabular-nums; }

/* Plain amounts from zero: longer means more, nothing more. The rows
   share one set of columns, so every bar is measured against the same
   track however wide its label or value is. */
.amount-bars {
  list-style: none;
  margin: var(--s3) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 8.5rem) 1fr auto;
  gap: var(--s1) var(--s2);
}
.amount-row {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: minmax(0, 8.5rem) 1fr auto;
  grid-template-columns: subgrid;
  align-items: center;
  font-size: var(--fs-sm);
  color: var(--muted);
}
.amount-row.is-today { color: var(--text); font-weight: 600; }
.amount-track { height: 12px; border-radius: var(--s1); background: var(--card); overflow: hidden; }
.amount-bar { display: block; height: 100%; border-radius: var(--s1); background: var(--bar-muted); }
.amount-row.is-today .amount-bar { background: var(--bar-today); }
.amount-value { font-variant-numeric: tabular-nums; text-align: right; min-width: 64px; }

.compare-meals { margin-top: var(--s4); border-top: 1px solid var(--border); }
.compare-meals summary {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: var(--s2) 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--accent-text);
  cursor: pointer;
  list-style: none;
}
.compare-meals summary::-webkit-details-marker { display: none; }
.compare-meals summary::before { content: '▸'; display: inline-block; width: 1.2em; flex-shrink: 0; }
.compare-meals[open] summary::before { content: '▾'; }

.meal-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.meal-table th, .meal-table td { padding: var(--s2) var(--s1); text-align: right; border-bottom: 1px solid var(--border); }
.meal-table th:first-child { text-align: left; }
.meal-table thead th { font-size: var(--fs-sm); color: var(--muted); font-weight: 600; }
.meal-table tbody th { font-weight: 600; }

.compare-caption { font-size: var(--fs-sm); color: var(--muted); margin: var(--s2) 0 0; }

.compare-first { color: var(--muted); font-size: var(--fs-sm); margin: var(--s2) 0 var(--s3); }

/* ------------------------------------------------------------ charts */

.segmented {
  display: inline-flex;
  gap: var(--s1);
  padding: var(--s1);
  margin: 0;
  border: none;
  border-radius: var(--r-md);
  background: var(--card-2);
}

.segmented-wide { display: flex; }
.segmented-wide .segment { flex: 1; }

.segment {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 var(--s3);
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
}

/* The chosen option: its own surface and an accent outline, clear in
   both themes. */
.segment[aria-pressed='true'],
input:checked + .segment {
  background: var(--segment-on);
  color: var(--text);
  box-shadow: inset 0 0 0 2px var(--accent), var(--shadow-sm);
}

input:focus-visible + .segment { outline: 3px solid var(--focus); outline-offset: 1px; }

.chart { margin-top: var(--s4); }

.chart-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s2);
}

.chart-title { font-size: var(--fs-md); font-weight: 600; margin: 0; }
.chart-sub { font-size: var(--fs-sm); color: var(--muted); margin: 0; }

.chart-head > :first-child { flex: 1; min-width: 0; }
/* The latest value and its date each stay on one line. */
.chart-latest { display: flex; flex-direction: column; align-items: flex-end; flex-shrink: 0; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.chart-latest-date { font-size: var(--fs-sm); font-weight: 500; color: var(--muted); }
.chart-latest.series-calories { color: var(--chart-calories); }
.chart-latest.series-weight { color: var(--chart-weight); }

.chart-plot { position: relative; }

.chart-svg { display: block; max-width: 100%; touch-action: pan-y; }
.chart-svg.series-calories { --series: var(--chart-calories); }
.chart-svg.series-weight { --series: var(--chart-weight); }
.chart-svg .gridline { stroke: var(--border); stroke-width: 1; }
.chart-svg .axis-label { fill: var(--muted); font-size: var(--fs-chart); font-variant-numeric: tabular-nums; }
.chart-svg .line { fill: none; stroke: var(--series); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.chart-svg .line-gap { stroke: var(--series); stroke-width: 1.5; stroke-dasharray: 3 5; opacity: 0.6; }
.chart-svg .dot { fill: var(--series); stroke: var(--card); stroke-width: 2; }
.chart-svg .dot-partial { fill: var(--card); stroke: var(--series); stroke-width: 2; }
.chart-svg .partial-label { fill: var(--muted); font-size: var(--fs-chart); font-weight: 600; }
.chart-svg .crosshair { stroke: var(--muted); stroke-width: 1; }

.chart-tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--s2) var(--s3);
  font-size: var(--fs-sm);
  transform: translate(-50%, calc(-100% - var(--s3)));
  white-space: nowrap;
  box-shadow: var(--shadow);
  opacity: 0;
  transition: opacity 0.08s ease;
}

.chart-tooltip.visible { opacity: 1; }
.chart-tooltip .tt-value { font-weight: 700; }
.chart-tooltip .tt-date { color: var(--muted); font-size: var(--fs-sm); }

/* ------------------------------------------------------------ photos */

.photo-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2); }

.photo-thumb {
  aspect-ratio: 1;
  padding: 0;
  border: none;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--card-2);
  cursor: pointer;
}

.photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.photo-missing { display: block; padding: var(--s2); font-size: var(--fs-sm); color: var(--muted); }
.photo-unviewable {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s1);
  width: 100%;
  min-height: 12rem;
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--card-2);
  text-align: center;
}
.photo-unviewable p { margin: 0; }
.photo-unviewable-title { font-weight: 600; }
.photo-unviewable-text { color: var(--muted); font-size: var(--fs-sm); }

/* ------------------------------------------------------------ dialogs */

.dialog {
  width: min(420px, calc(100vw - var(--s6)));
  padding: 0;
  border: none;
  border-radius: var(--r-lg);
  background: var(--card);
  color: var(--text);
  box-shadow: var(--shadow);
}

.dialog::backdrop { background: var(--scrim); }

.dialog-body { padding: var(--s5) var(--s4) var(--s4); }
.dialog-title { font-size: var(--fs-lg); margin: 0 0 var(--s2); }
.dialog-text { color: var(--muted); font-size: var(--fs-sm); margin: 0; }
.dialog-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); margin-top: var(--s4); }
.dialog-actions .btn { margin-top: 0; }

.dialog-viewer {
  width: min(560px, calc(100vw - var(--s4)));
  max-height: calc(100vh - var(--s4));
  background: var(--card);
}

.viewer { display: flex; flex-direction: column; gap: var(--s3); padding: var(--s4); }
.viewer-title { font-size: var(--fs-md); margin: 0; }
.viewer-img { width: 100%; max-height: 55vh; object-fit: contain; border-radius: var(--r-md); background: var(--card-2); }
.viewer-bar { display: grid; grid-auto-columns: 1fr; grid-auto-flow: column; gap: var(--s3); }
.viewer-position { margin: calc(-1 * var(--s2)) 0 0; color: var(--muted); font-size: var(--fs-sm); }
.viewer-position:empty { display: none; }
.viewer-frame { display: flex; justify-content: center; touch-action: pan-y; }
.viewer-nav { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.viewer-nav .btn { margin-top: 0; }

.dialog-compare { width: min(900px, calc(100vw - var(--s4))); }
.compare-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.compare-photo { margin: 0; display: flex; flex-direction: column; gap: var(--s2); min-width: 0; }
.compare-img { width: 100%; max-height: 60vh; object-fit: contain; border-radius: var(--r-md); background: var(--card-2); }
.compare-photo figcaption { display: flex; flex-direction: column; font-size: var(--fs-sm); }
.compare-date { font-weight: 700; }
.compare-weight { color: var(--muted); font-variant-numeric: tabular-nums; }
.dialog-compare .viewer > .btn { margin-top: 0; }

.compare-bar { position: sticky; top: var(--s2); z-index: 5; }
.compare-bar .notice-actions { margin-top: var(--s2); }
.is-picking .photo-thumb[aria-pressed='true'] { outline: 3px solid var(--accent); outline-offset: 2px; }
.is-picking .photo-thumb[aria-pressed='false'] img { opacity: 0.8; }
.viewer-bar .btn { margin-top: 0; }
.viewer-confirm { display: flex; flex-direction: column; gap: var(--s2); }
.viewer-confirm-title { font-size: var(--fs-md); font-weight: 700; margin: 0; }
.viewer-confirm .dialog-actions { margin-top: var(--s2); }
.viewer-confirm .dialog-actions .btn { margin-top: 0; }
.viewer .field { margin-bottom: 0; }

/* What's new: a guided tour. The light is a hole in a dimmed screen,
   around the feature; the card sits beside it with an arrow pointing at
   it, and both glide to the next stop. */
.tour-layer { position: fixed; inset: 0; z-index: 100; }
body.is-touring { padding-bottom: 100vh; }
.tour-spot {
  position: fixed;
  border-radius: var(--r-md);
  box-shadow: 0 0 0 9999px var(--scrim);
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  pointer-events: none;
  transition: top 0.35s ease, left 0.35s ease, width 0.35s ease, height 0.35s ease;
}
.tour-layer.is-centered .tour-spot { outline-color: transparent; }
.tour-card {
  position: fixed;
  padding: var(--s4);
  border-radius: var(--r-lg);
  background: var(--card);
  color: var(--text);
  box-shadow: var(--shadow);
  transition: top 0.35s ease, left 0.35s ease, opacity 0.2s ease;
}
.tour-layer.is-moving .tour-card { opacity: 0.4; }
.tour-arrow {
  position: absolute;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  background: var(--card);
  transform: rotate(45deg);
  transition: left 0.35s ease;
}
.tour-card[data-side='below'] .tour-arrow { top: -7px; }
.tour-card[data-side='above'] .tour-arrow { bottom: -7px; }
.tour-layer.is-centered .tour-arrow { display: none; }
.tour-head { position: relative; display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.tour-where { margin: 0; color: var(--accent-text); font-size: var(--fs-sm); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.tour-close { min-height: var(--tap); }
.tour-title { font-size: var(--fs-lg); margin: 0 0 var(--s2); }
.tour-title:focus { outline: none; }
.tour-points { margin: 0; padding-left: 1.2em; display: flex; flex-direction: column; gap: var(--s1); font-size: var(--fs-sm); line-height: 1.45; }
.tour-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); margin-top: var(--s3); }
.tour-dots { display: flex; gap: 5px; }
.tour-dot { width: 6px; height: 6px; border-radius: var(--r-pill); background: var(--border); transition: width 0.2s ease; }
.tour-dot.is-current { background: var(--accent); width: 16px; }
.tour-position { margin: 0; color: var(--muted); font-size: var(--fs-sm); }
.tour-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); margin-top: var(--s3); }
.tour-actions .btn { margin-top: 0; }
@media (max-height: 640px) {
  .tour-card { padding: var(--s3); }
  .tour-title { font-size: var(--fs-md); }
}

/* ------------------------------------------------------------ loading */

.main.is-loading { opacity: 0.35; pointer-events: none; transition: opacity 0.15s ease; }

.loading {
  position: fixed;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s5);
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--text);
  font-weight: 600;
  box-shadow: var(--shadow);
  z-index: 15;
}

.spinner {
  width: 20px;
  height: 20px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------ messages */

.notice-card {
  background: var(--warning-soft);
  color: var(--warning-text);
  border: 1px solid var(--warning-border);
}

.notice-card.is-done { background: var(--accent-soft); color: var(--text); border-color: var(--accent); }

.notice-title { font-size: var(--fs-md); font-weight: 700; margin: 0 0 var(--s1); }
.notice-text { font-size: var(--fs-sm); margin: 0; }
.notice-text + .notice-text { margin-top: var(--s2); }
.notice-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.notice-actions > :only-child { grid-column: 1 / -1; }
.notice-card .field-status { color: inherit; }

.notice-more { margin: var(--s1) 0 0; }
/* The summary is a full-height tap target, so the row already has air
   below its text; the buttons follow at the card's usual rhythm. */
.notice-more + .notice-actions > .btn { margin-top: var(--s1); }
.notice-more[open] + .notice-actions > .btn { margin-top: var(--s3); }
.notice-more summary {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  font-size: var(--fs-sm);
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
.notice-more summary::-webkit-details-marker { display: none; }
.notice-more summary::before { content: '▸'; display: inline-block; width: 1.2em; flex-shrink: 0; }
.notice-more[open] summary::before { content: '▾'; }
.notice-more .install-steps { margin-top: 0; }
.install-steps { margin: var(--s2) 0; padding-left: var(--s5); font-size: var(--fs-sm); }
.install-steps li { margin-bottom: var(--s1); }

/* A new user's first screen on a phone, until the app is on the Home
   Screen: a walkthrough, one step per slide, and nothing else in the app
   is reachable. The slides share one grid cell, so the card is as tall as
   the tallest and doesn't jump between steps. */
body.is-install-gate .tabs,
body.is-install-gate .settings-link { display: none; }
.walk { overflow: hidden; text-align: center; }
.walk-viewport { display: grid; touch-action: pan-y; }
.walk-slide { grid-area: 1 / 1; display: flex; flex-direction: column; align-items: center; }
.walk-slide:not(.is-active) { visibility: hidden; }
.walk-count { margin: var(--s4) 0 var(--s1); font-size: var(--fs-sm); font-weight: 700; color: var(--accent-text); text-transform: uppercase; letter-spacing: 0.06em; }
.walk-title { margin: 0 0 var(--s2); font-size: var(--fs-lg); line-height: 1.25; outline: none; }
.walk-text { margin: 0; color: var(--muted); max-width: 34ch; }
.walk-dots { display: flex; justify-content: center; gap: var(--s2); margin-top: var(--s5); }
.walk-dot { width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--border); }
.walk-dot.is-past { background: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.walk-dot.is-on { width: 24px; background: var(--accent); }
.walk-nav { display: grid; grid-template-columns: 1fr 2fr; gap: var(--s3); }
.walk-nav > :only-child,
.walk-nav > [hidden] + .btn { grid-column: 1 / -1; }
.walk-done:empty { display: none; }
.walk-done { margin: var(--s3) 0 0; font-weight: 700; color: var(--accent-text); }
.walk-foot { margin: var(--s4) 0 0; font-size: var(--fs-sm); color: var(--muted); }

/* The pictures: drawn with plain boxes, in the app's colors. */
.walk-art { position: relative; width: 220px; height: 170px; flex-shrink: 0; }
.walk-art-welcome { display: grid; place-items: center; }
.walk-hero-icon { position: relative; width: 112px; height: 112px; border-radius: 26px; box-shadow: var(--shadow); }
.walk-glow { position: absolute; width: 150px; height: 150px; border-radius: 50%; background: radial-gradient(circle, color-mix(in srgb, var(--accent) 40%, transparent), transparent 70%); }
.walk-phone {
  border: 3px solid var(--text);
  border-radius: 28px;
  background: var(--card-2);
  overflow: hidden;
  font-size: 11px;
  color: var(--text);
}
.walk-phone-bottom { border-top: none; border-top-left-radius: 0; border-top-right-radius: 0; }
.walk-phone-sheet,
.walk-phone-top { border-bottom: none; border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.walk-page-lines { position: absolute; inset: 18px 18px auto; display: grid; gap: 8px; }
.walk-phone-top .walk-page-lines { top: 56px; }
.walk-page-lines > span { height: 8px; border-radius: 4px; background: var(--border); }
.walk-page-lines > span:nth-child(2) { width: 70%; }
.walk-page-lines > span:nth-child(3) { width: 85%; }
.walk-address {
  display: block;
  padding: 6px 10px;
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.walk-phone-bottom .walk-address { position: absolute; left: 12px; right: 12px; bottom: 56px; }
.walk-toolbar { position: absolute; left: 0; right: 0; bottom: 0; height: 50px; display: flex; justify-content: space-around; align-items: center; background: var(--card); border-top: 1px solid var(--border); }
.walk-tool { position: relative; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%; font-size: 15px; font-weight: 700; color: var(--muted); }
.walk-tool.is-target { color: var(--on-accent); background: var(--accent); }
.walk-topbar { position: absolute; left: 0; right: 0; top: 0; display: flex; align-items: center; gap: 6px; padding: 8px 8px 8px 12px; background: var(--card); border-bottom: 1px solid var(--border); }
.walk-topbar .walk-address { flex: 1; min-width: 0; background: var(--card-2); }
.walk-kebab { font-size: 18px; }
.walk-sheet,
.walk-menu { position: absolute; display: flex; flex-direction: column; background: var(--card); box-shadow: var(--shadow); }
.walk-sheet { left: 0; right: 0; bottom: 0; top: 22px; border-radius: 18px 18px 0 0; padding: 10px; gap: 6px; }
.walk-menu { right: 8px; top: 40px; width: 150px; border-radius: 12px; padding: 4px 0; }
.walk-sheet-head { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; border-bottom: 1px solid var(--border); font-weight: 700; text-align: left; }
.walk-sheet-icon { width: 26px; height: 26px; border-radius: 7px; }
.walk-sheet-name { flex: 1; }
.walk-add { padding: 3px 10px; border-radius: var(--r-pill); color: var(--on-accent); background: var(--accent); }
.walk-row { position: relative; display: flex; align-items: center; justify-content: space-between; padding: 6px 10px; border-radius: 8px; background: var(--card-2); text-align: left; }
.walk-menu .walk-row { background: none; border-radius: 0; }
.walk-row.is-target { color: var(--accent-text); background: var(--accent-soft); font-weight: 700; }
.walk-row-dot { width: 14px; height: 14px; border-radius: 4px; background: var(--border); }
.walk-tap { position: absolute; top: 50%; left: 50%; width: 22px; height: 22px; margin: -11px 0 0 -11px; border-radius: 50%; border: 3px solid var(--focus); pointer-events: none; opacity: 0; }
.walk-row .walk-tap { left: auto; right: 2px; }
.walk-home { display: flex; flex-direction: column; justify-content: space-between; padding: 14px 18px 8px; border-radius: 28px; background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 35%, var(--card-2)), color-mix(in srgb, var(--chart-weight) 30%, var(--card-2))); }
.walk-grid,
.walk-dock { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; justify-items: center; }
.walk-dock { padding: 6px; border-radius: 16px; background: color-mix(in srgb, var(--card) 45%, transparent); }
.walk-slot { width: 32px; height: 32px; border-radius: 9px; background: color-mix(in srgb, var(--card) 70%, transparent); }
.walk-new { position: relative; width: 32px; height: 32px; }
.walk-new-icon { width: 32px; height: 32px; border-radius: 9px; box-shadow: var(--shadow-sm); }
.walk-video {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  width: 260px;
  height: 160px;
  padding: var(--s3);
  border-radius: var(--r-lg);
  border: 2px dashed var(--border);
  background: linear-gradient(150deg, var(--card-2), color-mix(in srgb, var(--accent) 18%, var(--card-2)));
}
.walk-play { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 50%; color: var(--on-accent); background: var(--accent); box-shadow: var(--shadow); }
.walk-play svg { margin-left: 3px; }
.walk-video-text { font-size: var(--fs-sm); font-weight: 600; color: var(--muted); }
.walk-sparks > span { position: absolute; top: 50%; left: 50%; width: 6px; height: 6px; margin: -3px; border-radius: 50%; background: var(--warning-border); opacity: 0; }

/* A day far back enough that its year was probably mistyped, and other
   notes inside a card. */
.far-back,
.note-box {
  margin: 0 0 var(--s4);
  padding: var(--s3);
  border: 1px solid var(--warning-border);
  border-radius: var(--r-md);
  background: var(--warning-soft);
  color: var(--warning-text);
}

/* A backup file that's been made but not saved anywhere yet. */
.backup-delivery {
  margin-top: var(--s3);
  padding: var(--s3);
  border: 1px solid var(--warning-border);
  border-radius: var(--r-md);
  background: var(--warning-soft);
  color: var(--warning-text);
}
.backup-delivery .card-sub { color: inherit; margin: 0; }
.backup-delivery .field-status { color: inherit; }
.backup-delivery .field-status.is-error { color: var(--danger); }
.notice-card .backup-delivery { margin-top: 0; padding: 0; border: none; background: none; }
.notice-card .field-status.is-error { color: var(--danger); }

.banners { margin: 0 var(--s4); }

.banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding: var(--s2) var(--s2) var(--s2) var(--s4);
  margin-bottom: var(--s3);
  border-radius: var(--r-md);
  background: var(--warning-soft);
  color: var(--warning-text);
  font-size: var(--fs-sm);
}

.banner p { margin: 0; }
.banner-error { background: var(--danger-soft); color: var(--danger); }
.banner .btn-text { color: inherit; }

.toasts {
  position: fixed;
  left: 50%;
  bottom: calc(var(--s4) + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  width: min(480px, calc(100vw - var(--s6)));
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  z-index: 20;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  padding: var(--s2) var(--s2) var(--s2) var(--s4);
  min-height: 52px;
  border-radius: var(--r-md);
  background: var(--toast-bg);
  color: var(--toast-text);
  font-size: var(--fs-sm);
  box-shadow: var(--shadow);
  /* A message alone never blocks a tap on what's under it. */
  pointer-events: none;
}

.toast-actionable { pointer-events: auto; }

.toast-error { background: var(--toast-error-bg); color: var(--toast-error-text); }

.toast-action {
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 var(--s3);
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

.progress { width: 100%; height: var(--s2); margin-top: var(--s3); accent-color: var(--accent); }

/* ------------------------------------------------------------ wide screens */

/* On a tablet or laptop the screens use the width: the day's entry or the
   answers on the left, charts and the rest on the right. */
@media (min-width: 700px) {
  .app { max-width: 1120px; }
  /* History: the months' averages beside the list (and in place of Go to
     month), staying in view while the list scrolls. */
  .months-overview { display: block; }
  .history-jump { display: none; }
  .history-side { position: sticky; top: var(--s4); }
  .months-overview-scroll { max-height: calc(100vh - 26rem); min-height: 12rem; overflow-y: auto; }
  .screen-stack.two-col {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
  }
  .screen-stack.two-col > .notice-card { grid-column: 1 / -1; }
  .photo-grid { grid-template-columns: repeat(4, 1fr); }
}

/* On a laptop the tabs join the brand and Settings in one row. */
@media (min-width: 900px) {
  /* Brand, tabs and Settings in one row, their outer edges lined up with
     the columns below. */
  .topbar { flex-wrap: nowrap; column-gap: var(--s4); padding-top: var(--s4); padding-bottom: var(--s4); }
  .tabs { order: 2; flex: 0 1 560px; }
  .topbar > .settings-link { order: 3; }
  .main > section.card { max-width: 560px; }
  .photo-grid { grid-template-columns: repeat(5, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .spinner { animation-duration: 2.4s; }
}

/* ------------------------------------------------------------ problem log */

.problem-list { list-style: none; margin: 0 0 var(--s2); padding: 0; display: flex; flex-direction: column; gap: var(--s2); }
.problem-list li { display: flex; flex-direction: column; padding: var(--s2) var(--s3); border-radius: var(--r-md); background: var(--card-2); }
.problem-op { font-size: var(--fs-sm); font-weight: 600; }
.problem-meta { font-size: var(--fs-sm); color: var(--muted); overflow-wrap: anywhere; }

/* ------------------------------------------------------------ lists in messages */

.item-list { margin: var(--s2) 0 0; padding-left: var(--s5); font-size: var(--fs-sm); color: var(--muted); }
.item-list li { margin-bottom: var(--s1); }
.dialog-text + .dialog-text { margin-top: var(--s2); }
.import-result > .btn { margin-top: var(--s3); }
.import-result .card-sub { margin-top: var(--s3); margin-bottom: 0; }

/* Shown in the page itself until the app's first screen is ready. */
.boot-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  margin: 0;
  padding: var(--s6) 0;
  color: var(--muted);
  font-weight: 600;
}

/* ------------------------------------------------------------ status page and updates */

.admin-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.update-list { margin: 0; padding-left: 1.25rem; display: grid; gap: var(--s2); font-size: var(--fs-sm); }
.admin-times { color: var(--muted); font-size: var(--fs-sm); margin: 0; }
.admin-json { overflow-x: auto; font-size: var(--fs-sm); }
.admin-status { display: inline-block; padding: 0 var(--s2); border-radius: var(--r-md); font-weight: 700; font-size: var(--fs-sm); border: 1px solid currentColor; }
.admin-status.is-ok { color: var(--accent-text); }
.admin-status.is-warning { color: var(--warning-text); background: var(--warning-soft); border-color: var(--warning-border); }
.admin-status.is-down { color: var(--danger); background: var(--danger-soft); }
.admin-status.is-unknown { color: var(--muted); }

/* ------------------------------------------------------------ motion */

/* Everything that moves lives here, and only for people who haven't asked
   their phone to reduce motion. Only opacity and transform are animated
   (plus a few short color fades), so the phone's GPU does the work and
   scrolling stays smooth on an iPhone. Nothing waits for an animation:
   the screen is usable the moment it's drawn. */

html {
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 0.16s;
  --dur: 0.32s;
  --dur-slow: 0.6s;
}

/* The sliding highlight behind the open tab. Placed by updateTabs (it
   sets --tab to the open tab's column); hidden on screens without a tab. */
.tabs { position: relative; }
.tab { position: relative; z-index: 1; }
.tab-indicator {
  position: absolute;
  top: var(--s1);
  bottom: var(--s1);
  left: var(--s1);
  width: calc((100% - 5 * var(--s1)) / 4);
  border-radius: var(--r-sm);
  background: var(--accent);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 35%, transparent);
  transform: translateX(calc(var(--tab, 0) * (100% + var(--s1))));
  opacity: 0;
  pointer-events: none;
}
.tabs.has-indicator .tab-indicator.is-on { opacity: 1; }
.tabs.has-indicator .tab[aria-current='page'] { background: transparent; }

/* The goal meter under the day's total: how much of the goal is used. */
.goal-meter {
  height: 8px;
  margin: var(--s3) auto 0;
  max-width: 260px;
  border-radius: var(--r-pill);
  background: var(--card);
  overflow: hidden;
}
.goal-meter-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transform-origin: left center;
  transform: scaleX(var(--p, 0));
}
.goal-meter.is-over .goal-meter-fill { background: var(--danger); }

@media (prefers-reduced-motion: no-preference) {
  /* ---- screens: each card rises into place, one after another, and
     slides in from the side of the tab it came from. */
  .view-enter.screen-stack > *,
  .view-enter:not(.screen-stack) {
    animation: screen-in var(--dur) var(--ease-out) both;
    animation-delay: calc(min(var(--i, 0), 5) * 55ms);
  }
  .main[data-dir='forward'] { --enter-x: 18px; }
  .main[data-dir='back'] { --enter-x: -18px; }
  @keyframes screen-in {
    from { opacity: 0; transform: translate3d(var(--enter-x, 0), 14px, 0) scale(0.985); }
    to { opacity: 1; transform: none; }
  }
  /* ---- the Home Screen walkthrough: slides glide in from the side
     they're coming from, the dots stretch to the step, and each picture
     acts out its tap once its slide is in view. */
  .walk-slide { transition: opacity var(--dur) var(--ease-out), transform var(--dur-slow) var(--ease-out), visibility 0s linear var(--dur); }
  .walk-slide[data-side='before'] { opacity: 0; transform: translate3d(-48px, 0, 0) scale(0.96); }
  .walk-slide[data-side='after'] { opacity: 0; transform: translate3d(48px, 0, 0) scale(0.96); }
  .walk-slide.is-active { transition-delay: 0s; }
  .walk-slide.is-active > :not(.walk-art) { animation: walk-rise var(--dur-slow) var(--ease-out) both; }
  .walk-slide.is-active > .walk-count { animation-delay: 60ms; }
  .walk-slide.is-active > .walk-title { animation-delay: 120ms; }
  .walk-slide.is-active > .walk-text { animation-delay: 180ms; }
  @keyframes walk-rise {
    from { opacity: 0; transform: translate3d(0, 12px, 0); }
    to { opacity: 1; transform: none; }
  }
  .walk-dot { transition: width var(--dur) var(--ease-spring), background-color var(--dur) ease; }

  /* Welcome: the icon floats on a breathing glow. */
  .walk-slide.is-active .walk-hero-icon { animation: walk-pop var(--dur-slow) var(--ease-spring) both, walk-float 3.2s ease-in-out 0.6s infinite; }
  .walk-slide.is-active .walk-glow { animation: walk-breathe 3.2s ease-in-out infinite; }
  @keyframes walk-pop {
    from { opacity: 0; transform: scale(0.6) rotate(-8deg); }
    to { opacity: 1; transform: none; }
  }
  @keyframes walk-float {
    0%, 100% { transform: translate3d(0, 0, 0); }
    50% { transform: translate3d(0, -8px, 0); }
  }
  @keyframes walk-breathe {
    0%, 100% { opacity: 0.55; transform: scale(0.9); }
    50% { opacity: 1; transform: scale(1.08); }
  }

  /* The mission video's play button pulses, waiting to be pressed. */
  .walk-slide.is-active .walk-video { animation: walk-phone-in var(--dur-slow) var(--ease-out) both; }
  .walk-slide.is-active .walk-play { animation: walk-pop var(--dur-slow) var(--ease-spring) 0.2s both, walk-glow-pulse 2s ease-in-out 1s infinite; }

  /* The phone pictures rise in, then the tap lands and ripples. */
  .walk-slide.is-active .walk-phone { animation: walk-phone-in var(--dur-slow) var(--ease-out) both; }
  @keyframes walk-phone-in {
    from { opacity: 0; transform: translate3d(0, 24px, 0); }
    to { opacity: 1; transform: none; }
  }
  .walk-slide.is-active .walk-tool.is-target,
  .walk-slide.is-active .walk-row.is-target { animation: walk-press 2s var(--ease-in-out) 0.7s infinite; }
  .walk-slide.is-active .walk-tap { animation: walk-ripple 2s var(--ease-out) 0.7s infinite; }
  @keyframes walk-press {
    0%, 30%, 100% { transform: none; }
    15% { transform: scale(0.9); }
  }
  @keyframes walk-ripple {
    0% { opacity: 0.9; transform: scale(0.4); }
    60%, 100% { opacity: 0; transform: scale(2.6); }
  }
  /* The share sheet and the menu slide out of the button that opens them. */
  .walk-slide.is-active .walk-sheet { animation: walk-sheet-up var(--dur-slow) var(--ease-out) 0.2s both; }
  .walk-slide.is-active .walk-menu { transform-origin: top right; animation: walk-menu-open var(--dur) var(--ease-spring) 0.25s both; }
  .walk-slide.is-active .walk-add { animation: walk-glow-pulse 2s ease-in-out 1s infinite; }
  @keyframes walk-sheet-up {
    from { transform: translate3d(0, 100%, 0); }
    to { transform: none; }
  }
  @keyframes walk-menu-open {
    from { opacity: 0; transform: scale(0.6); }
    to { opacity: 1; transform: none; }
  }
  @keyframes walk-glow-pulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent); }
    50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 0%, transparent); }
  }

  /* The Home Screen: the other icons settle, then the new one drops in
     with a bounce and a burst of sparkles, and keeps a gentle wiggle. */
  .walk-slide.is-active .walk-slot { animation: walk-rise var(--dur) var(--ease-out) both; }
  .walk-slide.is-active .walk-new-icon { animation: walk-drop 0.7s var(--ease-spring) 0.45s both, walk-wiggle 2.8s ease-in-out 1.6s infinite; }
  .walk-slide.is-active .walk-sparks > span { animation: walk-spark 0.8s var(--ease-out) 0.9s both; }
  .walk-sparks > span:nth-child(1) { --sx: -22px; --sy: -20px; }
  .walk-sparks > span:nth-child(2) { --sx: 22px; --sy: -20px; }
  .walk-sparks > span:nth-child(3) { --sx: -22px; --sy: 20px; }
  .walk-sparks > span:nth-child(4) { --sx: 22px; --sy: 20px; }
  @keyframes walk-drop {
    from { opacity: 0; transform: translate3d(0, -60px, 0) scale(0.4); }
    to { opacity: 1; transform: none; }
  }
  @keyframes walk-wiggle {
    0%, 88%, 100% { transform: none; }
    92% { transform: rotate(-6deg); }
    96% { transform: rotate(6deg); }
  }
  @keyframes walk-spark {
    0% { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
    100% { opacity: 0; transform: translate3d(var(--sx), var(--sy), 0) scale(0.3); }
  }

  /* The tour measures where things are, so screens open in place under it. */
  body.is-touring .view-enter.screen-stack > *,
  body.is-touring .view-enter:not(.screen-stack) { animation: none; }

  /* Lists on a freshly opened screen follow their card in. */
  .view-enter .meal-row,
  .view-enter .history-item,
  .view-enter .photo-thumb,
  .view-enter .compare-answer,
  .view-enter .amount-row {
    animation: item-in 0.38s var(--ease-out) both;
    animation-delay: calc(120ms + min(var(--i, 0), 10) * 35ms);
  }
  body.is-touring .view-enter .meal-row,
  body.is-touring .view-enter .history-item,
  body.is-touring .view-enter .photo-thumb,
  body.is-touring .view-enter .compare-answer,
  body.is-touring .view-enter .amount-row { animation: none; }
  @keyframes item-in {
    from { opacity: 0; transform: translate3d(0, 8px, 0); }
    to { opacity: 1; transform: none; }
  }
  .view-enter .photo-thumb { animation-name: thumb-in; }
  @keyframes thumb-in {
    from { opacity: 0; transform: scale(0.9); }
    to { opacity: 1; transform: none; }
  }

  /* ---- tabs */
  .tabs.has-indicator.is-ready .tab-indicator {
    transition: transform 0.42s var(--ease-spring), opacity var(--dur-fast) ease;
  }
  .tab, .settings-link { transition: color 0.2s ease, background-color 0.2s ease, transform var(--dur-fast) var(--ease-out); }
  .settings-link svg { transition: transform 0.6s var(--ease-out); }
  .settings-link[aria-current='page'] svg { transform: rotate(90deg); }

  /* ---- buttons: a soft press, and a spring back on release */
  .btn,
  .btn-text,
  .icon-btn,
  .meal-pill,
  .segment,
  .history-item,
  .photo-thumb,
  .toast-action {
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.2s ease, transform 0.36s var(--ease-spring);
  }
  .btn:active:not(:disabled),
  .meal-pill:active,
  .segment:active,
  .tab:active,
  .settings-link:active { transform: scale(0.96); transition-duration: 0.08s; }
  .btn-text:active,
  .icon-btn:active,
  .toast-action:active { transform: scale(0.9); transition-duration: 0.08s; }
  .history-item:active,
  .photo-thumb:active { transform: scale(0.98); transition-duration: 0.08s; }
  .meal-link { transition: transform var(--dur-fast) var(--ease-out); }
  .meal-link:active { transform: translateX(3px); }
  .btn-primary { box-shadow: 0 2px 10px color-mix(in srgb, var(--accent) 28%, transparent); }
  @media (hover: hover) {
    .btn-primary:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 34%, transparent); }
    .history-item:hover { transform: translateX(2px); }
    .history-item:hover .chevron { transform: translateX(3px); }
    .photo-thumb:hover img { transform: scale(1.04); }
  }
  .chevron { display: inline-block; transition: transform 0.25s var(--ease-out); }
  .photo-thumb img { transition: transform 0.4s var(--ease-out), opacity 0.2s ease; }

  /* The meal chosen on Log Meal pops a little as it lights up. */
  .meal-pill.active { animation: pop 0.36s var(--ease-spring); }
  .segment[aria-pressed='true'],
  input:checked + .segment { animation: pop 0.32s var(--ease-spring); }
  @keyframes pop {
    0% { transform: scale(0.94); }
    100% { transform: none; }
  }

  /* ---- the day's total and its goal */
  .total-num { display: inline-block; }
  .total-num.is-counting { animation: total-glow 0.7s var(--ease-out); }
  @keyframes total-glow {
    0% { transform: scale(0.96); }
    45% { transform: scale(1.04); }
    100% { transform: none; }
  }
  .goal-meter-fill { transition: transform 0.9s var(--ease-out), background-color 0.3s ease; }
  .goal-meter.is-fresh .goal-meter-fill { animation: meter-in 0.9s var(--ease-out) 0.15s both; }
  @keyframes meter-in { from { transform: scaleX(0); } }

  /* A meal just logged, changed, removed or put back flashes once. */
  .meal-row.is-changed { animation: row-flash 1s var(--ease-out); }
  .meal-row.is-changed .meal-value,
  .meal-row.is-changed .meal-empty { animation: value-pop 0.45s var(--ease-spring); }
  @keyframes row-flash {
    0% { background: color-mix(in srgb, var(--accent) 22%, transparent); }
    100% { background: transparent; }
  }
  @keyframes value-pop {
    0% { transform: scale(0.85); opacity: 0.4; }
    100% { transform: none; opacity: 1; }
  }
  .meal-value, .meal-empty { display: inline-block; transform-origin: left center; }

  /* ---- inputs: a saved tick that springs in, a nudge on a mistake */
  .field-status:not(:empty) { animation: status-in 0.28s var(--ease-out); }
  .field-status.is-saved::before { display: inline-block; animation: tick 0.5s var(--ease-spring); }
  @keyframes status-in {
    from { opacity: 0; transform: translate3d(0, -3px, 0); }
    to { opacity: 1; transform: none; }
  }
  @keyframes tick {
    0% { transform: scale(0) rotate(-30deg); }
    100% { transform: none; }
  }
  input[aria-invalid='true'] { animation: nudge 0.38s var(--ease-out); }
  @keyframes nudge {
    0%, 100% { transform: none; }
    20% { transform: translateX(-5px); }
    40% { transform: translateX(4px); }
    60% { transform: translateX(-3px); }
    80% { transform: translateX(2px); }
  }
  input[type='text'], input[type='date'], select { transition: border-color 0.2s ease, box-shadow 0.2s ease; }
  input[type='text']:focus, input[type='date']:focus { box-shadow: 0 0 0 4px color-mix(in srgb, var(--focus) 18%, transparent); }

  /* ---- charts: the line draws itself, then the dots land on it */
  .chart-svg.is-drawing .line {
    stroke-dasharray: 1;
    animation: draw-line 1s var(--ease-in-out) both;
  }
  @keyframes draw-line {
    from { stroke-dashoffset: 1; }
    to { stroke-dashoffset: 0; }
  }
  .chart-svg.is-drawing .line-gap { animation: fade-in 0.4s ease 0.6s both; }
  .chart-svg.is-drawing .dot:not(.dot-hover),
  .chart-svg.is-drawing .partial-label {
    transform-box: fill-box;
    transform-origin: center;
    animation: dot-in 0.4s var(--ease-spring) both;
    animation-delay: calc(0.25s + var(--t, 0) * 0.7s);
  }
  .chart-svg.is-drawing .gridline,
  .chart-svg.is-drawing .axis-label { animation: fade-in 0.4s ease both; }
  @keyframes dot-in {
    from { opacity: 0; transform: scale(0); }
    to { opacity: 1; transform: none; }
  }
  .chart-tooltip { transition: opacity 0.12s ease, left 0.12s var(--ease-out), top 0.12s var(--ease-out); }

  /* Compare's bars grow from zero. */
  .view-enter .amount-bar { transform-origin: left center; animation: bar-grow 0.8s var(--ease-out) both; animation-delay: calc(200ms + min(var(--i, 0), 10) * 60ms); }
  @keyframes bar-grow { from { transform: scaleX(0); } }

  /* ---- dialogs and the photo viewer: rise and settle, over a fading dim */
  .dialog[open] { animation: dialog-in 0.34s var(--ease-spring); }
  .dialog[open]::backdrop { animation: fade-in 0.25s ease; }
  @keyframes dialog-in {
    from { opacity: 0; transform: translate3d(0, 16px, 0) scale(0.95); }
    to { opacity: 1; transform: none; }
  }
  .viewer-img, .compare-img { animation: fade-in 0.35s ease; }

  /* ---- messages */
  .toast { animation: toast-in 0.42s var(--ease-spring); }
  .toast.is-leaving { animation: toast-out 0.2s ease forwards; }
  @keyframes toast-in {
    from { opacity: 0; transform: translate3d(0, 24px, 0) scale(0.92); }
    to { opacity: 1; transform: none; }
  }
  @keyframes toast-out {
    to { opacity: 0; transform: translate3d(0, 12px, 0) scale(0.96); }
  }
  .banner { animation: banner-in 0.36s var(--ease-out); }
  @keyframes banner-in {
    from { opacity: 0; transform: translate3d(0, -10px, 0); }
    to { opacity: 1; transform: none; }
  }
  .loading:not([hidden]) { animation: loading-in 0.25s var(--ease-spring); }
  @keyframes loading-in {
    from { opacity: 0; transform: translate(-50%, -50%) scale(0.9); }
    to { opacity: 1; transform: translate(-50%, -50%); }
  }
  .main.is-loading { transition: opacity 0.25s ease; }
  .notice-more[open] > :not(summary),
  .compare-meals[open] > :not(summary) { animation: item-in 0.3s var(--ease-out); }
  .compare-meals summary::before,
  .notice-more summary::before { transition: transform 0.2s var(--ease-out); }

  /* ---- What's new tour: the dim fades up, the card springs in, and
     the light around each feature breathes. */
  .tour-layer { animation: fade-in 0.3s ease; }
  .tour-card { animation: tour-card-in 0.45s var(--ease-spring); transition: top 0.45s var(--ease-out), left 0.45s var(--ease-out), opacity 0.2s ease, transform 0.25s var(--ease-out); }
  .tour-spot { transition: top 0.45s var(--ease-out), left 0.45s var(--ease-out), width 0.45s var(--ease-out), height 0.45s var(--ease-out); }
  .tour-layer.is-moving .tour-card { transform: scale(0.98); }
  .tour-arrow { transition: left 0.45s var(--ease-out); }
  .tour-spot::after {
    content: '';
    position: absolute;
    inset: -2px;
    border-radius: inherit;
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent);
    animation: spot-breathe 2.2s ease-in-out 0.5s infinite;
  }
  .tour-layer.is-centered .tour-spot::after { display: none; }
  .tour-points li { animation: item-in 0.35s var(--ease-out) both; }
  .tour-points li:nth-child(2) { animation-delay: 60ms; }
  .tour-points li:nth-child(3) { animation-delay: 120ms; }
  .tour-points li:nth-child(n + 4) { animation-delay: 180ms; }
  .tour-dot { transition: width 0.35s var(--ease-spring), background-color 0.2s ease; }
  @keyframes tour-card-in {
    from { opacity: 0; transform: translate3d(0, 20px, 0) scale(0.94); }
    to { opacity: 1; transform: none; }
  }
  @keyframes spot-breathe {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
    50% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--accent) 0%, transparent); }
  }

  /* First launch: the header settles in with the first screen. */
  .boot-loading { animation: fade-in 0.4s ease 0.15s both; }

  /* Switching theme in Settings cross-fades the whole app. */
  ::view-transition-old(root),
  ::view-transition-new(root) { animation-duration: 0.4s; animation-timing-function: var(--ease-in-out); }

  @keyframes fade-in { from { opacity: 0; } }
}
