/*
 * Balance shell layout.
 *
 * Colour, spacing, radius, type and tap-size values come from the token block in
 * public/styles.css. DESIGN_SYSTEM.md forbids new literals in feature components,
 * so every value below is either a token, a geometric constant (0, 50%, 1px hairline)
 * or a layout measurement with no palette meaning.
 */

.v2-frame {
  display: grid;
  grid-template-rows: 1fr auto;
  /* Dynamic viewport units so the browser chrome collapsing does not resize the
     scroll region mid-gesture. The fallback keeps older Safari usable. */
  height: 100vh;
  height: 100dvh;
  background: var(--paper);
  color: var(--ink);
  overflow: hidden;
}

.v2-main {
  overflow-y: auto;
  overscroll-behavior-y: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--space-4) var(--space-3) var(--space-4);
  /* The gutter the design keeps at every width. */
  padding-inline: max(var(--space-3), env(safe-area-inset-left)) max(var(--space-3), env(safe-area-inset-right));
}

.v2-main:focus { outline: none; }

/* FS-102: one server deadline on Home and one signed-in locked surface. */
.v2-logging-allowance {
  max-width: 640px; margin: var(--space-3) auto 0; padding: var(--space-3);
  border: 1px solid var(--line); border-inline-start: 4px solid var(--recovery);
  border-radius: var(--radius-small); background: var(--panel);
  display: grid; gap: var(--space-2);
}
.v2-logging-allowance[data-urgency="sun"] { border-inline-start-color: var(--sun); }
.v2-logging-allowance[data-urgency="effort"] { border-inline-start-color: var(--effort); }
.v2-logging-allowance-header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.v2-logging-allowance h2 { margin: 0; font-family: var(--display); font-size: 1.2rem; }
.v2-logging-allowance p { margin: var(--space-1) 0 0; font-size: 1rem; }
.v2-logging-countdown { font-family: var(--number); font-size: 2rem; font-variant-numeric: tabular-nums; color: var(--recovery); white-space: nowrap; }
.v2-logging-allowance[data-urgency="sun"] .v2-logging-countdown { color: var(--sun-ink); }
.v2-logging-allowance[data-urgency="effort"] .v2-logging-countdown { color: var(--effort); }
.v2-logging-allowance-times { display: grid; gap: var(--space-1); color: var(--ink-soft); font-size: 1rem; }
.v2-logging-allowance-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.v2-logging-allowance-actions button { min-height: 44px; }
.v2-logging-lock { min-height: 100%; display: grid; place-items: center; max-width: 640px; margin-inline: auto; }
.v2-logging-lock-card { width: 100%; padding: var(--space-4); border: 1px solid var(--line); border-radius: var(--radius-small); background: var(--panel); display: grid; gap: var(--space-3); }
.v2-logging-lock-card h1 { margin: 0; font-family: var(--display); }
.v2-logging-lock-card p { margin: 0; font-size: 1rem; }
.v2-logging-lock-card button { min-height: 44px; }

.v2-screen { max-width: 640px; margin-inline: auto; }

.v2-screen-title {
  margin: 0 0 var(--space-3);
  font-family: var(--display);
  font-size: 1.625rem;
  font-weight: 650;
  letter-spacing: -0.03em;
  color: var(--ink);
}

/* Quantities read left to right in both languages; see num() in v2/dom.js. */
.v2-number {
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}

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

.v2-nav {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0,1fr);
  gap: var(--space-1);
  padding: 4px var(--space-2);
  /* Reserve the home-indicator inset outside the scroll region, so the last row of
     a screen is never hidden behind it. */
  padding-bottom: calc(var(--space-1) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  border-radius: 22px 22px 0 0;
  /* Translucent over the scrolling screen, so content passing under the bar is
     still legible as movement rather than disappearing behind a solid slab. */
  background: var(--glass-light);
  backdrop-filter: blur(28px) saturate(1.4);
}

/* Without backdrop-filter the translucency would just look like a wash. */
@supports not (backdrop-filter: blur(1px)) {
  .v2-nav { background: var(--panel); }
}

/* `display: grid` outranks the hidden attribute, so restate it. */
.v2-nav[hidden] { display: none; }
.v2-frame.is-chromeless { grid-template-rows: 1fr; }

.v2-nav-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 60px;
  padding: var(--space-1) 0;
  border: 0;
  border-radius: 15px;
  background: none;
  color: var(--ink-soft);
  font-family: var(--body);
  font-weight: 650;
  cursor: pointer;
}

/* The active destination is a filled pill, not just a colour change. */
.v2-nav-item.is-active {
  background: color-mix(in srgb, var(--route-soft) 78%, transparent);
  color: var(--route);
}

/*
 * How many posts are waiting. It sits on the icon rather than in the label so it
 * survives translation, and it is hidden from assistive technology because the
 * button's own accessible name already carries the count.
 */
.v2-nav-badge {
  position: absolute;
  top: var(--space-1);
  inset-inline-end: 22px;
  display: grid;
  place-items: center;
  min-inline-size: 18px;
  block-size: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--effort);
  color: var(--on-inverse);
  font-size: 0.6875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.v2-nav-item:focus-visible {
  outline: 2px solid var(--route);
  outline-offset: 2px;
}

.v2-nav-label {
  /* DESIGN_SYSTEM.md: navigation labels stay at 14 px or larger, in both languages. */
  font-size: var(--text-small);
  font-weight: 600;
  line-height: 1.2;
}

/* ------------------------------------------------------------- balance card */

.v2-balance-card {
  padding: var(--space-4) var(--space-3);
  border-radius: var(--radius);
  background:
    radial-gradient(circle at 88% 4%, color-mix(in srgb, var(--route) 22%, transparent), transparent 26rem),
    var(--inverse);
  color: var(--on-inverse);
  text-align: center;
}

.v2-balance-card.is-over {
  background:
    radial-gradient(circle at 88% 4%, color-mix(in srgb, var(--effort) 30%, transparent), transparent 26rem),
    var(--inverse);
}

.v2-balance-caption {
  margin: 0;
  font-size: var(--text-small);
  color: color-mix(in srgb, var(--on-inverse) 72%, transparent);
}

.v2-balance-number {
  font-family: var(--number);
  /* Tabular figures and a reserved width so an animated count cannot reflow the
     card or retrigger a layout observer on every frame. */
  font-variant-numeric: tabular-nums;
  font-size: clamp(3.25rem, 20vw, 4.75rem);
  line-height: 1.02;
  letter-spacing: -0.04em;
  margin: var(--space-1) 0 0;
}

/* Over budget the number is the warning, so it carries the colour itself. */
.v2-balance-card.is-over .v2-balance-number { color: var(--effort-light); }
/* Activity credited is the good direction, in the tone that reads on the dark. */
.v2-balance-number.is-credit { color: var(--recovery-light); }

/*
 * How much of today has been spent. The colour is the message: green while there
 * is room, yellow as it fills, red once it is gone. The bar is capped at full so
 * an overspend does not paint outside its track.
 */
.v2-balance-bar {
  block-size: 6px;
  margin-top: var(--space-3);
  border-radius: 3px;
  background: color-mix(in srgb, var(--on-inverse) 16%, transparent);
  overflow: hidden;
}
.v2-balance-bar > span {
  display: block;
  block-size: 100%;
  border-radius: 3px;
  background: var(--sun);
  transition: inline-size var(--motion-page) var(--motion-ease-out);
}
.v2-balance-bar[data-tone="easy"] > span { background: var(--recovery); }
.v2-balance-bar[data-tone="over"] > span { background: var(--effort-light); }

.v2-balance-unit {
  margin: var(--space-1) 0 0;
  font-size: var(--text-small);
  color: color-mix(in srgb, var(--on-inverse) 72%, transparent);
}

.v2-balance-breakdown {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0,1fr);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid color-mix(in srgb, var(--on-inverse) 16%, transparent);
}

.v2-balance-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.v2-balance-stat b {
  /* Supporting calorie values stay glanceable at 16 px or more. */
  font-size: var(--text-body);
  font-variant-numeric: tabular-nums;
  font-weight: 650;
}

.v2-balance-stat b.is-credit { color: var(--recovery); }
.v2-balance-stat b.is-debit { color: var(--effort); }

.v2-balance-stat span {
  font-size: var(--text-small);
  color: color-mix(in srgb, var(--on-inverse) 70%, transparent);
}

/* ------------------------------------------------------------------- states */

.v2-state {
  display: grid;
  gap: var(--space-3);
  justify-items: center;
  padding: var(--space-4);
  text-align: center;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- transitions */

/*
 * A destination change slides a short distance and crossfades. The travel is
 * deliberately small: a full-width slide at 390 px fights the iOS edge-swipe
 * back gesture and feels heavy on the tenth use.
 *
 * Only the arriving screen animates, and it is a brand-new element on every
 * render, so the animation restarts by itself.
 */
.v2-main > [data-enter="end"] { animation: v2-page-in-end var(--motion-page) var(--motion-ease-out) both; }
.v2-main > [data-enter="start"] { animation: v2-page-in-start var(--motion-page) var(--motion-ease-out) both; }

@keyframes v2-page-in-end { from { opacity: 0; transform: translateX(8%); } to { opacity: 1; transform: none; } }
@keyframes v2-page-in-start { from { opacity: 0; transform: translateX(-8%); } to { opacity: 1; transform: none; } }

/* The design's two keyframes, ported. */
@keyframes v2-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes v2-pulse { 0%, 100% { opacity: 0.35; transform: scale(1); } 50% { opacity: 0.9; transform: scale(1.35); } }

@media (prefers-reduced-motion: reduce) {
  /*
   * .v2-frame alone was not enough: every dialog is appended to document.body,
   * outside the frame, and ::backdrop is not a descendant of anything.
   */
  .v2-frame, .v2-frame *, .v2-sheet, .v2-sheet * { animation: none !important; transition: none !important; }
  .v2-sheet::backdrop { animation: none !important; transition: none !important; }
  /* The arriving screen simply appears. */
  .v2-main > [data-enter] { animation: none !important; }
}

/* ------------------------------------------------------------------- header */

.v2-header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  min-block-size: var(--tap-min);
  margin-bottom: var(--space-3);
}
.v2-header > button:first-child { justify-self: start; }
.v2-header > button:last-child { justify-self: end; }

.v2-wordmark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  /* The brand keeps Latin order in Hebrew. */
  direction: ltr;
}

.v2-wordmark img { display: block; inline-size: 32px; block-size: 32px; border-radius: 10px; }

.v2-wordmark-text {
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 750;
  letter-spacing: -0.025em;
}

.v2-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--tap-min);
  block-size: var(--tap-min);
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}

.v2-icon-button:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-icon-button[disabled] { opacity: 0.35; cursor: default; }

/*
 * The chevron asset points right. "Back" points against the reading direction and
 * "forward" with it, so in Hebrew the pair swaps: back points right, forward left.
 */
.is-back > svg { transform: scaleX(-1); }
.is-forward > svg { transform: none; }
[dir="rtl"] .is-back > svg { transform: none; }
[dir="rtl"] .is-forward > svg { transform: scaleX(-1); }

/* -------------------------------------------------------------- primary action */

.v2-primary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: 56px;
  margin-block: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: 18px;
  background: var(--route);
  color: var(--on-inverse);
  font-family: var(--body);
  font-size: 1.0625rem;
  font-weight: 800;
  box-shadow: 0 12px 26px color-mix(in srgb, var(--route) 28%, transparent);
  cursor: pointer;
}

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

/* ----------------------------------------------------------------- sections */

.v2-section { margin-top: var(--space-4); }

.v2-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.v2-section-title {
  margin: 0;
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 650;
}

.v2-section-label {
  margin: 0 0 var(--space-2);
  font-size: var(--text-small);
  font-weight: 750;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
}

.v2-section-note { font-size: var(--text-small); color: var(--ink-soft); }

.v2-section-footnote {
  margin: var(--space-2) 0 0;
  font-size: var(--text-small);
  color: var(--ink-soft);
}

.v2-empty {
  margin: 0;
  padding: var(--space-4) var(--space-3);
  border-radius: var(--radius-small);
  background: var(--panel);
  color: var(--ink-soft);
  text-align: center;
}

/* ---------------------------------------------------------------- movements */

.v2-movements {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--panel);
  overflow: hidden;
}

.v2-movement {
  display: grid;
  grid-template-columns: 44px 1fr auto auto;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--tap-min);
  padding: var(--space-2) var(--space-3);
}

.v2-movement + .v2-movement { border-top: 1px solid var(--line); }
.v2-movement.is-buffer { background: var(--panel-muted); }

/*
 * A tile the size of the photo the design shows. Food has no picture stored yet,
 * so the tile carries the design's hatch with the meal colour as a corner mark;
 * activity carries its icon and the buffer stays blank, so an empty well never
 * reads as a picture that failed to load.
 */
.v2-movement-mark {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 12px;
}

.v2-movement-mark[data-meal]:not([data-meal="activity"]):not([data-meal="buffer"]):not([data-meal="estimate"]) {
  background: repeating-linear-gradient(135deg, var(--paper-deep) 0 6px, var(--paper) 6px 12px);
}

.v2-movement-mark[data-meal]:not([data-meal="activity"]):not([data-meal="buffer"]):not([data-meal="estimate"])::before {
  content: '';
  position: absolute;
  inset-block-end: 5px;
  inset-inline-end: 5px;
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: var(--meal-dot, var(--ink-soft));
}

.v2-movement-mark[data-meal="breakfast"] { --meal-dot: var(--sun); }
.v2-movement-mark[data-meal="lunch"] { --meal-dot: var(--route); }
.v2-movement-mark[data-meal="dinner"] { --meal-dot: var(--inverse); }
.v2-movement-mark[data-meal="snack"],
.v2-movement-mark[data-meal="evening_snack"],
.v2-movement-mark[data-meal="night_snack"] { --meal-dot: var(--recovery); }

.v2-movement.is-activity .v2-movement-mark {
  border-radius: 12px;
  background: var(--surface-resolved);
  color: var(--recovery);
}

/* A meal is one line that opens onto what was in it. */
.v2-movement.is-meal { grid-template-columns: 1fr auto; padding: 0; }
.v2-movement-open {
  display: grid;
  grid-template-columns: 44px 1fr auto auto;
  align-items: center;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  border: 0; background: none; color: inherit; font-family: var(--body);
  text-align: start; cursor: pointer;
}
.v2-movement-open:focus-visible { outline: 2px solid var(--route); outline-offset: -2px; }
.v2-movement-chevron { display: grid; place-items: center; color: var(--ink-soft); transition: transform var(--motion-fast) ease; }
.v2-movement-open[aria-expanded="true"] .v2-movement-chevron { transform: rotate(90deg); }
[dir="rtl"] .v2-movement-chevron svg { transform: scaleX(-1); }
[dir="rtl"] .v2-movement-open[aria-expanded="true"] .v2-movement-chevron { transform: rotate(-90deg); }

/* The component line under a meal title can be long; one line is enough. */
.v2-movement.is-meal .v2-movement-meta {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.v2-movement-parts {
  grid-column: 1 / -1;
  list-style: none; margin: 0;
  padding: 0 var(--space-3) var(--space-2) calc(var(--space-3) + 44px + var(--space-2));
  display: grid; gap: var(--space-1);
  background: var(--panel-muted);
}
[dir="rtl"] .v2-movement-parts {
  padding-inline: calc(var(--space-3) + 44px + var(--space-2)) var(--space-3);
}
.v2-movement-parts[hidden] { display: none; }
.v2-movement-part {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2);
  padding-block: var(--space-1);
  font-size: var(--text-small); color: var(--ink-soft);
}

@media (prefers-reduced-motion: reduce) {
  .v2-movement-chevron { transition: none; }
}

/* Taking a movement back: one tap asks, the second does it. */
.v2-movement-remove { display: inline-flex; align-items: center; gap: var(--space-1); }
.v2-movement-cancel, .v2-movement-confirm {
  min-block-size: var(--tap-min); padding: 0 var(--space-2);
  border: 1px solid var(--line); border-radius: 999px; background: var(--panel);
  font-family: var(--body); font-size: var(--text-small); font-weight: 650; cursor: pointer;
}
.v2-movement-cancel { color: var(--ink-soft); }
.v2-movement-confirm { border-color: var(--effort); background: var(--effort-soft); color: var(--effort); }
.v2-movement-cancel:focus-visible, .v2-movement-confirm:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-movement-confirm[disabled], .v2-movement-cancel[disabled] { opacity: 0.5; cursor: default; }

