/* ============================================================
   the tour
   ============================================================
   A hole, not an overlay with a gap in it. The dim is a single enormous
   box-shadow spreading outwards from the lit rectangle, which means
   there is exactly one element to position and the dimming can never
   drift out of register with the hole it is dimming around. */
#tourHost { position: fixed; inset: 0; z-index: 90; }

.tour-hole {
  position: absolute; border-radius: var(--r-lg);
  box-shadow: 0 0 0 9999px rgba(4, 20, 17, .62);
  /* The card underneath stays visible AND stays untappable: the tour
     owns every tap until it is dismissed, or somebody half-reading it
     logs a glass of water they did not drink. */
  pointer-events: none;
  transition: top .28s var(--ease), inset-inline-start .28s var(--ease),
              width .28s var(--ease), height .28s var(--ease);
}

.tour-card {
  /* Off-screen until paintTour() measures it and puts it somewhere. */
  position: absolute; inset-inline: 14px; top: -9999px;
  max-width: 560px; margin-inline: auto;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-lift);
  border-radius: var(--r-lg);
  padding: var(--pad-card);
}
.tour-step {
  margin: 0 0 var(--pair-y); font-size: .72rem; font-weight: 600;
  letter-spacing: .06em; color: var(--text-mute);
  font-variant-numeric: tabular-nums;
}
.tour-text { margin: 0; font-size: .95rem; line-height: 1.5; }
.tour-acts {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 14px;
}
.tour-acts .tour-next { width: auto; padding-inline: 22px; }

/* The tab bar sits above everything so a step can point at it, but the
   tour is above that — otherwise the last step dims the thing it is
   asking somebody to look at. */
html.touring .tabbar { z-index: 80; }
html.touring { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .tour-hole { transition: none; }
}

/* ---------- what you stayed away from, at the end of the day ---------- */
.avoid-open {
  min-block-size: 44px;
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 0 0; border: none; background: none;
  font: inherit; color: var(--text); text-align: start; cursor: pointer;
}
.avoid-dots { display: flex; gap: 5px; flex: 0 0 auto; }
.avoid-dot {
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--sunk-ink); color: var(--text-mute);
  border: 1px solid var(--edge);
}
.avoid-dot.on {
  background: color-mix(in srgb, var(--c) 16%, transparent);
  border-color: color-mix(in srgb, var(--c) 40%, transparent);
  color: var(--ci);
}
.avoid-say { flex: 1; min-width: 0; font-size: .82rem; color: var(--text-dim); }
.card.avoid-row.asking .avoid-say { color: var(--accent-ink); font-weight: 600; }
.avoid-open .menu-chev { flex: 0 0 auto; color: var(--text-mute); display: grid; place-items: center; }
.avoid-open .menu-chev svg { width: 18px; height: 18px; }

/* ---------- focus ----------
   Four rules covered four controls and everything else fell back to the
   browser's own ring, which is undefined on iOS with a keyboard and
   gets clipped by the overflow:hidden on the tab bar, the light-day art
   and the horizontal scrollers. One rule, on the accent ink rather than
   the accent, because the ink measures 6.09:1 in light against the
   accent's 3.01 and the ring has to be seen. */
:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
  border-radius: inherit;
}

/* Two things this one rule could not do by itself.

   An outline sitting 2px OUTSIDE a full-bleed row is drawn outside its
   container, and .card.menu, the two shopping lists and the eating-out
   rows all clip their overflow — so on those four the ring was there
   and invisible. A box-shadow is painted by the element, inside the
   clip, so it survives. Same 2px, same ink.

   And `border-radius: inherit` inherits the PARENT's radius, not the
   element's own. On a round control whose parent is square that
   resolves to 0 and the ring is drawn as a box around a circle. */
.card.menu :focus-visible,
.shop-items :focus-visible,
.eo-row:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent-ink);
}

.stepper:focus-visible,
.goal-dial:focus-visible,
.live-btn:focus-visible,
.icon-btn:focus-visible,
.chat-mic:focus-visible,
.chat-send:focus-visible,
.icon-corner:focus-visible { border-radius: 50%; }

.chip-btn:focus-visible,
.take-btn:focus-visible,
.pill:focus-visible { border-radius: 999px; }

/* A button keeps its own corners when it is focused. `inherit` above took
   the parent's radius, so a focused .btn in a sheet turned into a square
   with a ring round it — the update sheet's Install button. */
.btn:focus-visible { border-radius: 15px; }

/* A sheet takes focus when it opens so it is announced as the dialog it
   is — not because somebody tabbed to it — so it draws no ring. And the
   rule above gave it its parent's radius: the backdrop is square, so a
   focused sheet lost its rounded top and became a box. The sheet floats
   now (09-glass.css), rounded all the way round — and this rule, still
   squaring the bottom, did it to every sheet, since every sheet takes
   focus as it opens. */
