/* =====================================================================
   Ripe components
   Uses ONLY variables from tokens.css. States:
     :active   / .is-pressed   → pressed
     :disabled / .is-disabled  → disabled
     :focus-visible / .is-focus → keyboard focus
     [aria-invalid="true"] / .is-error → error
   The .is-* classes exist so the docs can show every state side by side.

   Hard rules
   1. Text is never clipped: no overflow: hidden around text, min-height instead of height.
   2. State visuals (pressed, focus, selected) stay inside their parent.
   3. Borders and rings are equal on all sides: inset box-shadow, never border changes.
   ===================================================================== */

/* ---------- base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  font-size: 100%;
  text-size-adjust: 100%;
  border-radius: 0;
}

body {
  margin: 0;
  border-radius: 0;
  background: var(--color-bg-canvas);
  color: var(--color-text-primary);
  font: var(--type-body);
  -webkit-font-smoothing: antialiased;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

/* The hidden attribute always wins over component display values (toggled panels, footers, toasts) */
[hidden] {
  display: none !important;
}

button {
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
}

/* Default focus ring: 2 px ring + 2 px gap outside the control (WCAG 2.4.7, 1.4.11).
   Components in tight containers (segments, tabs, list rows, steppers) override it with a contained ring. */
:focus-visible,
.is-focus {
  outline: var(--border-width-focus) solid var(--color-border-focus);
  outline-offset: var(--border-width-focus-gap);
}

/* Android: 48 dp touch targets and Material 3 bar heights. Put data-platform="android" on the app root. */
[data-platform="android"] {
  --size-touch-min: var(--size-touch-android);
  --size-button-m: var(--size-touch-android);
  --size-app-bar: var(--size-app-bar-android);
  --size-tab-bar: var(--size-tab-bar-android);
  --size-segment: var(--size-segment-android);
}

/* ---------- typography helpers ---------- */
.t-display {
  font: var(--type-display);
  letter-spacing: var(--type-display-tracking);
}

.t-h1 {
  font: var(--type-h1);
  letter-spacing: var(--type-h1-tracking);
}

.t-h2 {
  font: var(--type-h2);
}

.t-title {
  font: var(--type-title);
}

.t-body {
  font: var(--type-body);
}

.t-body-strong {
  font: var(--type-body-strong);
}

.t-callout {
  font: var(--type-callout);
}

.t-label {
  font: var(--type-label);
}

.t-caption {
  font: var(--type-caption);
  letter-spacing: var(--type-caption-tracking);
}

.t-overline {
  font: var(--type-overline);
  letter-spacing: var(--type-overline-tracking);
  text-transform: uppercase;
}

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

.t-num-xl {
  font: var(--type-num-xl);
  letter-spacing: var(--type-num-xl-tracking);
  font-variant-numeric: tabular-nums;
}

.t-num-l {
  font: var(--type-num-l);
  letter-spacing: var(--type-num-l-tracking);
  font-variant-numeric: tabular-nums;
}

.t-num-m {
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
}

.t-num-s {
  font: var(--type-num-s);
  font-variant-numeric: tabular-nums;
}

.text-secondary {
  color: var(--color-text-secondary);
}

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

.visually-hidden {
  position: absolute;
  width: var(--border-width-hairline);
  height: var(--border-width-hairline);
  margin: calc(var(--border-width-hairline) * -1);
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- icons (24 px grid, 2 px round stroke) ---------- */
.icon {
  width: var(--size-icon-l);
  height: var(--size-icon-l);
  flex: none;
  fill: none;
  stroke: currentcolor;
  stroke-width: var(--size-icon-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon--s {
  width: var(--size-icon-s);
  height: var(--size-icon-s);
}

.icon--m {
  width: var(--size-icon-m);
  height: var(--size-icon-m);
}

.icon--xl {
  width: var(--size-icon-xl);
  height: var(--size-icon-xl);
}

/* =====================================================================
   1. Buttons
   ===================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--size-button-l);
  min-width: var(--size-touch-min);
  padding: var(--space-2) var(--space-6);
  border-radius: var(--radius-md);
  font: var(--font-weight-bold) var(--type-body-size) / var(--type-body-line) var(--font-family-body);
  text-align: center;
  transition:
    background-color var(--motion-duration-fast) var(--motion-easing-standard),
    transform var(--motion-duration-fast) var(--motion-easing-standard);
  -webkit-tap-highlight-color: transparent;
}

.btn--m {
  min-height: var(--size-button-m);
  padding: var(--space-1) var(--space-4);
  font-size: var(--type-label-size);
}

.btn--block {
  display: flex;
  width: 100%;
}

.btn--primary {
  background: var(--color-bg-accent);
  color: var(--color-text-on-accent);
}

.btn--secondary {
  background: var(--color-bg-accent-subtle);
  color: var(--color-text-primary);
}

.btn--ghost {
  background: transparent;
  color: var(--color-text-accent);
  padding-inline: var(--space-3);
}

.btn--destructive {
  background: var(--color-status-error-subtle);
  color: var(--color-status-error-text);
}

.btn--primary:active,
.btn--primary.is-pressed {
  background: var(--color-bg-accent-pressed);
  transform: scale(0.98);
}

.btn--secondary:active,
.btn--secondary.is-pressed {
  background: var(--color-bg-accent-subtle-pressed);
  transform: scale(0.98);
}

.btn--ghost:active,
.btn--ghost.is-pressed {
  background: var(--color-bg-pressed);
}

.btn--destructive:active,
.btn--destructive.is-pressed {
  background: var(--color-status-error);
  color: var(--color-text-on-accent);
}

.btn:disabled,
.btn.is-disabled {
  background: var(--color-bg-disabled);
  color: var(--color-text-disabled);
  transform: none;
  cursor: not-allowed;
}

.btn--ghost:disabled,
.btn--ghost.is-disabled {
  background: transparent;
}

/* icon button: the glyph is 24, the hit region is always 44 (48 on Android) */
.icon-btn {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--size-touch-min);
  height: var(--size-touch-min);
  border-radius: var(--radius-full);
  color: var(--color-text-primary);
  transition: background-color var(--motion-duration-fast) var(--motion-easing-standard);
}

.icon-btn--surface {
  background: var(--color-bg-surface);
  box-shadow: var(--shadow-e1);
}

.icon-btn--tint {
  background: var(--color-bg-accent-subtle);
  color: var(--color-text-accent);
}

.icon-btn--accent {
  background: var(--color-bg-accent);
  color: var(--color-text-on-accent);
}

.icon-btn:active,
.icon-btn.is-pressed {
  background: var(--color-bg-pressed);
}

.icon-btn--accent:active,
.icon-btn--accent.is-pressed {
  background: var(--color-bg-accent-pressed);
}

.icon-btn:disabled,
.icon-btn.is-disabled {
  color: var(--color-text-disabled);
  background: transparent;
  box-shadow: none;
}

/* =====================================================================
   2. Text field (border drawn with inset box-shadow so states never change size)
   ===================================================================== */
.field {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  width: 100%;
}

.field__label {
  font: var(--type-label);
  color: var(--color-text-primary);
}

.field__control {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--size-input);
  padding: var(--space-1) var(--space-4);
  background: var(--color-bg-surface);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong);
  transition: box-shadow var(--motion-duration-fast) var(--motion-easing-standard);
}

.field__control input {
  flex: 1;
  min-width: 0;
  width: 0;
  min-height: var(--size-touch-min); /* the input itself is the 44 target, not just the box around it */
  border: 0;
  outline: 0;
  background: transparent;
  font: var(--type-body);
  color: var(--color-text-primary);
}

.field__control input::placeholder {
  color: var(--color-text-secondary);
}

.field__control textarea {
  flex: 1;
  align-self: stretch;
  min-width: 0;
  width: 0;
  min-height: calc(var(--size-touch-min) * 2);
  padding: var(--space-2) 0;
  border: 0;
  outline: 0;
  background: transparent;
  font: var(--type-body);
  color: var(--color-text-primary);
  resize: vertical;
  field-sizing: content; /* grows with its text, so a long step is never hidden inside the field */
}

.field__control select {
  flex: 1;
  min-width: 0;
  width: 0;
  min-height: var(--size-touch-min);
  border: 0;
  outline: 0;
  background: transparent;
  font: var(--type-body);
  color: var(--color-text-primary);
}