.v2-movement-body { display: grid; gap: 2px; min-inline-size: 0; }

.v2-movement-name {
  font-size: var(--text-body);
  font-weight: 600;
  /* Long dish names truncate rather than widening the row. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.v2-movement-meta { font-size: var(--text-small); color: var(--ink-soft); }

.v2-movement-amounts {
  display: grid;
  justify-items: end;
  gap: 2px;
  text-align: end;
}

.v2-movement-delta { font-size: var(--text-body); font-weight: 650; }
.v2-movement-delta.is-credit { color: var(--recovery); }
.v2-movement-delta.is-debit { color: var(--effort); }
.v2-movement-balance { font-size: var(--text-small); color: var(--ink-soft); }

/* --------------------------------------------------------------------- panel */

.v2-panel {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--panel);
}

.v2-panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

.v2-panel-title { margin: 0; font-size: 1.125rem; font-weight: 650; }
.v2-panel-figure { font-size: 1.125rem; font-weight: 700; }
.v2-panel-figure.is-credit { color: var(--recovery); }
.v2-panel-figure.is-debit { color: var(--effort); }

.v2-panel-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin: var(--space-2) 0 0;
  font-size: var(--text-small);
  color: var(--ink-soft);
}

.v2-panel-row .is-debit { color: var(--effort); font-weight: 650; }

/* ------------------------------------------------------ diary day navigator */

.v2-daynav {
  display: grid;
  grid-template-columns: var(--tap-min) 1fr var(--tap-min);
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.v2-daynav > .v2-icon-button {
  border: 1px solid var(--line);
  border-radius: var(--control-radius);
  background: var(--panel);
}

.v2-daynav-label {
  display: grid;
  gap: 2px;
  min-block-size: var(--tap-min);
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--panel);
  color: inherit;
  font-family: var(--body);
  text-align: center;
  cursor: pointer;
}

.v2-daynav-title { font-size: var(--text-body); font-weight: 650; }
.v2-daynav-date { font-size: var(--text-small); color: var(--ink-soft); }
.v2-daynav-label:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; border-radius: var(--control-radius); }

/*
 * Three tiles rather than one bar. What is left is the answer the screen exists
 * to give, so it takes the dark fill and the other two frame it.
 */
.v2-strip {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0,1fr);
  gap: var(--space-1);
}

.v2-strip-stat {
  display: grid;
  gap: 2px;
  padding: var(--space-2) var(--space-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-small);
  background: var(--panel);
  text-align: center;
}
.v2-strip-stat b { font-size: var(--text-body); font-weight: 650; }
.v2-strip-stat b.is-credit { color: var(--recovery); }
.v2-strip-stat b.is-debit { color: var(--effort); }
.v2-strip-stat span { font-size: var(--text-small); color: var(--ink-soft); }

.v2-strip-stat.is-primary {
  border-color: transparent;
  background: var(--inverse);
  color: var(--on-inverse);
}
.v2-strip-stat.is-primary span { color: color-mix(in srgb, var(--on-inverse) 70%, transparent); }
.v2-strip-stat.is-primary b.is-debit { color: var(--effort-light); }

/* --------------------------------------------------------------- macro panel */

.v2-macro {
  margin-top: var(--space-3);
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--panel);
  overflow: hidden;
}

/* Open, it is the thing being read, so it takes the route ring. */
.v2-macro:has(.v2-macro-toggle[aria-expanded="true"]) {
  border-color: var(--route);
  border-radius: 20px;
  box-shadow: 0 0 0 4px var(--route-soft);
}

.v2-macro-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  border: 0;
  background: none;
  color: inherit;
  font-family: var(--body);
  cursor: pointer;
  text-align: start;
}

.v2-macro-toggle:focus-visible { outline: 2px solid var(--route); outline-offset: -2px; }
.v2-macro-thumbs { display: inline-flex; }
.v2-macro-thumbs img { border-radius: 50%; }
/* A deliberate overlap, which is geometry rather than spacing rhythm. */
.v2-macro-thumbs img + img { margin-inline-start: -8px; }
.v2-macro-title { flex: 1; font-size: var(--text-body); font-weight: 650; }
.v2-macro-chevron { color: var(--ink-soft); transition: transform 160ms ease; }
.v2-macro-toggle[aria-expanded="true"] .v2-macro-chevron { transform: rotate(90deg); }
[dir="rtl"] .v2-macro-chevron svg { transform: scaleX(-1); }
[dir="rtl"] .v2-macro-toggle[aria-expanded="true"] .v2-macro-chevron { transform: rotate(-90deg); }

.v2-macro-body { padding: 0 var(--space-3) var(--space-3); }
.v2-macro-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.v2-macro-row { display: grid; grid-template-columns: 28px minmax(0, 1fr); align-items: center; gap: var(--space-2); }
.v2-macro-detail { display: grid; min-inline-size: 0; gap: var(--space-1); }
.v2-macro-line { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); font-size: var(--text-small); }
.v2-macro-line b { font-size: var(--text-body); font-weight: 600; }

.v2-macro-track {
  display: block;
  block-size: 6px;
  border-radius: 999px;
  background: var(--paper-deep);
  overflow: hidden;
}

/* A colour per macro, so a glance at the bars is already an answer. */
.v2-macro-fill { display: block; block-size: 100%; border-radius: 999px; background: var(--macro-tone, var(--route)); }
.v2-macro-row[data-macro="protein"] { --macro-tone: var(--route); }
.v2-macro-row[data-macro="carbs"] { --macro-tone: var(--sun); }
.v2-macro-row[data-macro="fat"] { --macro-tone: var(--recovery); }
.v2-macro-fill[data-over="true"] { background: var(--effort); }

/* The week, as seven columns. */
.v2-week { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-1); align-items: end; }
.v2-week-day { display: grid; gap: 4px; justify-items: center; }
.v2-week-track {
  display: flex; align-items: flex-end; inline-size: 100%; max-inline-size: 26px; block-size: 56px;
  border-radius: var(--control-radius); background: var(--paper-deep); overflow: hidden;
}
.v2-week-fill { inline-size: 100%; border-radius: var(--control-radius); background: var(--route); }
.v2-week-day.is-over .v2-week-fill { background: var(--effort); }
.v2-week-day.is-today .v2-week-track { outline: 2px solid var(--route); outline-offset: 1px; }
/* A day that has not happened is an outline, not a zero. */
.v2-week-day.is-future .v2-week-track { background: none; border: 1px dashed var(--line-strong); }
.v2-week-label { font-size: var(--text-small); color: var(--ink-soft); }

.v2-panel-note { margin: 0; font-size: var(--text-small); line-height: 1.45; color: var(--ink-soft); }
/* The same row without the card, for a link inside one. */
.v2-quiet-row.is-plain { justify-content: space-between; padding-inline: 0; border: 0; background: none; }

/* A dashed invitation rather than another filled button competing with Log. */
.v2-add-movement {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: var(--tap-min);
  margin-top: var(--space-3);
  padding: var(--space-2);
  border: 1px dashed var(--line-strong);
  border-radius: 18px;
  background: none;
  color: var(--ink-soft);
  font-family: var(--body);
  font-size: var(--text-body);
  font-weight: 650;
  cursor: pointer;
}
.v2-add-movement:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

.v2-macro-note {
  margin: var(--space-3) 0 0;
  font-size: var(--text-small);
  color: var(--ink-soft);
}

/* An estimated day explains itself, so its meta line wraps instead of truncating. */
.v2-movement-meta.is-wrapping { white-space: normal; }
.v2-movement.is-estimate .v2-movement-name { font-style: italic; color: var(--ink-soft); }
.v2-movement.is-estimate { background: var(--panel-muted); }
.v2-macro-note.is-partial { color: var(--ink); }

/* ----------------------------------------------------------------- boot screen */

/*
 * The first frame, in markup so it is painted before any script runs. Removed by
 * boot.js the moment the shell mounts, with no minimum display time.
 */
/*
 * The same surface as the balance card: the dark ink with a blue glow off the
 * top corner. The app's first frame and its signature screen are then the same
 * object, which is what makes the handover read as one continuous thing.
 */
.v2-boot {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-content: center;
  gap: var(--space-4);
  padding: var(--space-4);
  text-align: center;
  background: var(--inverse);
  color: var(--on-inverse);
}

.v2-boot-glow {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 88% 4%, color-mix(in srgb, var(--route) 22%, transparent), transparent 26rem);
}

.v2-boot-brand,
.v2-boot-line,
.v2-boot-pulse,
.v2-boot-noscript { position: relative; }

/* The app mark, not a photograph: a small round portrait the size of an icon. */
.v2-boot-mark {
  inline-size: 64px;
  block-size: 64px;
  border-radius: 50%;
  object-fit: cover;
}

.v2-boot-word {
  font-family: var(--display);
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.04em;
}

/*
 * The first frame settles rather than appearing. Each element rises a little
 * later than the one above it, which reads as the screen composing itself
 * instead of flashing into place.
 */
.v2-boot-brand { animation: v2-boot-rise 520ms cubic-bezier(0.22, 0.61, 0.36, 1) both; }
.v2-boot-line { animation: v2-boot-rise 520ms cubic-bezier(0.22, 0.61, 0.36, 1) 90ms both; }
.v2-boot-pulse { animation: v2-boot-rise 520ms cubic-bezier(0.22, 0.61, 0.36, 1) 160ms both; }
.v2-boot-mark { animation: v2-boot-settle 700ms cubic-bezier(0.22, 0.61, 0.36, 1) both; }
.v2-boot-glow { animation: v2-boot-glow 1400ms ease-out both; }

@keyframes v2-boot-rise {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* The mark settles in rather than appearing at full size. */
@keyframes v2-boot-settle {
  from { opacity: 0; transform: scale(0.88); }
  to { opacity: 1; transform: none; }
}

/* The glow arrives slowly behind everything, the way the balance card reads. */
@keyframes v2-boot-glow {
  from { opacity: 0; }
  to { opacity: 1; }
}

.v2-boot-pulse { display: flex; justify-content: center; gap: var(--space-1); }
.v2-boot-pulse i {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--route);
  opacity: 0.35;
  animation: v2-boot-pulse 1200ms ease-in-out infinite;
}
.v2-boot-pulse i:nth-child(2) { animation-delay: 160ms; }
.v2-boot-pulse i:nth-child(3) { animation-delay: 320ms; }

@keyframes v2-boot-pulse {
  0%, 100% { opacity: 0.35; transform: scale(1); }
  50% { opacity: 0.9; transform: scale(1.35); }
}

/*
 * Leaving. The screen fades and lifts away rather than being cut, and the shell
 * underneath is already painted by the time this runs.
 */
.v2-boot.is-leaving {
  animation: v2-boot-leave 320ms cubic-bezier(0.4, 0, 0.2, 1) both;
  pointer-events: none;
}

@keyframes v2-boot-leave {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: scale(1.02); }
}

@media (prefers-reduced-motion: reduce) {
  .v2-boot-brand, .v2-boot-line, .v2-boot-pulse, .v2-boot-mark, .v2-boot-glow,
  .v2-boot-pulse i, .v2-boot.is-leaving { animation: none; }
  .v2-boot.is-leaving { opacity: 0; }
}

.v2-boot-brand {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
}

.v2-boot-line { margin: 0; font-size: var(--text-small); letter-spacing: 0.12em; text-transform: uppercase; }
.v2-boot-noscript { margin: 0; font-size: var(--text-body); }

/* One language at a time, chosen by the document language the shell sets. */
.v2-boot [lang] { display: none; }
html[lang="he"] .v2-boot [lang="he"],
html:not([lang="he"]) .v2-boot [lang="en"] { display: inline; }

/* --------------------------------------------------------------------- sheets */

/*
 * The document must not scroll behind an open sheet, or dismissing it lands the
 * reader somewhere else.
 */
.v2-sheet-open, .v2-sheet-open body { overflow: hidden; }

.v2-sheet {
  --keyboard-inset: 0px;
  position: fixed;
  inset: 0;
  inline-size: 100%;
  max-inline-size: 100%;
  /*
   * The visible area, not the layout viewport. sheet.js follows visualViewport
   * because iOS shrinks and scrolls that one for the keyboard while leaving the
   * layout viewport alone — so a plain fixed sheet slides out from under the
   * caret. The fallbacks are what a browser without visualViewport gets.
   */
  block-size: var(--viewport-height, 100%);
  max-block-size: var(--viewport-height, 100%);
  transform: translateY(var(--viewport-offset, 0px));
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  /* The panel sits at the end of the flow; the space above it is the backdrop. */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
}

.v2-sheet::backdrop {
  background: color-mix(in srgb, var(--inverse) 50%, transparent);
  backdrop-filter: blur(3px);
}

.v2-sheet[open]::backdrop { animation: v2-backdrop-in var(--motion-sheet-in) var(--motion-ease-out) both; }
.v2-sheet[open] .v2-sheet-body { animation: v2-sheet-in var(--motion-sheet-in) var(--motion-ease-out) both; }

/*
 * Leaving. The dialog stays open for the whole exit — close() is what releases
 * the top layer and the focus trap, so it is called only once this has finished.
 */
.v2-sheet.is-closing { pointer-events: none; }
.v2-sheet.is-closing::backdrop { animation: v2-backdrop-out var(--motion-sheet-out) var(--motion-ease-in) both; }
.v2-sheet.is-closing .v2-sheet-body { animation: v2-sheet-out var(--motion-sheet-out) var(--motion-ease-in) both; }

@keyframes v2-sheet-in { from { transform: translateY(100%); } to { transform: none; } }
@keyframes v2-sheet-out { from { transform: none; } to { transform: translateY(100%); } }
@keyframes v2-backdrop-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes v2-backdrop-out { from { opacity: 1; } to { opacity: 0; } }

.v2-sheet-body {
  display: flex;
  flex-direction: column;
  inline-size: 100%;
  max-inline-size: 640px;
  margin-inline: auto;
  /* Of the visible area, which already excludes the keyboard. */
  max-block-size: 92%;
  padding: var(--space-3);
  padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom) + var(--keyboard-inset));
  border-start-start-radius: 28px;
  border-start-end-radius: 28px;
  background: var(--panel);
  color: var(--ink);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/*
 * The capture sheet is tall — a list, two big buttons and room for a keyboard —
 * but it is still a sheet. A strip of dimmed backdrop stays visible above it,
 * which is what says the day is still underneath and this closes.
 */
.v2-sheet.is-full .v2-sheet-body {
  --sheet-gap: clamp(48px, 9dvh, 82px);
  max-block-size: calc(100% - var(--sheet-gap));
  block-size: calc(100% - var(--sheet-gap));
}
/*
 * There was a rule here that collapsed the gap whenever the sheet held focus, to
 * reclaim the strip of backdrop once the keyboard was up. It moved the sheet the
 * instant anything was focused — including the close button, under the click that
 * was focusing it — which is the same layout-shift-on-focus this shell exists to
 * prevent. The sheet already sizes to the visual viewport, so the gap is a share
 * of what is actually visible and shrinks with the keyboard by itself.
 */

.v2-sheet-top { display: grid; gap: var(--space-2); margin-bottom: var(--space-3); }

/*
 * The grab handle. It is a full-width button so that the bar the design draws is
 * a real target: tap-height, focusable, and labelled "close" for a screen reader.
 */
.v2-sheet-grab {
  display: grid;
  place-items: center;
  inline-size: 100%;
  min-block-size: var(--tap-min);
  margin-block-start: calc(var(--space-2) * -1);
  padding: 0;
  border: 0;
  border-radius: var(--control-radius);
  background: none;
  cursor: pointer;
}
.v2-sheet-grab::before {
  content: '';
  inline-size: 38px;
  block-size: 4px;
  border-radius: 2px;
  background: var(--line-strong);
}
.v2-sheet-grab:focus-visible { outline: 2px solid var(--route); outline-offset: -8px; }
.v2-sheet-back { justify-self: start; margin-block-start: calc(var(--space-2) * -1); }

.v2-sheet-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

.v2-sheet-heading { display: grid; gap: 2px; min-inline-size: 0; }

.v2-sheet-title {
  margin: 0;
  font-family: var(--display);
  font-size: 1.6875rem;
  font-weight: 650;
  letter-spacing: -0.03em;
}