.sheet:focus, .sheet:focus-visible { outline: none; border-radius: var(--r-sheet); }
.btn.sm:focus-visible { border-radius: 13px; }
/* The composer removes its own outline so the ring can sit on the whole
   composer rather than the bare textarea inside it. */
.chat-composer:focus-within { outline: 2px solid var(--accent-ink); outline-offset: 2px; }

/* Three ways of looking back, on one line, each an icon over its words.
   The month is hidden for now — see views-progress.js. Three is also
   what gives the rest enough width to say what they are: at four
   columns "Health snapshot" wrapped.

   Same fill and same hairline as the tiles above them: these had a
   darker edge of their own for a while, which met the 3:1 that WCAG
   asks of a control boundary and looked like a different app. */
.lookback {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 12px;
}
.lb {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px; min-height: 64px; padding: 9px 4px; cursor: pointer;
  border: 1px solid var(--hairline-dim); border-radius: var(--r-md);
  background: var(--glass-sunk); color: var(--text-dim);
  font: inherit; font-size: 11.5px; line-height: 1.2; text-align: center;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.lb svg { width: 18px; height: 18px; flex: none; color: var(--accent-ink); }
.lb > span { display: block; overflow-wrap: anywhere; }
button.lb:hover { color: var(--text); }
button.lb:active { transform: scale(.97); }

@media (prefers-reduced-motion: reduce) { button.lb:active { transform: none; } }

/* ---------- this was you ---------- */
.eff-since { font-size: .72rem; color: var(--text-mute); font-weight: 500; }
.eff-intro { margin: 2px 0 0; }
/* A bento rather than a list of sentences. Eight lines each reading
   "You ate 95 meals from your plan" is a paragraph pretending to be
   data: the eye has to walk the whole sentence to reach the number,
   eight times. As cells the numbers line up in two columns and can be
   read down. */
.eff-bento {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px;
}
.eff-cell {
  display: grid; gap: 2px; align-content: start;
  padding: 14px 14px 15px; border-radius: var(--r-md);
  background: var(--glass-sunk); border: 1px solid var(--hairline-dim);
}
/* The odd one out, and the outcome. Nothing about a wide cell changes
   except how much room it has. */
.eff-cell.wide { grid-column: 1 / -1; }
.eff-ico {
  width: 30px; height: 30px; border-radius: 50%; margin-bottom: 6px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-ink);
}
.eff-n {
  font-size: 1.3rem; font-weight: 750; line-height: 1.15;
  letter-spacing: -.02em; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.eff-cap { font-size: .78rem; line-height: 1.35; color: var(--text-mute); }

/* The effort adds up to this one. It is the full stop, so it gets the
   width and the colour and nothing else. */
.eff-cell.outcome {
  background: color-mix(in srgb, var(--ds-good) 9%, transparent);
  border-color: color-mix(in srgb, var(--ds-good) 22%, transparent);
}
.eff-cell.outcome { position: relative; overflow: hidden; }
.eff-cell.outcome .eff-ico { background: color-mix(in srgb, var(--ds-good) 15%, transparent); color: var(--ds-good); }
.eff-cell.outcome .eff-n { color: var(--ds-good); font-size: 1.6rem; }
/* The figure, its caption and its icon all sit above the drawing. */
.eff-cell.outcome .eff-ico,
.eff-cell.outcome .eff-n,
.eff-cell.outcome .eff-cap { position: relative; z-index: 1; }

/* ---------- the scale behind the kilos ----------

   A render of the thing the number came off, on the side of the cell
   the words leave empty.

   Sized off the cell's own height, with the image's own ratio and
   object-fit so it is never stretched. Placed with a logical inset, so
   it swaps sides in Arabic without being mirrored — a scale is the
   same object either way round, and flipping it would only put the
   needle on the wrong side.

   The cell already has overflow:hidden and a radius, so if it ever
   gets shorter than the drawing the card crops it cleanly rather than
   letting it escape a corner. */
.eff-art {
  position: absolute; inset-block: 10px; inset-inline-end: 14px;
  block-size: calc(100% - 20px); inline-size: auto;
  aspect-ratio: 320 / 288; object-fit: contain;
  pointer-events: none; z-index: 0;
  opacity: .9;
}
/* The body of the scale is white, which on a near-black card is a
   bright cut-out rather than an object sitting on it. Taken down and
   warmed slightly so it belongs to the card it is on. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .eff-art { opacity: .5; }
}
:root[data-theme="dark"] .eff-art { opacity: .5; }

/* Narrow enough that the words would run into the drawing. */
@media (max-width: 359px) { .eff-art { display: none; } }

/* ---------- scans over time ---------- */
/* No border of its own. The reading above it is a .kv, which draws a
   bottom rule unless it is the last child — and it is not, because this
   block follows it. Two rules, twelve pixels apart. The .kv's line is
   the separator; this only needs the room. */
.scan-trend { margin-top: 22px; }
.st-head { font-size: .72rem; letter-spacing: .04em; text-transform: uppercase; color: var(--text-mute); font-weight: 600; }
.st-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-top: 8px; }
.st-k { font-size: .9rem; color: var(--text-dim); }
.st-v { font-weight: 600; font-variant-numeric: tabular-nums; }
.st-v small { color: var(--text-mute); font-weight: 500; }
.st-v.good { color: var(--ds-good); }
.st-v.bad { color: var(--ds-bad); }
.st-v i { font-style: normal; }
.scan-list { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.scan-item { padding: 12px 14px; border-radius: var(--r-sm); background: var(--sunk-ink); border: 1px solid var(--edge); }
.scan-when { display: flex; align-items: center; gap: 8px; }
.scan-vals { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 4px; font-size: .88rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.scan-acts { display: flex; gap: 16px; margin-top: 8px; }
.badge.sm { font-size: .66rem; padding: 2px 7px; }
.link-btn.danger { color: var(--danger-ink); }

/* ---------- how much of it ---------- */
.p-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 14px; }
.p-tile {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 14px 4px 12px; border-radius: var(--r-sm);
  background: var(--sunk-ink); border: 1px solid var(--edge);
  color: inherit; font: inherit; cursor: pointer;
}
.p-tile:active { transform: scale(.97); }
/* One bowl, filled to --f. The size of the meal is the thing being
   asked about, so the drawing is the thing that differs. */
.p-bowl {
  position: relative; width: 34px; height: 26px; overflow: hidden;
  border: 2px solid var(--text-mute); border-top: 0;
  border-radius: 0 0 16px 16px;
}
.p-bowl i {
  position: absolute; inset-inline: 0; bottom: 0;
  height: calc(var(--f) * 100%); background: var(--accent); opacity: .85;
}
.p-name { font-size: .78rem; font-weight: 500; color: var(--text-dim); }
.ctx-link { display: block; width: 100%; text-align: center; margin-top: 10px; padding: 6px; color: var(--text-mute); font-weight: 500; }

.med-why { font-size: .84rem; color: var(--text-dim); margin-top: var(--say-y); line-height: 1.45; }
.med-whyask { font-size: .82rem; margin-top: 4px; padding: 0; }

/* ---------- onboarding: where the questions stop being required ---------- */
.onb-optional {
  display: inline-block; margin-bottom: 8px; padding: 3px 9px;
  border-radius: 999px; background: var(--sunk-ink); border: 1px solid var(--edge);
  font-size: .68rem; letter-spacing: .04em; text-transform: uppercase;
  font-weight: 600; color: var(--text-mute);
}
/* A figure the app did not work out is not shown as a figure. */
.kcal-tag.unknown { opacity: .55; font-weight: 600; }
.meal-noitems { margin: 0 0 4px; }

/* ---------- what the assistant wrote down ---------- */
.card.aipend { border: 1px solid color-mix(in srgb, var(--warn) 40%, var(--edge)); }
.aip-list { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }
.aip-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 0; border-top: 1px solid var(--edge); }
.aip-row:first-child { border-top: 0; }
.aip-what { display: flex; flex-direction: column; gap: var(--pair-y); }
.aip-what small { color: var(--text-mute); font-size: .76rem; }
.aip-acts { display: flex; gap: 14px; flex: none; }