/* Label row with a live character count on the right ("28 / 60") */
.field__top {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

.field__count {
  font: var(--type-num-s);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-secondary);
}

.field__suffix {
  font: var(--type-num-m);
  color: var(--color-text-secondary);
}

.field__help {
  display: flex;
  margin: 0;
  gap: var(--space-1);
  align-items: flex-start;
  font: var(--type-caption);
  color: var(--color-text-secondary);
}

.field__control:focus-within,
.field.is-focus .field__control {
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-accent);
}

.field.is-focus {
  outline: 0;
}

.field.is-disabled .field__control {
  background: var(--color-bg-disabled);
  box-shadow: none;
}

.field.is-error .field__control,
.field .field__control:has(input[aria-invalid="true"]) {
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-error);
}

.field.is-error .field__help {
  color: var(--color-status-error-text);
}

/* =====================================================================
   3. Search bar
   ===================================================================== */
.search {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--size-input);
  padding: var(--space-1) calc(var(--space-card-inset) - var(--size-icon-inset)) var(--space-1) var(--space-card-inset);
  background: var(--color-bg-sunken);
  border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong);
  color: var(--color-text-secondary);
}

.search input {
  flex: 1;
  align-self: stretch;
  min-width: 0;
  width: 0;
  min-height: var(--size-touch-min);
  border: 0;
  outline: 0;
  background: transparent;
  font: var(--type-body);
  color: var(--color-text-primary);
}

.search input::placeholder {
  color: var(--color-text-secondary);
}

.search:focus-within,
.search.is-focus {
  outline: 0;
  background: var(--color-bg-surface);
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-accent);
}

.search.is-error {
  background: var(--color-bg-surface);
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-error);
}

.search.is-disabled {
  background: var(--color-bg-disabled);
  color: var(--color-text-disabled);
}

.search.is-disabled input::placeholder {
  color: var(--color-text-disabled);
}

.search__help {
  margin: 0;
  font: var(--type-caption);
  color: var(--color-status-error-text);
}

/* =====================================================================
   4. Chips (visual 36, hit region extended to 44 / 48)
   ===================================================================== */
.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--size-chip);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--color-bg-surface);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong);
  font: var(--type-label);
  color: var(--color-text-primary);
  text-align: left;
}

.chip::after {
  content: "";
  position: absolute;
  inset: calc((var(--size-chip) - var(--size-touch-min)) / 2) 0;
}

.chip .icon {
  width: var(--size-icon-s);
  height: var(--size-icon-s);
}

.chip:active,
.chip.is-pressed {
  background: var(--color-bg-sunken);
}

.chip[aria-pressed="true"],
.chip.is-selected {
  background: var(--color-bg-accent-subtle);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-accent);
}

.chip--fresh {
  background: var(--color-bg-fresh-subtle);
  box-shadow: none;
  color: var(--color-text-fresh);
}

/* Locked filter (allergy): a lock icon + the word "Allergy". It can't be removed here, only in Profile. */
.chip--locked {
  background: var(--color-bg-sunken);
  cursor: default;
}

.chip--locked small {
  font: var(--type-caption);
  letter-spacing: var(--type-caption-tracking);
  color: var(--color-text-secondary);
}

.chip:disabled,
.chip.is-disabled {
  background: var(--color-bg-disabled);
  box-shadow: none;
  color: var(--color-text-disabled);
}

.chip-row {
  display: flex;
  gap: var(--space-chip-gap);
  flex-wrap: wrap;
}

/* =====================================================================
   5. Segmented control (g / ml / portion)
   Segment + 4 px track padding = 44 (48 on Android) hit region.
   Focus: 2 px surface gap + 2 px rye ring OUTSIDE the segment. It fits exactly into the
   4 px track padding and the 8 px gap between segments, so it is never clipped and never
   touches a neighbour.
   ===================================================================== */
.segmented {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--size-col-min)), 1fr));
  gap: var(--space-2);
  width: 100%;
  min-inline-size: 0;
  margin: 0;
  padding: var(--space-1);
  border: 0;
  background: var(--color-bg-sunken);
  border-radius: var(--radius-md);
}

.segmented__opt {
  position: relative;
  display: grid;
  place-items: center;
  min-width: var(--size-touch-min);
  min-height: var(--size-segment);
  padding: var(--space-1) var(--space-3);
  border-radius: calc(var(--radius-md) - var(--space-1));
  font: var(--type-label);
  color: var(--color-text-secondary);
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
}

.segmented__opt::after {
  content: "";
  position: absolute;
  inset: calc(var(--space-1) * -1) 0;
}

.segmented__opt:active,
.segmented__opt.is-pressed {
  background: var(--color-bg-pressed);
}

.segmented__opt:has(input:checked),
.segmented__opt.is-selected {
  background: var(--color-bg-surface);
  color: var(--color-text-primary);
  font-weight: var(--font-weight-bold);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong), var(--shadow-e1);
}

.segmented__opt:has(input:focus-visible),
.segmented__opt.is-focus {
  outline: 0;
  box-shadow:
    0 0 0 var(--border-width-focus-gap) var(--color-bg-surface),
    0 0 0 calc(var(--border-width-focus-gap) + var(--border-width-focus)) var(--color-border-focus);
}

.segmented__opt:has(input:disabled),
.segmented__opt.is-disabled {
  color: var(--color-text-disabled);
  background: transparent;
  text-decoration: line-through;
  cursor: not-allowed;
}

/* selected + focused: keep the segment's own edge so the 2 px gap stays visible against its white fill */
.segmented__opt:has(input:checked:focus-visible),
.segmented__opt.is-focus:has(input:checked),
.segmented__opt.is-selected.is-focus {
  box-shadow:
    inset 0 0 0 var(--border-width-default) var(--color-border-strong),
    0 0 0 var(--border-width-focus-gap) var(--color-bg-surface),
    0 0 0 calc(var(--border-width-focus-gap) + var(--border-width-focus)) var(--color-border-focus);
}

/* =====================================================================
   6. Weight stepper (border is an inset ring, so the ± buttons are a full 44 × 44)
   ===================================================================== */
.stepper {
  display: inline-flex;
  align-items: stretch;
  max-width: 100%; /* never wider than its row; the unit wraps under the number instead (320 pt, 200 % text) */
  min-height: var(--size-touch-min);
  background: var(--color-bg-sunken);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong);
}

.stepper__btn {
  display: grid;
  flex: none; /* 44 × 44 always: only the value shrinks when the row is narrow */
  place-items: center;
  width: var(--size-touch-min);
  min-height: var(--size-touch-min);
  color: var(--color-text-primary);
  border-radius: var(--radius-md);
}

.stepper__btn:active,
.stepper__btn.is-pressed {
  background: var(--color-bg-pressed);
}

.stepper__btn:disabled,
.stepper__btn.is-disabled {
  color: var(--color-text-disabled);
  background: transparent;
  cursor: not-allowed;
}

.stepper__value {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  place-content: center;
  align-items: center;
  gap: var(--space-1);
  min-width: calc(var(--space-16) + var(--space-2));
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
}

.stepper__value small {
  font: var(--type-num-s);
  color: var(--color-text-secondary);
}

.stepper__input {
  width: 4ch;
  min-width: var(--size-touch-min);
  min-height: var(--size-touch-min);
  padding: 0;
  border: 0;
  outline: 0;
  background: transparent;
  font: inherit;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.stepper.is-focus,
.stepper:focus-within {
  outline: 0;
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-accent);
}

.stepper.is-error {
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-error);
}

.stepper.is-disabled {
  background: var(--color-bg-disabled);
  box-shadow: none;
  color: var(--color-text-disabled);
}

.stepper-help {
  margin-top: var(--space-1);
  font: var(--type-caption);
  color: var(--color-status-error-text);
}

/* =====================================================================
   7. Product list item
   Rows are inset in the list (4 px), have their own radius, and draw state outlines with an
   inset ring, so every state has identical geometry. Dividers hide next to a state row.
   ===================================================================== */
.list {
  display: grid;
  padding: var(--space-1);
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
}

.product {
  position: relative;
  display: grid;
  grid-template-columns: var(--size-thumb) minmax(0, 1fr) auto;
  gap: var(--space-3);
  align-items: center;
  min-height: calc(var(--size-thumb) + var(--space-4));
  padding: var(--space-2) calc(var(--space-card-inset) - var(--space-1));
  border-radius: var(--radius-md);
  background: transparent;
}