/* The balance reads as a fact worth keeping in view, not as a caption. */
.v2-sheet-pill {
  flex: none;
  padding: var(--space-1) var(--space-2);
  border-radius: 999px;
  background: var(--inverse);
  color: var(--on-inverse);
  font-size: var(--text-small);
  font-weight: 650;
  white-space: nowrap;
}

/* ------------------------------------------------------------ capture options */

.v2-log, .v2-bank { display: grid; gap: var(--space-3); }
.v2-option-group { display: grid; gap: var(--space-1); }
.v2-option-list { display: grid; gap: var(--space-1); }

/*
 * A card, not a row in a table. Each one is a separate decision with a picture,
 * a name, a reason and a price, and the design gives it its own edge to say so.
 */
.v2-option {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 78px;
  padding: var(--space-2);
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--panel);
  color: inherit;
  font-family: var(--body);
  text-align: start;
  cursor: pointer;
}

/* The one the app would pick. It is the fifteen-second path, so it is marked. */
.v2-option.is-lead { border-color: var(--route); box-shadow: 0 0 0 3px var(--route-soft); }
.v2-option:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

/*
 * The photo tile. Meals in the bank have no picture yet, so it carries the
 * design's hatch and keeps the meal colour as a small corner mark rather than
 * dropping the one piece of information the tile can actually carry.
 */
.v2-option-mark {
  position: relative;
  flex: none;
  inline-size: 54px;
  block-size: 54px;
  border-radius: 15px;
  background: repeating-linear-gradient(135deg, var(--paper-deep) 0 6px, var(--paper) 6px 12px);
}
.v2-option-mark::before {
  content: '';
  position: absolute;
  inset-block-end: 6px;
  inset-inline-end: 6px;
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: var(--meal-dot, var(--ink-soft));
}
.v2-option-mark[data-meal="breakfast"] { --meal-dot: var(--sun); }
.v2-option-mark[data-meal="lunch"] { --meal-dot: var(--route); }
.v2-option-mark[data-meal="dinner"] { --meal-dot: var(--inverse); }
.v2-option-mark[data-meal="snack"], .v2-option-mark[data-meal="evening_snack"], .v2-option-mark[data-meal="night_snack"] { --meal-dot: var(--recovery); }

.v2-option-body { flex: 1; display: grid; gap: 3px; min-inline-size: 0; }
.v2-option-body b { font-size: 1.0625rem; font-weight: 650; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v2-option-body small { font-size: var(--text-body); line-height: 1.35; color: var(--ink-soft); }
.v2-option.is-lead .v2-option-body small { color: var(--route-ink); font-weight: 650; }

.v2-option-amount {
  flex: none;
  display: grid;
  justify-items: center;
  gap: 4px;
  font-family: var(--number);
  font-size: 1.125rem;
  font-weight: 650;
}
.v2-option-plus {
  display: grid;
  place-items: center;
  inline-size: 34px;
  block-size: 34px;
  border-radius: 50%;
  background: var(--route-soft);
  color: var(--route);
}
.v2-option.is-lead .v2-option-plus { background: var(--route); color: var(--on-inverse); }

/* Where the suggestions came from, and the way into the whole bank. */
.v2-quiet-row {
  display: flex; align-items: center; gap: var(--space-2);
  inline-size: 100%; padding: var(--space-2) var(--space-2);
  border: 1px solid var(--line); border-radius: 18px; background: var(--panel-muted);
  color: inherit; font-family: var(--body); cursor: pointer; text-align: start;
}
.v2-quiet-row:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-quiet-icon {
  flex: none; display: grid; place-items: center;
  inline-size: 34px; block-size: 34px; border-radius: 11px;
  background: var(--panel); color: var(--ink-soft);
}
.v2-quiet-note { flex: 1; font-size: var(--text-body); line-height: 1.45; color: var(--ink); }
.v2-quiet-link { flex: none; font-size: var(--text-small); font-weight: 650; color: var(--route-ink); white-space: nowrap; }
.v2-quiet-arrow { flex: none; display: grid; place-items: center; color: var(--route-ink); }

/* Meal filters in the bank. */
.v2-chip-row { display: flex; gap: var(--space-1); overflow-x: auto; padding-block-end: 2px; }
.v2-chip {
  flex: none; min-block-size: 38px; padding: 0 var(--space-3);
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel); color: var(--ink);
  font-family: var(--body); font-size: 0.9375rem; font-weight: 650; cursor: pointer;
}
.v2-chip.is-on { border-color: transparent; background: var(--inverse); color: var(--on-inverse); font-weight: 750; }
.v2-chip:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

.v2-divider { display: flex; align-items: center; gap: var(--space-2); color: var(--ink-soft); font-size: var(--text-small); font-weight: 650; }
.v2-divider::before, .v2-divider::after { content: ''; flex: 1; block-size: 1px; background: var(--line); }

.v2-capture-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }

.v2-capture {
  display: grid; justify-items: center; align-content: center; gap: var(--space-2);
  min-block-size: 118px; padding: var(--space-3) var(--space-2);
  border: 0; border-radius: 20px;
  font-family: var(--body); font-size: 1.0625rem; font-weight: 750; cursor: pointer;
}
/*
 * The two are not twins. The photo route is the dark primary and the voice route
 * is the tinted secondary, which is how the design ranks them.
 */
.v2-capture.is-photo { background: var(--inverse); color: var(--on-inverse); }
.v2-capture.is-voice { background: var(--route-soft); color: var(--route-ink); border: 1px solid var(--route); }
/* The icon takes the button's own colour rather than overriding it. */
.v2-capture svg { color: currentColor; }
.v2-capture:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

.v2-capture-extra { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-3); }

/*
 * Barcode, restaurant and typing are capture routes, not footnotes. In grey on
 * grey they read as fine print under the two big buttons and were being missed;
 * in the route colour they read as the third, fourth and fifth ways in.
 */
.v2-text-link {
  display: inline-flex; align-items: center; gap: var(--space-1);
  min-block-size: var(--tap-min); padding-inline: var(--space-2);
  border: 0; border-radius: 999px; background: var(--route-soft);
  color: var(--route-ink); font-family: var(--body); font-size: 0.9375rem; font-weight: 650;
  cursor: pointer;
}
.v2-text-link span { text-decoration: none; }
.v2-text-link:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; border-radius: var(--control-radius); }

/* A box with a magnifier, per the design — not a pill. */
.v2-search { position: relative; display: block; }
.v2-search-icon {
  position: absolute; inset-block: 0; inset-inline-start: var(--space-2);
  display: grid; place-items: center; color: var(--ink-soft); pointer-events: none;
}
.v2-search input {
  inline-size: 100%; min-block-size: 48px;
  padding-inline: calc(var(--space-2) + 20px + var(--space-2)) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-small); background: var(--input); color: var(--ink);
  font-family: var(--body); font-size: var(--text-body);
}
.v2-search input:focus-visible { outline: 2px solid var(--route); outline-offset: -1px; }

/* ------------------------------------------------------------------- confirm */

.v2-confirm { display: grid; gap: var(--space-3); }
.v2-confirm-photo { inline-size: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius-small); }
.v2-confirm-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.v2-confirm-title { margin: 0; font-family: var(--display); font-size: 1.4rem; font-weight: 650; }
.v2-confirm-total { font-size: var(--text-body); font-weight: 700; }
.v2-confirm-note { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }

/*
 * Each recognised component is its own card. It is a separate real-world thing
 * with its own amount to correct, and a row in a table says the opposite.
 */
.v2-review-list { display: grid; gap: var(--space-1); }
.v2-review-item {
  display: grid; grid-template-columns: 1fr var(--tap-min); align-items: center;
  border: 1px solid var(--line); border-radius: 18px; background: var(--panel); overflow: hidden;
}

.v2-review-main {
  display: grid; grid-template-columns: 44px 1fr auto; align-items: center; gap: var(--space-2);
  min-block-size: 60px; padding: var(--space-2); padding-inline-end: 0;
  border: 0; background: none; color: inherit; font-family: var(--body); text-align: start; cursor: pointer;
}
.v2-review-mark {
  inline-size: 44px; block-size: 44px; border-radius: 12px;
  background: repeating-linear-gradient(135deg, var(--paper-deep) 0 6px, var(--paper) 6px 12px);
}
.v2-review-body { display: grid; gap: 2px; min-inline-size: 0; }
.v2-review-body b { font-size: var(--text-body); font-weight: 600; }
.v2-review-body small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-review-amount { font-family: var(--number); font-size: 1.0625rem; font-weight: 650; }

/*
 * An unresolved decision uses the checkpoint yellow the design system reserves,
 * and carries an edge in the same tone so it is a card that is waiting on you
 * rather than a differently coloured row.
 */
.v2-decision {
  padding: var(--space-3); border: 1px solid var(--sun); border-radius: 18px;
  background: var(--surface-decision);
}
.v2-decision .v2-decision-head small { color: var(--sun-ink); }
.v2-decision-head { display: grid; gap: 2px; margin-bottom: var(--space-2); }
.v2-decision-head b { font-size: var(--text-body); font-weight: 650; }
.v2-decision-head small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-decision-choices { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.v2-choice {
  display: inline-flex; align-items: center; gap: var(--space-1);
  min-block-size: var(--tap-min); padding: 0 var(--space-3);
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel); color: var(--ink); font-family: var(--body);
  font-size: var(--text-body); cursor: pointer;
}
.v2-choice:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-choice-amount { color: var(--ink-soft); font-size: var(--text-small); }

/* Outside the list and dashed, because it adds a card rather than being one. */
.v2-add-missed {
  display: flex; align-items: center; justify-content: center; gap: var(--space-2);
  inline-size: 100%; min-block-size: var(--tap-min); padding: var(--space-2) var(--space-3);
  border: 1px dashed var(--line-strong); border-radius: 18px; background: none;
  color: var(--route-ink); font-family: var(--body); font-size: var(--text-body); font-weight: 650;
  cursor: pointer;
}
.v2-add-missed:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

.v2-toggle-row { display: grid; gap: var(--space-1); padding: var(--space-3); border-radius: var(--radius-small); background: var(--panel); }
.v2-toggle { display: flex; align-items: center; gap: var(--space-2); min-block-size: var(--tap-min); cursor: pointer; }
.v2-toggle input { position: absolute; inline-size: 1px; block-size: 1px; opacity: 0; }
.v2-toggle-track { inline-size: 46px; block-size: 28px; border-radius: 999px; background: var(--paper-deep); transition: background 140ms ease; flex: none; }
.v2-toggle-knob { display: block; inline-size: 22px; block-size: 22px; margin: 3px; border-radius: 50%; background: var(--panel); box-shadow: var(--shadow-soft); transition: transform 140ms ease; }
.v2-toggle input:checked + .v2-toggle-track { background: var(--route); }
.v2-toggle input:checked + .v2-toggle-track .v2-toggle-knob { transform: translateX(18px); }
[dir="rtl"] .v2-toggle input:checked + .v2-toggle-track .v2-toggle-knob { transform: translateX(-18px); }
.v2-toggle input:focus-visible + .v2-toggle-track { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-toggle-label { font-size: var(--text-body); font-weight: 600; }
.v2-toggle-note { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }

/*
 * The save action is pinned. The review list can run past the fold, and a save
 * button that has to be scrolled to is the one step of this flow where someone
 * has already decided and just wants it recorded.
 */
.v2-confirm-actions {
  position: sticky;
  inset-block-end: 0;
  display: grid; gap: var(--space-2);
  margin-inline: calc(var(--space-3) * -1);
  margin-block-end: calc(var(--space-3) * -1);
  padding: var(--space-2) var(--space-3) calc(var(--space-2) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--panel);
}
.v2-confirm-actions .v2-primary { margin-block: 0; }
/* The amount leads the label rather than being read into it. */
.v2-confirm-save-amount { font-family: var(--number); font-variant-numeric: tabular-nums; }

/* The photo is the header of this screen, not a picture inside it. */
.v2-confirm.has-photo { gap: var(--space-3); }
.v2-confirm-photo-wrap {
  position: relative;
  margin-inline: calc(var(--space-3) * -1);
  margin-block-start: calc(var(--space-3) * -1);
  block-size: 230px;
  background: repeating-linear-gradient(135deg, var(--paper-deep) 0 12px, var(--paper) 12px 24px);
}
.v2-confirm-photo { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.v2-confirm-photo-back {
  position: absolute; inset-block-start: var(--space-2); inset-inline-start: var(--space-3);
  display: grid; place-items: center; inline-size: 40px; block-size: 40px;
  border: 0; border-radius: 50%; background: var(--glass-on-dark); color: var(--on-inverse); cursor: pointer;
}
.v2-confirm-photo-back:focus-visible { outline: 2px solid var(--on-inverse); outline-offset: 2px; }
/* The body lifts over the photo, which is what makes it read as a sheet. */
.v2-confirm.has-photo .v2-confirm-head {
  margin-block-start: calc(var(--space-4) * -1);
  padding-block-start: var(--space-3);
  padding-inline: var(--space-2);
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--panel);
}
.v2-blocked { margin: 0; font-size: var(--text-small); color: var(--ink-soft); text-align: center; }
.v2-error { margin: 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-small); background: var(--effort-soft); color: var(--effort); font-size: var(--text-small); }
/* A result, not a fault: nothing was recognised. Red would overstate it. */
.v2-notice { margin: 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-small); background: var(--panel-muted); color: var(--ink); font-size: var(--text-small); line-height: 1.45; }
.v2-primary[disabled] { opacity: 0.45; cursor: default; }

/* ------------------------------------------------------------ camera and voice */

/*
 * The camera is the whole screen, dark, with the controls floating over the
 * picture. A viewfinder in a light card with a caption underneath is a form about
 * a photo; this is the photo.
 */
.v2-camera { position: absolute; inset: 0; display: grid; background: var(--inverse); color: var(--on-inverse); }
.v2-camera-stage { position: relative; display: grid; place-items: center; overflow: hidden; border-radius: var(--radius-small); background: var(--inverse); }
/* Only the camera is full bleed. The scanner keeps its sheet header, and a stage
   spanning the sheet would cover the way out of it. */
.v2-camera > .v2-camera-stage { position: absolute; inset: 0; border-radius: 0; }
.v2-scanner { display: grid; gap: var(--space-3); grid-template-rows: 1fr auto auto auto; block-size: 100%; }
.v2-viewfinder { inline-size: 100%; block-size: 100%; object-fit: cover; }
.v2-camera-note, .v2-camera-hint { margin: 0; text-align: center; font-size: var(--text-small); }
.v2-camera-note { color: var(--on-inverse); padding: var(--space-4); }

/* Floating chrome. Both bars sit over the picture with a gradient behind them,
   so white controls stay legible whatever is in frame. */
.v2-camera-top {
  position: absolute; inset-block-start: 0; inset-inline: 0; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  padding: calc(var(--space-3) + env(safe-area-inset-top)) var(--space-3) var(--space-4);
  background: linear-gradient(to bottom, var(--glass-on-dark), transparent);
}
.v2-camera-bottom {
  position: absolute; inset-block-end: 0; inset-inline: 0; z-index: 1;
  display: grid; gap: var(--space-3); justify-items: center;
  padding: var(--space-4) var(--space-3) calc(var(--space-4) + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--inverse), transparent);
}
.v2-camera-hint { color: color-mix(in srgb, var(--on-inverse) 82%, transparent); }
.v2-camera-actions { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; justify-items: center; inline-size: 100%; }
.v2-camera-round {
  display: grid; place-items: center; inline-size: 44px; block-size: 44px;
  border: 0; border-radius: 50%; background: var(--glass-on-dark); color: var(--on-inverse); cursor: pointer;
}
.v2-camera-round.is-on { background: var(--on-inverse); color: var(--ink); }
.v2-camera-round:focus-visible { outline: 2px solid var(--on-inverse); outline-offset: 2px; }
/* The gallery is a thumbnail-shaped target, as the design draws it. */
.v2-camera-gallery {
  display: grid; place-items: center; inline-size: 52px; block-size: 52px;
  border: 1px solid color-mix(in srgb, var(--on-inverse) 40%, transparent);
  border-radius: 14px; background: var(--glass-on-dark); color: var(--on-inverse); cursor: pointer;
}
.v2-camera-gallery:focus-visible { outline: 2px solid var(--on-inverse); outline-offset: 2px; }
.v2-camera-pill {
  padding: var(--space-1) var(--space-2); border-radius: 999px;
  background: var(--glass-on-dark); color: var(--on-inverse);
  font-size: var(--text-small); font-weight: 650; white-space: nowrap;
}

