/* Dark-first and high contrast, built around one big number — deliberately unlike the car app's
   dashboard and the dog app's soft warmth. Light theme is a full inversion, not an afterthought.

   Every neutral is derived from one hue, so choosing an accent retints the whole app — the surfaces,
   the borders and the text — instead of only recolouring the buttons on top of a green room. The hue
   itself is set by the accent blocks at the bottom of this file. */
:root{
  --hue:145;
  --bg:hsl(var(--hue) 22% 5%);
  --bg2:hsl(var(--hue) 20% 9%);
  --card:hsl(var(--hue) 16% 11%);
  --card2:hsl(var(--hue) 16% 15%);
  --text-hi:hsl(var(--hue) 40% 94%);
  --text-mid:hsl(var(--hue) 12% 66%);
  --text-lo:hsl(var(--hue) 10% 44%);
  --border:hsl(var(--hue) 15% 19%);
  --border-soft:hsl(var(--hue) 15% 14%);
  --p:#38BDF8; --c:#FBBF24; --f:#FB7185;
  --danger:#F87171; --danger-soft:rgba(248,113,113,0.14);
  --radius:22px; --radius-sm:15px;
  --shadow:0 10px 30px rgba(0,0,0,0.35);
}
:root[data-theme="light"]{
  --bg:hsl(var(--hue) 30% 97%);
  --bg2:hsl(var(--hue) 32% 92%);
  --card:#FFFFFF;
  --card2:hsl(var(--hue) 30% 96%);
  --text-hi:hsl(var(--hue) 30% 8%);
  --text-mid:hsl(var(--hue) 12% 40%);
  --text-lo:hsl(var(--hue) 10% 62%);
  --border:hsl(var(--hue) 20% 87%);
  --border-soft:hsl(var(--hue) 22% 92%);
  --p:#0284C7; --c:#D97706; --f:#DB2777;
  --danger:#DC2626; --danger-soft:rgba(220,38,38,0.10);
  --shadow:0 8px 24px rgba(20,60,35,0.08);
}
@media (prefers-color-scheme:light){
  :root:not([data-theme]){
    --bg:hsl(var(--hue) 30% 97%);
    --bg2:hsl(var(--hue) 32% 92%);
    --card:#FFFFFF;
    --card2:hsl(var(--hue) 30% 96%);
    --text-hi:hsl(var(--hue) 30% 8%);
    --text-mid:hsl(var(--hue) 12% 40%);
    --text-lo:hsl(var(--hue) 10% 62%);
    --border:hsl(var(--hue) 20% 87%);
    --border-soft:hsl(var(--hue) 22% 92%);
    --p:#0284C7; --c:#D97706; --f:#DB2777;
    --danger:#DC2626; --danger-soft:rgba(220,38,38,0.10);
    --shadow:0 8px 24px rgba(20,60,35,0.08);
  }
}
*{ box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
html{ background:var(--bg); -webkit-text-size-adjust:100%; }
body{ margin:0; font-family:'Heebo',system-ui,sans-serif; color:var(--text-hi); min-height:100vh;
  background:radial-gradient(900px 420px at 100% -5%, var(--bg2), var(--bg) 65%); }
button, input, select{ font-family:inherit; color:inherit; }

.wrap{ max-width:520px; margin:0 auto; padding:0 15px calc(82px + env(safe-area-inset-bottom,0px)); }

/* Text size, applied to the containers that hold reading text. Deliberately not on <body>: the sheet
   is a <dialog> in the top layer, whose containing block is the viewport, so a zoom on an ancestor
   does not reach it — and the sheet's own max-height is in dvh, which must stay unzoomed or the sheet
   grows past the screen. Zooming the bar and the body inside it instead keeps the frame where it is
   and scales only what is read. */
.wrap, .tabbar, .sheet-bar, .sheet-body, .toast{ zoom:var(--z, 1); }

/* header */
.top{ display:flex; align-items:center; gap:10px; padding:calc(18px + env(safe-area-inset-top,0px)) 2px 14px; }
.top-txt{ flex:1; min-width:0; display:flex; flex-direction:column; }
.top-txt b{ font-family:'Rubik',sans-serif; font-weight:700; font-size:21px; }
.top-txt span{ font-size:12.5px; color:var(--text-mid); }
.streak{ --st:#FB923C; --st2:#F59E0B;
  display:flex; align-items:center; justify-content:center; gap:6px; height:40px; padding:0 12px;
  flex:0 0 auto; line-height:1;
  border-radius:999px; border:1px solid color-mix(in srgb, var(--st) 32%, transparent);
  background:linear-gradient(155deg, color-mix(in srgb, var(--st) 22%, transparent),
                                     color-mix(in srgb, var(--st) 7%, transparent)); }
.streak.warm{ --st:#F97316; --st2:#FBBF24; }
.streak.hot{ --st:#EF4444; --st2:#F59E0B; }
.streak svg{ display:block; width:18px; height:18px; flex:0 0 auto; }
.streak .fl-out{ fill:var(--st); }
.streak .fl-in{ fill:var(--st2); }
.streak b{ display:block; font-family:'Rubik',sans-serif; font-weight:700; font-size:15px;
  line-height:1; letter-spacing:-.02em; font-variant-numeric:tabular-nums; color:var(--st); }
.round{ width:40px; height:40px; flex:0 0 auto; border-radius:50%; border:1px solid var(--border);
  background:var(--card); font-size:17px; cursor:pointer;
  display:flex; align-items:center; justify-content:center; padding:0; }

/* week strip */
.week-row{ display:flex; align-items:stretch; gap:5px; margin-bottom:16px; }
.week{ display:flex; gap:5px; flex:1; min-width:0; }
.wnav{ flex:0 0 auto; width:26px; border:1px solid var(--border-soft); background:var(--card);
  border-radius:12px; color:var(--text-mid); font-size:17px; cursor:pointer; padding:0; }
.wnav:disabled{ opacity:.3; cursor:default; }
.wday{ flex:1; display:flex; flex-direction:column; align-items:center; gap:5px; padding:8px 2px 6px;
  background:var(--card); border:1px solid var(--border-soft); border-radius:14px; cursor:pointer; }
.wday:disabled{ opacity:.35; cursor:default; }
.wday.on{ border-color:var(--primary); background:var(--card2); }
.wday .wd{ font-size:11px; color:var(--text-mid); font-weight:600; }
.wday.today .wd{ color:var(--primary); }
.wday .wbar{ width:6px; height:26px; border-radius:99px; background:var(--border); display:flex;
  align-items:flex-end; overflow:hidden; }
.wday .wbar i{ width:100%; background:var(--primary); border-radius:99px; }
.wday .wn{ font-size:11px; color:var(--text-lo); }

/* rings */
.ring-wrap{ position:relative; display:grid; place-items:center; }
.ring-wrap svg{ transform:rotate(-90deg); }
.ring-bg{ stroke:var(--border); }
.ring-fg{ stroke:var(--primary); transition:stroke-dashoffset .5s ease; }
.ring-fg.over{ stroke:var(--danger); }
.ring-fg.p{ stroke:var(--p); } .ring-fg.c{ stroke:var(--c); } .ring-fg.f{ stroke:var(--f); }
.ring-mid{ position:absolute; inset:0; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:1px; text-align:center; }

/* hero */
.hero{ background:linear-gradient(165deg, var(--card2), var(--card)); border:1px solid var(--border-soft);
  border-radius:var(--radius); padding:22px 18px 18px; box-shadow:var(--shadow);
  display:flex; flex-direction:column; align-items:center; gap:18px; }
.hero-n{ font-family:'Rubik',sans-serif; font-weight:800; font-size:44px; line-height:1; }
.hero-l{ font-size:12px; color:var(--text-mid); }
.hero-s{ font-size:11.5px; color:var(--text-lo); margin-top:3px; }
.macro-trio{ display:flex; gap:6px; width:100%; justify-content:space-around; }
.mring{ display:flex; flex-direction:column; align-items:center; gap:3px; }
.mring .ring-mid b{ font-family:'Rubik',sans-serif; font-size:15px; }
/* protein target reached: the ring keeps a quiet halo all day, the sparks fire once */
.mring.hit .ring-wrap{ filter:drop-shadow(0 0 7px color-mix(in srgb, var(--p) 55%, transparent)); }
.mring{ position:relative; }
.burst{ position:absolute; top:31px; left:50%; pointer-events:none; }
.burst i{ position:absolute; width:5px; height:5px; margin:-2.5px; border-radius:50%; background:var(--p);
  transform:rotate(var(--a)) translateY(0); animation:spark .9s var(--d) cubic-bezier(.2,.7,.3,1) both; }
@keyframes spark{
  0%{ transform:rotate(var(--a)) translateY(0) scale(.4); opacity:0; }
  25%{ opacity:1; }
  100%{ transform:rotate(var(--a)) translateY(-38px) scale(.9); opacity:0; }
}
.mr-l{ font-size:12px; font-weight:600; }
.mr-g{ font-size:10.5px; color:var(--text-lo); }

/* cards */
.card{ background:var(--card); border:1px solid var(--border-soft); border-radius:var(--radius);
  padding:15px 16px; margin-top:12px; }
.card-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:11px;
  font-family:'Rubik',sans-serif; font-weight:600; font-size:14.5px; }
.card-head b{ font-size:12.5px; color:var(--text-mid); font-weight:600; }

/* meals */
.meal-head{ margin-bottom:8px; }
.meal-t{ flex:1; }
.meal-k{ font-size:12.5px; color:var(--text-mid); }
.add-sm{ width:28px; height:28px; border-radius:9px; border:1px solid var(--border); background:var(--card2);
  color:var(--primary); font-size:17px; line-height:1; cursor:pointer; flex:0 0 auto; }
.meal-empty{ color:var(--text-lo); font-size:13px; padding:4px 2px 2px; }

/* entry row */
.item{ display:flex; align-items:center; gap:10px; padding:8px 0; cursor:pointer;
  border-top:1px solid var(--border-soft); }
.item:first-of-type{ border-top:none; }
.thumb{ width:42px; height:42px; border-radius:11px; object-fit:cover; flex:0 0 auto; }
.thumb.ph{ display:grid; place-items:center; font-size:18px; background:var(--card2); }
.it-main{ flex:1; min-width:0; }
.it-name{ font-weight:600; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.it-name i{ font-style:normal; font-weight:400; color:var(--text-lo); font-size:12px; }
.it-sub{ font-size:11px; color:var(--text-mid); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.it-k b{ font-family:'Rubik',sans-serif; font-size:16px; }
.nudge{ text-align:center; font-size:13px; color:var(--text-lo); margin-top:18px; line-height:1.7; }

/* stats */
.tiles{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
.tile{ background:var(--card); border:1px solid var(--border-soft); border-radius:var(--radius-sm); padding:13px 14px; }
.tile b{ font-family:'Rubik',sans-serif; font-weight:700; font-size:23px; display:block; line-height:1.15; }
.tile span{ font-size:12.5px; color:var(--text-mid); display:block; margin-top:2px; }
.tile i{ font-style:normal; font-size:11px; color:var(--text-lo); }

.chart{ position:relative; display:flex; align-items:flex-end; gap:3px; height:140px; padding-top:8px; }
.goal-line{ position:absolute; left:0; right:0; bottom:var(--goal); border-top:1px dashed var(--text-lo); opacity:.6; }
.goal-line span{ position:absolute; inset-inline-end:0; top:-15px; font-size:10px; color:var(--text-lo); }
.bar{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:flex-end; gap:4px;
  height:100%; background:none; border:none; padding:0; cursor:pointer; }
.bar i{ width:100%; max-width:26px; background:var(--primary-dim); border-radius:5px 5px 2px 2px; min-height:2px; }
.bar.good i{ background:var(--primary); }
.bar.over i{ background:var(--danger); }
.bar.none i{ background:var(--border); }
.bar.sel i{ outline:2px solid var(--text-hi); outline-offset:1px; }
.bar span{ font-size:10px; color:var(--text-lo); }

.split-bar{ display:flex; height:12px; border-radius:99px; overflow:hidden; background:var(--border); }
.split-bar i.p{ background:var(--p); } .split-bar i.c{ background:var(--c); } .split-bar i.f{ background:var(--f); }
/* each label sits over its own share of the bar, the same way the meal legend does */
.split-legend{ display:flex; margin-top:10px; font-size:11.5px; color:var(--text-mid); }
.split-legend > span{ flex:0 0 auto; min-width:0; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; padding-inline-end:8px; }
.split-legend > span i{ display:block; font-style:normal; font-size:10.5px; color:var(--text-lo);
  margin-top:1px; padding-inline-start:14px; }
.split-legend em{ display:inline-block; width:9px; height:9px; border-radius:3px; margin-inline-end:5px; }
.split-legend em.p{ background:var(--p); } .split-legend em.c{ background:var(--c); } .split-legend em.f{ background:var(--f); }

.w-now{ font-size:13px; color:var(--text-mid); }
.w-now b{ font-family:'Rubik',sans-serif; font-size:30px; color:var(--text-hi); }
.w-tag{ font-size:10px; font-weight:700; color:var(--primary); background:color-mix(in srgb, var(--primary) 15%, transparent);
  padding:3px 8px; border-radius:99px; margin-inline-start:8px; vertical-align:middle; }
.w-now i{ display:block; font-style:normal; font-size:11.5px; color:var(--text-lo); margin-top:3px; }

.w-chart{ width:100%; height:120px; margin:12px 0 4px; overflow:visible; }
.wc-line{ stroke:var(--primary); stroke-width:2.5; stroke-linejoin:round; stroke-linecap:round; }
.wc-dots circle{ fill:var(--text-lo); opacity:.55; }
.wc-goal{ stroke:var(--text-lo); stroke-width:1; stroke-dasharray:5 6; opacity:.7; }

.w-stats{ display:grid; grid-template-columns:repeat(3,1fr); gap:1px; background:var(--border-soft);
  border-radius:var(--radius-sm); overflow:hidden; margin-top:10px; }
.w-stats div{ background:var(--card); padding:11px 6px; text-align:center; }
.w-stats b{ font-family:'Rubik',sans-serif; font-size:18px; display:block; }
.w-stats b.down{ color:var(--primary); } .w-stats b.up{ color:var(--c); }
.w-stats span{ font-size:10.5px; color:var(--text-lo); }
.w-actions{ display:flex; gap:8px; margin-top:12px; }
.w-actions .btn{ flex:1; }

/* profile */
.goal-card{ background:linear-gradient(165deg, var(--card2), var(--card)); }
.goal-big{ text-align:center; margin-bottom:14px; }
.goal-big b{ font-family:'Rubik',sans-serif; font-weight:800; font-size:46px; display:block; line-height:1; color:var(--primary); }
.goal-big span{ font-size:12.5px; color:var(--text-mid); }
.goal-why{ font-size:12.5px; color:var(--text-mid); }
.goal-why div{ display:flex; justify-content:space-between; padding:5px 0; border-top:1px solid var(--border-soft); }
.goal-why div b{ color:var(--text-hi); font-family:'Rubik',sans-serif; }
.warn-note{ font-size:12px; line-height:1.6; color:var(--c); background:rgba(251,191,36,0.10);
  padding:9px 11px; border-radius:11px; margin:10px 0 0; }
.macro-goals{ display:flex; justify-content:space-around; gap:6px; margin-top:14px;
  padding-top:12px; border-top:1px solid var(--border-soft); font-size:11.5px; color:var(--text-mid); }
.macro-goals b{ display:block; font-family:'Rubik',sans-serif; font-size:16px; color:var(--text-hi); text-align:center; }

/* forms */
.fld{ display:flex; flex-direction:column; gap:5px; margin-bottom:12px; }
.fld > span{ font-size:12px; color:var(--text-mid); font-weight:600; }
/* .fr-me-f is here because its two inputs used to live inside a .fld and were moved out of one: an
   input that misses this rule is a raw browser box, which on a dark theme means a white box. */
.fld input, .fld select, .fr-me-f input{ background:var(--card2); border:1px solid var(--border);
  border-radius:12px; padding:11px 13px; font-size:15px; width:100%; color:inherit; }
.fld input:focus, .fld select:focus, .fr-me-f input:focus{ outline:2px solid var(--primary-dim);
  border-color:var(--primary); }
.fld.rate input[type=range]{ padding:0; background:none; border:none; }
/* every slider, not only the rated one — a stock blue track on a green app reads as a browser default */
input[type=range]{ accent-color:var(--primary); }
.fld.inline{ flex-direction:row; align-items:center; gap:8px; margin:0; }
.fld.inline input{ width:86px; }
.grid2{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
.grid3{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; }
.seg{ display:flex; gap:4px; background:var(--card2); border:1px solid var(--border); border-radius:13px; padding:3px; }
.seg button{ flex:1; background:none; border:none; border-radius:10px; padding:9px 6px;
  font-size:13px; font-weight:600; color:var(--text-mid); cursor:pointer; white-space:nowrap; }
.seg button.on{ background:var(--primary); color:var(--on-primary); }
.seg.small{ flex:0 0 auto; padding:2px; }
.seg.small button{ padding:6px 11px; font-size:12px; }

.btn{ display:inline-flex; align-items:center; justify-content:center; gap:6px; background:var(--card2);
  border:1px solid var(--border); color:var(--text-hi); font-weight:600; font-size:14px;
  padding:11px 17px; border-radius:14px; cursor:pointer; }
.btn:active{ transform:translateY(1px); }
/* The one action a sheet exists for gets size, not another box — the page already has enough edges.
   Bigger type and more height is what separates "the thing to press" from "a thing you may press". */
.btn.primary{ background:var(--primary); border-color:var(--primary); color:var(--on-primary); font-weight:700; }
.btn.primary.wide{ font-size:16px; padding:15px 18px; letter-spacing:.01em; margin-top:14px; }
.btn.danger{ background:none; border-color:var(--danger); color:var(--danger); }
.btn.wide{ width:100%; margin-top:9px; }
.btn.sm{ padding:7px 12px; font-size:12.5px; border-radius:10px; }
.btn.ai-guess{ border-style:dashed; color:var(--primary); }
.link{ background:none; border:none; color:var(--primary); font-weight:600; font-size:13px;
  cursor:pointer; text-decoration:underline; padding:4px; }
.link.small{ font-size:12.5px; display:block; margin:12px auto 0; text-align:center; }
.icon-btn{ background:var(--card2); border:1px solid var(--border); color:var(--text-mid); font-size:15px;
  cursor:pointer; width:34px; height:34px; flex:0 0 auto; border-radius:10px; display:grid; place-items:center; }
.hint{ font-size:12.5px; color:var(--text-mid); line-height:1.65; background:var(--card2);
  padding:10px 12px; border-radius:12px; margin:0 0 13px; }
.hint code{ font-family:ui-monospace,monospace; color:var(--text-hi); }
.basis{ font-size:11.5px; color:var(--text-lo); line-height:1.6; margin:9px 0 0; }
.basis.bad{ color:var(--danger); }
.sep{ text-align:center; font-size:11.5px; color:var(--text-lo); margin:15px 0 11px;
  display:flex; align-items:center; gap:9px; }
.sep::before, .sep::after{ content:''; flex:1; height:1px; background:var(--border-soft); }

/* add menu */
.add-grid{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
.add-opt{ display:flex; flex-direction:column; align-items:center; gap:3px; text-align:center;
  background:var(--card2); border:1px solid var(--border); border-radius:var(--radius-sm);
  padding:16px 10px; cursor:pointer; }
.add-opt:active{ border-color:var(--primary); }
.add-opt span{ font-size:26px; }
.add-opt b{ font-size:13.5px; }
.add-opt i{ font-style:normal; font-size:11px; color:var(--text-lo); }

/* review rows */
.rev{ border:1px solid var(--border); border-radius:15px; padding:12px; margin-bottom:9px; background:var(--card2); }
.rev-top{ display:flex; align-items:center; gap:8px; }
.rev-name{ flex:1; background:none; border:none; font-weight:700; font-size:15px; padding:2px 0; min-width:0; }
.rev-name:focus{ outline:none; border-bottom:1px solid var(--primary); }
.rev-brand{ font-size:11.5px; color:var(--text-lo); margin-top:2px; }
.rev-row{ display:flex; align-items:center; justify-content:space-between; gap:10px; margin:9px 0 7px; }
.rev-kcal{ font-size:12.5px; color:var(--text-mid); }
.rev-kcal b{ font-family:'Rubik',sans-serif; font-size:19px; color:var(--text-hi); }
.rev-basis{ font-size:11px; color:var(--text-lo); margin-top:7px; }
.rev-total{ text-align:center; font-size:13.5px; color:var(--text-mid); margin-top:12px; }
.rev-total b{ font-family:'Rubik',sans-serif; font-size:19px; color:var(--text-hi); }
.macros.mini{ display:flex; gap:10px; font-size:11.5px; color:var(--text-mid); }

/* entry detail — a nutrition panel, not a cloud of pills */

.d-head{ text-align:center; margin-bottom:16px; }
.d-head b{ font-family:'Rubik',sans-serif; font-weight:300; font-size:56px; line-height:1;
  display:block; letter-spacing:-1px; }
.d-head span{ font-size:12.5px; color:var(--text-mid); letter-spacing:3px; }
.d-head i{ display:block; font-style:normal; font-size:11px; color:var(--text-lo); margin-top:6px; }

.d-amount{ background:var(--card2); border-radius:var(--radius-sm); padding:12px 14px 4px; margin-bottom:14px; }
.d-amount .qty{ margin-top:0; }

.nut-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:1px; background:var(--border-soft);
  border-radius:var(--radius-sm); overflow:hidden; margin-bottom:12px; }
.nut{ background:var(--card); padding:14px 8px 12px; text-align:center; border-top:3px solid transparent; }
.nut.p{ border-top-color:var(--p); } .nut.c{ border-top-color:var(--c); } .nut.f{ border-top-color:var(--f); }
.nut b{ font-family:'Rubik',sans-serif; font-weight:600; font-size:22px; display:block; line-height:1.1; }
.nut b i{ font-style:normal; font-size:13px; font-weight:400; color:var(--text-lo); }
.nut span{ font-size:12px; color:var(--text-mid); display:block; margin-top:3px; }
.nut em{ font-style:normal; font-size:10.5px; color:var(--text-lo); }

.nut-rows{ border:1px solid var(--border-soft); border-radius:var(--radius-sm); overflow:hidden; margin-bottom:14px; }
.nut-rows div{ display:flex; justify-content:space-between; align-items:center; padding:11px 14px;
  border-top:1px solid var(--border-soft); font-size:13px; }
.nut-rows div:first-child{ border-top:none; }
.nut-rows span{ color:var(--text-mid); }
.nut-rows b{ font-family:'Rubik',sans-serif; font-weight:600; }
/* The last row of a sum is not another entry in the list — it is what the rows above add up to, and at
   identical weight the reader has to work that out for themselves. */
.nut-rows div.total{ background:var(--card2); }
.nut-rows div.total span{ color:var(--text-hi); }
.nut-rows div.total b{ font-size:15.5px; color:var(--text-hi); }

/* recents */
.recent{ width:100%; display:flex; justify-content:space-between; align-items:center; gap:10px;
  background:var(--card2); border:1px solid var(--border-soft); border-radius:13px;
  padding:12px 13px; margin-bottom:7px; cursor:pointer; text-align:start; }
/* the name absorbs the slack, so every row's buttons land in the same column instead of drifting with
   the length of the text beside them */
.recent-name{ flex:1 1 auto; font-weight:600; font-size:14px; min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.recent-name i{ font-style:normal; font-weight:400; color:var(--text-lo); font-size:12px; }
.recent-kcal{ font-size:12px; color:var(--text-mid); flex:0 0 auto; }

/* tab bar with the centre action */
.tabbar{ position:fixed; bottom:0; left:0; right:0; z-index:6; display:flex; align-items:stretch;
  justify-content:space-around; gap:6px; padding:0 18px env(safe-area-inset-bottom,0px);
  background:color-mix(in srgb, var(--bg) 86%, transparent); backdrop-filter:blur(14px);
  border-top:1px solid var(--border-soft); }
/* The buttons fill the bar rather than sitting inside it. They used to be 47px tall in a 66px strip,
   which left nine dead pixels above and ten below — and the ten below are exactly where a thumb lands
   on a phone with a home indicator. The padding moved from the bar onto the buttons, so every pixel
   of the strip belongs to whatever is under it. */
.tab{ flex:1; max-width:120px; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:2px; background:none; border:none; font-size:11px; font-weight:600;
  color:var(--text-lo); cursor:pointer; padding:9px 2px 10px; }
.tabbar .fab{ align-self:center; }
/* One drawn set instead of emoji: same 24-grid, same stroke weight, coloured by currentColor so the
   active tab tints icon and label together. Emoji came from the system in four different styles. */
/* Sized in em, so one rule serves every place a mark sits beside text — the container's font-size is
   what decides how big it is, exactly as it did when these were emoji. */
svg.ico{ display:inline-block; vertical-align:-.2em; width:1.15em; height:1.15em; flex:0 0 auto;
  fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }
/* inside a square placeholder or a round button it is the only thing there, so centre it properly */
.recent-img.ph svg.ico, .pp-img.ph svg.ico, .icon-btn svg.ico, .add-opt span svg.ico{
  vertical-align:middle; display:block; }
.recent-img.ph, .pp-img.ph{ color:var(--text-lo); }

/* display:block, or the SVG sits on the text baseline and rides low inside its button. */
.tab svg, .round svg{ display:block; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round; }
.tab svg{ width:23px; height:23px; opacity:.7; }
.tab.on svg{ opacity:1; stroke-width:2; }
.round svg{ width:20px; height:20px; }
.tab span{ font-size:19px; opacity:.75; }
.tab.on{ color:var(--primary); }
.tab.on span{ opacity:1; }
.fab{ width:56px; height:56px; flex:0 0 auto; border-radius:20px; border:none; background:var(--primary);
  color:var(--on-primary); font-size:30px; font-weight:300; line-height:1; cursor:pointer;
  box-shadow:0 6px 20px color-mix(in srgb, var(--primary) 38%, transparent); margin-top:-22px; }
.fab:active{ transform:translateY(1px); }

/* sheet */
.sheet{ border:none; padding:0; background:var(--card); color:var(--text-hi); width:min(520px,100%);
  margin:auto auto 0; border-radius:26px 26px 0 0;
  flex-direction:column; overflow:hidden;
  /* --kb is how much of the viewport the keyboard is covering, set from visualViewport in core.js.
     dvh rather than vh so Safari's collapsing toolbars do not add a second source of error. */
  max-height:calc(90dvh - var(--kb, 0px));
  transform:translateY(calc(-1 * var(--kb, 0px)));
  transition:transform .2s ease, max-height .2s ease; }
/* A real column: the body is the scroller, not the dialog. Without this the sheet grew to its content
   and anything anchored to its foot ended up thousands of pixels down the page. Only when open — the
   browser hides a closed <dialog> with display:none, and setting display on .sheet itself overrode
   that, leaving an empty sheet sitting on the screen from the moment the app loaded. */
.sheet[open]{ display:flex; }
.sheet::backdrop{ background:rgba(0,0,0,0.55); }
.sheet-bar{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:17px 18px 11px; position:sticky; top:0; background:var(--card);
  border-bottom:1px solid var(--border-soft); z-index:2; }
.sheet-title{ font-family:'Rubik',sans-serif; font-weight:700; font-size:16px; }
.sheet-bar button{ background:none; border:none; font-size:20px; color:var(--text-mid); cursor:pointer;
  padding:6px 10px; margin-inline-end:-6px; line-height:1; }
.sheet-body{ padding:16px 18px calc(24px + env(safe-area-inset-bottom,0px));
  flex:1 1 auto; min-height:0; overflow-y:auto; }

/* scanner */
.scanner{ border:none; padding:0; width:100vw; max-width:100vw; height:100vh; max-height:100vh;
  margin:0; background:#000; overflow:hidden; }
.scanner::backdrop{ background:#000; }
#scan-video{ width:100%; height:100%; object-fit:cover; }
.scan-frame{ position:fixed; top:50%; left:50%; transform:translate(-50%,-50%);
  width:min(78vw,320px); aspect-ratio:1.55; border:2px solid rgba(255,255,255,.9); border-radius:18px;
  box-shadow:0 0 0 100vmax rgba(0,0,0,.5); }
.scan-hint{ position:fixed; top:calc(50% + 130px); left:0; right:0; text-align:center;
  color:#fff; font-size:13px; opacity:.85; }
.scan-bar{ position:fixed; bottom:calc(26px + env(safe-area-inset-bottom,0px)); left:0; right:0;
  display:flex; gap:10px; justify-content:center; }

/* toast + busy */
.toast{ position:fixed; bottom:calc(104px + env(safe-area-inset-bottom,0px)); left:50%;
  transform:translateX(-50%) translateY(14px); background:var(--text-hi); color:var(--bg);
  padding:11px 20px; border-radius:999px; font-size:13.5px; font-weight:600; opacity:0;
  pointer-events:none; transition:opacity .2s, transform .2s; z-index:60; max-width:90vw; text-align:center; }
.toast.show{ opacity:1; transform:translateX(-50%) translateY(0); }
.busy{ position:fixed; inset:0; display:none; flex-direction:column; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter:blur(5px); z-index:70; }
.busy.show{ display:flex; }
/* the app's mark, drawing itself for as long as there is something to wait for */
.busy-mark{ width:86px; height:86px; }
.busy-mark svg path{ animation:markDraw 1.9s cubic-bezier(.5,0,.2,1) infinite; }
.busy-mark svg circle{ animation:markDot 1.9s ease-out infinite; }
.bm-track{ stroke:var(--border); }
.bm-arc{ stroke:var(--primary); stroke-dasharray:70 181; transform-origin:50% 50%;
  animation:bm-turn 1.15s cubic-bezier(.5,.15,.35,.9) infinite; }
.bm-apple{ fill:var(--primary); opacity:.9; animation:bm-beat 1.9s ease-in-out infinite; transform-origin:50% 55%; }
.bm-stem{ stroke:var(--primary); opacity:.9; }
@keyframes bm-turn{ to{ transform:rotate(360deg); } }
@keyframes bm-beat{ 0%,100%{ transform:scale(.94); } 50%{ transform:scale(1.02); } }

@media (prefers-reduced-motion:reduce){
  /* Everything decorative stops — but not the progress indicator. Freezing the one element whose whole
     job is to say "still working" is how a loading screen starts looking like a crash.
     Skipped entirely when the app has been told to animate anyway: an explicit choice here outranks a
     system-wide default, and it is the only way to have it without turning the setting off for every
     other app on the phone. */
  :root:not([data-motion="on"]) *:not(.bm-anim), :root:not([data-motion="on"]) *::before,
  :root:not([data-motion="on"]) *::after{
    animation-duration:.01ms !important; transition-duration:.01ms !important;
  }
}

/* sign-in / gate screens */
.signin{ min-height:78vh; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:14px; text-align:center; padding:0 10px; }
.signin img{ border-radius:22px; }
.signin h1{ font-family:'Rubik',sans-serif; font-weight:800; font-size:24px; margin:0; }
.signin p{ font-size:13.5px; color:var(--text-mid); line-height:1.7; margin:0; max-width:300px; }
.signin .btn{ max-width:280px; }
.signin-err{ color:var(--danger); font-size:12px; }

/* the tab bar belongs to a signed-in session; the gate screen must not show app chrome.
   Separate rules, because the .tabbar shorthand block already sets display:flex further down. */
.tabbar{ display:none; }
body.signed-in .tabbar{ display:flex; }

/* library: search, catalogue, recipe builder */
.search-input{ width:100%; background:var(--card2); border:1px solid var(--border); border-radius:13px;
  padding:12px 14px; font-size:15px; margin-bottom:12px; }
.search-input:focus{ outline:2px solid var(--primary-dim); border-color:var(--primary); }
.lib-group{ font-size:11.5px; font-weight:700; color:var(--text-lo); margin:14px 0 7px; }
.lib-empty{ color:var(--text-lo); font-size:13px; text-align:center; padding:18px 6px; line-height:1.7; }
.lib-actions{ margin-top:16px; padding-top:14px; border-top:1px solid var(--border-soft); }
.add-opt.wide-opt{ grid-column:1 / -1; flex-direction:row; gap:10px; justify-content:flex-start; text-align:start; }
.add-opt.wide-opt span{ font-size:22px; }
.add-opt.wide-opt b{ display:block; }
.rb-item{ display:flex; align-items:center; gap:8px; background:var(--card2); border:1px solid var(--border-soft);
  border-radius:13px; padding:10px 12px; margin-bottom:7px; }
.rb-main{ flex:1; min-width:0; }
.rb-main b{ display:block; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.rb-main span{ font-size:11px; color:var(--text-mid); }
.rb-g{ width:66px; flex:0 0 auto; background:var(--card); border:1px solid var(--border);
  border-radius:10px; padding:8px; font-size:14px; text-align:center; }
.rb-total{ text-align:center; font-size:12.5px; color:var(--text-mid); margin:14px 0 4px; }
.rb-total b{ font-family:'Rubik',sans-serif; font-size:20px; color:var(--text-hi); }

/* Feel like an app, not a page: no double-tap zoom, no rubber-band chaining, and no scrolling the
   page behind an open sheet. :has() does the lock without a scroll-position dance in JS. */
html, body{ touch-action:manipulation; overscroll-behavior:none; }
html:has(dialog[open]){ overflow:hidden; }
.sheet-body{ overscroll-behavior:contain;
  /* The browser tries to be helpful when content above the viewport changes height, and shifts the
     scroll to compensate. Inside a sheet that redraws itself on every tap that reads as the page
     jumping on its own — so the compensation is switched off and the position is restored by hand. */
  overflow-anchor:none; }

/* an input with a button beside it (barcode + scan) */
.with-btn{ display:flex; gap:7px; align-items:stretch; }
.with-btn input{ flex:1; min-width:0; background:var(--card2); border:1px solid var(--border);
  border-radius:12px; padding:11px 13px; font-size:15px; }
.with-btn .btn{ flex:0 0 auto; white-space:nowrap; }

/* product picture in the catalogue form and lists */
.pp-row{ display:flex; align-items:center; gap:12px; margin-bottom:13px; }
.pp-img{ width:64px; height:64px; border-radius:14px; object-fit:cover; flex:0 0 auto; background:var(--card2); }
.pp-img.ph{ display:grid; place-items:center; font-size:24px; }
.pp-actions{ display:flex; flex-direction:column; gap:6px; }
.btn.sm.danger{ border-color:var(--danger); color:var(--danger); background:none; }
.recent-img{ width:38px; height:38px; border-radius:10px; object-fit:cover; flex:0 0 auto; background:var(--card); }
.recent-img.ph{ display:grid; place-items:center; font-size:16px; }

/* one-tap portions in the confirm sheet */
.chips{ display:flex; flex-wrap:wrap; gap:6px; margin:2px 0 8px; }
.chip{ background:var(--card); border:1px solid var(--border); color:var(--text-mid); font-size:12px;
  font-weight:600; padding:6px 11px; border-radius:999px; cursor:pointer; }
.chip.on{ background:var(--primary); border-color:var(--primary); color:var(--on-primary); }
/* The one chip row that is a segmented control rather than a list of filters: four equal options that
   together are narrower than the sheet, sitting above a full-width button. Hung off the start edge they
   read as an unfinished line; centred they read as a control. Filter chips elsewhere keep their edge —
   those are a list, and a list starts where every other line on the screen starts. */
.chips.meal-pick{ justify-content:center; }

/* ---- friends: one board, everybody on it ----------------------------------
   A row per friendship was several separate comparisons stacked up; this is one group. You are the
   first face on it, because standing outside a board you are part of is what made the old card read as
   a dashboard about other people. Filled or empty, nothing in between and no number beside anybody's
   name: a friend's intake is not published, and a half-filled ring would be inventing a figure the app
   was never given. There is nothing to rank here and nothing to be behind in. */
.fb-card .card-head b{ font-size:12px; font-weight:600; color:var(--text-mid); }
.fb-card .card-head .link{ margin-inline-start:auto; }
.fb-row{ display:flex; gap:6px; overflow-x:auto; padding:6px 0 2px; scrollbar-width:none; }
.fb-row::-webkit-scrollbar{ display:none; }
.fb-p{ flex:0 0 auto; width:58px; display:flex; flex-direction:column; align-items:center; gap:5px;
  background:none; border:none; padding:0; cursor:pointer; color:inherit; }
.fb-p[disabled]{ cursor:default; }
.fb-av{ width:44px; height:44px; border-radius:50%; display:grid; place-items:center; overflow:hidden;
  font-family:'Rubik',sans-serif; font-weight:700; font-size:17px;
  border:2px solid var(--border); background:var(--card2); color:var(--text-lo); }
/* The photograph fills the circle it was cropped for; the initial is what stands in until there is one */
.fb-av img, .fr-av img, .fr-me-av img{ width:100%; height:100%; object-fit:cover; display:block; }
.fb-p.done .fb-av{ background:var(--primary); border-color:var(--primary); color:var(--on-primary); }
/* still waiting to be accepted — an outline that has not been drawn yet */
.fb-p.wait .fb-av{ border-style:dashed; opacity:.6; }
.fb-p:active .fb-av{ transform:scale(.94); }
.fb-n{ font-size:10.5px; color:var(--text-lo); max-width:58px; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
/* what you already sent them today, so the same face is not cheered twice by accident */
.fb-sent{ font-size:10px; line-height:10px; height:10px; }
.fb-streak{ margin:8px 0 0; font-size:12px; color:var(--text-lo); }
.fb-streak b{ font-family:'Rubik',sans-serif; font-weight:300; font-size:19px; color:var(--text-hi);
  margin-inline-end:3px; }
.fb-note{ display:flex; align-items:center; gap:9px; margin-top:9px; padding-top:9px;
  border-top:1px solid var(--border-soft); }
.fb-note b{ flex:1; min-width:0; font-size:12.5px; font-weight:400; color:var(--text-mid); }
/* arriving cheers: one line, and tapping the ✕ is what marks them read */
.fb-inbox{ display:flex; align-items:center; gap:10px; font-size:13.5px; }
.fb-inbox span{ flex:1; min-width:0; }
.fb-invite{ display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.fb-invite b{ font-size:14px; }
.fb-invite i{ display:block; font-style:normal; font-size:11.5px; color:var(--text-lo); margin-top:3px; }
.fb-invite-acts{ display:flex; gap:7px; margin-inline-start:auto; }

.fr-av{ flex:0 0 auto; width:30px; height:30px; border-radius:50%; display:grid; place-items:center;
  background:var(--card2); color:var(--primary); font-weight:700; font-size:13px; overflow:hidden; }
/* your own row in the settings sheet: the picture is the control that changes it */
.fr-me{ display:flex; align-items:center; gap:12px; }
.fr-me-f{ flex:1; min-width:0; display:flex; flex-direction:column; gap:8px; }
.fr-me-av{ flex:0 0 auto; width:56px; height:56px; border-radius:50%; overflow:hidden; cursor:pointer;
  display:grid; place-items:center; padding:0;
  border:2px dashed var(--border); background:var(--card2); color:var(--text-lo);
  font-family:'Rubik',sans-serif; font-weight:700; font-size:20px; }
.fr-me-av:active{ border-color:var(--primary); }
/* The face is the tallest thing in this header, so it, and not the two lines of text, was setting the
   header's height — which left a band of air under a six-character handle before the goal card. Sized
   to the text block it belongs to, and the header closes up beneath it. */
.top.pf{ padding-bottom:6px; }
.top.pf .top-txt b{ font-size:19px; }
.pf-av{ flex:0 0 auto; width:40px; height:40px; border-radius:50%; overflow:hidden; padding:0;
  display:grid; place-items:center; cursor:pointer;
  border:1px solid var(--border); background:var(--card2); color:var(--text-lo);
  font-family:'Rubik',sans-serif; font-weight:700; font-size:17px; }
.pf-av img{ width:100%; height:100%; object-fit:cover; display:block; }
.pf-av:active{ border-color:var(--primary); }
.fr-n{ flex:1; min-width:0; font-size:14px; font-weight:600; }
.fr-n i{ display:block; font-style:normal; font-size:11px; font-weight:400; color:var(--text-lo);
  margin-top:1px; }
.fr-req{ display:flex; align-items:center; gap:8px; padding:8px 0;
  border-top:1px solid var(--border-soft); }
.fr-edit{ padding:11px 0; border-top:1px solid var(--border-soft); }
.fr-edit-top{ display:flex; align-items:center; gap:10px; }
.fr-add{ display:flex; gap:8px; align-items:center; }
.fr-add input{ flex:1; min-width:0; }

/* dragging an entry between meals */
body.dragging{ user-select:none; cursor:grabbing; }
/* Solid, not translucent. A picked-up object is the most real thing on the screen — it was the faded
   ghost sitting on top of an untouched original that made the gesture read as "copy this" rather than
   "carry this somewhere". The row it came from is what fades now, so the row and the ghost together
   say the item is in the air and its old place is waiting to be vacated. */
.drag-ghost{ position:fixed; z-index:80; pointer-events:none; background:var(--card);
  border:1px solid var(--primary); border-radius:14px; padding:8px 11px;
  box-shadow:0 16px 34px rgba(0,0,0,0.34), 0 2px 8px rgba(0,0,0,0.18);
  transform-origin:center; }
/* The gap left behind. Not display:none — the day must not reflow under a finger that is still
   deciding, or every card below jumps the moment the drag starts. */
.item.drag-src{ opacity:.3; }
/* The card being aimed at. The tinted background alone was easy to miss mid-gesture on a phone;
   an outline sits outside the card's own border and reads at a glance. */
.meal.drop-target{ border-color:var(--primary); background:var(--card2);
  outline:2px solid var(--primary); outline-offset:2px; border-radius:16px; }

/* A long press on an entry is a drag handle, not text. Safari starts selecting and shows the callout
   bubble the moment the press registers, so this is set permanently on the rows rather than only
   while a drag is in flight — by then the selection has already appeared. */
.item, .meal-head, .wday, .chip{
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
}
body.dragging, body.dragging *{ -webkit-user-select:none !important; user-select:none !important; }

/* brand + picture on a confirm row that is about to become a catalogue product */
.rev-product{ display:flex; align-items:center; gap:10px; margin:9px 0 4px; }
.rev-product-fields{ flex:1; min-width:0; display:flex; flex-direction:column; gap:6px; }
.rev-brand-in{ background:var(--card); border:1px solid var(--border); border-radius:10px;
  padding:8px 11px; font-size:13.5px; width:100%; }
.rev-note{ font-size:11px; color:var(--text-lo); margin:0 0 6px; }
/* An estimate has to be readable, not whispered — it is the one note that changes what the number means. */
.rev-note.est, .hint.est{ color:var(--text); border-inline-start:2px solid var(--accent); padding-inline-start:8px; }

/* correcting the per-100g basis, folded away until it is needed */
.rev-values{ margin-top:8px; }
.rev-values summary{ font-size:12px; color:var(--primary); cursor:pointer; padding:4px 0; }
.rev-values .fld{ margin-bottom:8px; }

/* an account that the rules reject — silence here was the bug */
.denied{ background:var(--danger-soft); border:1px solid var(--danger); color:var(--text-hi);
  border-radius:var(--radius-sm); padding:12px 14px; margin:14px 0 0; font-size:12.5px; line-height:1.7; }

/* ===== the day screen, tightened ===================================== */

/* one shade per meal, shared by the ring segments and the dot on each meal header —
   that pairing is what makes the ring readable without a legend */
.seg.breakfast{ stroke:var(--m1); } .dot.breakfast{ background:var(--m1); }
.seg.lunch    { stroke:var(--m2); } .dot.lunch    { background:var(--m2); }
.seg.dinner   { stroke:var(--m3); } .dot.dinner   { background:var(--m3); }
.seg.snack    { stroke:var(--m4); } .dot.snack    { background:var(--m4); }
.seg{ transition:stroke-dashoffset .5s ease, stroke-dasharray .5s ease; }
.dot{ width:8px; height:8px; border-radius:50%; flex:0 0 auto; }

/* the number carries the warning; the ring is busy saying which meal */
.hero-n{ transition:color .3s; }
.hero-n.close{ color:var(--c); }
.hero-n.over{ color:var(--danger); }

/* an empty meal: one quiet line instead of an empty card */
.meal-slim{ display:flex; align-items:center; gap:9px; padding:11px 16px; margin-top:8px;
  border:1px dashed var(--border); border-radius:var(--radius-sm); color:var(--text-lo); font-size:13.5px; }
.meal-slim .meal-t{ flex:1; }
.meal-slim.drop-target{ border-style:solid; border-color:var(--primary); background:var(--card2); }

/* a meal you photographed, shown as the photograph */
.photo-item{ position:relative; display:block; padding:0; margin:9px 0 0; border-radius:16px;
  overflow:hidden; border-top:none; height:132px; }
.photo-item img{ width:100%; height:100%; object-fit:cover; display:block; }
.pi-scrim{ position:absolute; inset-inline:0; bottom:0; padding:22px 13px 11px;
  background:linear-gradient(to top, rgba(0,0,0,.78), transparent); color:#fff;
  display:flex; flex-direction:column; gap:1px; }
.pi-name{ font-weight:700; font-size:15px; }
.pi-meta{ font-size:11.5px; opacity:.85; }
.pi-k{ position:absolute; top:10px; inset-inline-start:10px; background:rgba(0,0,0,.6);
  backdrop-filter:blur(6px); color:#fff; border-radius:12px; padding:5px 10px; text-align:center; }
.pi-k b{ font-family:'Rubik',sans-serif; font-size:16px; display:block; line-height:1.05; }
.pi-k span{ font-size:9.5px; opacity:.8; }

/* sugar / fibre / saturated fat / sodium — present when recorded, silent when not */
.extras-line{ display:flex; flex-wrap:wrap; justify-content:center; gap:4px 14px; width:100%;
  padding-top:12px; border-top:1px solid var(--border-soft); font-size:11.5px; color:var(--text-mid); }
.extras-line b{ font-family:'Rubik',sans-serif; font-size:13px; color:var(--text-hi); }
.detail-macros .extra{ background:var(--bg2); }

/* ===== accents ======================================================
   Placed last so they win over both theme blocks. Each supplies the primary, the text that sits on
   it, and the four meal shades the hero ring is built from — retinting the ring, not just buttons,
   is what makes the choice feel like the app is yours rather than a swapped highlight colour. */
:root, :root[data-accent="green"]{
  --hue:145; --primary:#22C55E; --primary-dim:#16803D; --on-primary:#04180C; --grad:linear-gradient(140deg,#22C55E,#16803D);
  --m1:#BBF7D0; --m2:#4ADE80; --m3:#22C55E; --m4:#15803D;
}
:root[data-accent="clay"]{
  --hue:18; --primary:#C2643F; --primary-dim:#8A4126; --on-primary:#FFF6F1; --grad:linear-gradient(140deg,#C2643F,#8A4126);
  --m1:#F3D5C6; --m2:#DC9271; --m3:#C2643F; --m4:#8A4126;
}
:root[data-accent="olive"]{
  --hue:78; --primary:#7A8B4F; --primary-dim:#4F5C31; --on-primary:#F7FAF0; --grad:linear-gradient(140deg,#7A8B4F,#4F5C31);
  --m1:#DDE5C6; --m2:#A6B577; --m3:#7A8B4F; --m4:#4F5C31;
}
:root[data-accent="ink"]{
  --hue:232; --primary:#4C5FD7; --primary-dim:#2E3B94; --on-primary:#F4F6FF; --grad:linear-gradient(140deg,#4C5FD7,#2E3B94);
  --m1:#C7CEF7; --m2:#7C8BE6; --m3:#4C5FD7; --m4:#2E3B94;
}
:root[data-accent="ochre"]{
  --hue:43; --primary:#C79A28; --primary-dim:#8A6A14; --on-primary:#241A00; --grad:linear-gradient(140deg,#C79A28,#8A6A14);
  --m1:#F2E0AE; --m2:#DDBB5C; --m3:#C79A28; --m4:#8A6A14;
}
:root[data-accent="teal"]{
  --hue:176; --primary:#2A8F87; --primary-dim:#17615B; --on-primary:#EFFCFA; --grad:linear-gradient(140deg,#2A8F87,#17615B);
  --m1:#B8E6E1; --m2:#5FB8B0; --m3:#2A8F87; --m4:#17615B;
}
:root[data-accent="plum"]{
  --hue:330; --primary:#8E4A6B; --primary-dim:#5E2C44; --on-primary:#FDF2F7; --grad:linear-gradient(140deg,#8E4A6B,#5E2C44);
  --m1:#EBC9DA; --m2:#B87496; --m3:#8E4A6B; --m4:#5E2C44;
}
/* An accent that is deliberately not a colour. With the editorial layout it reads as printed matter —
   the only ink on the page is the text itself. */
:root[data-accent="slate"]{
  --hue:160; --primary:#8D9A94; --primary-dim:#5B6763; --on-primary:#0D1211; --grad:linear-gradient(140deg,#8D9A94,#5B6763);
  --m1:#D7DEDB; --m2:#AAB5B0; --m3:#8D9A94; --m4:#5B6763;
}
:root[data-accent="pink"]{
  --hue:330; --primary:#EC4899; --primary-dim:#9D174D; --on-primary:#2A0715; --grad:linear-gradient(140deg,#EC4899,#9D174D);
  --m1:#FBCFE8; --m2:#F472B6; --m3:#EC4899; --m4:#BE185D;
}
:root[data-accent="blue"]{
  --hue:217; --primary:#3B82F6; --primary-dim:#1D4ED8; --on-primary:#F8FAFF; --grad:linear-gradient(140deg,#3B82F6,#1D4ED8);
  --m1:#BFDBFE; --m2:#60A5FA; --m3:#3B82F6; --m4:#1D4ED8;
}
:root[data-accent="purple"]{
  --hue:275; --primary:#A855F7; --primary-dim:#6B21A8; --on-primary:#FAF5FF; --grad:linear-gradient(140deg,#A855F7,#6B21A8);
  --m1:#E9D5FF; --m2:#C084FC; --m3:#A855F7; --m4:#7E22CE;
}
:root[data-accent="orange"]{
  --hue:25; --primary:#F97316; --primary-dim:#C2410C; --on-primary:#2A1000; --grad:linear-gradient(140deg,#F97316,#C2410C);
  --m1:#FED7AA; --m2:#FB923C; --m3:#F97316; --m4:#C2410C;
}
/* Two accents that are a pair of colours rather than one. --primary stays a solid, because half the app
   paints with it into places a gradient cannot go — an SVG stroke, a border, a text colour. --grad is
   what the filled surfaces use, so the button and the bars carry the blend and nothing breaks. */
:root[data-accent="sunset"]{
  --hue:8; --primary:#F0537A; --primary-dim:#B02649; --on-primary:#2C0510;
  --grad:linear-gradient(135deg,#F97316,#EC4899);
  --m1:#FBD5C4; --m2:#F79457; --m3:#F0537A; --m4:#B02649;
}
:root[data-accent="moss"]{
  --hue:166; --primary:#1FA47E; --primary-dim:#116B54; --on-primary:#F0FDF8;
  --grad:linear-gradient(135deg,#34D399,#0E7490);
  --m1:#B7EBD8; --m2:#4FC9A2; --m3:#1FA47E; --m4:#116B54;
}
/* The blend reaches every filled surface; everything else keeps the solid, so nothing loses contrast. */
.fab, .btn.primary, .seg button.on, .chip.on, .swatch.on{ background-image:var(--grad); }
:root[data-look="editorial"] .ed-strip i, :root[data-look="editorial"] .wday .wbar i{
  background-image:var(--grad); }

.swatches{ display:flex; flex-wrap:wrap; gap:8px; }
.swatch{ width:34px; height:34px; border-radius:50%; border:2px solid var(--border); cursor:pointer; padding:0; }
.swatch.on{ border-color:var(--text-hi); box-shadow:0 0 0 3px var(--card2); }

/* settings as an index: one screen of rows, each carrying its own current value */
.rows{ margin-top:12px; background:var(--card); border:1px solid var(--border-soft);
  border-radius:var(--radius); overflow:hidden; }
.srow{ width:100%; display:flex; align-items:center; gap:11px; padding:14px 15px; background:none;
  border:none; border-top:1px solid var(--border-soft); cursor:pointer; text-align:start; }
.srow:first-child{ border-top:none; }
.srow:active{ background:var(--card2); }
.srow-i{ font-size:18px; flex:0 0 auto; }
.srow-l{ font-size:14.5px; font-weight:600; flex:0 0 auto; }
.srow-v{ flex:1; min-width:0; font-size:12px; color:var(--text-lo); text-align:end;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.srow-c{ color:var(--text-lo); font-size:17px; flex:0 0 auto; }

/* filing to the shared catalogue: an informed tick after the numbers are on screen */
.rev-share{ display:flex; align-items:center; gap:8px; margin:9px 0 2px; font-size:12.5px; color:var(--text-mid); }
.rev-share input{ width:18px; height:18px; accent-color:var(--primary); }

/* a day that has not happened yet reads differently from one that has */
.planning{ background:var(--primary-soft, color-mix(in srgb, var(--primary) 16%, transparent));
  color:var(--primary); font-weight:700; font-size:12px; padding:6px 11px; border-radius:999px; flex:0 0 auto; }

/* quantity in units, beside the quantity in grams */
.qty{ display:flex; align-items:center; gap:8px; margin:8px 0 4px; }
.qty-b{ width:32px; height:32px; flex:0 0 auto; border-radius:10px; border:1px solid var(--border);
  background:var(--card); color:var(--primary); font-size:19px; line-height:1; cursor:pointer; }
.qty-n{ font-size:12.5px; color:var(--text-mid); }
.qty-n b{ font-family:'Rubik',sans-serif; font-size:16px; color:var(--text-hi); }
.qty-u{ flex:1; text-align:end; font-size:11px; color:var(--text-lo); }

/* what is notable about an item, and the macro split beside each meal total */
.badge{ display:inline-block; vertical-align:middle; font-style:normal; font-size:10px;
  font-weight:700; padding:2px 7px; border-radius:99px; line-height:1.5;
  margin-inline-start:6px; background:var(--card2); color:var(--text-mid); white-space:nowrap; }
.badge.good{ background:color-mix(in srgb, var(--primary) 18%, transparent); color:var(--primary); }
.badge.warn{ background:color-mix(in srgb, var(--c) 20%, transparent); color:var(--c); }
.meal-m{ font-style:normal; font-weight:400; color:var(--text-lo); font-size:11px; }

/* the balance of a meal, in the same colours as the rings above it */
.msplit{ margin:2px 0 10px; }
.msplit-bar{ display:flex; height:5px; border-radius:99px; overflow:hidden; background:var(--border); }
.msplit-bar i.p{ background:var(--p); } .msplit-bar i.c{ background:var(--c); } .msplit-bar i.f{ background:var(--f); }
/* each label sits over its own segment of the bar — same order, same widths, set inline from the
   actual shares so the legend and the bar can never drift apart */
.msplit-legend{ display:flex; margin-top:6px; font-size:10.5px; color:var(--text-lo); }
.msplit-legend span{ flex:0 0 auto; min-width:0; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; }
.msplit-legend span:nth-child(2){ text-align:center; }
.msplit-legend span:nth-child(3){ text-align:end; }
.msplit-legend em{ display:inline-block; width:7px; height:7px; border-radius:2px; margin-inline-end:4px; }
.msplit-legend em.p{ background:var(--p); } .msplit-legend em.c{ background:var(--c); } .msplit-legend em.f{ background:var(--f); }

/* the camera sits beside the add button as its equal, drawn rather than typed: an emoji rendered at
   different sizes on every device and never lined up with the + next to it */
.cam-btn{ width:28px; height:28px; flex:0 0 auto; display:grid; place-items:center; cursor:pointer;
  border-radius:9px; border:1px solid var(--border); background:var(--card2); color:var(--text-mid);
  padding:0; transition:color .15s, border-color .15s, background .15s; }
.cam-btn:hover, .cam-btn:active{ color:var(--primary); border-color:var(--primary);
  background:color-mix(in srgb, var(--primary) 12%, transparent); }

/* the finished story, shown before it goes anywhere */
/* Tall enough to judge, short enough that the finishes underneath are on screen with it — the choice
   is a comparison, and it cannot be one if you have to scroll away from the card to reach them. */
.story-preview{ display:block; margin:0 auto 12px; border-radius:16px;
  max-height:46vh; width:auto; max-width:100%; }

/* live preview of the story styling, on a stand-in background */
.story-thumb{ display:block; width:148px; aspect-ratio:9/16; margin:0 auto; border-radius:12px;
  border:1px solid var(--border); background:var(--card2); }

/* first paint, before any of our own code has run */
.boot{ min-height:70vh; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:14px; color:var(--text-lo); font-size:13.5px; }
/* The name, not the word "loading". The mark is already breathing, which says the app is working —
   saying it twice wastes the one moment the app gets to introduce itself. */
.boot-name{ font-family:'Rubik',sans-serif; font-size:20px; font-weight:600; letter-spacing:.01em;
  color:var(--text); direction:ltr; }
.boot img{ border-radius:20px; animation:boot-pulse 1.6s ease-in-out infinite; }
@keyframes boot-pulse{ 0%,100%{ opacity:.55; transform:scale(.96); } 50%{ opacity:1; transform:scale(1); } }

/* editing the meals themselves */
.meal-edit{ display:flex; align-items:center; gap:8px; margin-bottom:8px; }
.meal-edit input{ background:var(--card2); border:1px solid var(--border); border-radius:11px;
  padding:10px; font-size:14px; }
.me-icon{ width:52px; text-align:center; }
.me-name{ flex:1; min-width:0; }
.me-hour{ width:64px; text-align:center; }
/* Stacked rather than side by side: the row already carries a mark, a name, an hour and a bin, and two
   more full-width buttons would push the name field down to nothing on a phone. */
.me-move{ display:flex; flex-direction:column; flex:0 0 auto; }
.me-move button{ background:none; border:none; color:var(--text-lo); cursor:pointer;
  padding:0 3px; font-size:13px; line-height:1.2; }
.me-move button:disabled{ opacity:.22; cursor:default; }

/* the weight screen */
.w-hero{ text-align:center; }
.w-hero b{ font-family:'Rubik',sans-serif; font-weight:300; font-size:52px; line-height:1; display:block; }
.w-hero span{ font-size:12px; color:var(--text-mid); letter-spacing:2px; }
.w-hero i{ display:block; font-style:normal; font-size:11.5px; color:var(--text-lo); margin-top:6px; }
.nut-rows b i{ font-style:normal; font-size:12px; font-weight:600; margin-inline-start:8px; }
.nut-rows b i.down{ color:var(--primary); } .nut-rows b i.up{ color:var(--c); }

/* calories and weight on one frame */
.combo{ width:100%; height:150px; margin-top:4px; overflow:visible; }
.cb-bar{ fill:var(--primary-dim); }
.cb-bar.good{ fill:var(--primary); } .cb-bar.over{ fill:var(--danger); }
/* the target is a band, so it is drawn as one — faint enough to sit under the bars, not behind them */
.cb-band{ fill:var(--primary); opacity:.12; stroke:none; }
.cb-goal{ fill:none; stroke:var(--text-lo); stroke-width:1; stroke-dasharray:4 5; opacity:.55; }
.cb-line{ stroke:var(--p); stroke-width:2.5; stroke-linejoin:round; stroke-linecap:round; }
.combo-key{ display:flex; gap:16px; justify-content:center; margin-top:8px; font-size:11px; color:var(--text-lo); }
.combo-key em{ display:inline-block; width:10px; height:10px; border-radius:2px; margin-inline-end:5px; background:var(--primary); }
.combo-key em.k-line{ height:3px; border-radius:99px; background:var(--p); vertical-align:middle; }

/* the weigh-in, sitting with the meals */
.dot.w{ background:var(--p); }
.meal-slim.weighed{ border-style:solid; color:var(--text-hi); }
.meal-slim .meal-k{ font-size:13px; color:var(--text-mid); }

/* four destinations now, so the labels have to give way before the icons do */
.tab{ max-width:none; font-size:10px; }
.tab span{ font-size:18px; }

/* ---- recipes ------------------------------------------------------------- */
/* Two AI doors at the top of the page rather than buried in a menu: the whole argument for a recipes
   tab is that it knows what you have left today, and a button nobody finds cannot know anything. */
.rc-ai{ display:grid; grid-template-columns:1fr 1fr; gap:9px; margin-bottom:12px; }
.rc-act{ display:flex; flex-direction:column; align-items:flex-start; gap:2px; text-align:start;
  padding:13px 13px 14px; border-radius:var(--radius); cursor:pointer;
  border:1px solid color-mix(in srgb, var(--primary) 28%, transparent);
  background:linear-gradient(155deg, color-mix(in srgb, var(--primary) 14%, transparent),
                                     color-mix(in srgb, var(--primary) 4%, transparent)); }
.rc-act span{ color:var(--primary); font-size:20px; line-height:1; margin-bottom:5px; }
.rc-act b{ font-size:14px; color:var(--text-hi); }
.rc-act i{ font-size:11px; color:var(--text-mid); font-style:normal; line-height:1.4; }

.rc-card{ display:flex; align-items:center; gap:11px; width:100%; text-align:start; cursor:pointer;
  background:var(--card); border:1px solid var(--border-soft); border-radius:var(--radius);
  padding:9px; margin-bottom:8px; }
.rc-img{ width:62px; height:62px; border-radius:13px; object-fit:cover; flex:0 0 auto; background:var(--card2); }
.rc-img.ph{ display:grid; place-items:center; color:var(--text-lo); font-size:22px; }
.rc-body{ flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.rc-body b{ font-size:14.5px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.rc-meta{ font-size:11px; color:var(--text-lo); }
.rc-nums{ font-size:12px; color:var(--text-mid); }
.rc-nums em{ font-style:normal; font-weight:700; color:var(--text-hi); }

.rc-hero{ width:100%; height:190px; object-fit:cover; border-radius:var(--radius); margin-bottom:12px; }
.rc-serv{ display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:12px;
  font-size:13px; color:var(--text-mid); }
.rc-step{ display:flex; align-items:center; gap:10px; }
.rc-step b{ font-family:'Rubik',sans-serif; font-size:18px; min-width:22px; text-align:center; }
.rc-per{ display:block; font-style:normal; font-size:10.5px; color:var(--text-lo); font-weight:400; }
.rc-steps{ margin:0; padding-inline-start:20px; font-size:13.5px; line-height:1.75; color:var(--text-mid); }
.rc-steps li{ margin-bottom:5px; }
.rc-steps li::marker{ color:var(--primary); font-weight:700; }

.rc-prop{ background:var(--card2); border:1px solid var(--border-soft); border-radius:15px;
  padding:12px; margin-bottom:9px; display:flex; flex-direction:column; gap:3px; }
.rc-prop b{ font-size:14.5px; }
.rc-why{ font-style:normal; font-size:11.5px; color:var(--text-lo); line-height:1.5; }
.rc-prop-act{ display:flex; gap:7px; margin-top:7px; }
.rc-prop-act .btn{ flex:1; }
.rc-two{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
.rb-total i{ display:block; font-style:normal; font-size:11px; color:var(--text-lo); margin-top:2px; }

/* ---- desktop ------------------------------------------------------------
   The phone layout is not "the app" — it is the narrow case. With room to spare the bottom bar becomes
   a rail on the start edge, the day splits into what-you-have-left beside what-you-ate, and sheets stop
   pretending to slide up from the bottom of a handset. Nothing above this block changes below 980px. */
.panes{ display:contents; }

@media (min-width:980px){
  .wrap{ max-width:1040px; padding-inline-start:126px; padding-bottom:44px; }

  .tabbar{ inset:0 auto 0 0; inset-inline-start:0; inset-inline-end:auto; width:104px;
    flex-direction:column; justify-content:center; align-items:center; gap:6px; padding:20px 0;
    border-top:none; border-inline-end:1px solid var(--border-soft); }
  .tab{ flex:0 0 auto; width:80px; height:62px; max-width:none; padding:0; border-radius:16px;
    gap:4px; font-size:11px; justify-content:center; }
  .tab svg{ width:21px; height:21px; }
  .tab.on{ background:var(--card2); }
  .fab{ position:static; flex:0 0 auto; margin:10px 0; width:54px; height:54px; font-size:28px;
    border-radius:18px; }
  .fab:active{ transform:translateY(1px); }

  /* two columns: the day's standing on the left, the food itself on the right */
  .panes{ display:grid; grid-template-columns:352px minmax(0,1fr); gap:20px; align-items:start; }
  .pane{ min-width:0; }
  .pane > .card:first-child, .pane > section.meal:first-child{ margin-top:0; }
  .hero{ margin-top:0; }

  /* lists that were one per row have the room to pair up */
  #rc-list, #lib-results{ display:grid; grid-template-columns:1fr 1fr; gap:9px; align-items:start; }
  .rc-card, #lib-results .recent{ margin-bottom:0; }
  #lib-results .lib-group{ grid-column:1 / -1; }

  /* a sheet on a desktop is a dialog, not a drawer */
  .sheet{ margin:auto; border-radius:24px; width:min(560px,92vw); max-height:86vh; }
  .sheet::backdrop{ backdrop-filter:blur(3px); }

  .rc-hero{ height:260px; }
  .add-grid{ grid-template-columns:1fr 1fr 1fr; }
}

/* wide desktop: a third column of air rather than stretching the content further */
@media (min-width:1360px){
  .wrap{ max-width:1180px; }
  .panes{ grid-template-columns:380px minmax(0,1fr); }
}
.link.tiny{ font-size:10.5px; font-weight:600; padding:0; margin-inline-start:6px; }
.rb-photo{ display:flex; align-items:center; gap:11px; margin-bottom:11px; }

/* textareas were never styled at all — a raw browser box in the middle of a designed sheet */
textarea{ background:var(--card2); border:1px solid var(--border); border-radius:12px; color:inherit;
  padding:11px 13px; font-family:inherit; font-size:15px; width:100%; resize:vertical; line-height:1.6; }
textarea:focus{ outline:2px solid var(--primary-dim); border-color:var(--primary); }

/* recipe method: numbered rows, each its own field */
.rb-sec{ font-size:12px; font-weight:700; color:var(--text-mid); margin:16px 0 8px; }
.rb-step{ display:flex; align-items:flex-start; gap:7px; margin-bottom:7px; }
.rb-num{ flex:0 0 auto; width:24px; height:24px; margin-top:8px; border-radius:50%;
  background:color-mix(in srgb, var(--primary) 16%, transparent); color:var(--primary);
  font-family:'Rubik',sans-serif; font-weight:700; font-size:12px;
  display:grid; place-items:center; }
.rb-txt{ flex:1; min-width:0; min-height:42px; padding:10px 12px; font-size:14px; resize:none;
  overflow:hidden; }
.rb-step .icon-btn{ margin-top:5px; }
.rb-step-add{ display:flex; gap:7px; margin:4px 0 14px; }
.rb-step-add .btn{ flex:1; }
.rb-live{ font-size:13px; color:var(--text-lo); min-height:0; margin:4px 0 0; }
/* while the microphone is listening the button pulses — the only signal that it is still recording */
.icon-btn.mic.rec{ color:var(--danger); border-color:var(--danger); animation:micPulse 1.1s ease-in-out infinite; }
@keyframes micPulse{ 50%{ background:var(--danger-soft); } }

/* ---- progress photos ------------------------------------------------------ */
.sh-strip{ display:flex; gap:7px; overflow-x:auto; padding-bottom:4px; margin-bottom:8px;
  scrollbar-width:none; }
.sh-strip::-webkit-scrollbar{ display:none; }
.sh-thumb{ flex:0 0 auto; width:72px; padding:0; border:none; background:none; cursor:pointer;
  display:flex; flex-direction:column; gap:4px; }
.sh-thumb img, .sh-cell img{ width:100%; aspect-ratio:3/4; object-fit:cover; border-radius:12px;
  background:var(--card2); display:block; }
.sh-thumb span, .sh-cell span{ font-size:10.5px; color:var(--text-lo); text-align:center; }
.sh-acts{ display:flex; gap:7px; }
.sh-acts .btn{ flex:1; }
.sh-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin:4px 0 12px; }
.sh-cell{ padding:0; border:none; background:none; cursor:pointer; display:flex; flex-direction:column; gap:4px; }
.sh-cell.missing img, .sh-thumb.missing img{ opacity:.25; }
.sh-preview{ width:100%; max-height:52vh; object-fit:contain; border-radius:16px;
  background:var(--card2); margin-bottom:12px; display:block; }

/* the comparison: two frames of equal size, and the difference spelled out under them */
.sh-compare{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.sh-compare figure{ margin:0; }
.sh-compare img{ width:100%; aspect-ratio:3/4; object-fit:cover; border-radius:14px; background:var(--card2); }
.sh-compare figcaption{ margin-top:5px; text-align:center; font-size:11px; color:var(--text-lo); }
.sh-compare figcaption b{ display:block; font-size:13px; color:var(--text-hi); font-family:'Rubik',sans-serif; }
.sh-delta{ display:flex; align-items:baseline; justify-content:center; gap:6px; margin:12px 0 4px; }
.sh-delta b{ font-family:'Rubik',sans-serif; font-weight:700; font-size:22px; }
.sh-delta b.good{ color:var(--primary); }
.sh-delta span{ font-size:12px; color:var(--text-lo); margin-inline-end:8px; }

/* choosing a look: two miniatures rather than two words, since the difference is entirely visual */
.look-pick{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
.look-opt{ display:flex; flex-direction:column; align-items:stretch; gap:4px; cursor:pointer;
  padding:10px; border-radius:14px; border:1px solid var(--border); background:var(--card2); text-align:start; }
.look-opt.on{ border-color:var(--primary); }
.look-opt b{ font-size:13px; }
.look-opt i{ font-style:normal; font-size:10.5px; color:var(--text-lo); line-height:1.4; }
.look-demo{ display:flex; flex-direction:column; gap:4px; height:44px; justify-content:center;
  padding:7px 8px; margin-bottom:5px; background:var(--bg); border-radius:8px; }
.look-demo i{ display:block; background:color-mix(in srgb, var(--text-hi) 22%, transparent); }
.look-demo.classic i{ height:8px; border-radius:99px; }
.look-demo.classic i:first-child{ height:14px; width:14px; border-radius:50%;
  border:3px solid var(--primary); background:none; align-self:center; }
.look-demo.editorial i{ height:1px; }
.look-demo.editorial i:first-child{ height:11px; width:38%; background:var(--text-hi); }
.look-demo.editorial i:last-child{ height:4px; background:var(--primary); width:62%; }
.rev-wrong{ display:flex; align-items:center; justify-content:space-between; gap:8px;
  margin:9px 0 4px; font-size:12px; color:var(--text-lo); }
/* dictation of a whole method can run long — it wraps and scrolls rather than pushing the buttons away */
.rb-live:not(:empty){ max-height:120px; overflow-y:auto; line-height:1.6;
  padding:8px 10px; margin-top:6px; border-inline-start:2px solid var(--primary);
  background:var(--card2); border-radius:0 8px 8px 0; }
.toast-act{ background:none; border:none; color:var(--primary); font-weight:700; font-size:13px;
  cursor:pointer; padding:0 2px; margin-inline-start:12px; }
.btn.xs{ font-size:11px; padding:5px 9px; border-radius:8px; flex:0 0 auto; }

/* the coach: one card that has already read the charts for you */
.coach{ border-inline-start:3px solid var(--text-lo); }
.coach.good{ border-inline-start-color:var(--primary); }
.coach.warn{ border-inline-start-color:var(--c); }
.coach.bad{ border-inline-start-color:var(--danger); }
.coach-line{ margin:0 0 8px; font-size:15.5px; line-height:1.5; color:var(--text-hi); }
.coach-fix{ margin:0 0 8px; font-size:13px; line-height:1.6; color:var(--text-mid);
  background:var(--card2); border-radius:10px; padding:10px 12px; }
:root[data-look="editorial"] .coach{ padding-inline-start:13px; }
:root[data-look="editorial"] .coach-fix{ background:none; border-inline-start:1px solid var(--rule);
  border-radius:0; padding:2px 11px; }
.rec-src{ font-style:normal; font-size:10px; color:var(--primary); }

/* The log book. A table of numbers only works when a column reads as a column: the heading and every
   value under it share one alignment, and the numbers share one width. The month is a band across the
   whole table rather than a cell in the first column, which is what made it read as a stray row. */
/* No border on the scroller: sticky pins to the padding box, which begins after the border — so a
   1px rule here left the header a pixel low and a sliver of every scrolled row showed above it. The
   header's own edges do the separating. */
/* One scroller, not two. The list used to scroll inside itself while the sheet scrolled around it, and
   a sticky header in a nested scroller is composited against the outer one — during a flick it lagged
   behind its own rows and their text showed through where the header should have been. The sheet body
   is the only scroller now, so the header has nothing to disagree with. */
.wlog{ margin-top:4px; }
.wlog-h, .wlog-r{ display:grid; grid-template-columns:1.15fr 1fr .95fr 1fr; gap:4px; align-items:center; }
/* the date is a label and starts where the text starts; the three figures are centred under their names */
.wlog-h > span:first-child, .wlog-r > span:first-child{ text-align:start; padding-inline-start:6px; }
.wlog-h > span:not(:first-child), .wlog-r > span:not(:first-child){ text-align:center; }

/* top:0 means the top of the scrollport, and the scrollport starts inside .sheet-body's 16px padding —
   which left a 16px band above the header with rows sliding through it. The negative top pulls the
   header up onto the sheet's own top edge, so there is nothing above it to show. */
.wlog-h{ position:sticky; top:-16px; z-index:3; height:34px; padding:0;
  background:var(--card); border-top:1px solid var(--border);
  border-bottom:1px solid var(--border);
  font-size:10px; letter-spacing:.06em; color:var(--text-lo); font-weight:600; }

.wlog-sep{ position:sticky; top:18px; z-index:2; padding:9px 12px;
  background:var(--card2); border-bottom:1px solid var(--border);
  font-size:12px; font-weight:700; letter-spacing:.04em; color:var(--text-mid); }
.wlog-sep i{ font-style:normal; font-weight:400; color:var(--text-lo); margin-inline-start:6px; }

.wlog-r{ width:100%; background:none; border:none; border-bottom:1px solid var(--border-soft);
  color:inherit; font-size:13.5px; cursor:pointer; padding:9px 0;
  font-variant-numeric:tabular-nums; }
.wlog-r:active{ background:var(--card2); }
.wlog-day{ color:var(--text-mid); }
.wlog-day i{ font-style:normal; font-size:10.5px; color:var(--text-lo); margin-inline-start:5px; }
.wlog-kg{ font-weight:600; }
.wlog-r .up{ color:var(--danger); }
.wlog-r .dn{ color:var(--primary); }
.wlog-r .quiet{ color:var(--text-lo); }
:root[data-look="editorial"] .wlog-h{ background:var(--bg); }
:root[data-look="editorial"] .wlog-sep{ background:var(--bg); font-weight:600;
  border-top:1px solid var(--rule); }

/* every list row keeps the same square whether or not the item has a photograph */
.ph-letter{ display:grid; place-items:center; font-family:'Rubik',sans-serif; font-weight:600;
  font-size:15px; color:hsl(var(--h) 42% 62%);
  background:linear-gradient(150deg, hsl(var(--h) 34% 22% / .55), hsl(var(--h) 30% 14% / .35));
  border:1px solid hsl(var(--h) 30% 30% / .4); }
:root[data-theme="light"] .ph-letter, :root:not([data-theme]) .ph-letter{
  color:hsl(var(--h) 40% 38%);
  background:linear-gradient(150deg, hsl(var(--h) 46% 92%), hsl(var(--h) 40% 96%));
  border-color:hsl(var(--h) 34% 84%); }
@media (prefers-color-scheme:dark){ :root:not([data-theme]) .ph-letter{
  color:hsl(var(--h) 42% 62%);
  background:linear-gradient(150deg, hsl(var(--h) 34% 22% / .55), hsl(var(--h) 30% 14% / .35));
  border-color:hsl(var(--h) 30% 30% / .4); } }
/* Two stops: the column header pins to the very top, and each month heading pins directly beneath it —
   so scrolling through three years always says which month you are looking at, and the next month
   pushes the last one out of the way as it arrives. */
.wlog-h{ height:34px; padding-top:0; padding-bottom:0; }
.wlog-sep{ position:sticky; top:18px; z-index:1; background:var(--card);
  padding:10px 6px 8px; margin-top:2px;
  font-size:11.5px; font-weight:700; letter-spacing:.06em; color:var(--text-mid);
  border-bottom:1px solid var(--border); }
:root[data-look="editorial"] .wlog-h, :root[data-look="editorial"] .wlog-sep{ background:var(--bg); }

/* our own month grid — a weigh-in is nearly always within a few weeks, so a month is the right amount
   of calendar, and being ours it can mark the days that already carry a reading */
.cal-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:8px; }
.cal-head b{ font-family:'Rubik',sans-serif; font-size:14px; }
.cal-nav{ width:32px; height:32px; border-radius:10px; border:1px solid var(--border-soft);
  background:var(--card2); color:var(--text-mid); font-size:17px; line-height:1; cursor:pointer; padding:0; }
.cal-nav:disabled{ opacity:.3; cursor:default; }
.cal-dow{ display:grid; grid-template-columns:repeat(7,1fr); gap:3px; margin-bottom:4px; }
.cal-dow span{ text-align:center; font-size:10px; color:var(--text-lo); font-weight:600; }
.cal-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:3px; }
.cal-d{ position:relative; aspect-ratio:1; border:1px solid transparent; border-radius:11px;
  background:var(--card2); color:var(--text-hi); font-size:13.5px; cursor:pointer; padding:0;
  font-variant-numeric:tabular-nums; }
.cal-d:disabled{ opacity:.22; cursor:default; background:none; }
.cal-d.today{ border-color:var(--border); font-weight:700; }
/* a dot under a day that already has a reading — the only thing a native picker could never show */
.cal-d.has::after{ content:''; position:absolute; bottom:5px; left:50%; transform:translateX(-50%);
  width:4px; height:4px; border-radius:50%; background:var(--primary); opacity:.75; }
.cal-d.on{ background:var(--primary); color:var(--on-primary); border-color:var(--primary); font-weight:700; }
.cal-d.on::after{ background:var(--on-primary); opacity:.6; }
.cal-grid{ touch-action:pan-y; }
/* the month slides in from the side it came from, so a swipe reads as movement and not a redraw */
/* the incoming month enters from the far side, continuing the direction the finger was going */
@keyframes calPrev{ from{ transform:translateX(-110%); opacity:0 } to{ transform:none; opacity:1 } }
@keyframes calNext{ from{ transform:translateX(110%); opacity:0 } to{ transform:none; opacity:1 } }
.cal-grid.in-prev{ animation:calPrev .2s cubic-bezier(.22,.7,.3,1); }
.cal-grid.in-next{ animation:calNext .2s cubic-bezier(.22,.7,.3,1); }
/* the grid clips its own overflow so a half-dragged month does not spill over the sheet */
#w-cal{ overflow:hidden; }

/* a destination inside a card: the same anatomy as a settings row, so it reads as somewhere to go
   rather than as a link in a paragraph */
.rowlink{ display:flex; align-items:center; gap:11px; width:100%; margin-top:12px;
  padding:12px 13px; border-radius:14px; border:1px solid var(--border-soft);
  background:var(--card2); color:inherit; font-size:14px; cursor:pointer; text-align:start; }
.rowlink:active{ background:var(--border-soft); }
.rowlink-i{ color:var(--primary); display:flex; }
.rowlink-l{ flex:1; min-width:0; }
.rowlink-v{ font-size:12.5px; color:var(--text-lo); font-variant-numeric:tabular-nums; }
.rowlink-c{ color:var(--text-lo); font-size:17px; line-height:1; }
:root[data-look="editorial"] .rowlink{ background:none; border:none; border-top:1px solid var(--rule);
  border-radius:0; padding:13px 0; margin-top:14px; }

/* Focus was never styled, so every button fell back to Safari's blue ring — which flashed on the sheet's
   close button whenever a touch elsewhere moved focus. Keyboard users still get a clear ring; it is just
   ours, and it no longer appears for a finger. */
:focus{ outline:none; }
:focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }
.sheet-bar button:focus-visible, .round:focus-visible, .fab:focus-visible{ outline-offset:3px; }

:root[data-motion="off"] *:not(.bm-anim), :root[data-motion="off"] *::before,
:root[data-motion="off"] *::after{ animation-duration:.01ms !important; transition-duration:.01ms !important; }

/* the app mark: the field is the element so it can carry the accent gradient, which an SVG fill cannot */
.appmark{ display:block; width:72px; height:72px; border-radius:22%; background-image:var(--grad);
  background-color:var(--primary); overflow:hidden; }
.appmark svg{ display:block; width:100%; height:100%; }
.appmark svg path{ stroke:#0A100D; opacity:.86; }
.appmark svg circle{ fill:#EDFBF5; }
.gate-mark{ width:86px; height:86px; margin:0 auto; }

/* The mark draws itself: the trend accumulating is what the app does, so the logo does it too. The
   dot lands only once the line has arrived. On the boot screen it repeats, because that screen is
   waiting for something; everywhere else it plays once. */
.appmark svg path{ stroke-dasharray:1; stroke-dashoffset:0; }
/* Draws once — that pass is timed to the boot floor — and then the dot keeps breathing for as long as
   the app is still loading. A mark that finishes and freezes reads as a stall on a slow connection,
   which is exactly when someone is watching it. */
.boot-mark svg path{ animation:markDrawOnce .78s cubic-bezier(.45,0,.2,1) both; }
.boot-mark svg circle{ animation:markDotOnce .9s ease-out both, markWait 1.5s .9s ease-in-out infinite; }
@keyframes markWait{
  0%,100%{ transform:scale(1); opacity:1 }
  50%{ transform:scale(.72); opacity:.45 }
}
.gate-mark svg path{ animation:markDraw 1.5s cubic-bezier(.4,0,.2,1) 1 both; }
.gate-mark svg circle{ animation:markDotOnce 1.5s ease-out 1 both; }
@keyframes markDraw{
  0%{ stroke-dashoffset:1 } 55%{ stroke-dashoffset:0 } 88%{ stroke-dashoffset:0; opacity:.88 }
  100%{ stroke-dashoffset:0; opacity:0 }
}
@keyframes markDot{
  0%,45%{ transform:scale(0); opacity:0 } 62%{ transform:scale(1.18); opacity:1 }
  72%,88%{ transform:scale(1); opacity:1 } 100%{ transform:scale(1); opacity:0 }
}
@keyframes markDrawOnce{ from{ stroke-dashoffset:1 } to{ stroke-dashoffset:0 } }
@keyframes markDotOnce{
  0%,55%{ transform:scale(0); opacity:0 } 74%{ transform:scale(1.15); opacity:1 }
  100%{ transform:scale(1); opacity:1 }
}
.appmark svg circle{ transform-origin:396px 328px; transform-box:view-box; }
@media (prefers-reduced-motion:reduce){
  /* the same carve-out as the global rule: an explicit "always" in the app outranks the system default */
  :root:not([data-motion="on"]) .boot-mark svg path, :root:not([data-motion="on"]) .boot-mark svg circle,
  :root:not([data-motion="on"]) .gate-mark svg path, :root:not([data-motion="on"]) .gate-mark svg circle{
    animation:none; opacity:1; stroke-dashoffset:0; }
}
:root[data-motion="off"] .boot-mark svg path, :root[data-motion="off"] .boot-mark svg circle,
:root[data-motion="off"] .gate-mark svg path, :root[data-motion="off"] .gate-mark svg circle{
  animation:none; opacity:1; stroke-dashoffset:0; }
/* a meal's mark sits on the text baseline beside its name, at the size of the name */
.meal-t svg.ico{ color:var(--primary); margin-inline-end:3px; }
.meal-emoji{ margin-inline-end:3px; }
.me-mark{ width:52px; height:40px; flex:0 0 auto; display:grid; place-items:center; cursor:pointer;
  background:var(--card2); border:1px solid var(--border); border-radius:12px; color:var(--primary);
  font-size:17px; padding:0; }
.me-mark svg.ico{ width:20px; height:20px; }
/* the mark picker: a plain grid, sized so a thumb hits one square without aiming */
.mk-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(56px,1fr)); gap:8px; margin-top:4px; }
.mk-cell{ aspect-ratio:1; display:grid; place-items:center; cursor:pointer; padding:0;
  background:var(--card2); border:1px solid var(--border-soft); border-radius:14px; color:var(--text-mid); }
.mk-cell svg.ico{ width:24px; height:24px; }
.mk-cell.on{ border-color:var(--primary); color:var(--primary); background:color-mix(in srgb, var(--primary) 12%, transparent); }
.mk-cell:active{ background:var(--border-soft); }
/* the meal's own mark, at the size of the name beside it */
.meal-t svg.ico{ width:1.25em; height:1.25em; vertical-align:-.22em; }

/* Supplements: a tick is one tap, and the chip says which one — a pill glyph on its own is unreadable
   a fortnight after you set it up. The taken state is carried by the mark and the text rather than by
   filling the whole shape: a saturated capsule was the loudest thing on a page made of hairlines, and
   a dashed outline read as "disabled" rather than as "not yet". */
.supp-line{ display:flex; flex-wrap:wrap; gap:6px; margin:2px 0 10px; }
.supp-chip{ display:inline-flex; align-items:center; gap:6px; cursor:pointer; padding:5px 11px 5px 9px;
  border-radius:9px; border:1px solid var(--border); background:none; color:var(--text-lo);
  font-size:11.5px; transition:color .15s, border-color .15s; }
.supp-chip b{ font-weight:600; color:var(--text-mid); }
.supp-chip i{ font-style:normal; font-size:10px; opacity:.8; }
.supp-chip svg.ico{ width:14px; height:14px; }
.supp-chip.on{ border-color:color-mix(in srgb, var(--primary) 40%, transparent); color:var(--primary); }
.supp-chip.on b{ color:var(--primary); }
.supp-chip:active{ border-color:var(--primary); }
.meal-supp{ display:block; }
.meal-slim-row{ display:flex; align-items:center; gap:10px; }
.meal-supp .supp-line{ margin:9px 0 0; }
.supp-row{ display:flex; align-items:center; gap:9px; padding:9px 0;
  border-bottom:1px solid var(--border-soft); }
.supp-main{ flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.supp-name{ font-size:14px; font-weight:600; background:none; border:none; padding:0; width:100%; }
.supp-dose{ font-size:11px; color:var(--text-lo); background:none; border:none; padding:0; width:100%; }
.supp-stat{ text-align:center; flex:0 0 auto; min-width:52px; }
.supp-stat b{ display:block; font-family:'Rubik',sans-serif; font-size:15px; }
.supp-stat i{ font-style:normal; font-size:9.5px; color:var(--text-lo); }
.supp-when{ display:flex; gap:6px; align-items:center; }
.supp-when select{ background:none; border:none; color:var(--text-lo); font-size:11px; padding:0; }
.supp-note{ font-size:12.5px; line-height:1.6; color:var(--text-mid); background:var(--card2);
  border-radius:13px; padding:11px 13px; margin:10px 0 0; }
.supp-note svg.ico{ color:var(--primary); }
.menu-row{ align-items:flex-start; }
.menu-row i{ display:block; font-style:normal; font-size:10.5px; color:var(--text-lo); margin-top:2px; }

/* ---- story designer -------------------------------------------------------
   The preview leads and stays put: the controls under it are all live, and a change you cannot see is
   a change nobody makes. */
.story-stage{ position:sticky; top:0; z-index:2; background:var(--bg);
  padding:2px 0 8px; margin-bottom:2px; }
.story-stage .basis{ margin:5px 0 0; text-align:center; font-size:10.5px; }
.story-opts{ display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-bottom:12px; }
.story-opt{ display:flex; flex-direction:column; gap:3px; text-align:start; padding:10px 12px;
  border:1px solid var(--line); border-radius:12px; background:none; color:var(--text-lo); }
.story-opt-t{ font-size:13px; font-weight:600; }
.story-opt-s{ font-size:11px; line-height:1.35; opacity:.8; }
.story-opt.on{ border-color:var(--primary); color:var(--text); }
.story-opt.on .story-opt-t::after{ content:' ✓'; color:var(--primary); }

/* Camera or library, asked in our own words. The system picker is fine at what it does; it just does
   not belong in the middle of a flow that looks like this. */
.pick-src{ display:grid; gap:10px; margin-bottom:12px; }
.pick-opt{ display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto auto;
  align-items:center; column-gap:12px; padding:14px 16px; text-align:start;
  border:1px solid var(--line); border-radius:14px; background:none; color:var(--text); }
.pick-opt svg{ grid-row:1 / span 2; width:22px; height:22px; }
.pick-opt b{ font-size:14.5px; font-weight:600; }
.pick-opt i{ font-size:11.5px; font-style:normal; color:var(--text-lo); }
.pick-opt:active{ border-color:var(--primary); }

/* ---- chains ---------------------------------------------------------------
   The chain is what you know before you have looked at a menu, so it is what the screen offers. */
.chain-grid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-bottom:12px; }
.chain-tile{ display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto auto;
  align-items:center; column-gap:11px; padding:13px 14px; text-align:start;
  border:1px solid var(--line); border-radius:14px; background:none; color:var(--text); }
.chain-mark{ grid-row:1 / span 2; display:grid; place-items:center; width:38px; height:38px;
  border-radius:50%; background:var(--primary); color:#fff; font-weight:700; font-size:17px;
  flex:0 0 auto; }
/* A brand mark comes with its own ground — Aroma's is black, McDonald's is green — so the tile gets out
   of the way entirely and lets the mark fill it, the way an app icon does. */
.chain-mark.logo{ background:none; padding:0; overflow:hidden; border-radius:11px; }
.chain-mark.logo img{ width:100%; height:100%; object-fit:cover; }
.chain-head{ display:flex; align-items:center; gap:11px; margin-bottom:12px; }
.chain-head b{ font-family:'Rubik',sans-serif; font-size:16px; }
.chain-tile b{ font-size:14px; font-weight:600; }
.chain-tile i{ font-size:11px; font-style:normal; color:var(--text-lo); }

/* An order in progress. Pinned to the foot of the sheet rather than sticky inside the scroller: sticky
   put it at the end of a 170-line menu, which is exactly where you are not when you pick the second
   thing. The body gains room underneath so the last row is never hidden behind it. */
.tray-bar{ display:none; position:sticky; bottom:calc(-24px - env(safe-area-inset-bottom,0px));
  z-index:6; align-items:center; gap:10px;
  margin:8px -18px calc(-24px - env(safe-area-inset-bottom,0px));
  padding:10px 18px calc(10px + env(safe-area-inset-bottom,0px));
  background:var(--card); border-top:1px solid var(--border);
  box-shadow:0 -10px 24px -18px rgba(0,0,0,.7); }
.tray-bar.on{ display:flex; }
.recent.picked{ border-color:var(--primary); }
.pick-n{ display:inline-grid; place-items:center; width:19px; height:19px; margin-inline-end:7px;
  border-radius:50%; background:var(--primary); color:#fff; font-size:11px; line-height:1; }

/* Menu sections. Sticky like the month bands in the weight log, and set to be seen: on a menu of a
   hundred and forty items the section you are inside is the only thing telling you where you are. */
.menu-sec{ position:sticky; top:0; z-index:4; display:flex; align-items:center; gap:8px;
  margin:16px -18px 0; padding:10px 18px;
  /* Opaque, and the sheet's own colour rather than a tint: a sticky band you can see the list through
     reads as a rendering fault, not as a heading. */
  background:var(--card); box-shadow:0 1px 0 var(--border), 0 -1px 0 var(--border);
  font-family:'Rubik',sans-serif; font-size:13px; font-weight:700;
  letter-spacing:.02em; color:var(--text-hi); }
.menu-sec::before{ content:''; width:3px; height:13px; border-radius:2px; background:var(--primary); }
/* Each section is its own box so its heading is released when the section ends, instead of every
   heading piling up at the top of the sheet. */
.menu-grp:first-child .menu-sec{ margin-top:0; }
.menu-sec i{ margin-inline-start:auto; font-style:normal; font-weight:500; font-size:11px;
  color:var(--text-lo); font-variant-numeric:tabular-nums; }
/* the first row under a band should not float away from it */
.menu-sec + .recent{ margin-top:8px; }

/* A row with two jobs: the + picks it, the rest opens it. */
.recent.prow{ display:flex; align-items:stretch; gap:0; padding:0; overflow:hidden; }
.prow-main{ flex:1; min-width:0; display:flex; align-items:center; gap:10px;
  padding:9px 12px; background:none; border:none; color:inherit; text-align:start; font:inherit; }
.prow-add{ flex:0 0 auto; width:42px; display:grid; place-items:center;
  background:none; border:none; border-inline-start:1px solid var(--border);
  color:var(--text-lo); font-size:19px; line-height:1; }
.prow-add.on{ background:var(--primary); color:#fff; }
.recent .prow-add{ font-size:16px; }

/* product detail */
.pi-img{ display:block; width:100%; max-height:200px; object-fit:contain; margin-bottom:10px; }
.pi-tab{ width:100%; border-collapse:collapse; margin:8px 0 14px; font-size:13px; }
.pi-tab th{ font-size:10.5px; font-weight:600; color:var(--text-lo); text-align:start;
  padding:0 0 6px; border-bottom:1px solid var(--border); }
.pi-tab td{ padding:7px 0; border-bottom:1px solid var(--border-soft);
  font-variant-numeric:tabular-nums; }
.pi-tab td:first-child{ color:var(--text-lo); }
.pi-tab td:last-child{ color:var(--text-lo); }

/* This is an app, not a document: a long-press that selects the word "צהריים" is never what was meant.
   Anything genuinely readable — the fields you type in — keeps selection. */
body{ -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
input, textarea, [contenteditable], .pi-tab{ -webkit-user-select:text; user-select:text; }
.tray-bin{ flex:0 0 auto; width:34px; height:34px; }
.tray-sum{ flex:1; display:flex; align-items:center; gap:6px; padding:0; background:none; border:none;
  color:var(--text-lo); font:inherit; font-size:12.5px; text-align:start; }
.tray-sum b{ color:var(--text); font-size:14px; }
.tray-sum i{ font-style:normal; color:var(--text-lo); font-size:15px; }
.prow-main.as-row{ cursor:default; }
/* which column of the label these numbers came from */
.basis-pick{ display:flex; align-items:center; gap:8px; margin:0 0 8px; font-size:11.5px;
  color:var(--text); border-inline-start:2px solid var(--accent); padding-inline-start:8px; }
.basis-pick span{ flex:1; }
.basis-pick i{ font-style:normal; color:var(--text-lo); font-size:10.5px; }
/* a chain mark standing in for a missing product photo — quieter than the real thing */
.brand-fallback{ object-fit:contain; padding:4px; background:#fff; opacity:.9; }
/* how much one unit weighs — typed, not only inherited from whatever was scanned */
.unit-in{ width:46px; padding:1px 4px; border:1px solid var(--border); border-radius:6px;
  background:var(--card2); color:var(--text); font:inherit; font-size:11px; text-align:center; }
/* extras, ticked on the dish the way the chain sells them */
/* Twenty-seven toppings in a 190px box, cut off mid-row with no edge, no shadow and no count — the
   only clue that there was more was that the last row looked wrong. Now the header says how many there
   are, and the box fades at the bottom while there is still something below it, which is the one
   convention people already read as "keep scrolling". */
.addon-head{ display:flex; align-items:baseline; justify-content:space-between; gap:8px;
  margin:16px 0 8px; padding-bottom:7px; border-bottom:1px solid var(--border-soft); }
.addon-head b{ font-size:13px; font-weight:600; color:var(--text-hi); }
.addon-head span{ font-size:11.5px; color:var(--text-lo); }
.chips.addons{ max-height:230px; overflow-y:auto; align-content:flex-start; margin-bottom:12px;
  padding-bottom:2px; overscroll-behavior:contain; }
.chips.addons[data-more="1"]{
  -webkit-mask-image:linear-gradient(to bottom, #000 calc(100% - 34px), transparent);
  mask-image:linear-gradient(to bottom, #000 calc(100% - 34px), transparent); }
/* once you reach the end there is nothing left to hint at, so the fade goes away */
.chips.addons[data-more="1"].at-end{ -webkit-mask-image:none; mask-image:none; }
.chips.addons .chip{ display:inline-flex; align-items:baseline; gap:5px; }
.chips.addons .chip i{ font-style:normal; font-size:10px; opacity:.65; font-variant-numeric:tabular-nums; }
.chips.addons .chip.on i{ opacity:.85; }
/* an extra you can take twice gets a minus beside it; one you cannot just toggles */
.chip.addon{ display:inline-flex; align-items:stretch; gap:0; padding:0; overflow:hidden; }
.chip.addon .addon-main{ display:inline-flex; align-items:baseline; gap:5px;
  padding:6px 10px; background:none; border:none; color:inherit; font:inherit; font-size:12px; }
.chip.addon .addon-main b{ font-size:11px; }
.chip.addon .addon-step{ padding:0 8px; background:none; border:none; color:inherit;
  border-inline-end:1px solid var(--border); font-size:14px; line-height:1; }
.chip.addon.on .addon-step{ border-inline-end-color:currentColor; opacity:.7; }
.seg.sizes{ margin:0 0 12px; }

/* iOS gets confused when a long-ish press lands on something it might want to select or callout: the
   press is swallowed, a blue box appears, and the next tap goes to clearing that state rather than to
   the button. Every control opts out explicitly rather than relying on the rule set on body. */
button, .chip, .recent, .tab, .srow, .add-opt, .qty-b, .icon-btn, label{
  -webkit-user-select:none; user-select:none; -webkit-touch-callout:none;
  touch-action:manipulation; -webkit-tap-highlight-color:transparent; }

/* Tap targets on the small controls — every ✕ and every round icon button.
   They were drawn at the size their glyph wanted: 30px for the icon buttons, and barely 25px tall for
   the sheet's close button. A fingertip lands on about 44px, so people were not mis-pressing these,
   they were missing them. The glyphs grow a little, but the fix that matters is the invisible box
   around each one — a pseudo-element, so nothing in any layout moves to pay for it. Height is where the
   whole win is; width stops at 38px because the tightest row of these (the photo nudge pad) sits on a
   4px gap, and two hit boxes that overlap would have the second one quietly stealing the first's taps.
   The second half of "it doesn't respond": tap highlighting is switched off above, and these were the
   controls with no :active state of their own, so a press that did land looked exactly like one that
   missed. Nothing to do with the hit area, everything to do with believing you hit it. */
.sheet-bar button, .icon-btn, .prow-add, .link.tiny, .meal-left, .meal-move{ position:relative; }
.sheet-bar button::after, .icon-btn::after, .prow-add::after, .link.tiny::after{
  content:''; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  width:max(100%, 38px); height:max(100%, 44px); }
.sheet-bar button:active, .icon-btn:active, .prow-add:active, .link.tiny:active{ opacity:.5; }
.sheet-body:focus{ outline:none; }
/* picking a picture without leaving the app */
.pp-hits{ display:flex; flex-wrap:wrap; gap:7px; margin:0 0 12px; align-items:center; }
.pp-hit{ width:64px; height:64px; padding:0; border:1px solid var(--border); border-radius:10px;
  overflow:hidden; background:var(--card2); }
.pp-hit img{ width:100%; height:100%; object-fit:cover; display:block; }
.pp-hit:active{ border-color:var(--primary); }
.chips.filters{ margin-bottom:10px; }

/* the finishes, side by side on your own photograph */
.film{ display:flex; gap:8px; overflow-x:auto; padding-bottom:4px; margin-bottom:10px;
  scroll-snap-type:x proximity; }
.film-o{ flex:0 0 auto; width:66px; padding:0; background:none; border:none; color:var(--text-lo);
  scroll-snap-align:start; }
.film-i{ display:block; width:66px; height:88px; border-radius:10px; background:var(--card2);
  background-size:cover; background-position:center; border:2px solid transparent; }
.film-o i{ display:block; font-style:normal; font-size:10.5px; margin-top:4px; }
.film-o.on .film-i{ border-color:var(--primary); }
.film-o.on i{ color:var(--text); font-weight:600; }

/* framing a progress photo before it is filed */
.sh-frame{ position:relative; width:100%; aspect-ratio:3/4; overflow:hidden; border-radius:14px;
  background:#000; margin-bottom:8px; touch-action:none; }
.sh-frame img{ width:100%; height:100%; object-fit:cover; display:block;
  transform-origin:center; transition:transform .08s linear; }
/* Positioned in the shape it will be seen in. A square frame with "it will be a circle, trust us" is
   how you end up with a chin at the edge of the crop. */
.av-frame{ position:relative; width:min(62vw, 230px); aspect-ratio:1; margin:0 auto 12px;
  overflow:hidden; border-radius:50%; background:#000; touch-action:none; cursor:grab; }
.av-frame img{ width:100%; height:100%; object-fit:cover; display:block;
  transform-origin:center; transition:transform .08s linear; pointer-events:none; }
.sh-crop{ display:flex; align-items:center; gap:6px; margin-bottom:12px; font-size:12px; }
.sh-crop b{ min-width:42px; text-align:center; font-variant-numeric:tabular-nums; }
.sh-pad{ display:flex; gap:4px; margin-inline-start:auto; }
.basis .dim{ font-style:normal; opacity:.6; }
.from-log{ font-style:normal; font-size:10.5px; color:var(--text-lo); }

/* the next milestone — the one card that looks forward instead of back */
.ms-gauge{ position:relative; margin:4px auto 2px; max-width:230px; }
.ms-gauge svg{ display:block; width:100%; overflow:visible; }
.ms-track{ stroke:var(--border); stroke-width:7; stroke-linecap:round; }
.ms-fill{ stroke:var(--primary); stroke-width:7; stroke-linecap:round;
  transition:stroke-dasharray .5s cubic-bezier(.4,0,.2,1); }
.ms-mid{ position:absolute; inset:auto 0 4px; text-align:center; }
.ms-lbl{ display:block; font-size:10.5px; letter-spacing:.1em; color:var(--text-lo); }
.ms-kg{ display:block; font-family:'Rubik',sans-serif; font-size:38px; font-weight:300;
  line-height:1.05; font-variant-numeric:tabular-nums; }
.ms-facts{ display:grid; grid-template-columns:repeat(3,1fr); margin-top:10px;
  border-top:1px solid var(--border); }
.ms-facts div{ text-align:center; padding:9px 4px; }
.ms-facts div + div{ border-inline-start:1px solid var(--border); }
.ms-facts b{ display:block; font-size:17px; font-weight:600; font-variant-numeric:tabular-nums; }
.ms-facts span{ font-size:10.5px; color:var(--text-lo); }
.ms-track-dots{ display:flex; align-items:center; justify-content:center; gap:0; margin:12px 0 2px; }
.ms-dot{ width:11px; height:11px; border-radius:50%; background:var(--border); flex:0 0 auto; }
.ms-dot.on{ background:var(--primary); }
.ms-link{ width:34px; height:2px; background:var(--border); }
.ms-link.on{ background:var(--primary); }
/* the total since the start — the one number on this screen that rewards staying */
.w-total{ display:inline-flex; align-items:baseline; gap:6px; margin-top:10px; padding:5px 12px;
  border-radius:999px; font-style:normal; font-size:15px; font-weight:600;
  background:color-mix(in srgb, var(--primary) 12%, transparent); color:var(--primary); }
.w-total.up{ background:color-mix(in srgb, var(--danger) 12%, transparent); color:var(--danger); }
.w-total span{ font-size:11px; font-weight:400; opacity:.85; }

/* A date field is a text field with a picker attached, and it should not look like a different species:
   the native control adds its own line-height and an indicator, which left it two pixels taller than
   the number field beside it — enough for the two underlines to disagree. */
input[type="date"]{
  -webkit-appearance:none; appearance:none;
  height:46px; line-height:22px; font-variant-numeric:tabular-nums;
  direction:ltr; text-align:right;
}
input[type="date"]::-webkit-date-and-time-value{ text-align:right; margin:0; }
input[type="date"]::-webkit-calendar-picker-indicator{ margin:0; opacity:.55; cursor:pointer; }
/* a date written the way the app writes dates, not the way the browser's locale does */
.daybtn{ width:100%; height:46px; padding:0 13px; font-size:15px; font-weight:500; text-align:start; }
.gs-cal{ margin-top:10px; }

/* Folded shut: it is a record for the day something looks wrong, not something to read every meal. */
.trace{ margin-top:12px; background:var(--card2); border:1px solid var(--border); border-radius:13px;
  padding:10px 13px; font-size:12.5px; color:var(--text-mid); }
.trace summary{ cursor:pointer; font-weight:600; color:var(--text-lo); font-size:11.5px;
  letter-spacing:.04em; list-style:none; }
.trace summary::-webkit-details-marker{ display:none; }
.trace summary::after{ content:' ⌄'; }
.trace[open] summary::after{ content:' ⌃'; }
.trace p{ margin:8px 0 0; line-height:1.5; }
.trace b{ color:var(--text-hi); font-weight:600; }
.trace-edit{ color:var(--warn, var(--danger)); }

.bad-card{ background:var(--card2); border:1px solid var(--border); border-radius:14px;
  padding:12px 14px; margin-top:10px; font-size:12.5px; color:var(--text-mid); }
.bad-head{ display:flex; flex-direction:column; align-items:flex-start; gap:2px; width:100%;
  background:none; border:none; padding:0; text-align:start; color:inherit; cursor:pointer; }
.bad-head b{ font-size:14.5px; color:var(--text-hi); font-weight:600; }
.bad-head i{ font-style:normal; font-size:11.5px; color:var(--text-lo); }
.bad-card p{ margin:8px 0 0; line-height:1.5; }
.bad-card b{ color:var(--text-hi); font-weight:600; }
.bad-card .link{ margin-top:10px; }

/* One photograph, one plate — drawn in the list's own vocabulary. The picture had been a full-width
   slab with its own border, background and floating badge, sitting inside a card that already had all
   three: a card inside a card, which is exactly what "pasted on" looks like. Now it is a row. */
.plate{ position:relative; }
.plate-thumb{ position:relative; width:70px; height:70px; flex:0 0 auto; }
.plate-thumb img{ width:100%; height:100%; border-radius:15px; object-fit:cover; display:block; }
/* There was a camera badge here. It said "this is a photograph" to a row that is already showing a
   photograph, at nearly twice the size of every other thumbnail, above a rule holding the items read
   out of it. Same reason the placeholder glyphs came off the child rows: a mark that restates what is
   already visible is noise wearing the costume of a feature. */
/* what the picture was read into, hanging off it */
/* Without a photograph there is no 70px thumbnail to hang the rule under, so the rule comes back to
   the edge and the row keeps its meaning: a named meal with its parts listed beneath it. */
.plate-head.no-shot{ padding-bottom:4px; }
.plate:has(.no-shot) .plate-rows{ margin-inline-start:6px; }
.plate-rows{ margin-inline-start:34px; padding-inline-start:14px;
  border-inline-start:2px solid color-mix(in srgb, var(--primary) 30%, transparent); }
.plate-rows .item:first-of-type{ border-top:none; }
.plate-rows .item{ padding:7px 0; }
.plate-rows .thumb{ width:34px; height:34px; border-radius:9px; }
/* A camera glyph on every child row repeated the one thing the plate above it already says, three
   times in a column. A real product picture still earns its place; the placeholder does not. */
.plate-rows .thumb.ph, .plate-list .thumb.ph{ display:none; }

/* Text size, second half. Growing everything pushed the first meal from 325px down the screen to 454 —
   past the fold, so enlarging the type cost you the thing you were trying to read. The block that grew
   worst was the one that needed it least: a 44px figure does not become clearer at 58px, and widening
   it wrapped the summary beside it onto three lines. So the headline figure, the week strip and the
   page title hold their normal size while everything below them grows. Dividing by the same factor the
   ancestor multiplies by cancels it exactly. Measured after: the first meal starts at 356 instead of
   454, against 325 at normal size — and the item names are still a third larger. */
.ed-figure, .week-row, .top{ zoom:calc(1 / var(--z, 1)); }

.tile{ position:relative; }
.tile-q{ position:absolute; top:6px; inset-inline-end:6px; width:19px; height:19px; padding:0;
  border-radius:50%; border:1px solid var(--border); background:var(--card2); color:var(--text-lo);
  font-size:11px; font-weight:700; line-height:1; cursor:pointer; }
.tile-q:active{ background:var(--border); }

.plate-full{ display:block; width:100%; aspect-ratio:4/3; object-fit:cover; border-radius:16px;
  margin-bottom:14px; }
.plate-list{ margin-top:4px; }

.rev-fix{ margin:14px 0 10px; background:var(--card2); border:1px solid var(--border);
  border-radius:14px; padding:12px 14px; }
.rev-fix summary{ cursor:pointer; font-weight:600; font-size:13px; color:var(--text-mid);
  list-style:none; }
.rev-fix summary::-webkit-details-marker{ display:none; }
.rev-fix summary::after{ content:' ⌄'; color:var(--text-lo); }
.rev-fix[open] summary::after{ content:' ⌃'; }
.rev-fix textarea{ width:100%; margin:10px 0; background:var(--card); color:var(--text-hi);
  border:1px solid var(--border); border-radius:12px; padding:10px 12px; font:inherit;
  font-size:14px; resize:none; }

.rev-note.unsure{ display:flex; align-items:center; gap:6px; color:var(--warn, var(--danger)); }
.rev-note.unsure svg{ width:14px; height:14px; flex:0 0 auto; }

.busy-msg{ margin-top:14px; font-size:14px; font-weight:500; color:var(--text-hi);
  text-align:center; max-width:15em; line-height:1.4; }
.busy-dots{ display:flex; gap:6px; margin-top:10px; }
.busy-dots i{ width:6px; height:6px; border-radius:50%; background:var(--border);
  transition:background .25s; }
.busy-dots i.on{ background:var(--primary); }

.swap-link{ margin-top:8px; display:inline-flex; align-items:center; gap:5px; }
.swap-link svg{ width:13px; height:13px; }

.bad-shot{ display:block; width:100%; aspect-ratio:4/3; object-fit:cover; border-radius:12px;
  margin-top:10px; background:var(--card); }
.bad-shot:not([src]){ display:none; }

/* ---- meat & fish: a menu, not a form -------------------------------------
   Cards with their own figure and a fat bar across the top, so which cuts are lean is answered by
   looking rather than by reading four numbers per row. */
.mt-tabs{ display:flex; gap:2px; margin:14px 0 12px; background:var(--card2);
  border:1px solid var(--border); border-radius:var(--radius-sm); padding:3px; }
.mt-tabs button{ flex:1; padding:9px 4px; border:none; background:none;
  border-radius:calc(var(--radius-sm) - 4px);
  font-size:13px; font-weight:500; color:var(--text-lo); cursor:pointer; }
.mt-tabs button.on{ background:var(--primary); color:#fff; font-weight:600; }

.mc-grid{ display:grid; grid-template-columns:1fr 1fr; gap:9px; }
.mc{ position:relative; display:flex; flex-direction:column; align-items:flex-start; gap:1px;
  background:var(--card2); border:1px solid var(--border); border-radius:var(--radius-sm);
  padding:18px 15px 15px; cursor:pointer; overflow:hidden; text-align:start; }
.mc:active{ border-color:var(--primary); }
.mc-fat{ position:absolute; top:0; inset-inline-start:0; width:100%; height:4px;
  background:color-mix(in srgb, var(--text-hi) 7%, transparent); }
.mc-fat i{ display:block; height:100%; background:var(--f); }
.mc b{ font-family:'Rubik',sans-serif; font-weight:700; font-size:26px; line-height:1;
  color:var(--text-hi); font-variant-numeric:tabular-nums; }
.mc-n{ margin-top:6px; font-size:14px; font-weight:600; color:var(--text-hi); }
.mc-s{ font-size:10.5px; color:var(--text-lo); white-space:nowrap; }

.mt-head{ text-align:center; padding:10px 0 16px; }
.mt-head b{ display:block; font-family:'Rubik',sans-serif; font-weight:700; font-size:44px;
  line-height:1; color:var(--text-hi); font-variant-numeric:tabular-nums; }
.mt-head span{ display:block; margin-top:6px; font-size:12px; color:var(--text-lo); }
.mt-head i{ display:block; margin-top:7px; font-style:normal; font-size:13px; color:var(--text-mid); }
.mt-lab{ display:block; font-size:11px; color:var(--text-lo); margin:16px 0 8px; }
.mt-recent .mt-chips{ display:flex; flex-wrap:wrap; gap:7px; }
.mt-recent .chip{ background:var(--card2); border:1px solid var(--border); border-radius:calc(var(--radius-sm) - 4px);
  padding:8px 12px; font-size:13px; color:var(--text-hi); cursor:pointer; }

.mt-ports{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.mp{ display:flex; flex-direction:column; gap:2px; align-items:flex-start; padding:12px 13px;
  background:var(--card2); border:1px solid var(--border); border-radius:var(--radius-sm);
  cursor:pointer; text-align:start; }
.mp.on{ border-color:var(--primary); background:color-mix(in srgb, var(--primary) 12%, var(--card2)); }
.mp b{ font-size:13.5px; font-weight:600; color:var(--text-hi); }
.mp i{ font-style:normal; font-size:11px; color:var(--text-lo); }
.mt-seg{ margin-bottom:16px; }

/* ---- the + sheet, sorted by how often it is actually used -----------------
   Nine equal tiles each with its own explanatory line is a sheet you have to read before you can use
   it. Photographing the plate is what this app is for, so it gets the room; the rest are labels. */
/* One block, two ways to get a picture in — photograph it now, or fetch one already taken. Giving the
   gallery its own tile down in the grid left seven tiles in a three-wide grid, which reads as two rows
   and a leftover. It also filed it next to "barcode" and "manual", which is the wrong neighbourhood:
   this is the camera path, just deferred. Split hero rather than a seventh tile. */
.add-hero{ display:flex; align-items:stretch; width:100%;
  background:var(--primary); border-radius:var(--radius-sm); overflow:hidden; color:#fff; }
.add-hero > button{ background:none; border:none; color:inherit; cursor:pointer; text-align:start;
  display:flex; align-items:center; gap:13px; flex:1; padding:16px 17px; }
.add-hero > button:active{ filter:brightness(.94); }
.add-hero span{ display:flex; flex:0 0 auto; }
.add-hero svg{ width:26px; height:26px; }
.add-hero b{ display:block; font-size:16px; font-weight:600; }
.add-hero i{ display:block; font-style:normal; font-size:12px; opacity:.82; margin-top:2px; }
/* The hairline is on the inline-start edge so the divider stays between the two halves in either
   direction, and the label is small enough that the plate photo is still obviously the main road. */
.add-hero > button.add-hero-alt{ flex:0 0 auto; flex-direction:column; justify-content:center; gap:6px;
  padding:16px 15px; border-inline-start:1px solid rgba(255,255,255,.25); }
.add-hero-alt svg{ width:20px; height:20px; }
.add-hero-alt b{ font-size:11.5px; font-weight:600; }

.add-grid2{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; margin-top:12px; }
.add-tile{ display:flex; flex-direction:column; align-items:center; gap:7px; padding:14px 6px;
  background:var(--card2); border:1px solid var(--border); border-radius:var(--radius-sm);
  cursor:pointer; color:var(--text-mid); }
.add-tile:active{ border-color:var(--primary); }
.add-tile svg{ width:21px; height:21px; }
.add-tile b{ font-size:11.5px; font-weight:600; color:var(--text-hi); text-align:center;
  line-height:1.25; }

/* Weighing yourself and photographing yourself are not food, and giving them tiles the same size as
   "scan a barcode" was a large part of what made this sheet read as a list of everything the app can do.
   Quiet buttons rather than underlined coloured text: nothing here navigates to a web page, and
   anything that looks like a hyperlink is claiming that it does. */
.add-other{ display:flex; gap:9px; margin-top:16px; padding-top:14px;
  border-top:1px solid var(--border-soft); }
.add-other button{ flex:1; display:inline-flex; align-items:center; justify-content:center; gap:7px;
  padding:11px 8px; font-size:12.5px; font-weight:500; color:var(--text-mid);
  background:none; border:1px solid var(--border); border-radius:var(--radius-sm); cursor:pointer; }
.add-other button:active{ border-color:var(--primary); }
.add-other svg{ width:15px; height:15px; }

/* Going back is not a link either — it is a control, and it belongs at the top left of what it leaves. */
.backlink{ display:inline-flex; align-items:center; gap:4px; background:none; border:none;
  padding:2px 0 10px; font-size:13px; font-weight:500; color:var(--text-mid); cursor:pointer; }



/* A glyph standing in for a photograph should look like a mark, not like a broken image. */
.thumb.ph .ico{ width:19px; height:19px; opacity:.55; }

/* ---- one hue per animal --------------------------------------------------
   No photographs: a grid of stock meat shot in five different kitchens looks worse than a clean grid of
   numbers, and a generic steak is not the steak you ate. What a photograph would have given here is
   recognition — knowing you have moved from chicken to beef without reading the tab — and a hue gives
   that for nothing. Kept to a tinted ground and the fat bar so the figure stays the loudest thing on
   the card, and drawn from the food itself: poultry pale, beef deep red, fish blue-green. */
.mc-chicken{ --kind:38 72% 52%; }
.mc-turkey { --kind:22 62% 48%; }
.mc-beef   { --kind:355 58% 46%; }
.mc-lamb   { --kind:330 38% 46%; }
.mc-fish   { --kind:192 58% 42%; }

.mc[class*="mc-"]{ background:color-mix(in srgb, hsl(var(--kind)) 7%, var(--card2));
  border-color:color-mix(in srgb, hsl(var(--kind)) 22%, var(--border)); }
.mc[class*="mc-"] .mc-fat{ background:color-mix(in srgb, hsl(var(--kind)) 14%, transparent); }
.mc[class*="mc-"] .mc-fat i{ background:hsl(var(--kind)); }
.mc[class*="mc-"] .mc-n{ color:color-mix(in srgb, hsl(var(--kind)) 62%, var(--text-hi)); }

/* the tab carries the same hue, so the grid changing colour is explained by the thing you just tapped */
.mt-tabs button.on.mt-chicken{ background:hsl(38 72% 46%); }
.mt-tabs button.on.mt-turkey { background:hsl(22 62% 44%); }
.mt-tabs button.on.mt-beef   { background:hsl(355 58% 44%); }
.mt-tabs button.on.mt-lamb   { background:hsl(330 38% 44%); }
.mt-tabs button.on.mt-fish   { background:hsl(192 58% 38%); }

/* and the detail screen says which world it came from, in that world's colour */
.mt-kind{ display:inline-block; margin-inline-start:10px; padding:3px 9px; border-radius:999px;
  font-size:11px; font-weight:600; color:hsl(var(--kind));
  background:color-mix(in srgb, hsl(var(--kind)) 12%, transparent); }

@media (prefers-color-scheme: dark){
  .mc-chicken{ --kind:42 68% 60%; }
  .mc-turkey { --kind:24 58% 58%; }
  .mc-beef   { --kind:356 62% 62%; }
  .mc-lamb   { --kind:332 42% 62%; }
  .mc-fish   { --kind:190 54% 56%; }
}
:root[data-theme="dark"] .mc-chicken{ --kind:42 68% 60%; }
:root[data-theme="dark"] .mc-turkey { --kind:24 58% 58%; }
:root[data-theme="dark"] .mc-beef   { --kind:356 62% 62%; }
:root[data-theme="dark"] .mc-lamb   { --kind:332 42% 62%; }
:root[data-theme="dark"] .mc-fish   { --kind:190 54% 56%; }
:root[data-theme="light"] .mc-chicken{ --kind:38 72% 52%; }
:root[data-theme="light"] .mc-turkey { --kind:22 62% 48%; }
:root[data-theme="light"] .mc-beef   { --kind:355 58% 46%; }
:root[data-theme="light"] .mc-lamb   { --kind:330 38% 46%; }
:root[data-theme="light"] .mc-fish   { --kind:192 58% 42%; }





/* ---- the cut drawings ----------------------------------------------------
   Filled two-tone forms, not hairlines: at forty pixels a 1.5px outline is a suggestion and a solid
   silhouette is an object. The pale mass is the meat, the solid marks are what name it — bone, fat cap,
   marbling, grill lines. Full strength and in the animal's own hue, because a drawing faded to a third
   of its opacity is a smudge whatever it was drawn as. */
.cut-art .b{ fill:currentColor; opacity:.3; }
.cut-art .a{ fill:currentColor; }
/* Tucked into the corner and sized so the macro line still fits on one row — a drawing that pushes
   "12.6g שומן" onto a second line has cost more than it gave. */
.mc-art{ position:absolute; top:12px; inset-inline-end:12px; display:flex; pointer-events:none; }
.mc-art .cut-art{ width:32px; height:32px; color:var(--text-lo); }
.mc[class*="mc-"] .mc-art .cut-art{ color:hsl(var(--kind)); }
.mt-art{ display:flex; justify-content:center; margin:8px 0 0; }
.mt-art .cut-art{ width:64px; height:64px; color:hsl(var(--kind)); }

/* ---- what was left on the plate ------------------------------------------ */
/* The quiet strip along the bottom of a meal: what is left over on one side, where the rows should have
   gone on the other. Both are afterthought actions, so neither gets a button that looks like one. */
.meal-foot{ display:flex; align-items:baseline; gap:12px; margin-top:6px; padding:9px 0 2px;
  border-top:1px solid var(--border-soft); }
.meal-left{ display:block; flex:1; text-align:start; margin:0; padding:0; background:none;
  border:none; font-size:12px; color:var(--text-lo); cursor:pointer; }
.meal-left:active{ color:var(--primary); }
.meal-move{ flex:0 0 auto; background:none; border:none; padding:0; font-size:12px; font-weight:600;
  color:var(--text-lo); cursor:pointer; }
.meal-move:active{ color:var(--primary); }
/* a destination with nothing to send to it */
.chip[disabled]{ opacity:.35; }
.chip.mv-item i{ font-style:normal; font-size:10px; opacity:.65; margin-inline-start:3px; }
.left-note{ font-style:normal; color:var(--text-lo); opacity:.85; }
.lo-lab{ display:block; font-size:11px; color:var(--text-lo); margin:16px 0 8px; }
.lo-steps{ display:grid; grid-template-columns:repeat(5,1fr); gap:5px; }
.lo-steps button{ padding:8px 2px; background:var(--card2); border:1px solid var(--border);
  border-radius:calc(var(--radius-sm) - 5px); font-size:11.5px; color:var(--text-mid); cursor:pointer; }
.lo-steps button.on{ border-color:var(--primary); color:#fff; font-weight:600; background:var(--primary); }
.lo-steps.big button{ padding:12px 2px; font-size:13px; }
.lo-row{ padding:12px 0; border-bottom:1px solid var(--border-soft); }
.lo-name{ margin-bottom:8px; }
.lo-name b{ font-size:14px; }
.lo-name i{ display:block; font-style:normal; font-size:11.5px; color:var(--text-lo); margin-top:2px; }
.lo-sum{ margin:16px 0 12px; padding:12px 14px; border-radius:var(--radius-sm);
  background:var(--card2); font-size:13px; color:var(--text-mid); text-align:center; }
.lo-sum b{ font-family:'Rubik',sans-serif; font-size:18px; color:var(--text-hi); }

/* Coming back to a plate is the common half of this feature, so it is a button and not a re-reading of
   the scale. */
.lo-back{ display:flex; align-items:center; justify-content:center; gap:7px; margin-bottom:4px; }
.lo-back svg{ width:15px; height:15px; }

/* The unfinished recipe, offered back rather than mourned. */
.rc-draft{ display:flex; align-items:center; gap:9px; margin-top:9px; padding:11px 13px;
  background:var(--card2); border:1px dashed var(--border); border-radius:var(--radius-sm); }
/* The whole card opens it. A "continue" button beside a card that does nothing when tapped is a card
   pretending not to be a button. */
.rc-draft-main{ flex:1; min-width:0; text-align:start; background:none; border:none; padding:0;
  color:inherit; cursor:pointer; }
.rc-draft b{ display:block; font-size:14px; }
.rc-draft i{ font-style:normal; font-size:11.5px; color:var(--text-lo); }

/* The per-serving figure reads as a figure, not as a table cell with a caption crammed beside it. */
.rc-head{ padding:4px 0 12px; }

/* The meal picker is the one control whose number of options the user decides. Up to four it stays a
   segmented row; past that the names get crushed to a few letters each, so it becomes a list — which
   the platform already draws better than a wrapped block of buttons ever would.

   Styled as the same "value you can change" control the date field uses: the chosen meal reads as a
   value, not as form furniture, and the chevron is drawn rather than left to the browser — the stock
   one arrives in the wrong colour, the wrong size and, in a right-to-left sheet, occasionally the
   wrong side. */
select#d-meal{
  -webkit-appearance:none; appearance:none;
  width:100%; height:46px; padding:0 13px; padding-inline-start:38px;
  background:var(--card2); border:1px solid var(--border); border-radius:var(--radius-sm);
  font-size:15px; font-weight:500; color:var(--text-hi); text-align:start; cursor:pointer;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237C8C82' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-size:17px 17px;
  background-position:left 13px center;
}
select#d-meal:focus{ outline:none; border-color:var(--primary);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent); }
select#d-meal:active{ background-color:var(--border-soft); }