.product + .product::before {
  content: "";
  position: absolute;
  top: 0;
  right: var(--space-3);
  left: calc(var(--space-3) + var(--size-thumb) + var(--space-3));
  border-top: var(--border-width-hairline) solid var(--color-border-subtle);
}

.product:is(:active, .is-pressed, .is-selected, .is-error, .is-check)::before,
.product:is(:active, .is-pressed, .is-selected, .is-error, .is-check) + .product::before {
  visibility: hidden;
}

.product__thumb {
  width: var(--size-thumb);
  height: var(--size-thumb);
  border-radius: var(--radius-sm);
  background: var(--color-bg-sunken) center / cover;
  object-fit: cover;
}

/* No photo: an icon on the sunken tile */
.product__thumb--icon {
  display: grid;
  place-items: center;
  color: var(--color-text-secondary);
}

/* Detected item (photo result): marker | name, confidence, weight stepper | kcal */
.product--detected {
  grid-template-columns: var(--space-6) minmax(0, 1fr) auto;
  align-items: start;
  padding-block: var(--space-3);
}

.product--detected + .product--detected::before,
.product--chips + .product--chips::before {
  left: var(--space-3);
}

.product__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.product__name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
  font: var(--type-body-strong);
  overflow-wrap: anywhere;
}

.product__meta {
  margin-top: var(--space-1);
  font: var(--type-num-s);
  color: var(--color-text-secondary);
}

/* Words instead of numbers (for example the foods in a meal) */
.product__meta--text {
  font: var(--type-callout);
}

/* Search rows: the photo (the Meals thumbnail, .product__thumb) with the name beside it, top-aligned; the
   P / F / C chips under the photo from the card-inset line; kcal per 100 g + Add on the right edge, centred
   on the whole row (both lines) */
.product--chips {
  grid-template-columns: var(--size-thumb) minmax(0, 1fr) auto;
  align-items: start;
  row-gap: var(--space-2);
}

.product__macros {
  grid-column: 1 / 3;
}

.product__end {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin: calc((var(--border-width-focus-gap) + var(--border-width-focus)) * -1);
  padding: calc(var(--border-width-focus-gap) + var(--border-width-focus)); /* room for the focus ring of the Add button */
}

.product__kcal {
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.product__kcal small {
  display: block;
  font: var(--type-caption);
  color: var(--color-text-secondary);
}

.product:active,
.product.is-pressed {
  background: var(--color-bg-sunken);
}

.product.is-selected {
  background: var(--color-bg-accent-subtle);
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-accent);
}

/* "Check portion": the row is tinted and the user is asked to confirm the weight */
.product.is-check {
  background: var(--color-status-warning-subtle);
}

.product.is-error {
  background: var(--color-status-error-subtle);
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-error);
}

.product.is-error .product__meta {
  color: var(--color-status-error-text);
}

.product.is-disabled .product__thumb {
  filter: grayscale(1);
  opacity: 0.5;
}

.product:focus-visible,
.product.is-focus {
  outline: 0;
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-focus);
}

/* =====================================================================
   8. Recipe card (no clipping: the image rounds its own top corners)
   ===================================================================== */
.recipe-card {
  position: relative;
  display: block;
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
  transition: transform var(--motion-duration-fast) var(--motion-easing-standard);
}

.recipe-card__img {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: var(--color-bg-sunken) center / cover;
}

.recipe-card__img .icon-btn {
  position: absolute;
  z-index: 1;
  top: var(--space-3);
  right: var(--space-3);
}

.recipe-card__body {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
  padding: var(--space-card-inset);
}

.recipe-card__title {
  margin: 0;
  font: var(--type-h2);
  overflow-wrap: anywhere;
}

/* A link in the title makes the whole card clickable (stretched link) and keyboard reachable */
.recipe-card__title a {
  color: inherit;
  text-decoration: none;
}

.recipe-card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-lg);
}

.recipe-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  align-items: center;
  font: var(--type-callout);
  color: var(--color-text-secondary);
}

.recipe-card__meta span {
  display: inline-flex;
  align-items: center;
  gap: var(--space-inline-icon);
}

.recipe-card__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  justify-content: space-between;
  margin-top: var(--space-2);
}

.recipe-card__kcal {
  font: var(--type-num-l);
  font-variant-numeric: tabular-nums;
}

.recipe-card__kcal small {
  font: var(--type-callout);
  color: var(--color-text-secondary);
}

/* The image of a card with a "View recipe" button is a pointer-only shortcut to the same recipe
   (aria-hidden; the button is the keyboard and screen-reader path) */
.recipe-card__img--link {
  cursor: pointer;
}

.recipe-card__img--link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: transparent;
  transition: background-color var(--motion-duration-fast) var(--motion-easing-standard);
}

.recipe-card__img--link:active::after,
.recipe-card__img--link.is-pressed::after {
  background: var(--color-bg-pressed);
}

.recipe-card__img > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

.recipe-card__fit {
  display: inline-flex;
  align-items: center;
  gap: var(--space-inline-icon);
  font: var(--type-label);
  color: var(--color-text-fresh);
}

/* Compact card for ranked lists: image on the left, the same content on the right */
.recipe-card--compact {
  display: grid;
  grid-template-columns: var(--size-recipe-thumb) minmax(0, 1fr);
  align-items: stretch;
  gap: var(--space-3);
  padding: var(--space-card-inset);
}

/* Same width in every card; the height runs from the top to the bottom padding of the card and grows
   with the text. Own rounded corners (the card itself never clips); the photo is cropped with cover */
.recipe-card--compact .recipe-card__img {
  width: var(--size-recipe-thumb);
  min-height: 0;
  aspect-ratio: auto;
  border-radius: var(--radius-md);
}

/* One text column, everything left-aligned, one gap between all rows:
   title → time → reason → P / F / C → "Fits" → kcal */
.recipe-card--compact .recipe-card__body {
  min-width: 0;
  gap: var(--space-2);
  padding: 0;
}

.recipe-card--compact .recipe-card__title {
  font: var(--type-title);
}

.recipe-card--compact .recipe-card__kcal {
  font: var(--type-num-m);
}

.recipe-card:active,
.recipe-card.is-pressed {
  transform: scale(0.98);
}

.recipe-card.is-disabled .recipe-card__img {
  filter: grayscale(1);
  opacity: 0.5;
}

.recipe-card.is-disabled .recipe-card__title,
.recipe-card.is-disabled .recipe-card__kcal {
  color: var(--color-text-disabled);
}

/* =====================================================================
   9. Nutrition summary (calorie ring + macro bars)
   ===================================================================== */
.nutri {
  padding: var(--space-5) var(--space-card-inset) var(--space-card-inset);
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
}

.nutri__ring {
  display: grid;
  width: 100%;
  max-width: calc(var(--space-16) * 4);
  margin: 0 auto;
}

.nutri__ring > * {
  grid-area: 1 / 1;
}

.nutri__ring svg {
  display: block;
  align-self: start;
  width: 100%;
  height: auto;
}

.nutri__track {
  fill: none;
  stroke: var(--color-macro-track);
  stroke-linecap: round;
}

.nutri__value {
  fill: none;
  stroke: var(--color-macro-kcal);
  stroke-linecap: round;
  transition: stroke-dasharray var(--motion-duration-slow) var(--motion-easing-standard);
}

.nutri__center {
  align-self: end;
  text-align: center;
}

.nutri__big {
  display: block;
  font: var(--type-num-xl);
  letter-spacing: var(--type-num-xl-tracking);
  font-variant-numeric: tabular-nums;
}

.nutri__center small {
  font: var(--type-callout);
  color: var(--color-text-secondary);
}

.nutri__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-4);
  font: var(--type-callout);
  color: var(--color-text-secondary);
}

.nutri__row b {
  font: var(--type-num-m);
  color: var(--color-text-primary);
  font-variant-numeric: tabular-nums;
}

.nutri--over .nutri__value {
  stroke: var(--color-status-warning);
}

.macros {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--size-col-min)), 1fr));
  gap: var(--space-3);
}

.macro__label {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font: var(--type-caption);
  letter-spacing: var(--type-caption-tracking);
  color: var(--color-text-secondary);
}