.v2-shutter {
  inline-size: 78px; block-size: 78px;
  border: 4px solid color-mix(in srgb, var(--on-inverse) 90%, transparent);
  border-radius: 50%; background: var(--on-inverse);
  box-shadow: 0 0 0 8px color-mix(in srgb, var(--on-inverse) 22%, transparent);
  cursor: pointer;
}
.v2-shutter:focus-visible { outline: 3px solid var(--route); outline-offset: 3px; }

.v2-voice { display: grid; gap: var(--space-3); justify-items: center; padding: var(--space-4) 0; }
.v2-voice-wave { display: flex; align-items: center; gap: 4px; block-size: 48px; }
.v2-voice-wave span { inline-size: 4px; block-size: 12px; border-radius: 999px; background: var(--line-strong, var(--line)); }
.v2-voice-wave[data-active="true"] span { background: var(--route); animation: v2-wave 900ms ease-in-out infinite; }
.v2-voice-wave span:nth-child(2n) { animation-delay: 120ms; }
.v2-voice-wave span:nth-child(3n) { animation-delay: 240ms; }
@keyframes v2-wave { 0%, 100% { block-size: 12px; } 50% { block-size: 40px; } }
.v2-voice-status { margin: 0; font-size: var(--text-body); color: var(--ink-soft); }

/*
 * After the recording stops, the transcript is the screen: it is what the person
 * has to check before anything is saved, so it is set as primary text and the
 * match sits under it as a resolved card.
 */
.v2-voice-transcript {
  margin: 0; font-family: var(--display); font-size: 1.375rem; font-weight: 650;
  line-height: 1.3; color: var(--ink); text-align: center;
}
.v2-voice-match {
  display: flex; align-items: center; gap: var(--space-2); inline-size: 100%;
  padding: var(--space-2); border: 1px solid var(--recovery); border-radius: 18px;
  background: var(--surface-resolved); text-align: start;
}
.v2-voice-match-body { flex: 1; display: grid; gap: 2px; min-inline-size: 0; }
.v2-voice-match-body b { font-size: var(--text-body); font-weight: 650; }
.v2-voice-match-body small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-voice-match-amount { font-family: var(--number); font-size: 1.125rem; font-weight: 650; }
.v2-voice-warning { margin: 0; font-size: var(--text-small); font-weight: 650; color: var(--effort); text-align: center; }
.v2-voice-actions { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2); inline-size: 100%; align-items: center; }
.v2-voice-actions .v2-primary { margin-block: 0; }
.v2-record { inline-size: 88px; block-size: 88px; border: 0; border-radius: 50%; background: var(--route); color: var(--on-inverse); cursor: pointer; }
.v2-record[data-recording="true"] { background: var(--effort); }
.v2-record:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

.v2-text-entry { display: grid; gap: var(--space-3); }
.v2-textarea {
  inline-size: 100%; padding: var(--space-3); border: 1px solid var(--line);
  border-radius: var(--radius-small); background: var(--input); color: var(--ink);
  font-family: var(--body); font-size: var(--text-body); resize: none;
}

.v2-spinner {
  inline-size: 28px; block-size: 28px; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--route);
  animation: v2-spin 700ms linear infinite;
}
@keyframes v2-spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------- item editor */

.v2-item-edit { display: grid; gap: var(--space-3); }
.v2-item-head { display: grid; gap: 2px; }
.v2-item-title { margin: 0; font-family: var(--display); font-size: 1.375rem; font-weight: 650; }
.v2-item-sub { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }

.v2-segmented { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: 4px; padding: 4px; border-radius: 999px; background: var(--paper-deep); }
.v2-segment { min-block-size: 40px; border: 0; border-radius: 999px; background: none; color: var(--ink-soft); font-family: var(--body); font-size: var(--text-small); font-weight: 600; cursor: pointer; }
.v2-segment.is-active { background: var(--panel); color: var(--ink); }
.v2-segment:focus-visible { outline: 2px solid var(--route); outline-offset: -2px; }

.v2-stepper { display: grid; grid-template-columns: auto 1fr auto; gap: var(--space-2); align-items: center; padding: var(--space-2); border-radius: var(--radius-small); background: var(--panel); }
/* Big plain − and + (founder decision 24 September 2026); each tap is 10 g. */
.v2-step { inline-size: 56px; block-size: 56px; padding: 0; border: 1px solid var(--route); border-radius: 50%; background: var(--route-soft); color: var(--route); font-family: var(--number); font-size: 2rem; font-weight: 500; line-height: 1; cursor: pointer; }
.v2-step:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-conversation-amount { display: grid; gap: var(--space-2); margin-block: var(--space-3); }
.v2-conversation-amount-label, .v2-conversation-amount-preview { margin: 0; color: var(--ink-soft); font-size: var(--text-small); }
.v2-conversation-amount .v2-quiet-button { justify-self: start; }
.v2-stepper-value { display: flex; align-items: baseline; justify-content: center; gap: var(--space-1); font-size: 1.25rem; font-weight: 650; }
/* The amount can be typed; the dashed underline marks it as editable. 1.25rem keeps iOS from zooming. */
.v2-amount-input {
  inline-size: 5ch; min-block-size: var(--tap-min); padding: 0;
  border: 0; border-block-end: 1px dashed var(--line); border-radius: 0; background: none; color: var(--ink);
  font-family: var(--number); font-size: 1.25rem; font-weight: 650; font-variant-numeric: tabular-nums;
  direction: ltr; text-align: center;
}
.v2-amount-input:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; border-radius: var(--control-radius); }

.v2-presets { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-2); }
.v2-preset { min-block-size: var(--tap-min); border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--ink); font-family: var(--body); font-size: var(--text-small); cursor: pointer; }
.v2-preset.is-active { border-color: var(--route); background: var(--route-soft); color: var(--route); font-weight: 650; }
.v2-preset:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

/*
 * Correcting the numbers directly. Closed by default: this is the one keyboard in
 * the logging flow, and almost every correction is an amount, not a nutrient.
 */
.v2-correct-toggle {
  min-block-size: var(--tap-min); padding: 0; border: 0; background: none;
  color: var(--route-ink); font-family: var(--body); font-size: var(--text-small); font-weight: 650;
  text-align: start; cursor: pointer;
}
.v2-correct-toggle:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; border-radius: var(--control-radius); }

.v2-correct {
  display: grid; gap: var(--space-2);
  padding: var(--space-3); border: 1px solid var(--line); border-radius: 18px; background: var(--panel);
}
.v2-correct-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
.v2-correct-field { display: grid; gap: 4px; min-inline-size: 0; }
.v2-correct-field span { font-size: var(--text-small); color: var(--ink-soft); }
.v2-correct-input {
  min-block-size: var(--tap-min); inline-size: 100%;
  padding: 0 var(--space-2); border: 1px solid var(--line); border-radius: var(--control-radius);
  background: var(--input); color: var(--ink);
  font-family: var(--number); font-size: var(--text-body); font-variant-numeric: tabular-nums;
  /* Quantities read left to right in both languages. */
  direction: ltr; text-align: start;
}
.v2-correct-input:focus-visible { outline: 2px solid var(--route); outline-offset: -1px; }
.v2-correct-note { margin: 0; font-size: var(--text-small); line-height: 1.45; color: var(--ink-soft); }

/* The picture the post will carry. */
.v2-share-photo { display: grid; gap: var(--space-2); margin-top: var(--space-2); }
.v2-share-photo-preview {
  inline-size: 100%; max-block-size: 180px; object-fit: cover;
  border-radius: var(--radius-small); background: var(--paper-deep);
}
.v2-share-photo-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

.v2-item-total { display: flex; align-items: baseline; justify-content: space-between; padding: var(--space-3); border-radius: var(--radius-small); background: var(--panel); font-weight: 650; }
.v2-item-macros { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-2); }
.v2-item-macro { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); font-size: var(--text-small); }
.v2-item-macro .is-unknown { color: var(--ink-soft); font-style: italic; }
.v2-item-actions { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2); align-items: center; }

.v2-quiet-button { min-block-size: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--ink); font-family: var(--body); font-size: var(--text-body); cursor: pointer; }
.v2-quiet-button.is-danger { color: var(--effort); border-color: var(--effort-soft); }
.v2-quiet-button:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

.visually-hidden { position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* ---------------------------------------------------------------------- feed */

.v2-feed-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-3); }
.v2-feed-head .v2-screen-title { margin: 0; }
.v2-feed-note { font-size: var(--text-small); color: var(--ink-soft); }

.v2-locked { display: grid; gap: var(--space-3); }
.v2-locked-stack { display: grid; gap: var(--space-2); }
/*
 * A stand-in for the posts that are being withheld. It carries no content, so the
 * blur is decoration rather than an attempt to hide something that is really there.
 */
.v2-locked-card { block-size: 96px; border-radius: var(--radius-small); background: linear-gradient(120deg, var(--panel), var(--paper-deep)); filter: blur(1px); opacity: 0.7; }
.v2-locked-note { display: grid; justify-items: center; gap: var(--space-1); padding: var(--space-4) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-small); background: var(--panel); text-align: center; }
.v2-locked-icon { color: var(--route); }
.v2-locked-note strong { font-size: var(--text-body); font-weight: 650; }
.v2-locked-waiting { font-size: var(--text-small); color: var(--ink-soft); }

.v2-stories { display: flex; gap: var(--space-2); margin-bottom: var(--space-3); padding-bottom: var(--space-1); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; }
.v2-stories::-webkit-scrollbar { display: none; }
.v2-story { display: grid; justify-items: center; gap: 4px; border: 0; background: none; color: inherit; font-family: var(--body); cursor: pointer; }

/*
 * A ring, not a gradient disc. The ring is what says "unopened"; once the story
 * has been seen it goes dashed and dim, so the rail can hold everyone without
 * all of them shouting.
 */
.v2-story-ring {
  display: grid; place-items: center; inline-size: 54px; block-size: 54px;
  border: 2px solid var(--route); border-radius: 50%; padding: 2px;
}
.v2-story.is-seen .v2-story-ring { border-style: dashed; border-color: var(--line-strong); opacity: 0.7; }
.v2-story-name { max-inline-size: 60px; font-size: var(--text-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v2-story:focus-visible .v2-story-ring { outline: 2px solid var(--route); outline-offset: 3px; }

/*
 * Avatars are tinted per person rather than all the same grey, so a rail of
 * initials is still readable as different people. The tint is picked from the
 * name, so it is stable for a given person without storing anything.
 */
.v2-avatar {
  display: grid; place-items: center; inline-size: 40px; block-size: 40px;
  border-radius: 50%;
  background: var(--avatar-fill, var(--paper-deep)); color: var(--avatar-ink, var(--ink-soft));
  font-size: var(--text-small); font-weight: 700; text-transform: uppercase; object-fit: cover;
}
.v2-avatar[data-tint="1"] { --avatar-fill: var(--route-soft); --avatar-ink: var(--route-ink); }
.v2-avatar[data-tint="2"] { --avatar-fill: var(--recovery-soft); --avatar-ink: var(--ink); }
.v2-avatar[data-tint="3"] { --avatar-fill: var(--sun-soft); --avatar-ink: var(--sun-ink); }
.v2-avatar.is-sm { inline-size: 40px; block-size: 40px; }
.v2-avatar.is-md { inline-size: 46px; block-size: 46px; }
.v2-avatar.is-story { inline-size: 46px; block-size: 46px; }
.v2-avatar.is-lg { inline-size: 78px; block-size: 78px; font-size: 1.5rem; }

.v2-post-list { display: grid; gap: var(--space-3); }
.v2-post { border: 1px solid var(--line); border-radius: 22px; background: var(--panel); overflow: hidden; }
.v2-post-head { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); }
.v2-post-who { display: grid; gap: 1px; min-inline-size: 0; }
.v2-post-who strong { font-size: var(--text-body); font-weight: 700; }
.v2-post-who small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-post-photo { inline-size: 100%; block-size:auto; max-block-size:360px; object-fit: contain; display: block; }
.v2-post-body { display: grid; gap: var(--space-2); padding: var(--space-3); }
.v2-post-title { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.v2-post-title h3 { margin: 0; font-family: var(--display); font-size: 1.25rem; font-weight: 650; }
/* The number is a fact about the meal, so it is set as a value, not a caption. */
.v2-post-calories {
  flex: none; padding: 4px var(--space-2); border-radius: 999px;
  background: var(--panel-muted); color: var(--ink);
  font-size: var(--text-small); font-weight: 650; white-space: nowrap;
}
.v2-post-foods { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }
.v2-post-note { margin: 0; font-size: var(--text-small); color: var(--ink-soft); font-style: italic; }

/* Keep comments visibly separate from the post's nutrition or workout facts. */
.v2-post-comments-preview {display:grid;gap:var(--space-2);border-block-start:1px solid var(--line);padding-block-start:var(--space-3);margin-block-start:var(--space-1);}
.v2-post-comment {display:grid;grid-template-columns:32px minmax(0,1fr);align-items:start;gap:var(--space-2);inline-size:100%;min-block-size:var(--tap-min);margin:0;padding:0;border:0;background:none;color:var(--ink);font:inherit;text-align:start;cursor:pointer;}
.v2-post-comment-copy {display:grid;gap:var(--space-1);min-inline-size:0;padding:var(--space-2) var(--space-3);border-radius:var(--radius-small);background:var(--paper);}
.v2-post-comment-author {font-size:14px;line-height:1.4;font-weight:700;overflow-wrap:anywhere;}
.v2-post-comment-text {font-size:16px;line-height:1.45;overflow-wrap:anywhere;white-space:pre-wrap;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;}
.v2-post-comment:focus-visible {outline:2px solid var(--route);outline-offset:2px;border-radius:var(--radius-small);}
.v2-post-comment:disabled {cursor:default;}
.v2-post-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }

/*
 * A chip you have not pressed is still a thing you can press, so it sits on the
 * panel with its own edge rather than fading into the card. The row keeps a
 * 44px target; the chip itself is the 36px the design draws inside it.
 */
.v2-reaction, .v2-post-comments {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-block-size: var(--tap-min); min-inline-size: var(--tap-min);
  padding: 0 var(--space-2); border: 0; background: none;
  color: var(--ink); font-family: var(--body); font-size: var(--text-small); cursor: pointer;
}
.v2-reaction > *, .v2-post-comments > * { position: relative; z-index: 1; }
.v2-reaction::before, .v2-post-comments::before {
  content: ''; position: absolute; inset-block: calc((var(--tap-min) - 36px) / 2); inset-inline: 0;
  border: 1px solid var(--line); border-radius: 999px; background: var(--panel);
  transition: background var(--motion-fast), border-color var(--motion-fast);
}
.v2-reaction, .v2-post-comments { position: relative; }
.v2-reaction.is-mine { color: var(--route-ink); font-weight: 650; }
.v2-reaction.is-mine::before { border-color: var(--route); background: var(--route-soft); }
.v2-reaction:focus-visible, .v2-post-comments:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-reaction-glyph { font-size: 1.05rem; line-height: 1; }
.v2-reaction-count { font-weight: 650; }
.v2-post-comments { margin-inline-start: auto; }

/* ------------------------------------------------------- social sheets */

.v2-feed-head-end { display: flex; align-items: center; gap: var(--space-1); }
.v2-avatar.is-sm { inline-size: 32px; block-size: 32px; font-size: 0.75rem; }

.v2-comments { display: grid; grid-template-rows: auto minmax(0,1fr) auto auto; gap: var(--space-2); min-block-size: 40dvh; }
.v2-comment-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); overflow-y: auto; }
.v2-comment { display: grid; grid-template-columns: 40px 1fr; gap: var(--space-2); }
.v2-comment-body p { margin: 0; font-size: var(--text-body); line-height: 1.45; }
.v2-comment-meta { display: flex; align-items: center; gap: var(--space-2); }
.v2-comment-body small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-comment-reply {
  min-block-size: var(--tap-min); padding: 0; border: 0; background: none;
  color: var(--ink-soft); font-family: var(--body); font-size: var(--text-small); font-weight: 650; cursor: pointer;
}
.v2-comment-reply:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; border-radius: var(--control-radius); }