/* ---------- one thing ---------- */
.fc-head { font-size: 1.15rem; font-weight: 600; line-height: 1.35; margin: 10px 0 0; }
.fc-tip {
  margin-top: 14px; padding: 14px; border-radius: var(--r-sm);
  background: var(--accent-wash); border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
}
.fc-tip span { display: block; font-size: .7rem; letter-spacing: .05em; text-transform: uppercase; font-weight: 600; color: var(--accent-ink); }
.fc-tip b { display: block; margin-top: 5px; font-size: .98rem; line-height: 1.5; }

/* ---------- the quick view ---------- */
.quick-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; padding: 8px 2px 14px;
}
/* The text takes the room and the button takes what it needs. .btn is
   full-width everywhere else in the app, which is right in a sheet and
   wrong beside a heading. */
.quick-head > div { flex: 1 1 auto; min-width: 0; }
.quick-head h2 { margin: 0 0 3px; font-size: 1.5rem; }
.quick-head .btn { flex: 0 0 auto; width: auto; padding: 8px 16px; }
/* A medication somebody has stopped is history, not a task. */
.med-manage.stopped { opacity: .6; }
.med-manage.stopped .med-name { text-decoration: line-through; }

/* ---------- the number, when it cannot wait ---------- */
.btn.emergency {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin-top: 12px; text-decoration: none;
  background: var(--danger); color: #fff; border: 0; font-weight: 600;
}
.btn.emergency svg { flex: none; }

/* The build, at the foot of About. Small on purpose: it is there to be
   found when somebody asks "did the update land", not to be read daily. */
.build-tag {
  margin: 4px 4px 0; text-align: center;
  font-size: .68rem; color: var(--text-mute);
  font-variant-numeric: tabular-nums;
}