.macro__key {
  flex: none;
  width: var(--space-3);
  height: var(--space-3);
  border-radius: var(--radius-full);
}

.macro__value {
  margin: var(--space-1) 0;
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
}

.macro__value small,
.macro__goal {
  font: var(--type-num-s);
  color: var(--color-text-secondary);
}

.macro__goal {
  margin-top: var(--space-1);
}

.macro__bar {
  height: var(--space-2);
  border-radius: var(--radius-full);
  background: var(--color-bg-sunken);
}

.macro__bar > i {
  display: block;
  width: var(--w, 0%);
  height: 100%;
  max-width: 100%;
  border-radius: var(--radius-full);
}

.macro--p .macro__key,
.macro--p .macro__bar > i {
  background: var(--color-macro-protein);
}

.macro--f .macro__key,
.macro--f .macro__bar > i {
  background: var(--color-macro-fat);
}

.macro--c .macro__key,
.macro--c .macro__bar > i {
  background: var(--color-macro-carbs);
}

/* Standalone macro keys (for example in tables) */
.macro__key--p {
  background: var(--color-macro-protein);
}

.macro__key--f {
  background: var(--color-macro-fat);
}

.macro__key--c {
  background: var(--color-macro-carbs);
}

.macro.is-over .macro__value,
.macro.is-over .macro__goal {
  color: var(--color-status-warning-text);
}

/* Macro tiles: three equal columns, identical padding, shared baselines, tabular numbers */
.macro-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--size-col-min)), 1fr));
  grid-auto-rows: auto;
  gap: var(--space-2);
}

.macro-tile {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  align-items: baseline;
  row-gap: var(--space-1);
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
}

.macro-tile__label {
  font: var(--type-caption);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--type-caption-tracking);
}

.macro-tile__value {
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-primary);
}

.macro-tile__value small {
  font: var(--type-num-s);
  color: var(--color-text-secondary);
}

/* Macro chips: the same macro tile, inline. Letter + value, macro colours, no dot separators */
.macro-tiles--inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-chip-gap);
}

.macro-tile--chip {
  display: inline-flex;
  grid-row: auto;
  align-items: center;
  gap: var(--space-inline-icon);
  min-height: var(--size-macro-chip);
  padding: 0 var(--space-2);
  border-radius: var(--radius-xs);
  white-space: nowrap; /* a chip never breaks inside; the row of chips may wrap only at large text sizes */
}

.macro-tile--chip .macro-tile__value {
  font: var(--type-num-s);
}

.macro-tile--p {
  background: var(--color-macro-protein-subtle);
  color: var(--color-macro-protein-text);
}

.macro-tile--f {
  background: var(--color-macro-fat-subtle);
  color: var(--color-macro-fat-text);
}

.macro-tile--c {
  background: var(--color-macro-carbs-subtle);
  color: var(--color-macro-carbs-text);
}

/* =====================================================================
   10. Nutrition facts table
   ===================================================================== */
.facts {
  padding: var(--space-card-inset);
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
}

.facts__title {
  margin: 0 0 var(--space-1);
  font: var(--type-h2);
}

.facts__source {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font: var(--type-caption);
  color: var(--color-text-secondary);
}

.facts table,
.ingredients--facts {
  width: 100%;
  overflow-wrap: anywhere; /* long names and headers wrap at 200% text instead of widening the card */
  margin-top: var(--space-3);
  border-collapse: collapse;
  font: var(--type-callout);
}

.facts th,
.ingredients__head {
  padding: var(--space-2) 0;
  border-bottom: var(--border-width-rule) solid var(--color-text-primary);
  font: var(--type-overline);
  letter-spacing: var(--type-overline-tracking);
  text-transform: uppercase;
  text-align: right;
  color: var(--color-text-secondary);
}

.facts th + th {
  white-space: nowrap;
}

.facts th:first-child {
  text-align: left;
}

.facts .macro__key {
  display: inline-block;
  margin-right: var(--space-2);
  vertical-align: middle;
}

/* =====================================================================
   11. Top app bar (icons 24 in 44 / 48 hit regions; titles wrap instead of truncating)
   ===================================================================== */
.app-bar {
  display: grid;
  grid-template-columns: var(--size-touch-min) minmax(0, 1fr) var(--size-touch-min);
  align-items: center;
  gap: var(--space-2);
  min-height: var(--size-app-bar);
  padding: var(--space-1) calc(var(--space-screen-margin) - var(--size-icon-inset));
  background: var(--color-bg-canvas);
}

.app-bar__title {
  margin: 0;
  font: var(--type-title);
  text-align: center;
  overflow-wrap: anywhere;
}

.app-bar.is-scrolled {
  background: var(--color-bg-surface);
  box-shadow: inset 0 calc(var(--border-width-hairline) * -1) 0 var(--color-border-subtle);
}

.app-bar--large {
  grid-template-columns: minmax(0, 1fr) auto;
  padding: var(--space-1) calc(var(--space-screen-margin) - var(--size-icon-inset)) var(--space-1) var(--space-screen-margin);
}

.app-bar--large .app-bar__title {
  font: var(--type-h1);
  text-align: left;
}

.app-bar__actions {
  display: flex;
}

/* =====================================================================
   12. Tab bar
   Each tab is a 44 pt (48 dp) hit region inside the bar, with padding above and below.
   Pressed = pill drawn INSIDE the tab. Focus = inset ring. The Scan button sits inside the bar.
   ===================================================================== */
.tab-bar {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: center;
  gap: var(--space-1);
  min-height: calc(var(--size-tab-bar) + var(--size-safe-bottom));
  padding:
    calc((var(--size-tab-bar) - var(--size-touch-min)) / 2) var(--space-2)
    calc((var(--size-tab-bar) - var(--size-touch-min)) / 2 + var(--size-safe-bottom));
  background: var(--color-bg-surface);
  box-shadow: inset 0 var(--border-width-hairline) 0 var(--color-border-subtle);
}

.tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-width: var(--size-touch-min);
  min-height: var(--size-touch-min);
  border-radius: var(--radius-md);
  font: var(--type-caption);
  font-size: min(var(--type-caption-size), var(--size-tab-label-max));
  color: var(--color-text-secondary);
  text-align: center;
  overflow-wrap: anywhere;
}

.tab::before {
  content: "";
  position: absolute;
  inset: 0 var(--space-1);
  border-radius: var(--radius-md);
  background: transparent;
  pointer-events: none;
}

.tab .icon,
.tab span {
  position: relative;
}

.tab[aria-current="page"],
.tab.is-active {
  color: var(--color-text-accent);
  font-weight: var(--font-weight-bold);
}

.tab:active::before,
.tab.is-pressed::before {
  background: var(--color-bg-pressed);
}

.tab[aria-current="page"] span,
.tab.is-active span {
  text-decoration: underline var(--border-width-focus) var(--color-bg-accent);
  text-underline-offset: var(--space-1);
}

.tab:focus-visible,
.tab.is-focus {
  outline: 0;
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-focus);
}

.tab:disabled,
.tab.is-disabled {
  color: var(--color-text-disabled);
}

.tab--scan::before {
  display: none;
}

.tab__fab {
  display: grid;
  place-items: center;
  width: min(var(--size-scan-button), 100% - var(--space-2));
  height: calc(var(--size-touch-min) - var(--space-2));
  border-radius: var(--radius-full);
  background: var(--color-bg-accent);
  color: var(--color-text-on-accent);
}

.tab--scan:active .tab__fab,
.tab--scan.is-pressed .tab__fab {
  background: var(--color-bg-accent-pressed);
}

.tab--scan:focus-visible,
.tab--scan.is-focus {
  box-shadow: none;
}

.tab--scan:focus-visible .tab__fab,
.tab--scan.is-focus .tab__fab {
  box-shadow:
    0 0 0 var(--border-width-focus-gap) var(--color-bg-surface),
    0 0 0 calc(var(--border-width-focus-gap) + var(--border-width-focus)) var(--color-border-focus);
}

/* =====================================================================
   13. Bottom sheet
   ===================================================================== */
.scrim {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--color-bg-scrim);
}

.sheet {
  position: relative;
  inset: auto;
  width: auto;
  max-width: none;
  margin: 0;
  padding: var(--space-2) var(--space-5) var(--size-safe-bottom);
  border: 0;
  background: var(--color-bg-surface);
  color: inherit;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  box-shadow: var(--shadow-e3);
  animation: ripe-sheet-in var(--motion-duration-slow) var(--motion-easing-standard);
}