/* The meal the thread is about, so a comment sheet is never about nothing. */
.v2-comment-post {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2); border: 1px solid var(--line); border-radius: 18px; background: var(--panel-muted);
}
.v2-comment-post-photo {
  flex: none; inline-size: 52px; block-size: 52px; border-radius: var(--control-radius); object-fit: cover;
}
.v2-comment-post-photo.is-blank {
  background: repeating-linear-gradient(135deg, var(--paper-deep) 0 6px, var(--paper) 6px 12px);
}
.v2-comment-post-body { flex: 1; display: grid; gap: 2px; min-inline-size: 0; }
.v2-comment-post-body b { font-size: var(--text-body); font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v2-comment-post-body small { font-size: var(--text-small); color: var(--ink-soft); }
/* The one keyboard in the feed. It sits outside the scrolling list, so the list
   does not jump when the composer gains focus. */
.v2-comment-composer { display: grid; grid-template-columns: 40px 1fr var(--tap-min); align-items: center; gap: var(--space-2); }
.v2-comment-input { min-block-size: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: 999px; background: var(--input); color: var(--ink); font-family: var(--body); font-size: var(--text-body); }
.v2-comment-send { display: grid; place-items: center; padding: 0; inline-size: var(--tap-min); block-size: var(--tap-min); border: 0; border-radius: 50%; background: var(--route); color: var(--on-inverse); cursor: pointer; }
.v2-comment-send svg { display: block; stroke-width: 2.2; }
.v2-comment-send:focus-visible { outline: 2px solid var(--route); outline-offset: 3px; }
.v2-comment-input { min-inline-size: 0; }
.v2-comment-workout-icon { display: grid; place-items: center; flex: none; inline-size: 44px; block-size: 44px; border-radius: var(--control-radius); color: var(--route); background: var(--route-soft); }
.v2-workout-summary { display: grid; gap: var(--space-1); }
.v2-workout-summary p { margin: 0; }
.v2-workout-burn { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-1); }
.v2-comment-send[disabled] { opacity: 0.4; cursor: default; }

.v2-profile, .v2-friends { display: grid; gap: var(--space-3); }
.v2-profile-head { display: flex; align-items: center; gap: var(--space-3); }
.v2-profile-name { margin: 0; font-family: var(--display); font-size: 1.375rem; font-weight: 650; }
.v2-profile-sub { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }
/* Three separate cards, so each number is its own claim. */
.v2-stat-row { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-1); }
.v2-stat { display: grid; gap: 2px; padding: var(--space-2) var(--space-1); border: 1px solid var(--line); border-radius: var(--radius-small); background: var(--panel); text-align: center; }
.v2-stat b { font-size: 1.375rem; font-weight: 650; }
.v2-stat b.is-good { color: var(--recovery); }
.v2-stat span { font-size: var(--text-small); color: var(--ink-soft); }

/* What has been shared, as pictures. A post with no photo keeps its name. */
.v2-photo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-1); }
.v2-photo-cell {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--radius-small);
  background: repeating-linear-gradient(135deg, var(--paper-deep) 0 6px, var(--paper) 6px 12px);
  overflow: hidden;
}
.v2-photo-cell img { inline-size: 100%; block-size: 100%; object-fit: cover; }
.v2-photo-name {
  display: grid; place-items: center; block-size: 100%; padding: var(--space-1);
  font-size: var(--text-small); font-weight: 650; text-align: center; color: var(--ink-soft);
}
.v2-photo-calories {
  position: absolute; inset-block-end: var(--space-1); inset-inline-end: var(--space-1);
  padding: 2px 6px; border-radius: 999px;
  background: var(--glass-on-dark); color: var(--on-inverse);
  font-size: 0.6875rem; font-weight: 650;
}

.v2-person-list { display: grid; gap: var(--space-1); }
.v2-person {
  display: grid; grid-template-columns: 40px 1fr auto; align-items: center; gap: var(--space-2);
  min-block-size: 56px; padding: var(--space-2); border: 1px solid var(--line);
  border-radius: 18px; background: var(--panel);
}
.v2-person-wall, .v2-person-identity {
  color: var(--ink); font: inherit; text-align: start; cursor: pointer; inline-size: 100%;
}
.v2-person.has-actions { grid-template-columns: minmax(0, 1fr) auto; }
.v2-person-identity {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto;
  align-items: center; gap: var(--space-2); min-block-size: var(--tap-min);
  border: 0; padding: 0; background: none; border-radius: var(--control-radius);
}
.v2-person-wall { grid-template-columns: 40px minmax(0, 1fr) auto; }
.v2-person-wall:hover { border-color: var(--route); background: var(--route-soft); }
.v2-person-wall:active { background: var(--route-soft); }
.v2-person-wall:focus-visible, .v2-person-identity:focus-visible {
  outline: 2px solid var(--route); outline-offset: 2px;
}
.v2-person-chevron { display: flex; color: var(--route); }
/* Someone waiting on an answer is the one thing on this screen to act on. */
.v2-person.is-pending { border-color: var(--route); box-shadow: 0 0 0 3px var(--route-soft); }
.v2-person-body { display: grid; gap: 1px; min-inline-size: 0; }
.v2-person-body b { overflow-wrap: anywhere; font-size: var(--text-body); font-weight: 600; }
.v2-person-body small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-person-body small.v2-person-wall-label { color: var(--route); font-weight: 600; }
.v2-person-body small.is-good { color: var(--recovery); font-weight: 650; }
.v2-person-actions { display: flex; align-items: center; gap: var(--space-1); }
.v2-person-state { font-size: var(--text-small); color: var(--ink-soft); }

/* The link, on screen, with a way to pass it on. */
.v2-invite-link {
  display: grid; gap: var(--space-2);
  padding: var(--space-3); border: 1px solid var(--route); border-radius: 18px;
  background: var(--route-soft);
}
.v2-invite-note { margin: 0; font-size: var(--text-small); color: var(--route-ink); }
.v2-invite-url {
  padding: var(--space-2); border-radius: var(--control-radius); background: var(--panel);
  font-family: var(--utility, monospace); font-size: var(--text-small); color: var(--ink);
  overflow-wrap: anywhere;
}
.v2-invite-actions { display: flex; gap: var(--space-2); }

/* A feed with nobody in it is the one thing the product cannot fix by itself. */
.v2-invite {
  display: flex; align-items: center; justify-content: center; gap: var(--space-2);
  inline-size: 100%; min-block-size: 52px; padding: var(--space-2) var(--space-3);
  border: 0; border-radius: 18px; background: var(--inverse); color: var(--on-inverse);
  font-family: var(--body); font-size: var(--text-body); font-weight: 650; cursor: pointer;
}
.v2-invite:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

/* ------------------------------------------------------------------- signup */

.v2-onboarding { display: grid; grid-template-rows: auto 1fr auto; gap: var(--space-3); min-block-size: 100%; padding-bottom: env(safe-area-inset-bottom); }
.v2-progress { display: flex; gap: var(--space-1); }
.v2-progress-pip { flex: 1; block-size: 4px; border-radius: 999px; background: var(--paper-deep); }
.v2-progress-pip.is-done { background: var(--route); }

.v2-signup { display: grid; align-content: start; gap: var(--space-3); }

/*
 * The first screen is dark. It is the only screen in the app that is selling
 * rather than reporting, and the dark ground is what separates the pitch from
 * the product — after this, everything is paper.
 */
.v2-signup-intro {
  align-content: center;
  margin: calc(var(--space-4) * -1) calc(var(--space-3) * -1);
  padding: var(--space-4) var(--space-3) calc(var(--space-4) + env(safe-area-inset-bottom));
  min-block-size: 100dvh;
  background:
    radial-gradient(circle at 78% 8%, color-mix(in srgb, var(--route) 28%, transparent), transparent 24rem),
    linear-gradient(160deg, var(--chrome), var(--inverse-soft));
  color: var(--on-inverse);
}
.v2-signup-hero { display: grid; gap: var(--space-2); }
.v2-signup-eyebrow {
  margin: 0; font-size: var(--text-small); font-weight: 750;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--sun);
}
.v2-signup-headline { margin: 0; font-family: var(--display); font-size: clamp(2.5rem, 14vw, 3.375rem); line-height: 0.98; font-weight: 650; letter-spacing: -0.05em; }
.v2-signup-intro-note { margin: 0; font-size: var(--text-body); color: color-mix(in srgb, var(--on-inverse) 76%, transparent); }
.v2-signup-title { margin: 0; font-family: var(--display); font-size: 2rem; line-height: 1.12; font-weight: 650; letter-spacing: -0.035em; }
.v2-signup-note { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }
/* Apple Health's mark is its own colour, not the route blue. */
.v2-signup-icon { display: inline-flex; inline-size: 52px; block-size: 52px; align-items: center; justify-content: center; border-radius: 16px; background: var(--effort-soft); color: var(--effort); }
.v2-signup-actions { display: grid; gap: var(--space-2); }
/* The change the target is, said in the colour a change is said in. */
.v2-signup-delta { margin: 0; font-size: var(--text-body); font-weight: 650; color: var(--effort); }
/* What connecting actually gives, so the permission has a reason attached. */
.v2-signup-bullets { list-style: none; display: grid; gap: var(--space-2); margin: 0; padding: 0; }
.v2-signup-bullets li { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-body); }
.v2-signup-bullets svg { flex: none; color: var(--ink-soft); }
.v2-signup-legal { margin: 0; font-size: var(--text-small); color: var(--ink-soft); text-align: center; }
.v2-signup-legal a { color: var(--ink-soft); }

/*
 * On the dark screen the primary is the white button and the secondary is an
 * outline. A route-blue pill on a route-blue glow reads as decoration.
 */
.v2-signup-intro .v2-primary {
  background: var(--on-inverse); color: var(--ink); box-shadow: none;
}
.v2-signup-intro .v2-primary.is-dark {
  background: none; color: var(--on-inverse);
  border: 1px solid color-mix(in srgb, var(--on-inverse) 45%, transparent);
}
.v2-signup-intro .v2-signup-legal,
.v2-signup-intro .v2-signup-legal a { color: color-mix(in srgb, var(--on-inverse) 62%, transparent); }
.v2-signup-footer { display: grid; gap: var(--space-2); }
.v2-primary.is-dark { background: var(--inverse); }
a.v2-primary { text-decoration: none; }

.v2-wheels, .v2-measures { display: grid; gap: var(--space-2); }

/* ---------------------------------------------------------- measurement field */

/*
 * A row that opens. Collapsed it is an answer; open it is the one thing being
 * edited, which is why only one carries the route ring at a time.
 */
.v2-measure {
  border: 1px solid var(--line); border-radius: 18px; background: var(--panel); overflow: hidden;
}
.v2-measure.is-open { border-color: var(--route); box-shadow: 0 0 0 4px var(--focus-ring); }

.v2-measure-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  inline-size: 100%; min-block-size: 68px; padding: 0 var(--space-3);
  border: 0; background: none; color: inherit; font-family: var(--body); text-align: start; cursor: pointer;
}
.v2-measure-head:focus-visible { outline: 2px solid var(--route); outline-offset: -3px; }
/* Where the ruler is the only control, the head is a caption rather than a toggle. */
.v2-measure-head.as-static { cursor: default; }
.v2-measure-label { font-size: var(--text-body); color: var(--ink-soft); }
.v2-measure.is-open .v2-measure-label { color: var(--route); }
.v2-measure-value { display: flex; align-items: baseline; gap: var(--space-1); }
.v2-measure-value b { font-family: var(--number); font-size: 1.625rem; font-weight: 650; line-height: 1; }
.v2-measure.is-open .v2-measure-value b { font-size: 2rem; }
.v2-measure-value small { font-size: 0.9375rem; color: var(--ink-soft); }

/* ------------------------------------------------------------------- the ruler */

.v2-ruler { padding-block-end: var(--space-3); }

.v2-ruler-track {
  position: relative;
  block-size: 72px;
  overflow: hidden;
  /*
   * The scale always increases to the right, in both languages — the same
   * convention as the weight chart and as a physical ruler. Left as RTL, the
   * numbers grew leftwards while each one still read left to right, which is a
   * scale that disagrees with itself.
   *
   * This also makes the offset unambiguous: with the track LTR, the logical
   * inline-start the ticks are anchored and shifted by is the left, everywhere.
   */
  direction: ltr;
  /* The ruler is dragged sideways; the page keeps its vertical scroll. */
  touch-action: pan-y;
  cursor: grab;
}
.v2-ruler-track.is-dragging { cursor: grabbing; }
.v2-ruler-track:focus-visible { outline: 2px solid var(--route); outline-offset: -2px; border-radius: var(--control-radius); }

/*
 * The ticks sit centred and are shifted by the control, so the current value is
 * always the one under the needle whatever the range.
 */
.v2-ruler-ticks {
  position: absolute; inset-block: 0 20px;
  inset-inline-start: 50%;
  display: flex; align-items: flex-end;
  /* --tick-step and --tick-width come from ruler.js, which owns the geometry
     because it is the thing converting a drag in pixels into steps. */
  gap: calc(var(--tick-step) - var(--tick-width));
  /* The offset is set by ruler.js as a logical margin; see the note there. */
  will-change: margin-inline-start;
}
/*
 * A tick is the bar plus, on the tall ones, the number under it. The number is
 * what makes movement legible: the bars are identical and the tall ones repeat
 * every fifth step, so without labels a fast swipe looks like nothing moving.
 */
.v2-ruler-tick {
  position: relative; flex: none;
  inline-size: var(--tick-width); block-size: 16px;
  background: var(--line-strong);
}
.v2-ruler-tick.is-major { block-size: 24px; }

.v2-ruler-mark {
  position: absolute;
  inset-block-start: calc(100% + 4px);
  inset-inline-start: 50%;
  margin-inline-start: -2rem;
  inline-size: 4rem;
  text-align: center;
  /* Quantities read left to right in both languages. */
  direction: ltr;
  font-family: var(--number);
  font-variant-numeric: tabular-nums;
  font-size: 0.8125rem;
  white-space: nowrap;
  line-height: 1;
  color: var(--ink-soft);
  pointer-events: none;
}
/* The one under the needle is the value, so it is not a neighbour. */
.v2-ruler-tick.is-current .v2-ruler-mark { color: var(--route); font-weight: 650; }

/* The needle does not move. The ruler moves under it, which is what a dial does. */
.v2-ruler-needle {
  position: absolute; inset-block-end: 20px; inset-inline-start: 50%;
  inline-size: 3px; block-size: 40px; border-radius: 2px;
  background: var(--route);
  /* Centred on the 50% line with a logical offset, for the same reason. */
  margin-inline-start: -1.5px;
}

.v2-ruler-hint { margin: var(--space-1) 0 0; text-align: center; font-size: var(--text-small); color: var(--ink-soft); }

/* A drag is a direct manipulation; animating it would lag the thumb. */
@media (prefers-reduced-motion: reduce) {
  .v2-ruler-ticks { will-change: auto; }
}

/* The current value's tick, under the needle, reads as part of the needle. */
.v2-ruler-tick.is-current { background: var(--route); block-size: 24px; }

/*
 * The wheel: a scroll-snapping column with one value in view. Each row is a full
 * tap target, and the whole control is a slider to assistive technology.
 */
.v2-wheel {
  block-size: 44px;
  inline-size: 5.5ch;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  text-align: center;
  font-variant-numeric: tabular-nums;
  /* Numbers read left to right in both languages. */
  direction: ltr;
}
.v2-wheel::-webkit-scrollbar { display: none; }
.v2-wheel:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; border-radius: var(--control-radius); }
.v2-wheel-item { block-size: 44px; line-height: 44px; scroll-snap-align: center; font-size: 1.125rem; color: var(--ink-soft); }
.v2-wheel-item.is-selected { font-family: var(--number); font-size: 1.625rem; color: var(--ink); font-weight: 650; }

/* The budget the answers produced, on the dark card it will live on every day. */
.v2-budget-preview {
  display: grid; gap: var(--space-1); padding: var(--space-3);
  border-radius: var(--radius); background: var(--inverse); color: var(--on-inverse); text-align: center;
}
.v2-budget-label { margin: 0; font-size: var(--text-small); font-weight: 750; letter-spacing: 0.12em; text-transform: uppercase; color: var(--sun); }
.v2-budget-value { display: flex; align-items: baseline; justify-content: center; gap: var(--space-1); }
.v2-budget-value .v2-number { font-family: var(--number); font-size: 2.625rem; font-weight: 650; letter-spacing: -0.03em; }
.v2-budget-preview .v2-signup-note { color: color-mix(in srgb, var(--on-inverse) 72%, transparent); }
.v2-budget-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  margin-top: var(--space-2); padding-top: var(--space-2);
  border-top: 1px solid color-mix(in srgb, var(--on-inverse) 16%, transparent);
  font-size: var(--text-small);
}
.v2-budget-row span:first-child { color: color-mix(in srgb, var(--on-inverse) 72%, transparent); }
.v2-budget-row b { font-weight: 650; }