/* Typing a promo code. Monospaced and tracked out because it is read off
   a screen and typed by hand, and because the alphabet it comes from
   leaves out the characters that get confused — see codes-schema.sql. */
.row-inline { display: flex; gap: 8px; align-items: center; }
.code-in {
  flex: 1; min-width: 0;
  font: inherit; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .95rem; letter-spacing: .08em; text-transform: uppercase;
  padding: 11px 13px; border-radius: var(--r-sm, 12px);
  background: var(--glass-sunk); border: 1px solid var(--hairline);
  color: var(--text);
}
.code-in::placeholder { letter-spacing: .08em; color: var(--text-mute); }
.row-inline .btn { width: auto; flex: 0 0 auto; padding: 11px 16px; }

/* ---------- a new APK is ready ---------- */
.apk-offer { text-align: center; }
.apk-offer-logo { inline-size: 64px; block-size: 64px; object-fit: contain; margin: 4px auto 12px; display: block; }
.apk-offer .note { margin: 6px auto 16px; max-inline-size: 32ch; }

/* ---------- the liver in 3D ----------
   A full-screen viewer that follows the app's theme: a soft pale studio
   in light, a dark stage in dark. Its colours are local tokens, set once
   per theme the same three ways as :root's (light, dark by the system,
   dark by choice), so the rules below never name a colour. */