/* modal version: <dialog class="sheet-dialog"> opened with showModal(); Esc closes, focus returns to the opener */
.sheet-dialog {
  width: min(100%, var(--size-screen-width));
  max-width: 100%;
  max-height: 100%;
  margin: auto auto 0;
  padding: 0;
  border: 0;
  background: transparent;
}

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

.sheet__confirm {
  margin: 0 0 var(--space-3);
  padding-left: var(--space-5);
  font: var(--type-body);
}

@keyframes ripe-sheet-in {
  from {
    transform: translateY(var(--space-16));
    opacity: 0;
  }
}

.sheet__handle {
  width: var(--space-10);
  height: var(--space-1);
  margin: 0 auto var(--space-3);
  border-radius: var(--radius-full);
  background: var(--color-border-default);
}

.sheet__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.sheet__title {
  margin: 0;
  font: var(--type-h2);
}

.sheet__sub {
  margin: var(--space-1) 0 0;
  font: var(--type-callout);
  color: var(--color-text-secondary);
}

.sheet__body {
  display: grid;
  gap: var(--space-4);
}

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

.sheet__foot {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

/* =====================================================================
   14. Toast
   ===================================================================== */
.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--size-button-l);
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--color-bg-inverse);
  color: var(--color-text-inverse);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-e2);
  font: var(--type-callout);
  animation: ripe-toast-in var(--motion-duration-base) var(--motion-easing-standard);
}

.toast__msg {
  flex: 1;
}

.toast__close {
  display: grid;
  place-items: center;
  flex: none;
  width: var(--size-touch-min);
  height: var(--size-touch-min);
  border-radius: var(--radius-sm);
  color: var(--color-text-inverse);
}

.toast__close:active,
.toast__close.is-pressed {
  background: var(--color-bg-inverse-pressed);
}

@keyframes ripe-toast-in {
  from {
    transform: translateY(var(--space-2));
    opacity: 0;
  }
}

.toast__action {
  min-width: var(--size-touch-min);
  min-height: var(--size-touch-min);
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font: var(--type-label);
  color: var(--color-text-inverse-accent);
}

.toast__action:active,
.toast__action.is-pressed {
  background: var(--color-bg-inverse-pressed);
}

.toast--success .icon {
  color: var(--color-text-inverse-success);
}

.toast--warning .icon {
  color: var(--color-text-inverse-warning);
}

.toast--error {
  background: var(--color-status-error);
  color: var(--color-text-on-accent);
}

.toast--error .toast__action {
  color: var(--color-text-on-accent);
  text-decoration: underline;
}

.toast .toast__action:focus-visible,
.toast .toast__action.is-focus,
.toast .toast__close:focus-visible,
.toast .toast__close.is-focus {
  outline-color: var(--color-text-inverse);
  outline-offset: calc(var(--border-width-focus-gap) * -1);
}

/* =====================================================================
   15. Empty state
   ===================================================================== */
.empty {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-6);
  text-align: center;
}

.empty__icon {
  display: grid;
  place-items: center;
  width: var(--size-empty-icon);
  height: var(--size-empty-icon);
  border-radius: var(--radius-full);
  background: var(--color-bg-accent-subtle);
  color: var(--color-text-accent);
}

.empty__title {
  margin: 0;
  font: var(--type-h2);
}

.empty__text {
  max-width: calc(var(--space-16) * 5);
  margin: 0;
  font: var(--type-body);
  color: var(--color-text-secondary);
}

.empty__actions {
  display: grid;
  gap: var(--space-1);
  margin-top: var(--space-2);
}

.empty--error .empty__icon {
  background: var(--color-status-error-subtle);
  color: var(--color-status-error);
}

/* =====================================================================
   16. Badges and confidence labels
   ===================================================================== */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--size-badge);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-xs);
  font: var(--type-caption);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--type-caption-tracking);
}

.badge .icon {
  width: var(--size-icon-s);
  height: var(--size-icon-s);
}

.badge--verified {
  background: var(--color-status-success-subtle);
  color: var(--color-status-success-text);
}

.badge--new {
  background: var(--color-bg-accent-subtle);
  color: var(--color-text-accent);
}

.badge--fresh {
  background: var(--color-bg-fresh-subtle);
  color: var(--color-text-fresh);
}

.badge--count {
  justify-content: center;
  min-width: var(--size-badge);
  border-radius: var(--radius-full);
  background: var(--color-bg-accent);
  color: var(--color-text-on-accent);
}

.badge--p {
  background: var(--color-macro-protein-subtle);
  color: var(--color-macro-protein-text);
}

.badge--f {
  background: var(--color-macro-fat-subtle);
  color: var(--color-macro-fat-text);
}

.badge--c {
  background: var(--color-macro-carbs-subtle);
  color: var(--color-macro-carbs-text);
}

.confidence {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font: var(--type-caption);
  font-weight: var(--font-weight-semibold);
}

.confidence .icon {
  width: var(--size-icon-s);
  height: var(--size-icon-s);
}

.confidence--high {
  color: var(--color-status-success-text);
}

.confidence--check,
.confidence--unsure {
  color: var(--color-status-warning-text);
}

.confidence--unsure.is-marked {
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-xs);
  background: var(--color-status-warning-subtle);
}

.marker {
  display: inline-grid;
  place-items: center;
  width: var(--space-6);
  height: var(--space-6);
  border-radius: var(--radius-full);
  background: var(--color-bg-accent-subtle);
  font: var(--type-caption);
  font-weight: var(--font-weight-bold);
  color: var(--color-text-primary);
}

.marker--unsure {
  background: var(--color-bg-highlight);
}

/* =====================================================================
   17. Inline banner (info, offline). Stays until the situation changes; never auto-hides.
   ===================================================================== */
.banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-card-inset);
  border-radius: var(--radius-md);
  background: var(--color-bg-sunken);
  color: var(--color-text-primary);
  font: var(--type-callout);
}

.banner > .icon {
  color: var(--color-text-secondary);
}

.banner__text {
  flex: 1;
  margin: 0;
}

.banner__text b {
  font-weight: var(--font-weight-semibold);
}

.banner .btn {
  margin-block: calc(var(--space-2) * -1);
}

.banner--offline {
  background: var(--color-status-warning-subtle);
}

.banner--offline > .icon {
  color: var(--color-status-warning);
}

/* =====================================================================
   18. Skeleton (loading placeholder). Static when the user prefers reduced motion.
   Put aria-busy="true" on the container and a visually hidden "Loading…" text inside.
   ===================================================================== */
.skeleton {
  display: block;
  height: var(--space-4);
  border-radius: var(--radius-xs);
  background:
    linear-gradient(90deg, var(--color-bg-sunken) 30%, var(--color-bg-surface) 50%, var(--color-bg-sunken) 70%)
    0 0 / 300% 100%;
  animation: ripe-shimmer var(--motion-duration-shimmer) linear infinite;
}

.skeleton--title {
  height: var(--space-6);
  width: 60%;
}

.skeleton--short {
  width: 40%;
}

.skeleton--thumb {
  width: var(--size-thumb);
  height: var(--size-thumb);
  border-radius: var(--radius-sm);
}

.skeleton--block {
  height: calc(var(--space-16) * 3);
  border-radius: var(--radius-lg);
}

@keyframes ripe-shimmer {
  from {
    background-position: 100% 0;
  }

  to {
    background-position: 0 0;
  }
}

/* =====================================================================
   19. Camera viewfinder (plate guide, tips, live hint, shutter row)
   The live feed is a full-bleed image. Everything on it sits on solid dark pills, so text
   contrast never depends on the photo.
   ===================================================================== */
.viewfinder {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr auto;
  flex: 1;
  min-height: 0;
  background: var(--color-bg-inverse);
  color: var(--color-text-inverse);
  overflow: hidden;
}

.viewfinder__feed {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.viewfinder__plate {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle calc(var(--size-plate-guide) / 2) at 50% 50%, transparent 99%, var(--color-bg-scrim) 100%);
  pointer-events: none;
}

.viewfinder__plate::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--size-plate-guide);
  aspect-ratio: 1;
  border-radius: var(--radius-full);
  outline: var(--border-width-focus) dashed var(--color-border-inverse);
  outline-offset: calc(var(--border-width-focus) * -1);
  translate: -50% -50%;
}