/* A choice you can see the shape of, rather than a pill of text. */
.v2-choice-cards { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-1); }
.v2-choice-card {
  display: grid; place-items: center; gap: 4px; min-block-size: 56px; padding: var(--space-2) var(--space-1);
  border: 1px solid var(--line); border-radius: var(--radius-small); background: var(--panel);
  color: var(--ink); font-family: var(--body); font-size: var(--text-body); font-weight: 600; cursor: pointer;
}
.v2-choice-card[aria-pressed="true"] { border-color: var(--route); background: var(--route-soft); color: var(--route-ink); font-weight: 700; }
.v2-choice-card:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-budget-value span { font-size: var(--text-small); color: var(--ink-soft); }

/* ---------------------------------------------------------------- progress */

/*
 * The chart is the screen. It takes the dark card the balance card uses, so the
 * two things the app is actually about — today's balance and the line to the
 * target — read as the same kind of statement.
 */
.v2-chart-card {
  display: grid; gap: var(--space-3); margin-top: var(--space-3); padding: var(--space-3) var(--space-3) var(--space-2);
  border-radius: var(--radius); background: var(--inverse); color: var(--on-inverse);
}
.v2-chart-figures { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-2); }
.v2-figure { display: grid; gap: 2px; }
.v2-figure-label { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }
/*
 * Smaller than it was. At 46px these read as the headline of the screen, but the
 * headline is the chart — these are the two facts beside it.
 */
.v2-figure-value { font-family: var(--number); font-size: 1.875rem; font-weight: 650; line-height: 1.1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.v2-figure-note { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }

/* On the dark card the muted tones invert with it. */
.v2-chart-card .v2-figure-label,
.v2-chart-card .v2-figure-note,
.v2-chart-card .v2-chart-legend { color: color-mix(in srgb, var(--on-inverse) 70%, transparent); }
.v2-chart-card .v2-empty { color: color-mix(in srgb, var(--on-inverse) 70%, transparent); }
.v2-figure-pair { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0,1fr); gap: var(--space-2); margin-top: var(--space-3); padding: var(--space-3); border-radius: var(--radius-small); background: var(--panel); }

.v2-chart-wrap { inline-size: 100%; }
/* The chart is drawn left to right in time in both languages. */
.v2-chart { inline-size: 100%; block-size: 140px; direction: ltr; }
/* Where the weight actually went, solid; where the plan says it should go, dashed. */
.v2-chart-actual { fill: none; stroke: var(--route); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.v2-chart-plan { fill: none; stroke: var(--sun); stroke-width: 2; stroke-dasharray: 5 5; }
.v2-chart-target { stroke: color-mix(in srgb, var(--on-inverse) 24%, transparent); stroke-width: 1; }
.v2-chart-point { fill: var(--route); }
.v2-chart-legend { display: flex; gap: var(--space-3); font-size: var(--text-small); color: var(--ink-soft); }
.v2-legend { display: inline-flex; align-items: center; gap: var(--space-1); }
.v2-legend i { inline-size: 16px; block-size: 2px; border-radius: 999px; background: var(--route); }
.v2-legend.is-plan i { background: repeating-linear-gradient(90deg, var(--sun) 0 4px, transparent 4px 8px); }

/* ------------------------------------------------------ activity and settings */

.v2-activity { display: grid; gap: var(--space-3); }
.v2-balance-card.is-compact { padding: var(--space-3); }
.v2-balance-card.is-compact .v2-balance-number { font-size: 2.5rem; }
.v2-balance-stat.is-action { border: 0; background: none; color: inherit; font-family: var(--body); cursor: pointer; padding: 0; }
.v2-balance-stat.is-action:focus-visible { outline: 2px solid var(--on-inverse); outline-offset: 3px; border-radius: var(--control-radius); }

.v2-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-2); }
.v2-chip { min-block-size: var(--tap-min); padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: 999px; background: var(--paper); color: var(--ink); font-family: var(--body); font-size: var(--text-small); cursor: pointer; }
.v2-chip.is-active { border-color: var(--route); background: var(--route-soft); color: var(--route); font-weight: 650; }
.v2-chip:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

.v2-settings { display: grid; gap: var(--space-2); }
.v2-settings-panel { display: grid; gap: var(--space-2); min-inline-size: 0; }
.v2-settings-panel[hidden] { display: none; }
.v2-settings-tabs { display: flex; position: sticky; inset-block-start: 0; z-index: 1; flex-shrink: 0; }
.v2-settings-tabs .v2-segment { min-block-size: var(--tap-min); flex: 1 1 auto; padding-inline: var(--space-1); white-space: nowrap; }
.v2-settings-tabs .v2-segment.is-active { background: var(--route-soft); color: var(--route-ink); }
.v2-setting-account-body small { overflow-wrap: anywhere; }

.v2-setting-account {
  display: flex; align-items: center; gap: var(--space-2); inline-size: 100%;
  min-block-size: var(--tap-min); padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line); border-radius: 18px; background: var(--panel);
  color: inherit; font-family: var(--body); text-align: start; cursor: pointer;
}
.v2-setting-account:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-setting-account-body { flex: 1; display: grid; gap: 2px; min-inline-size: 0; }
.v2-setting-account-body b { font-size: var(--text-body); font-weight: 700; }
.v2-setting-account-body small { color: var(--ink-soft); font-size: var(--text-small); }
.v2-setting-avatar {
  flex: none; display: grid; place-items: center; inline-size: 44px; block-size: 44px;
  border-radius: 50%; background: var(--route-soft); color: var(--route-ink);
  font-size: var(--text-body); font-weight: 700;
}
.v2-setting-go { flex: none; display: grid; place-items: center; color: var(--ink-soft); }

.v2-setting-group { display: grid; border: 1px solid var(--line); border-radius: 18px; background: var(--panel); overflow: hidden; }
.v2-setting { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); inline-size: 100%; min-block-size: var(--tap-min); padding: var(--space-2) var(--space-3); border: 0; background: none; color: inherit; font-family: var(--body); text-align: start; }
.v2-setting.is-action { border: 1px solid var(--line); border-radius: 18px; background: var(--panel); cursor: pointer; }
.v2-setting.is-toggle { border: 1px solid var(--line); border-radius: 18px; background: var(--panel); cursor: pointer; }
.v2-setting + .v2-setting { border-top: 1px solid var(--line); }
.v2-setting:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }
.v2-setting-body { display: grid; gap: 2px; min-inline-size: 0; }
.v2-setting-label { font-size: var(--text-body); font-weight: 600; }
.v2-setting-note { font-size: var(--text-small); color: var(--ink-soft); line-height: 1.4; }
.v2-setting-value { font-size: var(--text-small); color: var(--ink-soft); text-align: end; }

/* A connection: what it is, whether it is on, and the one thing to do about it. */
.v2-connection { display: flex; align-items: center; gap: var(--space-2); min-block-size: 64px; padding: var(--space-2) var(--space-3); }
.v2-connection + .v2-connection { border-top: 1px solid var(--line); }
.v2-connection-mark {
  flex: none; display: grid; place-items: center; inline-size: 42px; block-size: 42px;
  border-radius: 13px; background: var(--panel-muted); color: var(--ink-soft);
}
.v2-connection-body { flex: 1; display: grid; gap: 2px; min-inline-size: 0; }
.v2-connection-body b { font-size: var(--text-body); font-weight: 650; }
.v2-connection-body small { font-size: var(--text-small); color: var(--ink-soft); }
.v2-connection-body small.is-good { color: var(--recovery); font-weight: 650; }

/* Signing out is a whole decision, so it gets a whole row rather than a pill. */
.v2-signout {
  inline-size: 100%; min-block-size: 52px; margin-top: var(--space-2);
  border: 1px solid var(--line); border-radius: 18px; background: var(--panel);
  color: var(--effort); font-family: var(--body); font-size: var(--text-body); font-weight: 650; cursor: pointer;
}
.v2-signout:focus-visible { outline: 2px solid var(--route); outline-offset: 2px; }

/*
 * A switch. The input is the control — it keeps the keyboard, the state and the
 * label association — and the track beside it is what is drawn.
 */
.v2-switch { position: relative; flex: none; inline-size: 52px; block-size: 32px; }
.v2-switch-input { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; margin: 0; opacity: 0; cursor: pointer; }
.v2-switch-track {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--paper-deep); transition: background var(--motion-fast) var(--motion-ease-out);
  pointer-events: none;
}
.v2-switch-track::after {
  content: ''; position: absolute; inset-block-start: 3px; inset-inline-start: 3px;
  inline-size: 26px; block-size: 26px; border-radius: 50%; background: var(--panel);
  box-shadow: var(--shadow-soft);
  transition: transform var(--motion-fast) var(--motion-ease-out);
}
.v2-switch-input:checked + .v2-switch-track { background: var(--route); }
.v2-switch-input:checked + .v2-switch-track::after { transform: translateX(20px); }
[dir="rtl"] .v2-switch-input:checked + .v2-switch-track::after { transform: translateX(-20px); }
.v2-switch-input:focus-visible + .v2-switch-track { outline: 2px solid var(--route); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .v2-switch-track, .v2-switch-track::after { transition: none; }
}

.v2-quiet-button.is-route { border-color: var(--route); background: var(--route-soft); color: var(--route-ink); font-weight: 650; }
.v2-icon-button.is-small { inline-size: var(--tap-min); block-size: var(--tap-min); color: var(--ink-soft); }
.v2-setting-links { display: flex; gap: var(--space-3); padding: var(--space-2) var(--space-3); font-size: var(--text-small); }
.v2-setting-links a { color: var(--ink-soft); }
a.v2-quiet-button { display: inline-flex; align-items: center; text-decoration: none; }

.v2-restaurants { display: grid; gap: var(--space-3); }

/* The barcode frame: a target to line the code up with, not a decoration. */
.v2-barcode-frame {
  position: absolute;
  inset-inline: 12%;
  inset-block: 38%;
  border: 2px solid var(--on-inverse);
  border-radius: var(--control-radius);
  box-shadow: 0 0 0 100vmax color-mix(in srgb, var(--inverse) 45%, transparent);
}
.v2-barcode-result { margin-top: var(--space-2); border-radius: var(--radius-small); background: var(--panel); overflow: hidden; }

/* ------------------------------------------------------------ press feedback */

/*
 * Every target acknowledges a touch before its result lands. A transform does not
 * change hit geometry, so the 44 px minimum is unaffected — never animate padding
 * or block-size on an interactive element.
 */
.v2-nav-item,
.v2-primary,
.v2-icon-button,
.v2-option,
.v2-chip,
.v2-reaction,
.v2-story,
.v2-capture,
.v2-choice,
.v2-preset,
.v2-step,
.v2-quiet-button { transition: transform var(--motion-fast) var(--motion-ease-out); }

.v2-nav-item:active,
.v2-primary:active,
.v2-icon-button:active,
.v2-option:active,
.v2-chip:active,
.v2-reaction:active,
.v2-story:active,
.v2-capture:active,
.v2-choice:active,
.v2-preset:active,
.v2-step:active,
.v2-quiet-button:active { transform: scale(0.97); }

/* State changes the design implies but that were snapping. */
.v2-macro-fill { transition: inline-size var(--motion-page) var(--motion-ease-out); }
.v2-progress-pip { transition: background var(--motion-fast) var(--motion-ease-out); }
.v2-locked-card { transition: filter var(--motion-page) var(--motion-ease-out), opacity var(--motion-page) var(--motion-ease-out); }
.v2-reaction { transition: transform var(--motion-fast) var(--motion-ease-out), background var(--motion-fast), border-color var(--motion-fast); }

/* An unseen post is marked, which the card already asked for but nothing drew. */
.v2-post.is-unseen { box-shadow: inset 0 0 0 1px var(--route-soft); }

/* FS-086: existing v2 surfaces and tokens, with explicit logging actions. */
.v2-log-actions { display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-2);align-items:stretch;margin-block:var(--space-3); }
.v2-log-actions > button {box-sizing:border-box;inline-size:100%;min-inline-size:0;min-block-size:56px;margin:0;padding:var(--space-2);border:1px solid transparent;border-radius:999px;display:flex;align-items:center;justify-content:center;gap:var(--space-1);font-family:var(--body);font-size:16px;font-weight:800;line-height:1.4;white-space:normal;}
.v2-log-actions > .v2-secondary {border-color:var(--line);}
.v2-log-actions > button svg {flex:none;}
.v2-secondary {border:1px solid var(--line);border-radius:var(--radius);background:var(--panel);color:var(--ink);padding:var(--space-3);font:inherit;}
.v2-daily-allocation {margin-block:var(--space-3);text-align:start;}
.v2-daily-allocation .v2-panel-row {display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:var(--space-2);}
.v2-daily-allocation .v2-number {font-size:24px;}
.v2-daily-allocation details {font-size:16px;line-height:1.5;}
.v2-daily-allocation summary {min-block-size:44px;cursor:pointer;padding-block:var(--space-2);}
.v2-calorie-equivalent {display:flex;gap:var(--space-2);justify-content:space-between;align-items:center;}
.v2-calorie-equivalent .v2-number {white-space:nowrap;font-size:20px;}
.v2-composer {display:grid;gap:var(--space-2);}
.v2-composer-actions {display:flex;align-items:center;gap:var(--space-2);}
.v2-composer-actions [type=submit] {margin-inline-start:auto;}
.v2-composer-actions .v2-primary {inline-size:auto;min-block-size:var(--tap-min);margin-block:0;padding-inline:var(--space-4);border-radius:999px;}
.v2-field {display:grid;gap:var(--space-1);font-size:16px;margin-block:var(--space-2);}
.v2-input,.v2-textarea {box-sizing:border-box;inline-size:100%;min-inline-size:0;min-block-size:44px;font:inherit;font-size:16px;padding:var(--space-2);color:var(--ink);background:var(--input);border:1px solid var(--line);border-radius:var(--control-radius);}
.v2-conversation-message {white-space:pre-line;overflow-wrap:anywhere;font-size:16px;line-height:1.6;background:var(--panel);padding:var(--space-3);border-radius:var(--radius-small);}
.v2-restaurant-frame {inline-size:100%;block-size:70dvh;border:0;min-block-size:360px;}
.v2-movement-part {flex-wrap:wrap;gap:var(--space-1);}
.v2-movement-part button {min-block-size:44px;min-inline-size:44px;}
.v2-diary-meal-actions {display:flex;gap:var(--space-2);grid-column:1 / -1;}
.v2-activity .v2-panel-note {overflow-wrap:anywhere;}
.v2-daily-allocation .v2-panel-row {color:var(--on-inverse);}
.v2-daily-allocation .v2-panel-row small {opacity:.8;}

.v2-screen-restaurants {display:flex;flex-direction:column;block-size:100%;min-block-size:0;}
.v2-screen-restaurants > h1 {margin-block:var(--space-2);}
.v2-restaurant-frame.is-destination {flex:1;min-block-size:0;block-size:100%;}
@media(max-width:359px){.v2-nav {padding-inline:2px;gap:0;}}

.v2-diary-part {margin-block:var(--space-3);}
.v2-diary-part > h2 {font-size:var(--text-body);margin-block:var(--space-2);}

.v2-nav:has([data-route=restaurants]) {grid-template-columns:repeat(3,minmax(0,1fr)) minmax(78px,1.3fr) minmax(0,1fr);}

.v2-meal-library-actions {display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-2);}
.v2-meal-library-actions > button {min-inline-size:0;padding:var(--space-2);line-height:1.4;}
.v2-save-meal {display:grid;gap:var(--space-2);}

/* Room for quantities and references; actions stay below the focus ring. */
.v2-composer form {display:grid;gap:var(--space-3);}
.v2-composer .v2-textarea {display:block;margin:0;text-align:start;block-size:calc(6lh + 2 * var(--space-2) + 2px);min-block-size:calc(4 * var(--tap-min));}