.liver-3d-btn {
  position: absolute; inset-block-end: 6px; inset-inline-start: 2px; z-index: 2;
  display: inline-flex; align-items: center; gap: 5px; block-size: 32px; padding: 0 11px;
  border-radius: 999px; border: 1px solid var(--hairline); cursor: pointer;
  background: var(--glass-strong); color: var(--accent-ink);
  font: inherit; font-size: .8rem; font-weight: 700; box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
.liver-3d-btn::after { content: ''; position: absolute; inset: -6px; }
.liver-stage .liver-3d-btn svg { inline-size: 16px; block-size: 16px; flex: none; }
html.l3d-open, html.l3d-open body { overflow: hidden; }
.l3d {
  --l3d-stage: radial-gradient(120% 70% at 50% 35%, #ffffff 0%, #eef3f1 58%, #dce5e2 100%);
  --l3d-ink: #0f1a17;
  --l3d-dim: #4f5f5a;
  --l3d-soft: rgba(15,26,23,.06);
  --l3d-line: rgba(15,26,23,.12);
  --l3d-panel: rgba(255,255,255,.8);
  --l3d-label: #0f1a17;
  --l3d-halo: 0 0 2px #fff, 0 0 6px rgba(255,255,255,.95), 0 1px 2px rgba(255,255,255,.9);
  --l3d-dot-ring: rgba(255,255,255,.9);
  --l3d-thumb: #ffffff;
  --l3d-thumb-shadow: 0 0 0 1px rgba(15,26,23,.14), 0 2px 8px rgba(15,26,23,.25);
  --l3d-tick: rgba(15,26,23,.35);
  --l3d-mine: #0b6b62;
  --l3d-on-mine: #ffffff;
  position: fixed; inset: 0; z-index: 90; display: flex; flex-direction: column;
  background: var(--l3d-stage);
  color: var(--l3d-ink); padding-top: env(safe-area-inset-top);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .l3d {
    --l3d-stage: radial-gradient(120% 70% at 50% 35%, #1d2a27 0%, #0d1413 60%, #070b0a 100%);
    --l3d-ink: #eef5f2;
    --l3d-dim: rgba(231,239,236,.8);
    --l3d-soft: rgba(255,255,255,.08);
    --l3d-line: rgba(255,255,255,.12);
    --l3d-panel: rgba(8,12,11,.72);
    --l3d-label: #f2f7f5;
    --l3d-halo: 0 1px 3px rgba(0,0,0,.9);
    --l3d-dot-ring: rgba(0,0,0,.45);
    --l3d-thumb: #f4f9f7;
    --l3d-thumb-shadow: 0 2px 8px rgba(0,0,0,.5);
    --l3d-tick: rgba(238,245,242,.45);
    --l3d-mine: #9df3cf;
    --l3d-on-mine: #0d1413;
  }
}
:root[data-theme="dark"] .l3d {
  --l3d-stage: radial-gradient(120% 70% at 50% 35%, #1d2a27 0%, #0d1413 60%, #070b0a 100%);
  --l3d-ink: #eef5f2;
  --l3d-dim: rgba(231,239,236,.8);
  --l3d-soft: rgba(255,255,255,.08);
  --l3d-line: rgba(255,255,255,.12);
  --l3d-panel: rgba(8,12,11,.72);
  --l3d-label: #f2f7f5;
  --l3d-halo: 0 1px 3px rgba(0,0,0,.9);
  --l3d-dot-ring: rgba(0,0,0,.45);
  --l3d-thumb: #f4f9f7;
  --l3d-thumb-shadow: 0 2px 8px rgba(0,0,0,.5);
  --l3d-tick: rgba(238,245,242,.45);
  --l3d-mine: #9df3cf;
  --l3d-on-mine: #0d1413;
}
.l3d-top { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px 0; }
.l3d-top h3 { margin: 0; font-size: 1.08rem; font-weight: 600; }
.l3d-x {
  inline-size: 44px; block-size: 44px; border-radius: 50%; border: none; cursor: pointer;
  display: grid; place-items: center; color: var(--l3d-ink); background: var(--l3d-soft);
}
.l3d-view { position: relative; flex: 1; min-block-size: 0; }
.l3d-canvas { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; display: block; cursor: grab; }
.l3d-canvas:active { cursor: grabbing; }
.l3d-labels { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.l3d-label {
  position: absolute; inset-block-start: 0; inset-inline-start: 0; left: 0; right: auto;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-size: .72rem; font-weight: 600; color: var(--l3d-label);
  text-shadow: var(--l3d-halo); transition: opacity .2s;
}
.l3d-label { direction: ltr; }
.l3d-label.rev { flex-direction: row-reverse; }
.l3d-label i { flex: none; inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--l3d-label); box-shadow: 0 0 0 2px var(--l3d-dot-ring); margin-left: -3.5px; }
.l3d-label.rev i { margin-left: 0; margin-right: -3.5px; }
.l3d-label.hid { opacity: 0; }
.l3d-hint {
  position: absolute; inset-inline: 0; inset-block-end: 8px; margin: 0; text-align: center;
  font-size: .78rem; color: var(--l3d-dim); transition: opacity .4s;
}
.l3d-hint.gone { opacity: 0; }
.l3d-wait { position: absolute; inset: 0; display: grid; place-items: center; color: var(--l3d-dim); font-size: .9rem; }
.l3d-fail { position: absolute; inset: 0; display: grid; place-items: center; padding: 24px; text-align: center; color: var(--l3d-dim); }
.l3d-panel {
  padding: 12px 14px calc(14px + env(safe-area-inset-bottom));
  background: var(--l3d-panel); border-top: 1px solid var(--l3d-line);
  -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
}
.l3d-reset {
  position: absolute; inset-block-end: 10px; inset-inline-end: 12px;
  inline-size: 44px; block-size: 44px; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center; color: var(--l3d-ink);
  background: var(--l3d-soft); border: 1px solid var(--l3d-line);
}
.l3d-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-block-size: 40px; }
.l3d-name { margin: 0; font-size: 1.12rem; font-weight: 700; color: var(--l3d-ink); }
.l3d-mine {
  flex: none; min-block-size: 36px; padding: 0 14px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: .84rem; font-weight: 700; color: var(--l3d-on-mine);
  background: var(--l3d-mine); border: none;
}
.l3d-desc { margin: 4px 0 14px; min-block-size: 3em; font-size: .9rem; line-height: 1.5; color: var(--l3d-dim); }
/* One slider, its track tinted with the colour the liver has at each
   point along it; the stops are ticks, and the person's own liver is
   the mint mark above. The thumb's centre travels 14px in from each end,
   so the ticks and the mark are laid out on that same inset. */
.l3d-slide { --mine-f: 0; position: relative; padding-block-start: 12px; }
.l3d-slide input {
  -webkit-appearance: none; appearance: none; display: block; inline-size: 100%; block-size: 32px;
  margin: 0; background: transparent; cursor: pointer; position: relative; z-index: 1;
}
.l3d-slide input::-webkit-slider-runnable-track {
  block-size: 8px; border-radius: 999px;
  background: linear-gradient(to right, #5a1a12, #8c4a2a, #b27d3e, #d4ab55, #9b6a42, #7a5432);
}
.l3d-slide input::-moz-range-track {
  block-size: 8px; border-radius: 999px;
  background: linear-gradient(to right, #5a1a12, #8c4a2a, #b27d3e, #d4ab55, #9b6a42, #7a5432);
}
[dir="rtl"] .l3d-slide input::-webkit-slider-runnable-track { background: linear-gradient(to left, #5a1a12, #8c4a2a, #b27d3e, #d4ab55, #9b6a42, #7a5432); }
[dir="rtl"] .l3d-slide input::-moz-range-track { background: linear-gradient(to left, #5a1a12, #8c4a2a, #b27d3e, #d4ab55, #9b6a42, #7a5432); }
.l3d-slide input::-webkit-slider-thumb {
  -webkit-appearance: none; inline-size: 28px; block-size: 28px; margin-block-start: -10px; border-radius: 50%;
  background: var(--l3d-thumb); border: none; box-shadow: var(--l3d-thumb-shadow);
}
.l3d-slide input::-moz-range-thumb { inline-size: 28px; block-size: 28px; border-radius: 50%; background: var(--l3d-thumb); border: none; box-shadow: var(--l3d-thumb-shadow); }
.l3d-slide input:focus-visible { outline: none; }
.l3d-slide input:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 3px var(--l3d-thumb), 0 0 0 5px var(--l3d-mine); }
.l3d-slide input:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 3px var(--l3d-thumb), 0 0 0 5px var(--l3d-mine); }
.l3d-ticks { position: absolute; inset-inline: 14px; inset-block-start: 38px; block-size: 6px; pointer-events: none; }
.l3d-ticks i { position: absolute; inset-block-start: 0; inline-size: 2px; block-size: 6px; margin-inline-start: -1px; border-radius: 1px; background: var(--l3d-tick); }
.l3d-mark {
  position: absolute; inset-block-start: 2px; inset-inline-start: calc(14px + (100% - 28px) * var(--mine-f));
  inline-size: 0; block-size: 0; margin-inline-start: -6px;
  border-inline: 6px solid transparent; border-block-start: 8px solid var(--l3d-mine);
}
.l3d-ends { display: flex; justify-content: space-between; margin-block-start: 8px; font-size: .76rem; color: var(--l3d-dim); }
.l3d-note { margin: 10px 0 0; font-size: .72rem; color: var(--l3d-dim); }

/* Separate report sections remain readable at narrow widths and large text. */
.doc > .doc-intro { margin: 0 0 var(--pad-card); }
.doc-section > .doc-h:first-child { margin: 0 0 var(--say-y); }
.doc-section .doc-row { gap: var(--pair-x); }
.doc-section .doc-value { min-width: 0; white-space: normal; overflow-wrap: anywhere; }
.doc-section .doc-label { flex-shrink: 0; max-width: 45%; }
.doc > .doc-foot { margin: 0 0 var(--pad-card); padding: 0; border: 0; }
.metric-weight { cursor: default; }

/* ---------- your level, badges, and the Friday week card ----------
   motivate.js. Earned and not-yet differ by their icon (the badge's own,
   or a lock) and their words ("earned", or how to earn it) as well as
   their tint — never the colour alone. The accent is the brand teal;
   warm stays rare. */
.lv-rule { margin: 10px 0 0; font-size: .78rem; }
.bdg-list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 14px 8px; }
.bdg-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* A medal over its name, like a shelf of them. */
.bdg { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.bdg-txt { display: grid; gap: 2px; min-inline-size: 0; }
.bdg-txt b { font-size: .8rem; font-weight: 650; line-height: 1.25; }
.bdg-txt small { font-size: .7rem; color: var(--text-dim); line-height: 1.3; }
.bdg.off .bdg-txt b { color: var(--text-dim); }
/* A new one arrives with a small lift and a light passing over it. */
.bdg-new { grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); margin-bottom: 4px; }
.bdg-new .gmedal { animation: medalIn .6s var(--ease) both; }
.bdg-new .bdg:nth-child(2) .gmedal { animation-delay: .08s; }
.bdg-new .bdg:nth-child(3) .gmedal { animation-delay: .16s; }
@keyframes medalIn { from { transform: translateY(10px) scale(.86); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .bdg-new .gmedal { animation: none; } }
@media (max-width: 340px) { .bdg-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.weekcard { display: grid; gap: 12px; }
.wkc-row { display: flex; align-items: center; gap: 12px; }
.wkc-ico { flex: none; display: grid; place-items: center; inline-size: 40px; block-size: 40px; border-radius: 12px; background: var(--accent-wash); color: var(--accent-ink); }
.wkc-txt { display: grid; gap: 2px; }
.wkc-txt b { font-size: .98rem; }
.wkc-txt small { font-size: .8rem; color: var(--text-dim); }

/* ---------- clear-glass badges (medals.js) ---------- */
.gmedal {
  --gm: 72px; --gm-c: #087f78;
  position: relative; display: inline-grid; place-items: center; flex: none;
  inline-size: var(--gm); block-size: var(--gm);
}
.gm-glass {
  position: relative; display: grid; place-items: center; overflow: hidden; isolation: isolate;
  inline-size: 88%; block-size: 88%; border-radius: 50%;
  background:
    radial-gradient(95% 70% at 50% -12%, rgba(255,255,255,.82), transparent 74%),
    linear-gradient(155deg, rgba(255,255,255,.26), rgba(213,229,223,.12) 56%, rgba(109,145,132,.19));
  -webkit-backdrop-filter: blur(20px) saturate(155%);
  backdrop-filter: blur(20px) saturate(155%);
  box-shadow: inset 0 1px 1px rgba(255,255,255,.72), inset 0 -5px 9px rgba(21,71,59,.08),
    0 6px 12px -9px rgba(20,55,47,.25);
}
/* A narrow optical edge and a directional light, without a painted-on shine. */
.gm-glass::before {
  content: ''; position: absolute; z-index: 2; inset: 2% 8% 54%; border-radius: 50%;
  background: radial-gradient(ellipse at 50% 0, rgba(255,255,255,.72), transparent 74%);
  pointer-events: none;
}
.gm-glass::after {
  content: ''; position: absolute; z-index: 3; inset: 0; border: 1px solid rgba(255,255,255,.55);
  border-radius: inherit; box-shadow: inset 1px 1px 1px rgba(255,255,255,.34), inset -1px -1px 1px rgba(25,80,66,.08);
  pointer-events: none;
}
.gm-mark {
  position: relative; z-index: 1; inline-size: 46%; block-size: 46%;
  color: var(--gm-c); filter: drop-shadow(0 1px 1px rgba(255,255,255,.75));
}
.gmedal:has(.gm-num) .gm-mark { transform: translateY(-9%); }
.gm-num {
  position: absolute; z-index: 4; inset-block-end: 12%; left: 50%; transform: translateX(-50%);
  min-inline-size: 29%; padding: 1px 5px; border-radius: 999px; white-space: nowrap; text-align: center;
  font-size: calc(var(--gm) * .15); font-weight: 800; line-height: 1.35;
  /* The badge's own ink, a quarter of the way to the text colour: the
     figure is 11px text on the glass's lower tint, where the ink itself
     measured 3.5–3.9:1. Darker ink, not a chip — the glass stays clear. */
  color: color-mix(in srgb, var(--gm-c) 75%, var(--text));
}
.gm-lock {
  position: absolute; z-index: 5; inset-block-end: 0; inset-inline-end: 0;
  display: grid; place-items: center; inline-size: 24px; block-size: 24px; border-radius: 50%;
  color: #fff; background: #5e6c68; border: 2px solid var(--surface);   /* cut from the card it sits on */
}
.gmedal.locked .gm-glass { background: linear-gradient(155deg, rgba(255,255,255,.26), rgba(193,210,203,.18)); }
.gmedal.locked .gm-mark { color: #5d6c67; filter: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gm-glass { background: linear-gradient(155deg, rgba(255,255,255,.25), rgba(204,237,224,.11)); box-shadow: inset 0 1px 1px rgba(255,255,255,.35), inset 0 -5px 9px rgba(0,0,0,.13), 0 6px 12px -9px rgba(0,0,0,.5); }
  :root:not([data-theme="light"]) .gm-glass::before { background: radial-gradient(ellipse at 50% 0, rgba(255,255,255,.3), transparent 74%); }
  :root:not([data-theme="light"]) .gm-mark, :root:not([data-theme="light"]) .gm-num { color: #e5fff5; filter: none; }
  :root:not([data-theme="light"]) .gmedal.locked .gm-glass { background: linear-gradient(155deg, rgba(220,240,231,.17), rgba(172,205,192,.08)); }
  :root:not([data-theme="light"]) .gmedal.locked .gm-mark { color: #d7e1dc; }
}
:root[data-theme="dark"] .gm-glass { background: linear-gradient(155deg, rgba(255,255,255,.25), rgba(204,237,224,.11)); box-shadow: inset 0 1px 1px rgba(255,255,255,.35), inset 0 -5px 9px rgba(0,0,0,.13), 0 6px 12px -9px rgba(0,0,0,.5); }
:root[data-theme="dark"] .gm-glass::before { background: radial-gradient(ellipse at 50% 0, rgba(255,255,255,.3), transparent 74%); }
:root[data-theme="dark"] .gm-mark, :root[data-theme="dark"] .gm-num { color: #e5fff5; filter: none; }
:root[data-theme="dark"] .gmedal.locked .gm-glass { background: linear-gradient(155deg, rgba(220,240,231,.17), rgba(172,205,192,.08)); }
:root[data-theme="dark"] .gmedal.locked .gm-mark { color: #d7e1dc; }
@media (prefers-reduced-transparency: reduce) {
  .gmedal.won .gm-glass { background: #e7f2ed; -webkit-backdrop-filter: none; backdrop-filter: none; }
  .gmedal.locked .gm-glass { background: #e0e8e4; -webkit-backdrop-filter: none; backdrop-filter: none; }
  /* Both darks — the app's and the phone's. With only the app's, the
     phone's dark mode drew the light mark on this light fill, and every
     earned badge went blank. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .gmedal.won .gm-glass { background: #344a40; }
    :root:not([data-theme="light"]) .gmedal.locked .gm-glass { background: #394f47; }
  }
  :root[data-theme="dark"] .gmedal.won .gm-glass { background: #344a40; }
  :root[data-theme="dark"] .gmedal.locked .gm-glass { background: #394f47; }
}

/* ---------- the week ring and the level (levels.js) ----------
   On Progress. The ring's arc is this week's count towards four; the
   number inside is the level; the words beside say both, so neither
   depends on reading the arc. */
.lv-ring { flex: none; overflow: visible; }
.lv-ring-track { fill: none; stroke: var(--sunk-ink); stroke-width: 9; }
.lv-ring-fill {
  fill: none; stroke: var(--accent); stroke-width: 9; stroke-linecap: round;
  /* Snappy, not bouncy: bouncy swings to 1.045 of full, and a full ring
     pushed that far opens a notch at the top mid-celebration. */
  transition: stroke-dashoffset var(--spring-snappy-d) var(--spring-snappy);
}
.lv-ring-num { font-family: var(--font); font-size: 34px; font-weight: 700; fill: var(--text); }
.lv-tier { font-size: 1.5rem; font-weight: 650; letter-spacing: -.02em; line-height: 1.15; }

/* The level as tiles (the owner's pick, 2026-10-11): the rank across
   the top, this week and the badges side by side, the next badge
   across the bottom. The rank and the badges are buttons — the week day
   by day, the road and every badge are in the sheets behind them. */
.levelcard { margin-bottom: 12px; }   /* the gap .card gives every card, which it no longer is */
.lv-bento { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.lv-tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-inline-size: 0;
  padding: 14px; border-radius: var(--r-lg); text-align: start; font: inherit; color: var(--text);
  background: var(--glass); border: 1px solid var(--hairline); box-shadow: var(--shadow);
}
button.lv-tile { cursor: pointer; -webkit-tap-highlight-color: transparent; }
button.lv-tile:active { transform: scale(.985); }
.lv-tile-wide { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: 14px; }
.lv-tile-txt { display: flex; flex-direction: column; gap: 6px; flex: 1; min-inline-size: 0; }
.lv-tile-txt small, .lv-line { font-size: .78rem; color: var(--text-dim); line-height: 1.4; }
.lv-line { display: flex; align-items: flex-start; gap: 4px; }
.lv-k { font-size: .76rem; font-weight: 600; color: var(--text-dim); margin: 0; }
.lv-big { font-size: 1.7rem; font-weight: 700; line-height: 1; letter-spacing: -.02em; }
.lv-big small { font-size: .85rem; font-weight: 500; color: var(--text-dim); letter-spacing: 0; }
.lv-bar { display: block; inline-size: 100%; block-size: 7px; border-radius: 99px; background: var(--sunk-ink); overflow: hidden; }
.lv-bar i { display: block; block-size: 100%; border-radius: inherit; background: var(--accent); }
.lv-stack { display: flex; margin-top: auto; }
.lv-stack svg + svg { margin-inline-start: -12px; }
.lv-next b { font-size: .95rem; }
.lv-sheet { display: grid; gap: 4px; }
.lv-sheet .lv-k { margin-top: 14px; }
.lv-sheet .lv-days, .lv-sheet .lv-road { margin-top: 8px; }
@media (prefers-reduced-motion: reduce) { button.lv-tile:active { transform: none; } }
.lv-days {
  list-style: none; margin: 18px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; text-align: center;
}
.lv-days li { display: grid; justify-items: center; gap: 5px; }
.lv-dot {
  inline-size: 30px; block-size: 30px; border-radius: 50%;
  display: grid; place-items: center; background: var(--sunk-ink); color: var(--on-bright);
}
.lv-dot svg { inline-size: 15px; block-size: 15px; }
.lv-days li.on .lv-dot { background: var(--accent); }
.lv-days li.today .lv-dot { box-shadow: inset 0 0 0 2px var(--accent); }
/* A ring of ink, cut from the card: a wash halo was 1.15:1, colour alone. */
.lv-days li.today.on .lv-dot { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ink); }
.lv-days li.future .lv-dot { background: transparent; box-shadow: inset 0 0 0 1px var(--edge); }
.lv-day { font-size: .72rem; font-weight: 600; color: var(--text-mute); }
.lv-road {
  list-style: none; position: relative; margin: 20px 0 6px; padding: 0;
  display: grid; grid-template-columns: repeat(5, 1fr);
}
.lv-road::before {
  content: ''; position: absolute; inset-inline: 10%; inset-block-start: 11px; block-size: 2px;
  background: var(--edge);
}
.lv-road li { position: relative; display: grid; justify-items: center; gap: 6px; text-align: center; }
.lv-stop {
  inline-size: 24px; block-size: 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); box-shadow: inset 0 0 0 2px var(--edge); color: var(--on-bright);
}
.lv-stop svg { inline-size: 13px; block-size: 13px; }
.lv-road li.past .lv-stop, .lv-road li.now .lv-stop { background: var(--accent); box-shadow: none; }
.lv-road li.now .lv-stop { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ink); }
.lv-stop-name { font-size: .72rem; font-weight: 600; color: var(--text-mute); }
.lv-road li.now .lv-stop-name { color: var(--accent-ink); font-weight: 700; }
.lv-up { display: grid; justify-items: center; gap: 6px; padding-top: 6px; text-align: center; }
.lv-up h3 { margin: 8px 0 0; font-size: 1.45rem; }
.lv-up-tier { margin: 0; font-weight: 600; color: var(--accent-ink); }
.lv-up .btn { justify-self: stretch; }
@media (prefers-reduced-motion: reduce) {
  .lv-ring-fill { transition: none; }
}