.viewfinder__top,
.viewfinder__bottom {
  position: relative;
  display: grid;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-screen-margin);
}

.viewfinder__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.viewfinder__tips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.viewfinder__tip,
.viewfinder__hint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--size-badge);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--color-bg-inverse);
  color: var(--color-text-inverse);
  font: var(--type-caption);
  letter-spacing: var(--type-caption-tracking);
}

.viewfinder__hint {
  justify-self: center;
  background: var(--color-bg-surface);
  color: var(--color-text-primary);
  font: var(--type-label);
}

.viewfinder__hint .icon {
  color: var(--color-status-success);
}

.viewfinder__controls {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  margin-inline: calc(var(--space-1) * -1);
  padding: var(--space-2) var(--space-1) var(--size-safe-bottom);
}

.viewfinder__controls > :first-child {
  justify-self: start;
}

.viewfinder__controls > :last-child {
  justify-self: end;
}

.viewfinder__library {
  width: var(--size-touch-android);
  height: var(--size-touch-android);
  border-radius: var(--radius-sm);
  outline: var(--border-width-focus) solid var(--color-border-inverse);
  outline-offset: calc(var(--border-width-focus) * -1);
  object-fit: cover;
}

.viewfinder__side {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
  min-width: var(--size-touch-min);
  font: var(--type-caption);
  color: var(--color-text-inverse);
}

.shutter {
  display: grid;
  place-items: center;
  width: var(--size-shutter);
  height: var(--size-shutter);
  border-radius: var(--radius-full);
  background: var(--color-bg-accent);
  color: var(--color-text-on-accent);
  box-shadow:
    0 0 0 var(--space-1) var(--color-bg-inverse),
    0 0 0 calc(var(--space-1) + var(--border-width-focus)) var(--color-border-inverse);
}

.shutter:active,
.shutter.is-pressed {
  background: var(--color-bg-accent-pressed);
}

.icon-btn--inverse {
  background: var(--color-bg-inverse);
  color: var(--color-text-inverse);
}

.viewfinder :focus-visible,
.viewfinder .is-focus {
  outline-color: var(--color-border-inverse);
}

.viewfinder .shutter:focus-visible,
.viewfinder .shutter.is-focus {
  outline-offset: calc(var(--space-1) + var(--border-width-focus) + var(--border-width-focus-gap));
}

/* =====================================================================
   20. Screen layout: the 390 × 844 frame every screen in 03-screens uses
   ===================================================================== */
.screen {
  position: relative;
  display: flex;
  flex-direction: column;
  width: var(--size-screen-width);
  max-width: 100%;
  height: var(--size-screen-height);
  background: var(--color-bg-canvas);
  overflow: hidden;
}

.status-bar {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  min-height: var(--size-safe-top);
  padding: var(--space-1) var(--space-6) 0 var(--space-8);
  font: var(--type-body-strong);
  font-variant-numeric: tabular-nums;
}

.status-bar__icons {
  display: flex;
  gap: var(--space-1);
}

.status-bar--inverse {
  background: var(--color-bg-inverse);
  color: var(--color-text-inverse);
}

.screen > .app-bar,
.screen > .tab-bar {
  flex: none;
}

.screen__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr); /* the column never grows past the screen; content wraps instead */
  flex: 1;
  align-content: start;
  gap: var(--space-stack);
  min-height: 0;
  padding: var(--space-2) var(--space-screen-margin) var(--space-6);
  overflow-y: auto;
}

/* Spacing comes from the grid gap, so direct children never add their own margins */
.screen__body > *,
.card > *,
.row-between > * {
  margin: 0;
}

/* The body scrolls, so keyboard users can focus it to scroll (WCAG 2.1.1). The ring is inset because the screen clips. */
.screen__body:focus-visible {
  outline-offset: calc(var(--border-width-focus) * -1);
}

.screen__body--flush {
  padding-top: 0;
}

.screen__bleed {
  margin-inline: calc(var(--space-screen-margin) * -1);
}

.screen__foot {
  display: grid;
  flex: none;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-screen-margin) var(--size-safe-bottom);
  background: var(--color-bg-surface);
  box-shadow: inset 0 var(--border-width-hairline) 0 var(--color-border-subtle);
}

.screen__foot--split {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--size-col-min)), 1fr));
}

.screen__note {
  margin: 0;
  font: var(--type-caption);
  letter-spacing: var(--type-caption-tracking);
  color: var(--color-text-secondary);
  text-align: center;
}

/* The toast takes its own row above the tab bar, so it never covers content or a focused control (WCAG 2.4.11) */
.screen__toast {
  flex: none;
  padding: var(--space-3) var(--space-screen-margin);
}

.screen__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin: var(--space-2) 0 calc(var(--space-2) * -1);
}

/* Text buttons at a row edge: the label, not the padded box, sits on the margin line */
.screen__body > .btn--ghost {
  justify-self: start;
  margin-left: calc(var(--space-3) * -1);
}

/* Text buttons inside a card: the label sits on the card-inset line */
.card > .btn--ghost {
  justify-self: start;
  margin-left: calc(var(--space-3) * -1);
}

.section-head:has(> .btn--ghost:last-child) {
  margin-right: calc(var(--space-3) * -1);
}

.section-head h2 {
  margin: 0;
  font: var(--type-title);
}

.card {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-card-inset);
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
}

.row-between {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
}

/* Photo with numbered markers. Marker positions are data: style="--x: 30%; --y: 40%" */
.photo {
  position: relative;
}

.photo > img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

.photo--hero > img {
  aspect-ratio: 4 / 3;
}

.photo .marker {
  position: absolute;
  top: var(--y);
  left: var(--x);
  box-shadow: 0 0 0 var(--border-width-focus) var(--color-bg-surface);
  translate: -50% -50%;
}

.photo__status {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--color-bg-scrim);
}

.photo .app-bar {
  position: absolute;
  inset: 0 0 auto;
  padding-inline: var(--space-screen-margin);
  background: transparent;
}

/* =====================================================================
   21. Date button (Today): calendar glyph + day + kcal left, on the margin line
   ===================================================================== */
.date-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--size-touch-min);
  padding: 0;
  border-radius: var(--radius-sm);
  font: var(--type-callout);
  color: var(--color-text-primary);
  text-align: left;
}

.date-btn .icon {
  color: var(--color-text-accent);
}

.date-btn b {
  font-weight: var(--font-weight-semibold);
}

.date-btn:active,
.date-btn.is-pressed {
  background: var(--color-bg-pressed);
}

/* =====================================================================
   22. Title row with an edit button, and inline name editing
   The edit glyph sits on the right margin line (the 44 hit area extends past it).
   ===================================================================== */
.title-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-2);
}

.title-row > h1,
.title-row > h2 {
  margin: 0;
  overflow-wrap: anywhere;
}

.title-row:has(> .icon-btn:last-child) {
  margin-right: calc(var(--size-icon-inset) * -1);
}

.name-edit {
  display: grid;
  gap: var(--space-3);
}

.name-edit__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* =====================================================================
   23. Ingredient rows: view (name, amount, kcal, macro chips) and edit (fields + delete)
   Same insets as list rows, so text starts on the card-inset line in both modes.
   ===================================================================== */
.ingredients {
  display: grid;
  margin: 0;
  padding: var(--space-1);
  list-style: none;
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
}

.ingredient {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-1) var(--space-3);
  align-items: baseline;
  padding: var(--space-2) calc(var(--space-card-inset) - var(--space-1));
  border-radius: var(--radius-md);
}

.ingredient + .ingredient::before {
  content: "";
  position: absolute;
  top: 0;
  right: var(--space-3);
  left: var(--space-3);
  border-top: var(--border-width-hairline) solid var(--color-border-subtle);
}

.ingredient__name {
  display: block;
  font: var(--type-body-strong);
  overflow-wrap: anywhere;
}