/* Conversation uses the existing visual-viewport sheet sizing for keyboards. */
.v2-sheet.is-conversation .v2-sheet-body {block-size:100%;max-block-size:100%;border-radius:0;overflow:hidden;padding-bottom:calc(var(--space-3) + env(safe-area-inset-bottom));}
.v2-sheet.is-conversation .v2-sheet-top {flex:none;}
.v2-conversation {display:flex;flex-direction:column;flex:1;min-block-size:0;gap:var(--space-2);}
.v2-conversation-log {flex:0 1 auto;min-block-size:0;overflow-y:auto;overscroll-behavior:contain;}
.v2-conversation-message {margin-block:var(--space-2);}
.v2-conversation-message.user {background:var(--route-soft);margin-inline-start:var(--space-4);}
.v2-conversation-intro {font-size:var(--text-body);line-height:1.6;}
.v2-conversation .v2-conversation-review {display:grid;gap:var(--space-2);}
.v2-composer.is-conversation-composer {flex:none;padding-block-start:var(--space-2);border-block-start:1px solid var(--line);background:var(--panel);}
.v2-composer.is-conversation-composer .v2-textarea {block-size:calc(4lh + 2 * var(--space-2) + 2px);min-block-size:calc(2 * var(--tap-min));max-block-size:30dvh;}
.v2-conversation > .v2-conversation-save,
.v2-conversation > .v2-save-meal {flex:none;}
.v2-conversation .v2-camera {min-block-size:0;}

.v2-conversation-top {display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);flex:none;padding-block:var(--space-3);}
.v2-conversation-top .v2-sheet-title {font-size:1.375rem;font-weight:800;}
.v2-conversation-top .v2-icon-button {flex:none;}
.v2-conversation-meal {display:block;font-size:14px;color:var(--muted);margin-block-start:var(--space-1);}

.v2-calorie-equivalent-label {display:flex;align-items:center;gap:var(--space-1);}
.v2-calorie-equivalent-label .v2-icon-button {color:inherit;flex:none;}
.v2-info-popover {position:fixed;inset:0;margin:auto;inline-size:min(380px,calc(100% - 2 * var(--space-4)));box-sizing:border-box;padding:var(--space-3);border:1px solid var(--line);border-radius:var(--radius-small);background:var(--panel);color:var(--ink);font-family:var(--body);font-size:16px;line-height:1.6;box-shadow:var(--shadow-soft);max-block-size:calc(100dvh - 2 * var(--space-4));overflow:auto;}
.v2-info-popover header {display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);}
.v2-daily-allocation .v2-info-popover .v2-number {font-size:inherit;}
.v2-sheet-controls {display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);}
.v2-sheet-controls > .v2-icon-button {flex:none;}
.v2-sheet-controls > .v2-sheet-grab {margin:0;flex:1;}
.v2-save-meal-option {position:relative;display:flex;flex-direction:row;justify-content:flex-start;align-items:center;gap:var(--space-2);min-block-size:44px;padding:var(--space-2);border:1px solid var(--line);border-radius:var(--radius-small);background:var(--panel);color:var(--ink);font:400 16px/1.4 var(--body);text-align:start;cursor:pointer;}
.v2-save-meal-option input {position:absolute;inset:0;opacity:0;inline-size:100%;block-size:100%;min-inline-size:0;min-block-size:0;margin:0;padding:0;cursor:pointer;}
.v2-save-meal-check {display:grid;place-items:center;flex:none;inline-size:22px;block-size:22px;box-sizing:border-box;border:1.5px solid var(--ink-soft);border-radius:6px;background:var(--panel);}
.v2-save-meal-option input:checked + .v2-save-meal-check {border-color:var(--route);background:var(--route);color:var(--on-inverse);}
.v2-save-meal-option input:checked + .v2-save-meal-check::after {content:'';inline-size:6px;block-size:11px;border:solid currentColor;border-width:0 2px 2px 0;transform:translateY(-1px) rotate(45deg);}
.v2-save-meal-option:has(input:focus-visible) {outline:2px solid var(--route);outline-offset:2px;}
.v2-save-meal-option:has(input:disabled) {opacity:.6;cursor:default;}
.v2-save-meal-label {min-inline-size:0;overflow-wrap:break-word;}

/* Compact workout fields; empty shortcut/status rows must not create gaps. */
.v2-activity {align-content:start;gap:var(--space-3);}
.v2-activity > .v2-field, .v2-activity > .v2-chips, .v2-activity > .v2-panel-row, .v2-activity > .v2-panel-note {margin-block:0;}
.v2-activity > .v2-chips:empty, .v2-activity > .v2-panel-note:empty {display:none;}

/* Budget explanations use body typography, including inline dates and values. */
.v2-budget-detail-list {margin:0;padding-inline-start:1.4em;display:grid;gap:var(--space-2);list-style:disc outside;text-align:start;font-family:var(--body);font-size:16px;font-weight:400;line-height:1.5;}
.v2-daily-allocation .v2-budget-detail-list .v2-number {font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;letter-spacing:normal;font-variant-numeric:tabular-nums;}

.v2-activity .v2-input {block-size:44px;line-height:1.4;}
.v2-activity-select {position:relative;display:grid;}
.v2-activity-select select {appearance:none;-webkit-appearance:none;padding-inline-end:54px;}
.v2-activity-select > svg {position:absolute;inset-inline-end:var(--space-4);inset-block-start:50%;transform:translateY(-50%) rotate(90deg);pointer-events:none;}

/* Diary calories describe food amounts; action rows stay aligned inside the card. */
.v2-screen-diary .v2-movement-delta, .v2-diary-food-calories {color:var(--ink);}
.v2-diary-meal-actions {display:flex;align-items:stretch;gap:var(--space-2);grid-column:1 / -1;min-inline-size:0;}
.v2-movement.is-meal > .v2-diary-meal-actions {padding:0 var(--space-3) var(--space-3);}
.v2-diary-action {display:flex;align-items:center;justify-content:center;gap:var(--space-1);flex:1;min-inline-size:0;min-block-size:44px;padding:var(--space-1) var(--space-2);border:1px solid var(--line);border-radius:var(--control-radius);background:var(--panel);color:var(--route-ink);font:650 14px/1.4 var(--body);cursor:pointer;text-align:center;}
.v2-diary-action svg {flex:none;}
.v2-diary-action:focus-visible {outline:2px solid var(--route);outline-offset:2px;}
.v2-diary-action:disabled {opacity:.5;cursor:default;}
.v2-diary-meal-actions > .v2-icon-button {flex:none;}
.v2-diary-move-form {display:grid;gap:var(--space-2);inline-size:100%;}
.v2-diary-move-form label {display:grid;gap:var(--space-1);font-size:16px;}
.v2-diary-move-buttons {display:flex;gap:var(--space-2);}
.v2-diary-move-form .v2-error:empty {display:none;}
.v2-movement-open {min-inline-size:0;}

.v2-diary-danger-zone {margin-block:0 var(--space-2);font:400 14px/1.5 var(--body);color:var(--ink-soft);}

/* Coordinated sport artwork; no text is baked into the assets. */
.v2-sport-art {display:block;inline-size:100%;block-size:100%;object-fit:cover;border-radius:inherit;}
.v2-movement.is-activity {grid-template-columns:56px minmax(0,1fr) auto auto;}
.v2-movement.is-activity .v2-movement-mark {inline-size:56px;block-size:56px;overflow:hidden;border-radius:var(--radius-small);background:var(--inverse);}
.v2-activity-artwork {display:flex;align-items:center;gap:var(--space-3);font:650 16px/1.4 var(--body);color:var(--ink);}
.v2-activity-artwork[hidden] {display:none;}
.v2-activity-artwork .v2-sport-art {inline-size:80px;block-size:80px;flex:none;border-radius:var(--radius-small);}

/* Meal and workout artwork share one tile size and alignment. */
.v2-screen-diary .v2-movement.is-food {grid-template-columns:56px minmax(0,1fr) auto auto;}
.v2-screen-diary .v2-movement-open {grid-template-columns:56px minmax(0,1fr) auto auto;}
.v2-screen-diary .v2-movement-mark {inline-size:56px;block-size:56px;overflow:hidden;border-radius:var(--radius-small);background:var(--inverse);}
.v2-screen-diary .v2-movement-mark::before {display:none;}
.v2-meal-art {display:block;inline-size:100%;block-size:100%;object-fit:cover;border-radius:inherit;}

/* Choose a food before showing editing or moving actions. */
.v2-food-select-body {display:block;border:0;padding:0;background:none;color:inherit;font:inherit;text-align:start;cursor:pointer;min-block-size:44px;}
.v2-food-select-body .v2-movement-name,.v2-food-select-body .v2-movement-meta {display:block;}
.v2-food-select-body:focus-visible,.v2-food-select:focus-visible {outline:2px solid var(--route);outline-offset:2px;border-radius:var(--radius-small);}
.v2-food-actions {grid-column:1 / -1;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-2);align-items:stretch;min-inline-size:0;}
.v2-food-actions[hidden] {display:none;}
.v2-screen-diary .v2-movement-parts {padding:var(--space-2) var(--space-3);gap:var(--space-2);}
.v2-screen-diary .v2-movement-part {display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--space-1);}
.v2-food-select {display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);min-inline-size:0;min-block-size:44px;padding:var(--space-1) var(--space-2);border:1px solid var(--line);border-radius:var(--radius-small);background:var(--panel);color:var(--ink);font:inherit;text-align:start;cursor:pointer;}
.v2-food-select > span:first-child {overflow-wrap:anywhere;min-inline-size:0;}
.v2-food-select .v2-diary-food-calories {flex:none;}

/* Explicit selection precedes food actions; no pencil/delete clutter at rest. */
.v2-screen-diary .v2-movement.is-meal {grid-template-columns:minmax(0,1fr);}
.v2-screen-diary .v2-movement-part {grid-template-columns:minmax(0,1fr);}
.v2-item-selector {display:grid;place-items:center;inline-size:44px;block-size:44px;padding:0;border:0;background:none;color:var(--route-ink);cursor:pointer;}
.v2-selection-check {display:inline-flex;align-items:center;justify-content:center;inline-size:22px;block-size:22px;box-sizing:border-box;border:1.5px solid var(--ink-soft);border-radius:6px;background:var(--panel);flex:none;}
[aria-checked=true] > .v2-selection-check {border-color:var(--route);background:var(--route);color:var(--on-inverse);}
[aria-checked=true] > .v2-selection-check::after {content:'';inline-size:6px;block-size:11px;border:solid currentColor;border-width:0 2px 2px 0;transform:translateY(-1px) rotate(45deg);}
.v2-food-select .v2-selection-name {flex:1;min-inline-size:0;overflow-wrap:anywhere;}
.v2-food-select[aria-checked=true] {border-color:var(--route);background:var(--route-soft);}
.v2-screen-diary .v2-movement.is-selected {background:var(--panel-muted);}
.v2-food-actions > .v2-diary-move-form {grid-column:1 / -1;}
.v2-item-selector:focus-visible {outline:2px solid var(--route);outline-offset:2px;border-radius:var(--radius-small);}

.v2-selection-toolbar {list-style:none;min-inline-size:0;padding-block:var(--space-2);}
.v2-selection-toolbar[hidden] {display:none;}
.v2-selection-count {margin:0 0 var(--space-2);font:650 14px/1.4 var(--body);color:var(--ink);}

.v2-item-actions > :only-child {grid-column:1 / -1;}

/* Recording belongs to the initial capture form until speech is transcribed. */
.v2-voice.is-inline {gap:var(--space-2);padding:var(--space-2) 0;}
.v2-voice.is-inline .v2-voice-wave {block-size:24px;}
.v2-composer-actions [data-recording=true] {color:var(--effort);background:var(--route-soft);}

/* Diary rows share centered content and action columns; workouts have a recovery frame. */
.v2-screen-diary .v2-movements {
  display:grid;
  gap:var(--space-2);
  border:0;
  border-radius:0;
  background:transparent;
  overflow:visible;
}
.v2-screen-diary .v2-movement {
  border:1px solid var(--line);
  border-radius:20px;
  background:var(--panel);
  overflow:hidden;
}
.v2-screen-diary .v2-movement.is-activity,
.v2-screen-diary .v2-movement.is-food,
.v2-screen-diary .v2-movement-open {
  grid-template-columns:56px minmax(0,1fr) minmax(3.5ch,max-content) 44px;
  align-items:center;
}
.v2-screen-diary .v2-movement-chevron,
.v2-screen-diary .v2-movement-remove {
  justify-self:center;
}
.v2-screen-diary .v2-movement.is-activity {
  border:2px solid var(--recovery);
  padding:calc(var(--space-2) - 1px) calc(var(--space-3) - 1px);
}
.v2-screen-diary .v2-movement.is-activity:has(.v2-movement-confirm) .v2-movement-remove {
  grid-column:2 / -1;
  justify-self:end;
}

/* Compact restaurant logging uses short rows, then an explicit consumed portion. */
.v2-restaurant-picker,.v2-restaurant-portion {display:grid;gap:var(--space-3);min-inline-size:0;}
.v2-restaurant-picker h3,.v2-restaurant-portion h3 {margin:0;font:650 18px/1.4 var(--body);}
.v2-restaurant-results {display:grid;gap:var(--space-1);}
.v2-restaurant-row {display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);inline-size:100%;min-block-size:56px;padding:var(--space-2) var(--space-3);border:1px solid var(--line);border-radius:var(--control-radius);background:var(--panel);color:var(--ink);font:400 16px/1.4 var(--body);text-align:start;cursor:pointer;}
.v2-restaurant-row-name {min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:650;}
.v2-restaurant-card-copy{display:grid;gap:var(--space-1);min-inline-size:0;flex:1}
.v2-restaurant-card-copy .v2-restaurant-row-name{white-space:normal;overflow-wrap:anywhere}
.v2-restaurant-card-location{font-size:16px;color:var(--ink-soft);overflow-wrap:anywhere}
.v2-restaurant-cuisines{display:flex;flex-wrap:wrap;gap:var(--space-1);margin-block-start:4px}
.v2-restaurant-cuisine{font-size:14px;padding:2px var(--space-2);border-radius:999px;background:var(--paper);color:var(--ink)}
.v2-restaurant-row small {font-size:14px;color:var(--ink-soft);max-inline-size:45%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;}
.v2-restaurant-recents {display:grid;gap:var(--space-2);}
.v2-restaurant-recents .v2-diary-action {justify-content:flex-start;overflow-wrap:anywhere;}
.v2-portion-presets {display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-2);}
.v2-portion-presets button {min-block-size:44px;}
.v2-portion-presets [aria-pressed=true] {background:var(--route-soft);color:var(--route-ink);border-color:var(--route);}
.v2-restaurant-total {margin:0;font:650 18px/1.4 var(--body);}
.v2-restaurant-row:focus-visible {outline:2px solid var(--route);outline-offset:2px;}

/* FS-059 shared wall: existing shell surfaces, no independent palette. */
.v2-author-link { border:0; background:none; padding:0; min-height:44px; color:inherit; font:inherit; text-align:start; cursor:pointer; }
.v2-author-link:disabled { opacity:1; cursor:default; }
.v2-friend-wall { display:grid; gap:var(--space-3); min-width:0; }
.v2-shared-entry { display:flex; align-items:center; justify-content:space-between; gap:var(--space-3); padding:var(--space-3); margin-block:var(--space-2); background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-small); }
.v2-shared-entry span { overflow-wrap:anywhere; }
.v2-shared-entry.is-workout { border:2px solid var(--recovery); }

.v2-wall-day .v2-daynav { grid-template-columns:auto minmax(0,1fr) auto; gap:var(--space-1); }
.v2-wall-day .v2-input { min-width:0; width:100%; box-sizing:border-box; }
.v2-wall-day .v2-strip-stat span { font-size:14px; }
.v2-setting input[type=checkbox] { width:22px; height:22px; flex-shrink:0; accent-color:var(--route); }
.v2-setting:has(input[type=checkbox]) { min-height:44px; }
.v2-feed-head { flex-wrap:wrap; gap:var(--space-2); }

.v2-wall-day .v2-strip {grid-template-columns:repeat(2,minmax(0,1fr));}
.v2-wall-details {color:var(--muted);font-size:14px;}
.v2-wall-details summary {min-height:44px;display:flex;align-items:center;cursor:pointer;gap:8px;}
.v2-wall-details summary::after {content:'+';}
.v2-wall-details[open] summary::after {content:'−';}
.v2-wall-details p {margin:0 0 10px;}