.ingredient__amount {
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.ingredient__kcal {
  font: var(--type-num-m);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.ingredient__kcal small {
  display: block;
  font: var(--type-caption);
  color: var(--color-text-secondary);
}

.ingredient__wide {
  grid-column: 1 / -1;
}

.ingredient--edit {
  gap: var(--space-2) var(--space-3);
  align-items: start;
  padding-block: var(--space-3);
  background: var(--color-bg-canvas);
}

.ingredient--edit > .icon-btn {
  align-self: end;
  margin-right: calc(var(--size-icon-inset) * -1);
  margin-bottom: calc((var(--size-input) - var(--size-touch-min)) / 2);
}

/* Amount and unit share the row with the delete button; they stack at large text sizes */
.ingredient__fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--size-col-min)), 1fr));
  gap: var(--space-3);
}

.ingredient.is-error {
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-error);
}

/* Meal-type icon in an empty meal row: passive, muted but legible (not a button) */
.product__thumb--meal {
  pointer-events: none;
}

/* Ingredients in the Nutrition Facts look: no own surface, rows ruled like table rows */
.ingredients--facts {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  background: none;
  border-radius: 0;
  box-shadow: none;
  font: var(--type-callout);
}

.ingredients--facts > .ingredient {
  border-radius: 0;
}

.ingredients__head {
  display: flex;
  flex-wrap: wrap; /* 320 pt at 200 % text: "Amount" moves under "Ingredient", still on the right edge */
  justify-content: space-between;
  gap: 0 var(--space-3);
  margin-top: var(--space-3);
}

.ingredients__head > :last-child {
  margin-left: auto;
}

/* Servings row in the Ingredients card: a label + the weight stepper (06). It scales the ingredient list;
   the dish summary stays per portion. The same gap above it as above the header row */
.ingredients__servings {
  margin-top: var(--space-3);
}

.ingredients--facts .ingredient__name {
  font: var(--type-callout);
}

.ingredients--facts > .ingredient.ingredient--edit {
  margin-inline: calc(var(--space-3) * -1);
  padding: var(--space-3);
  border-radius: var(--radius-md);
}

.row-between:has(> .btn--ghost:last-child) {
  margin-right: calc(var(--space-3) * -1);
}

/* =====================================================================
   24. Recipe steps (Method): numbered steps in an ordered list, view and edit
   Number disc on the card-inset line, text in one column (≤ 80 characters, 16 / 1.5).
   ===================================================================== */
.recipe-steps {
  display: grid;
  margin: 0;
  padding: var(--space-1);
  list-style: none;
  background: var(--color-bg-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-e1);
}

.recipe-step {
  position: relative;
  display: grid;
  grid-template-columns: var(--size-step-number) minmax(0, 1fr);
  gap: var(--space-2) var(--space-3);
  align-items: start;
  padding: var(--space-3) calc(var(--space-card-inset) - var(--space-1));
  border-radius: var(--radius-md);
}

.recipe-step + .recipe-step::before {
  content: "";
  position: absolute;
  top: 0;
  right: var(--space-3);
  left: var(--space-3);
  border-top: var(--border-width-hairline) solid var(--color-border-subtle);
}

.recipe-step__num {
  display: grid;
  place-items: center;
  width: var(--size-step-number);
  height: var(--size-step-number);
  border-radius: var(--radius-full);
  background: var(--color-bg-accent-subtle);
  font: var(--type-label);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-primary);
}

.recipe-step__text {
  max-width: var(--size-measure);
  margin: 0;
  font: var(--type-body);
  text-align: left;
  overflow-wrap: anywhere;
}

.recipe-step--edit {
  background: var(--color-bg-canvas);
}

.recipe-step__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  grid-column: 2;
  margin-right: calc(var(--size-icon-inset) * -1);
}

.recipe-step.is-error {
  box-shadow: inset 0 0 0 var(--border-width-focus) var(--color-border-error);
}

/* =====================================================================
   25. Step indicator (onboarding progress): the text is always shown, the bar repeats it
   ===================================================================== */
.progress {
  display: grid;
  gap: var(--space-2);
}

.progress__text {
  margin: 0;
  font: var(--type-label);
  color: var(--color-text-secondary);
}

.progress__bar {
  display: flex;
  gap: var(--space-1);
}

/* upcoming · done · current: done and current fill, current is the last filled one (the text says which) */
.progress__seg {
  flex: 1 1 0;
  height: var(--space-1);
  border-radius: var(--radius-full);
  background: var(--color-macro-track);
}

.progress__seg.is-done,
.progress__seg.is-current {
  background: var(--color-bg-accent);
}

/* =====================================================================
   26. Option card: a native radio or checkbox in a card with a title and a description
   ===================================================================== */
.option-group {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.option-group__legend {
  margin-bottom: var(--space-2);
  padding: 0;
  font: var(--type-title);
}

.option-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--size-icon-l);
  align-items: center;
  gap: var(--space-3);
  min-height: var(--size-touch-min);
  padding: var(--space-3) var(--space-card-inset);
  border-radius: var(--radius-md);
  background: var(--color-bg-surface);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong);
  cursor: pointer;
}

.option-card__body {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.option-card__title {
  font: var(--type-body-strong);
  color: var(--color-text-primary);
  overflow-wrap: anywhere;
}

.option-card__desc {
  font: var(--type-callout);
  color: var(--color-text-secondary);
}

/* The mark: a ring (radio) or a rounded square (checkbox); the check shows only when selected */
.option-card__mark {
  display: grid;
  place-items: center;
  width: var(--size-icon-l);
  height: var(--size-icon-l);
  border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-strong);
  color: var(--color-text-on-accent);
}

.option-card--check .option-card__mark {
  border-radius: var(--radius-xs);
}

.option-card__mark .icon {
  width: var(--size-icon-s);
  height: var(--size-icon-s);
  visibility: hidden;
}

.option-card:active,
.option-card.is-pressed {
  background: var(--color-bg-pressed);
}

.option-card:has(input:checked),
.option-card.is-selected {
  background: var(--color-bg-accent-subtle);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-accent);
}

/* Focus: a 2 px ring drawn just inside the card edge (it never leaves the group); the padding is the gap to the text */
.option-card:has(input:focus-visible),
.option-card.is-focus {
  outline: var(--border-width-focus) solid var(--color-border-focus);
  outline-offset: calc(var(--border-width-focus) * -1);
}

.option-card:has(input:disabled),
.option-card.is-disabled {
  background: var(--color-bg-surface);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-subtle);
  cursor: not-allowed;
}

/* Error: the group needs an answer. The message names the fix; the cards get the error border */
.option-group.is-error .option-card {
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-error);
}

.option-group__error {
  display: flex;
  align-items: center;
  gap: var(--space-inline-icon);
  margin: 0;
  font: var(--type-callout);
  color: var(--color-status-error-text);
}

/* =====================================================================
   27. Week strip (Diary): 7 day buttons, each a weekday, a date in a mini ring and a short note
   ===================================================================== */

/* One row of 7 at 100 % text (cells ≥ 44); at large text the cells grow with the text and the strip
   reflows to two rows instead of clipping. 7 × 44 don't fit 280 pt: use the margins, never shrink targets */
.week {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(var(--size-touch-min), 3.4em), 1fr));
  margin-inline: max(calc(var(--space-4) * -1), min(0%, calc((100% - 7 * var(--size-touch-min)) / 2)));
  font: var(--type-caption);
}

.week__day {
  position: relative;
  display: grid;
  justify-items: center;
  align-content: start;
  gap: var(--space-1);
  min-width: var(--size-touch-min);
  padding: var(--space-2) 0;
  border-radius: var(--radius-md);
  color: var(--color-text-primary);
}

.week__dow {
  font: var(--type-caption);
  color: var(--color-text-secondary);
}

.week__ring {
  position: relative;
  display: grid;
  place-items: center;
  width: max(var(--size-day-ring), 2.4em);
  height: max(var(--size-day-ring), 2.4em);
  font: var(--type-num-s);
}

.week__ring svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.week__track,
.week__value {
  fill: none;
  stroke-width: 3;
}

.week__track {
  stroke: var(--color-macro-track);
}

.week__value {
  stroke: var(--color-macro-kcal);
  stroke-linecap: round;
}

.week__date {
  font: var(--type-num-s);
  font-variant-numeric: tabular-nums;
}

/* The note under the ring: "Today", or "+45" on a day over the goal (a number, never colour alone) */
.week__note {
  min-height: calc(var(--type-caption-size) * var(--type-caption-line));
  font: var(--type-caption);
  color: var(--color-text-secondary);
}

.week__day:active,
.week__day.is-pressed {
  background: var(--color-bg-pressed);
}

.week__day[aria-pressed="true"],
.week__day.is-selected {
  background: var(--color-bg-accent-subtle);
  box-shadow: inset 0 0 0 var(--border-width-default) var(--color-border-accent);
}

.week__day[aria-current="date"] .week__date,
.week__day[aria-current="date"] .week__note {
  font-weight: var(--font-weight-bold);
  color: var(--color-text-primary);
}

.week__day.is-over .week__value {
  stroke: var(--color-status-warning);
}

.week__day.is-over .week__note {
  font-weight: var(--font-weight-bold);
  color: var(--color-status-warning-text);
}

/* Empty day: nothing logged, the track is shown dashed */
.week__day.is-empty .week__track {
  stroke-dasharray: 3 3;
}

.week__day:disabled,
.week__day.is-disabled {
  color: var(--color-text-disabled);
  cursor: not-allowed;
}

.week__day:disabled .week__dow,
.week__day.is-disabled .week__dow {
  color: var(--color-text-disabled);
}

/* Focus: drawn inside the day (the strip has no room around it); the padding is the gap to the content */
.week__day:focus-visible,
.week__day.is-focus {
  outline: var(--border-width-focus) solid var(--color-border-focus);
  outline-offset: calc(var(--border-width-focus) * -1);
}

/* =====================================================================
   State overrides for descendants. Kept last so higher-specificity state
   selectors never precede generic ones (stylelint no-descending-specificity).
   ===================================================================== */
.field.is-disabled .field__control input,
.field.is-disabled .field__label,
.field.is-disabled .field__suffix {
  color: var(--color-text-disabled);
}

.stepper.is-disabled .stepper__btn,
.stepper.is-disabled small {
  color: var(--color-text-disabled);
}

.product--detected .marker {
  margin-top: var(--space-1);
}

.nutri--over .nutri__center small {
  color: var(--color-status-warning-text);
  font-weight: var(--font-weight-semibold);
}

.product.is-disabled .product__name,
.product.is-disabled .product__kcal,
.product.is-disabled .product__kcal small {
  color: var(--color-text-disabled);
}

.recipe-step:is(.recipe-step--edit, .is-error)::before,
.recipe-step:is(.recipe-step--edit, .is-error) + .recipe-step::before {
  visibility: hidden;
}

.recipe-step__actions .icon-btn:focus-visible,
.recipe-step__actions .icon-btn.is-focus,
.ingredient--edit > .icon-btn:focus-visible,
.ingredient--edit > .icon-btn.is-focus {
  outline-offset: calc(var(--border-width-focus) * -1);
}

.ingredient.is-error > .field__help {
  color: var(--color-status-error-text);
}

.ingredients--facts > .ingredient::before,
.ingredient:is(.ingredient--edit, .is-error)::before,
.ingredient:is(.ingredient--edit, .is-error) + .ingredient::before {
  visibility: hidden;
}

.tab[aria-current="page"] .icon,
.tab.is-active .icon {
  fill: var(--color-bg-accent-subtle);
}

/* Nutrition Facts rows, shared with the Ingredients card (one definition for both) */
.facts td,
.ingredients--facts > .ingredient {
  padding: var(--space-2) 0;
  border-bottom: var(--border-width-hairline) solid var(--color-border-subtle);
}

.facts td + td,
.ingredients--facts .ingredient__amount,
.ingredients--facts .ingredient__kcal {
  padding-left: var(--space-3);
  white-space: nowrap; /* a number never breaks; the name column wraps instead */
  font: var(--type-num-s);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.facts tr.is-energy td {
  border-bottom: var(--border-width-rule) solid var(--color-text-primary);
  font: var(--type-body-strong);
}

.facts tr.is-energy td + td {
  font: var(--type-num-m);
  font-weight: var(--font-weight-semibold);
}

.facts tr.is-sub td:first-child {
  padding-left: var(--space-4);
  color: var(--color-text-secondary);
}

.product--chips > .product__end {
  grid-row: 1 / span 2;
  grid-column: 3;
  align-self: center;
}

/* Settings rows (Profile): a plain chevron button at the row end puts its glyph on the inset line */
.product--nav > .product__end > .icon-btn:last-child {
  margin-right: calc(var(--size-icon-inset) * -1);
}

/* Option card (26): the mark fills and shows its check when selected; disabled text */
.option-card.is-selected .option-card__mark {
  background: var(--color-bg-accent);
  box-shadow: none;
}

.option-card:has(input:checked) .option-card__mark {
  background: var(--color-bg-accent);
  box-shadow: none;
}

.option-card.is-selected .option-card__mark .icon {
  visibility: visible;
}

.option-card:has(input:checked) .option-card__mark .icon {
  visibility: visible;
}

.option-card.is-disabled .option-card__title,
.option-card.is-disabled .option-card__desc {
  color: var(--color-text-disabled);
}

.option-card:has(input:disabled) .option-card__title,
.option-card:has(input:disabled) .option-card__desc {
  color: var(--color-text-disabled);
}

/* =====================================================================
   Reduced motion (WCAG 2.3.3). Durations are already 0 via tokens.css; also drop movement.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  .sheet,
  .toast,
  .skeleton {
    animation: none;
  }

  .btn:active,
  .btn.is-pressed,
  .recipe-card:active,
  .recipe-card.is-pressed {
    transform: none;
  }
}

/* =====================================================================
   Forced colours (Windows High Contrast). box-shadow is removed by the browser in this mode,
   so every boundary, selection and focus ring gets a real outline in system colours.
   ===================================================================== */
@media (forced-colors: active) {
  .field__control,
  .search,
  .stepper,
  .chip,
  .segmented,
  .list,
  .recipe-card,
  .nutri,
  .facts,
  .sheet,
  .toast,
  .tab-bar,
  .btn,
  .icon-btn--surface,
  .icon-btn--tint,
  .icon-btn--accent,
  .tab__fab,
  .badge,
  .macro-tile,
  .macro__bar,
  .banner,
  .card,
  .skeleton,
  .viewfinder__tip,
  .viewfinder__hint,
  .shutter,
  .chip--locked,
  .ingredients,
  .recipe-steps,
  .recipe-step__num,
  .macro-tile--chip {
    outline: var(--border-width-hairline) solid canvastext;
    outline-offset: calc(var(--border-width-hairline) * -1);
  }

  .segmented__opt:has(input:checked),
  .segmented__opt.is-selected,
  .chip.is-selected,
  .chip[aria-pressed="true"],
  .product.is-selected,
  .product.is-check,
  .ingredient.is-error,
  .recipe-step.is-error,
  .product.is-error,
  .field.is-error .field__control,
  .stepper.is-error,
  .search.is-error {
    outline: var(--border-width-focus) solid canvastext;
    outline-offset: calc(var(--border-width-focus) * -1);
  }

  :focus-visible,
  .is-focus,
  .segmented__opt.is-focus,
  .segmented__opt:has(input:focus-visible),
  .tab--scan:focus-visible .tab__fab,
  .tab--scan.is-focus .tab__fab {
    outline: var(--border-width-focus) solid highlight;
    outline-offset: var(--border-width-focus-gap);
  }

  .field .field__control:focus-within,
  .search:focus-within,
  .stepper:focus-within,
  .stepper.is-focus,
  .tab:focus-visible,
  .tab.is-focus,
  .date-btn:focus-visible,
  .product:focus-visible,
  .product.is-focus {
    outline: var(--border-width-focus) solid highlight;
    outline-offset: calc(var(--border-width-focus) * -1);
  }

  .macro .macro__bar > i,
  .sheet__handle {
    forced-color-adjust: none;
    background: highlight;
  }

  .nutri__ring svg {
    forced-color-adjust: none;
  }

  .nutri__track {
    stroke: graytext;
  }

  .nutri .nutri__value {
    stroke: highlight;
  }

  .tab[aria-current="page"] span,
  .tab.is-active span {
    text-decoration-color: highlight;
  }
}

/* Compact recipe card: the photo fills the image column from the top to the bottom padding */
.recipe-card--compact .recipe-card__img > img {
  position: absolute;
  inset: 0;
  object-position: center;
}

/* View row, two lines: name | amount, then P / F / C chips | kcal. The right column ends on one edge */
.ingredients--facts > .ingredient:not(.ingredient--edit) {
  row-gap: var(--space-2);
}