.v2-wall-diary {min-width:0;}
.v2-wall-dates {display:grid;grid-template-columns:1fr 1fr 1fr;align-items:center;gap:8px;text-align:center;}
.v2-wall-dates strong {font-size:18px;}
.v2-wall-neighbor {background:none;border:0;color:var(--muted);font:inherit;font-size:13px;min-height:44px;cursor:pointer;}
.v2-wall-neighbor:disabled {opacity:.35;cursor:default;}
.v2-wall-carousel {position:relative;display:flex;gap:var(--space-3);overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding:calc(2 * var(--space-3));padding:var(--space-2) calc(2 * var(--space-3)) var(--space-3);overscroll-behavior-x:contain;scrollbar-width:none;touch-action:pan-x pan-y;cursor:grab;}
.v2-wall-carousel::-webkit-scrollbar {display:none;}
.v2-wall-carousel.is-dragging {scroll-snap-type:none;cursor:grabbing;user-select:none;}
.v2-wall-page {flex:0 0 100%;min-width:0;scroll-snap-align:center;}
.v2-wall-day {padding:var(--space-4);background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-soft);min-height:260px;}
.v2-wall-date-label {text-align:center;color:var(--muted);font-size:13px;margin:0 0 14px;}

.v2-wall-day .v2-strip-stat {border:0;background:transparent;padding:10px 2px;}
.v2-wall-day .v2-strip {border-bottom:1px solid var(--line);padding-bottom:8px;}
.v2-wall-day .v2-shared-entry {border:0;padding:10px 0;margin:0;background:none;}
.v2-wall-day .v2-shared-entry.is-workout {border-inline-start:3px solid var(--recovery);padding-inline-start:10px;}
.v2-wall-page {align-self:stretch;}
.v2-wall-page>.v2-wall-day {height:100%;box-sizing:border-box;}

/* Post actions belong to the author header, with the shared quiet controls. */
.v2-post-head { position: relative; }
.v2-post-menu { margin-inline-start: auto; }
.v2-post-menu-trigger { display: grid; place-items: center; min-inline-size: 44px; min-block-size: 44px; border: 0; padding: 0; color: var(--ink); background: transparent; border-radius: var(--radius); cursor: pointer; }
.v2-post-menu-trigger:focus-visible, .v2-post-menu-item:focus-visible { outline: 2px solid var(--route); outline-offset: -2px; }
.v2-post-menu-panel { position: absolute; inset-inline-end: var(--space-2); inset-block-start: calc(100% - var(--space-1)); z-index: 2; max-inline-size: calc(100% - 2 * var(--space-2)); background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-soft); padding: var(--space-1); }
.v2-post-menu-item { min-block-size: 44px; border: 0; background: transparent; color: var(--ink); text-align: start; padding: var(--space-2); font: inherit; cursor: pointer; }

/* FS-075: a quiet summary below the existing logging actions. */
.v2-daily-recap { margin-block-start:var(--space-4); }
.v2-daily-recap ul { margin-block:var(--space-3); padding-inline-start:var(--space-4); }
.v2-daily-recap li { margin-block:var(--space-2); font-size:var(--text-body); line-height:1.5; }
.v2-daily-recap details { margin-block:var(--space-2); }
.v2-daily-recap summary { min-height:var(--tap-min); display:flex; align-items:center; font-size:var(--text-small); cursor:pointer; }
.v2-daily-recap details p { font-size:var(--text-body); line-height:1.5; }
.v2-daily-recap > button { min-height:var(--tap-min); }
.v2-recap-preference { display:flex; align-items:center; gap:var(--space-2); min-height:var(--tap-min); font-size:var(--text-body); }
.v2-food-planning { margin-block-start:var(--space-4); overflow-wrap:anywhere; }
.v2-food-planning p { line-height:1.5; }
.v2-food-planning summary,.v2-food-planning button { min-height:var(--tap-min); }
.v2-food-planning summary { display:flex; align-items:center; cursor:pointer; }
.v2-food-planning textarea { width:100%; min-height:var(--tap-min); box-sizing:border-box; resize:vertical; font:inherit; border:1px solid var(--line); border-radius:var(--radius); padding:var(--space-3); background:var(--panel); color:var(--ink); }
.v2-planning-turn { border-block-start:1px solid var(--line); padding-block:var(--space-2); }
.v2-planning-user { font-weight:600; }
.v2-planning-actions { display:flex; flex-wrap:wrap; gap:var(--space-2); }
.v2-food-image { width:100%; max-width:240px; max-height:160px; object-fit:cover; border-radius:var(--radius); }
.v2-food-feedback { display:flex; flex-wrap:wrap; gap:var(--space-2); }
.v2-food-feedback button,.v2-food-feedback select { min-height:var(--tap-min); font:inherit; max-width:100%; }
.v2-recap-preference input[type=checkbox] { width:22px; height:22px; min-width:22px; min-height:22px; flex:0 0 22px; accent-color:var(--route); }

.v2-planning-context,.v2-planning-review { border-block-start:1px solid var(--line); padding-block:var(--space-3); }
.v2-food-planning h3 { font:inherit; font-weight:600; margin-block:var(--space-2); }

/* Recap/planning reuse the Settings switch, with room for explanatory text. */
.v2-preference-setting .v2-setting { cursor: pointer; gap: var(--space-3); padding-block: var(--space-3) var(--space-1); }
.v2-preference-setting .v2-setting-label { min-inline-size: 0; line-height: 1.4; }
:is(.v2-preference-setting, .v2-sharing-settings) .v2-switch { block-size: var(--tap-min); }
:is(.v2-preference-setting, .v2-sharing-settings) .v2-switch-track { inset-block: 6px; }
.v2-preference-setting > p { margin: 0; padding: 0 var(--space-3) var(--space-3); font-size: var(--text-body); line-height: 1.5; }
.v2-preference-setting > p:empty { display: none; }
:is(.v2-preference-setting, .v2-sharing-settings) .v2-switch-input:disabled + .v2-switch-track { opacity: .5; }

:is(.v2-preference-setting, .v2-sharing-settings) .v2-setting input.v2-switch-input { width: 100%; height: 100%; min-width: 0; min-height: 0; padding: 0; }
/* Settings target editor uses the existing field-sheet controls. */
.v2-target-editor { padding: var(--space-3); border-block: 1px solid var(--line); }
.v2-target-editor[hidden] { display: none; }
[data-testid="settings-weight"] .v2-quiet-button { flex-shrink: 0; }
.v2-target-editor .v2-error:empty,
[data-testid="weigh-in-view"] .v2-error:empty { display: none; }
.v2-target-editor + .v2-setting { border-block-start: 1px solid var(--line); }

.v2-post-menu-item.is-danger { color: var(--effort); }
.v2-post-menu-panel p { margin: var(--space-2); font-size: var(--text-body); }

/* Post type determines the fields; photo tools edit only the selected copy. */
.v2-post-composer,.v2-post-fields,.v2-post-photo-editor,.v2-post-photo-review {display:grid;gap:var(--space-3);min-inline-size:0;}
.v2-post-composer [hidden] {display:none !important;}
.v2-post-fields:empty,.v2-post-composer p:empty {display:none;}
.v2-post-photo-actions {display:flex;flex-wrap:wrap;gap:var(--space-2);}
.v2-post-photo-editor canvas {display:block;max-inline-size:100%;max-block-size:200px;inline-size:auto;block-size:auto;margin-inline:auto;border-radius:var(--radius-small);}
.v2-post-photo-tools {display:grid;gap:var(--space-2);}
.v2-post-photo-tools > .v2-post-fields {max-block-size:min(320px,40dvh);overflow-y:auto;overscroll-behavior:contain;padding:var(--space-1);}
.v2-post-photo-tools input[type=range] {min-block-size:var(--tap-min);inline-size:100%;accent-color:var(--route);}
.v2-post-composer .v2-field {min-inline-size:0;margin-block:0;}

/* Portion presets must not remain visible in the weighed-gram entry mode. */
.v2-portion-presets[hidden] {display:none;}
.v2-restaurant-entry-mode {grid-template-columns:repeat(2,minmax(0,1fr));}

.v2-restaurant-estimate-note {margin:0;font:400 16px/1.45 var(--body);color:var(--ink-soft);}

/* Recipe basis controls must honor hidden even when shared fields use grid. */
.v2-restaurant-portion [hidden] {display:none !important;}
.v2-review-weight-link {color:var(--route);font-size:16px;text-decoration:underline;}

/* Public discovery stays a quiet link on entry, before account access. */
.v2-assistant-guide {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: var(--tap-min);
  padding-inline: var(--space-2);
  color: inherit;
  font-size: var(--text-small);
  text-align: center;
  text-underline-offset: .2em;
}
.v2-assistant-guide:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 3px; }

/* Feed actions share the shell's outline family, with one compose emphasis. */
.v2-feed-head {display:grid;grid-template-columns:minmax(0,1fr);justify-content:stretch;gap:var(--space-3);}
.v2-feed-heading,.v2-feed-tools,.v2-feed-actions {display:flex;align-items:center;gap:var(--space-2);justify-content:space-between;min-inline-size:0;}
.v2-feed-heading .v2-sheet-pill {font-size:14px;}
.v2-feed-actions {gap:var(--space-1);}
.v2-feed-action,.v2-feed-my-wall {display:inline-flex;align-items:center;justify-content:center;gap:var(--space-1);min-block-size:var(--tap-min);border:0;border-radius:var(--radius-small);font:600 16px var(--body);color:var(--ink);background:transparent;padding:var(--space-1) var(--space-2);cursor:pointer;white-space:nowrap;}
.v2-feed-my-wall {padding-inline-start:0;}
.v2-feed-my-wall .v2-avatar {inline-size:32px;block-size:32px;}
.v2-feed-action {background:var(--panel);border:1px solid var(--line);}
.v2-feed-action.is-primary {color:var(--panel);background:var(--route);border-color:var(--route);}
.v2-feed-action:focus-visible,.v2-feed-my-wall:focus-visible {outline:2px solid var(--route);outline-offset:2px;}
.v2-post-composer .v2-textarea {text-align:start;}
.v2-post-title h3 {min-inline-size:0;overflow-wrap:anywhere;white-space:pre-wrap;text-align:start;}
.v2-post-who,.v2-post-body,.v2-profile-name {text-align:start;}
.v2-post-comment .v2-avatar {inline-size:32px;block-size:32px;}
.v2-wall-content {display:grid;gap:var(--space-3);min-inline-size:0;}
.v2-wall-loading {display:flex;align-items:center;gap:var(--space-2);min-block-size:var(--tap-min);color:var(--ink-soft);}

.v2-post-composer select.v2-input {block-size:var(--tap-min);}

/* Instinct setup uses the existing Connections panel and link controls. */
.v2-instinct-connection { padding:var(--space-3); border-block-start:1px solid var(--line); }
.v2-instinct-connection p { margin-block:var(--space-2); font-size:var(--text-body); line-height:1.5; }
.v2-instinct-actions { display:flex; flex-wrap:wrap; gap:var(--space-2); }

/* Sharing uses the same Settings switches, in compact, padded rows. */
.v2-sharing-heading { display: grid; gap: var(--space-1); padding: var(--space-3); }
.v2-sharing-heading > h2, .v2-sharing-heading > p { margin: 0; }
.v2-sharing-heading > p { font-size: var(--text-body); line-height: 1.5; }
.v2-sharing-toggles .v2-setting { margin: 0; padding-block: var(--space-1); gap: var(--space-3); cursor: pointer; }
.v2-sharing-toggles .v2-setting-label { min-inline-size: 0; line-height: 1.4; }
.v2-sharing-fields { display: grid; gap: var(--space-3); border-block-start: 1px solid var(--line); padding: var(--space-3); }
.v2-sharing-fields .v2-field { margin: 0; min-inline-size: 0; }
.v2-sharing-fields .v2-input { min-inline-size: 0; inline-size: 100%; }
.v2-sharing-settings > .v2-error { margin: 0; padding: 0 var(--space-3) var(--space-3); }
.v2-sharing-settings > .v2-error:empty { display: none; }

/* Weekly planning follows the existing Itay panel, date and quiet-action tokens. */
.v2-planning-calendar-heading,.v2-planning-fact { display:flex; align-items:center; justify-content:space-between; gap:var(--space-2); }
.v2-planning-week-nav { display:grid; grid-template-columns:var(--tap-min) minmax(0,1fr) var(--tap-min); align-items:center; gap:var(--space-1); text-align:center; font-size:var(--text-small); margin-block-end:var(--space-2); }
.v2-planning-week-nav button { padding:0; min-width:var(--tap-min); }
.v2-planning-days,.v2-planning-events { list-style:none; padding:0; margin:0; }
.v2-planning-days { position:relative; display:flex; align-items:flex-start; gap:var(--space-1); overflow-x:auto; scroll-snap-type:x mandatory; overscroll-behavior-x:contain; touch-action:pan-x pan-y; scrollbar-width:none; cursor:grab; padding-block:var(--space-2); }
.v2-planning-days::-webkit-scrollbar { display:none; }
.v2-planning-days.is-dragging { scroll-snap-type:none; cursor:grabbing; user-select:none; }
.v2-planning-days:focus-visible { outline:2px solid var(--route); outline-offset:2px; border-radius:var(--radius-small); }
.v2-planning-day { flex:0 0 calc((100% - 2 * var(--space-1)) / 3); min-width:0; min-height:112px; scroll-snap-align:center; border:1px solid var(--line); border-radius:var(--radius-small); padding:var(--space-2); box-sizing:border-box; background:var(--panel); }
.v2-planning-date { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--space-1); padding-block-end:var(--space-2); margin-block-end:var(--space-2); border-block-end:1px solid var(--line); font-size:var(--text-small); color:var(--ink-soft); }
.v2-planning-date time { font:600 16px/1.4 var(--body); color:var(--ink); }
.v2-planning-day.is-today { border-color:var(--route); background:var(--route-soft); }
.v2-planning-day.is-today .v2-planning-date time { color:var(--route); }
.v2-planning-event { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:var(--space-1); padding:var(--space-1) 0; }
.v2-planning-event>div,.v2-planning-fact>span { min-width:0; }
.v2-planning-event strong { font-size:16px; font-weight:600; }
.v2-planning-event p,.v2-planning-empty { margin:0; }
.v2-food-planning .v2-planning-remove { flex:none; min-width:var(--tap-min); padding-inline:var(--space-1); font-size:var(--text-small); color:var(--ink-soft); border-color:transparent; }
.v2-food-planning .v2-planning-location-link { padding:0; border:0; color:var(--route); font-size:var(--text-small); }
.v2-planning-preferences { border-block-start:1px solid var(--line); margin-block-start:var(--space-2); padding-block:var(--space-2); }
.v2-planning-facts { list-style:none; padding:0; margin:0; }
.v2-planning-fact { display:grid; grid-template-columns:auto minmax(0,1fr) auto; }
.v2-planning-bullet { color:var(--route); }
.v2-planning-removal { padding:var(--space-3); border:1px solid var(--line); border-radius:var(--radius-small); background:var(--input); }
.v2-planning-location-field { display:grid; gap:var(--space-1); margin-block:var(--space-3); font-size:16px; }
.v2-planning-location-field input { box-sizing:border-box; width:100%; min-height:var(--tap-min); border:1px solid var(--line); border-radius:var(--control-radius); background:var(--input); color:var(--ink); padding:var(--space-2); font:inherit; }

@media (max-width:359px) { .v2-planning-day { flex-basis:calc((100% - var(--space-1)) / 2); } }
@media (min-width:600px) { .v2-planning-day { flex-basis:calc((100% - 3 * var(--space-1)) / 4); } }

/* Home weigh-in reminder: the evening before and the weigh-in morning. */
.v2-weigh-reminder { border-color: var(--route); }
.v2-weigh-reminder .v2-section-note { margin: var(--space-1) 0 var(--space-2); }
.v2-weigh-reminder-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* Overnight budget change: explains a balance that moved since the last visit. */
[data-testid="budget-update"] { margin-block: var(--space-2) 0; }
/* Weigh-in reminder settings. */
.v2-weigh-device { display: grid; gap: var(--space-2); margin-top: var(--space-4); }
.v2-weigh-device .v2-section-note { margin: 0; }
