/* ============================================================
   PLATE — SCREEN LAYOUTS
   ============================================================ */

/* ---------- Shared bits ------------------------------------ */
.chiprow { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.linkbtn { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; font-size: inherit; }
.rlist { display: block; }
.img--missing { background: var(--surface-3); }

.pulse { animation: pulseNum 620ms var(--e-out); }
@keyframes pulseNum {
  0%   { transform: none; color: var(--ink); }
  30%  { transform: scale(1.16); color: var(--accent); }
  100% { transform: none; color: var(--ink); }
}
.input.saved, .textarea.saved, .select.saved {
  border-color: color-mix(in srgb, var(--good) 55%, transparent);
  box-shadow: 0 0 0 3px var(--good-soft);
}

/* ============================================================
   LOYALTY PREVIEW
   ============================================================ */
.loyalty { max-width: 920px; display: grid; gap: var(--s-4); }
.loyalty__hero { padding: var(--s-6); border-radius: var(--r-lg); background: linear-gradient(135deg, var(--accent-soft), var(--surface)); }
.loyalty__hero h1 { max-width: 590px; margin: var(--s-2) 0; font-family: var(--font-display); font-size: var(--fs-3xl); line-height: 1.05; }
.loyalty__hero p { max-width: 610px; color: var(--ink-2); margin: 0; }
.loyalty__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4); }
.loyalty .field__lb { display: block; }
.loyalty .btn { margin-top: var(--s-4); }
.loyalty__link { margin-top: var(--s-3); padding: var(--s-3); border: 1px dashed var(--line-strong); border-radius: var(--r-sm); font-family: var(--font-mono); color: var(--accent-on-soft); }
.loyalty__staff { max-width: 600px; }
.loyalty__progress { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: var(--s-4) 0; }
.loyalty__dot { width: 24px; height: 24px; border: 2px solid var(--line-strong); border-radius: 50%; background: var(--surface-2); }
.loyalty__dot.is-done { background: var(--accent); border-color: var(--accent); box-shadow: inset 0 0 0 5px var(--accent-soft); }
.loyalty__ready { color: var(--good); font-weight: 700; margin: var(--s-3) 0 0; }
.loyalty--guest { max-width: 600px; margin: 0 auto; }
.loyalty__back { justify-self: start; border: 0; background: none; cursor: pointer; margin-top: var(--s-2); }
@media (max-width: 620px) { .loyalty__grid { grid-template-columns: 1fr; } .loyalty__hero { padding: var(--s-5); } }

/* ============================================================
   WELCOME (first run)
   ============================================================ */
.welcome {
  min-height: 100vh;
  display: grid; place-items: center;
  padding: var(--s-7) var(--s-5);
  background:
    radial-gradient(80% 60% at 50% -10%, var(--accent-soft), transparent 70%),
    var(--bg);
}
.welcome__in { max-width: 620px; text-align: center; }
.welcome__mark {
  width: 54px; height: 54px; margin: 0 auto var(--s-5);
  border-radius: var(--r-md);
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center;
  font-size: 38px;
  box-shadow: var(--shadow-2);
}
.welcome__h1 { font-family: var(--font-ui); font-weight: 800;
  letter-spacing: -0.025em; font-size: var(--fs-4xl); margin-bottom: var(--s-3); }
.welcome__lead { font-size: var(--fs-lg); color: var(--ink-2); line-height: 1.5; margin-bottom: var(--s-7); }
.welcome__lead em { color: var(--accent); font-style: italic; }
.welcome__pts {
  display: grid; gap: var(--s-2);
  text-align: left;
  max-width: 420px; margin: 0 auto var(--s-7);
  font-size: var(--fs-sm); color: var(--ink-2);
}
.welcome__pts > div {
  padding: 10px var(--s-4);
  border-left: 2px solid var(--line-strong);
  background: var(--surface);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
.welcome__pts .num { color: var(--accent); font-weight: 600; }
.welcome__acts { display: flex; gap: var(--s-3); justify-content: center; flex-wrap: wrap; }
.welcome__note { font-size: var(--fs-xs); margin-top: var(--s-6); }

/* ============================================================
   HOME
   ============================================================ */
.home__top {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--s-4);
  align-items: stretch;
}
@media (max-width: 1000px) { .home__top { grid-template-columns: 1fr; } }


.home__stats { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3); }
@media (max-width: 520px) { .home__stats { grid-template-columns: 1fr; } }

.nudges { display: grid; gap: var(--s-2); margin-top: var(--s-4); }
.nudges .banner { align-items: center; }
@media (max-width: 640px) {
  .nudges .banner { flex-wrap: wrap; }
  .nudges .banner__act { margin-left: 0; width: 100%; }
  .nudges .banner__act .btn { width: 100%; }
}

.famfilter { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--s-4); }
.famfilter .chip { cursor: pointer; transition: all var(--t-fast) var(--e-out); }
.famfilter .chip[aria-pressed="true"] {
  background: var(--fam, var(--accent));
  /* White on the flame accent measures 3.97:1 — a fail on the one chip the
     owner has actually selected. --accent-ink is the token that exists for
     text ON the accent, and it clears at 4.87:1. */
  color: var(--accent-ink); border-color: transparent;
}
.famfilter .chip[aria-pressed="true"] .fam-dot { background: #fff; }

.tickets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: var(--s-4);
}
@media (max-width: 560px) { .tickets { grid-template-columns: 1fr; } }

.levers { margin-top: var(--s-8); }
.levers__lead { font-size: var(--fs-sm); color: var(--ink-3); margin: 4px 0 var(--s-4); }
.levers__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s-3); }
.lever {
  display: grid; gap: 3px;
  text-align: left;
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color var(--t-fast) var(--e-out), transform var(--t-fast) var(--e-out);
}
.lever:hover { border-color: var(--accent-line); transform: translateY(-1px); }
.lever__gain { font-size: var(--fs-xl); font-weight: 600; color: var(--accent); line-height: 1; }
.lever__lab { font-size: var(--fs-sm); font-weight: 600; }
.lever__hint { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.4; }

/* ============================================================
   IDEA DETAIL
   ============================================================ */
.idea { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: var(--s-6); }
@media (max-width: 820px) {
  /* ⛔ `1fr` is not `minmax(0, 1fr)`. A grid track defaults to a MIN of
     auto, so one child's min-content -- here the caption box -- blew the
     column out to 464px inside a 348px sheet and pushed Copy, the time
     field and Forget it off the right edge. `min-width: 0` on the container
     does nothing about it; the TRACK is what has to be told. */
  .idea { grid-template-columns: minmax(0, 1fr); gap: var(--s-5); }
  .idea > * { min-width: 0; max-width: 100%; }
  /* ⭐ On a phone the caption came 477px and seven buttons into the sheet.
     It is the thing the owner opened this for, so it goes first and the
     controls follow it. */
  .idea__left { display: contents; }
  .idea__hookwrap { order: 1; }
  .idea__capwrap  { order: 2; }
  .idea__note     { order: 3; }
  .writebar       { order: 4; }
  .idea__rate     { order: 5; }
  .idea__right    { order: 6; }
  .idea > [data-versions] { order: 1; }
}
/* ⛔ The caption header is `label | tabs` in a flex row. The tabs block
   sized to its own content -- 392px of it -- so it pushed the header, and
   with it the whole column, past the sheet. The strip scrolls INSIDE its
   box; for that to mean anything the box has to be allowed to be small. */
.sechd__act { min-width: 0; }
@media (max-width: 640px) {
  .idea .sechd { flex-wrap: wrap; gap: var(--s-2); }
  .idea .sechd > * { min-width: 0; max-width: 100%; }
  .idea .sechd__act { flex: 1 1 100%; }
  .idea .seg { max-width: 100%; }
}

.idea, .idea__left, .idea__right { min-width: 0; }
.idea__sched { min-width: 0; }
.idea__sched .input { min-width: 0; }

.idea__meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: var(--s-3); }
.idea__hook {
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  line-height: 1.22;
  letter-spacing: var(--tracking-tight);
  margin-bottom: var(--s-6);
}
.idea__note { font-size: var(--fs-xs); margin-top: var(--s-3); line-height: 1.5; }
.idea__sec { margin-bottom: var(--s-6); }
.idea__sec .eyebrow { display: block; margin-bottom: var(--s-3); }

.shotlist { counter-reset: shot; display: grid; gap: var(--s-2); }
.shotlist li {
  position: relative;
  padding-left: 30px;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--ink-2);
}
.shotlist li::before {
  counter-increment: shot;
  content: counter(shot);
  position: absolute; left: 0; top: 1px;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  background: var(--surface-3);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
}

/* ⭐ The photograph being published. It was a 108px square rendering at
   150x110 -- smaller than the thumbnail beside a dish name on Menu, on the
   one screen where the question is whether to post it. Now it is the width
   of its column at the ratio the system uses everywhere. */
.photopick { display: grid; gap: var(--s-3); }
.photopick__ph { width: 100%; aspect-ratio: 3 / 2; border-radius: var(--r-md); }
.photopick__ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photopick__ph.is-missing img { display: none; }
.photopick__ph.is-missing {
  display: grid; place-items: center;
  background: var(--surface-2); border: 1px dashed var(--line);
}
.photopick__ph.is-missing::after {
  content: "photo unavailable";
  font-family: var(--font-display); font-size: var(--fs-sm); color: var(--ink-4);
}
.photopick__meta { display: grid; gap: var(--s-2); }
.photopick__nm { font-size: var(--fs-md); font-weight: 600; }
.photopick__sub { font-size: var(--fs-xs); color: var(--ink-3); }
.photopick__acts { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.photoslot__acts { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: 10px; }

.photorow { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-2); }
.photorow__opt {
  display: grid; gap: 5px; text-align: left;
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 5px; background: var(--surface-2);
  transition: border-color var(--t-fast) var(--e-out);
}
.photorow__opt:hover { border-color: var(--accent-line); }
.photorow__opt img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--r-sm); background: var(--surface-3); }
.photorow__opt span {
  font-size: var(--fs-2xs); color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 2px 2px;
}

.idea__sched { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.idea__sched .input { width: auto; flex: 1 1 130px; }
.idea__why { font-size: var(--fs-xs); margin-top: var(--s-2); line-height: 1.5; }

/* ============================================================
   CALENDAR
   ============================================================ */
.cal__title { font-size: var(--fs-2xl); margin-bottom: var(--s-4); }

.calgrid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}
.calgrid__dow {
  background: var(--surface-2);
  padding: 7px var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-cap);
  text-transform: uppercase;
  color: var(--ink-3);
}
.calweek {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}
.calweek .cell { min-height: 320px; }

.cell {
  background: var(--surface);
  min-height: 104px;
  padding: 6px;
  display: flex; flex-direction: column; gap: 4px;
  transition: background var(--t-fast) linear;
}
.cell--muted { background: var(--bg-sunk); }
/* A day outside this month is secondary, not unreadable — the sunk cell
   background already says which month it belongs to. --ink-4 was 4.1:1. */
.cell--muted .cell__n { color: var(--ink-quiet); }
.cell--today { box-shadow: inset 0 0 0 2px var(--accent-line); }
.cell--slow { background: color-mix(in srgb, var(--warn) 7%, var(--surface)); }
.cell.is-over { background: var(--accent-soft); }
.cell__hd { display: flex; align-items: center; gap: 5px; }
.cell__n { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-3); }
.cell__dow { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--ink-4); text-transform: uppercase; }
/* ⛔ Was `.cell__tag`: uppercase mono, 24 of them across a month that is
   81% empty, louder than the dates. It is the owner's own rhythm data, so
   it stays -- sentence case, quiet, subordinate. Not a status, not a
   warning, not a calendar object. */
.cell__rhythm {
  font-size: var(--fs-2xs);
  /* --ink-4 measured 4.1:1 — quiet is not the same as unreadable */
  color: var(--ink-quiet);
  letter-spacing: normal;
  text-transform: none;
  margin-left: auto;
}
.cell__tag {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 9px;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-4);
}
.cell__tag--slow { color: var(--warn); }

/* ⭐ A promotion, saying so. It used to be its name alone in a dashed box,
   with "Recurring special" available only on hover -- indistinguishable
   from a scheduled post, or from a failed one, on any touch device. */
.anchor {
  display: grid; gap: 1px;
  font-size: var(--fs-2xs);
  padding: 5px 6px;
  border-radius: var(--r-xs);
  border: 1px dashed var(--line-strong);
  background: transparent;
}
.anchor__kind {
  font-size: 9px; font-weight: 600;
  color: var(--ink-3); letter-spacing: 0.02em;
}
.anchor__nm { color: var(--ink-2); line-height: 1.3; }

.ev {
  position: relative;
  /* stretch, so the open control is as tall as the pill it covers -- and
     44px, so the pill IS the target rather than a 39px approximation of one */
  display: flex; align-items: stretch; gap: 4px;
  min-height: 44px;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--fam) 15%, var(--surface));
  border-left: 2px solid var(--fam);
  font-size: var(--fs-2xs);
  cursor: grab;
}
.ev.is-dragging { opacity: 0.4; }
/* The hook IS the control; its ::after covers the pill, and the remove x
   sits above that overlay. Whole pill clickable, both focusable, and no
   button nested inside a button. */
.ev__open {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: flex-start; gap: 5px;
  padding: 6px 5px; text-align: left; color: inherit;
}
.ev__open::after { content: ""; position: absolute; inset: 0; z-index: 0; }
.ev__open:focus-visible { outline: none; }
.ev__open:focus-visible::after {
  outline: 2px solid var(--focus); outline-offset: -2px; border-radius: var(--r-xs);
}
.ev__open .fam-dot { margin-top: 5px; flex: 0 0 auto; }
/* ⛔ NO MID-WORD TRUNCATION. It used to be one nowrap line with an
   ellipsis, so every pill read "We cut it in half f…". Two lines, clamped
   at a word, and the title carries the rest. */
.ev__hook {
  flex: 1 1 auto; min-width: 0;
  line-height: 1.3;
  /* ⛔ A month cell can be under 60px of text width, and v195 made the
     "With your scheduler" note render here for the first time -- a fresh
     browser could never reach that state before. A word longer than the
     column has to break rather than push the pill open. */
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Handed over / refused, in words. Never colour alone. */
.ev__state {
  display: block; margin-top: 2px;
  font-size: 9px; color: var(--ink-3);
}
.ev__x {
  position: relative; z-index: 1;
  opacity: 0; color: var(--ink-3);
  display: grid; place-items: center; flex: 0 0 auto;
  width: 22px; align-self: stretch;
}
.ev__x::after { content: ""; position: absolute; inset: -2px -16px -2px -8px; }
.ev__x svg { width: 11px; height: 11px; }
.ev:hover .ev__x, .ev__x:focus-visible { opacity: 1; }
.ev__x:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; border-radius: var(--r-xs); }

/* the 17-family legend is gone; `.leg` has no markup left to style */

/* ============================================================
   CALENDAR  ·  the parts added in v193
   ============================================================ */
.cal { min-width: 0; }
.cal__banner { margin-bottom: var(--s-3); }
.cal__bannerAct { margin-top: var(--s-2); }
.sechd--cal { margin-top: var(--s-7); }

/* ⭐ The affordance on an empty day. 34 of 42 cells were silently
   clickable; the behaviour is unchanged and now it can be seen and
   tabbed to. */
.cell { position: relative; }
.cell__add {
  position: absolute; right: 4px; bottom: 4px;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  color: var(--ink-4); border-radius: var(--r-sm);
  opacity: 0;
  transition: opacity var(--t-fast) var(--e-out), color var(--t-fast) var(--e-out);
}
.cell__add svg { width: 14px; height: 14px; }
.cell:hover .cell__add { opacity: 1; }
.cell__add:focus-visible {
  opacity: 1; color: var(--ink);
  outline: 2px solid var(--focus); outline-offset: -2px;
}
.cell__add:hover { color: var(--ink); background: var(--surface-2); }

/* ⭐ THE PHONE'S MONTH. Swapped by CSS rather than by a width check in JS,
   so a rotation cannot leave the wrong one on screen. */
.calagenda { display: none; }
@media (max-width: 560px) {
  .calgrid { display: none; }
  .calagenda { display: grid; gap: var(--s-4); }
}
.agday {
  border-top: 1px solid var(--line);
  padding-top: var(--s-3);
  display: grid; gap: var(--s-2);
}
.agday--today .agday__date { color: var(--accent-on-soft); }
.agday__hd { display: flex; align-items: baseline; gap: var(--s-3); }
.agday__date { font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2); }
.agday .cell__rhythm { margin-left: 0; }
/* in the agenda there is room to read, so nothing is clamped */
.agday .ev { font-size: var(--fs-sm); }
.agday .ev__hook { -webkit-line-clamp: 3; }
.agday .ev__state { font-size: var(--fs-2xs); }
.agday .ev__x { opacity: 1; width: 44px; }
.agday .anchor { font-size: var(--fs-sm); }
.agday .anchor__kind { font-size: var(--fs-2xs); }

/* the scheduled list: same valid-nesting pattern as the pill */
.schedrow { position: relative; }
.schedrow__open {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: var(--s-3);
  text-align: left; color: inherit;
  padding: var(--s-3) 0;
  min-height: 44px;
}
.schedrow__open::after { content: ""; position: absolute; inset: 0; z-index: 0; }
.schedrow__open:focus-visible { outline: none; }
.schedrow__open:focus-visible::after {
  outline: 2px solid var(--focus); outline-offset: -2px; border-radius: var(--r-sm);
}
.schedrow__x {
  position: relative; z-index: 1;
  opacity: 1; width: 44px; height: 44px;
}
.schedrow__x::after { content: none; }

.poolitem { min-height: 44px; }
.poolitem:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.cal__pool { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.poolitem {
  display: flex; align-items: center; gap: 7px;
  padding: 7px var(--s-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--fam);
  border-radius: var(--r-sm);
  font-size: var(--fs-xs);
  cursor: grab;
  max-width: 320px;
}
.poolitem.is-dragging { opacity: 0.4; }
.poolitem__hook { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ⛔ THIS BLOCK USED TO CONTAIN `.ev__hook { display: none }`.

   That is what produced the coloured blobs: below 700px every pill on the
   calendar showed a dot and nothing else, so the screen said THAT something
   was scheduled and never WHAT. It also silently blanked the new agenda,
   which is the same class in a different container.

   Nothing is ever hidden to make it fit now. Under 560px the month becomes
   the agenda, where there is room to read; between 560 and 700 the grid
   keeps its text at a smaller size and a tighter clamp. */
@media (max-width: 700px) {
  .calgrid .cell { min-height: 84px; padding: 4px; }
  .calgrid .ev { font-size: 9px; }
  .calgrid .ev__hook { -webkit-line-clamp: 2; }
  .calgrid .ev__open { padding: 4px 3px; }
  .calgrid .ev__x { display: none; }   /* removal lives in the list below */
  .anchor { font-size: 9px; }
}

/* ============================================================
   MEDIA LIBRARY
   ============================================================ */
.lib__top { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s-4); }
@media (max-width: 900px) { .lib__top { grid-template-columns: 1fr; } }

.cov { padding: var(--s-5); }
.cov__row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-4); margin-bottom: var(--s-3); }
.cov__val { font-size: var(--fs-md); margin-top: 6px; }
.cov__val .num { font-family: var(--font-mono); font-weight: 600; }
.cov__pct { font-family: var(--font-mono); font-size: var(--fs-2xl); font-weight: 600; letter-spacing: -0.02em; }
.cov__missing { margin-top: var(--s-3); display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: var(--fs-xs); }
.cov__missing .chip { cursor: pointer; }
.cov__missing .chip svg { width: 12px; height: 12px; }

.drop {
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  display: grid; place-items: center;
  padding: var(--s-6);
  text-align: center;
  transition: border-color var(--t-fast) var(--e-out), background var(--t-fast) var(--e-out);
  background:
    repeating-linear-gradient(135deg, transparent 0 10px, color-mix(in srgb, var(--line) 35%, transparent) 10px 11px);
}
.drop.is-over { border-color: var(--accent-on-soft); background: var(--accent-soft); }
.drop__in { display: grid; gap: 6px; justify-items: center; }
.drop__in svg { width: 26px; height: 26px; color: var(--ink-3); margin-bottom: 4px; }
.drop__in strong { font-size: var(--fs-md); }
.drop__in span { font-size: var(--fs-sm); }
.drop__note { font-size: var(--fs-xs) !important; color: var(--ink-quiet) !important; margin-top: 4px; }

/* Photos · the one media state an owner can resolve. Quiet by design:
   it is a thing to get round to, not an alarm, and it is not rendered at
   all once every photograph is backed up. */
.backupnote {
  display: flex; align-items: center; gap: var(--s-4);
  flex-wrap: wrap;
  margin: var(--s-5) 0 0;
  padding: var(--s-3) 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
/* The originals that are NOT here: informational, not a call to action —
   there is no button that could fix it from this device. */
.backupnote--gone { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md); padding: var(--s-3) var(--s-4); }
.backupnote__t { flex: 1 1 340px; font-size: var(--fs-sm); color: var(--ink-2); }
.backupnote__t strong { color: var(--ink); }
.backupnote__a { display: flex; gap: var(--s-2); flex-wrap: wrap; }

/* ============================================================
   POSTED  ·  the restaurant's own record
   ============================================================ */
.hist__search { min-width: 240px; }
.hist__found { margin: calc(var(--s-3) * -1) 0 var(--s-4); }
.hist__when { color: var(--ink-2); }
/* ⭐ A record, not a decision. The idea row is 156px because an owner is
   choosing there; here they are looking something up, and fifty of those
   is nine screens. The photograph stays -- it just stops setting the
   height -- and the meta and the action share one line. */
/* ⛔ `.tpost--idea` is defined LATER in this file, so a bare `.tpost--hist`
   rule of equal specificity loses every property they share. Qualified
   with both classes rather than reordering two big blocks. */
.tpost--idea.tpost--hist { padding: var(--s-3) var(--s-1); gap: var(--s-4); }
.tpost--idea.tpost--hist .tpost__ph.ph--idea { width: 132px; }
.tpost--idea.tpost--hist .tpost__hook {
  font-size: var(--fs-md);
  -webkit-line-clamp: 1;
}
.tpost--idea.tpost--hist .tpost__bd {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--s-4);
  row-gap: 2px;
}
.tpost--idea.tpost--hist .tpost__open { grid-column: 1 / -1; }
.tpost--idea.tpost--hist .tpost__meta { grid-column: 1; margin: 0; }
.tpost--idea.tpost--hist .idearow__acts { grid-column: 2; grid-row: 2; margin: 0; }
@media (max-width: 560px) {
  .tpost--idea.tpost--hist .tpost__ph.ph--idea { width: 84px; }
  .tpost--idea.tpost--hist .tpost__bd { grid-template-columns: minmax(0, 1fr); }
  .tpost--idea.tpost--hist .idearow__acts { grid-column: 1; grid-row: auto; }
}
/* ⛔ A missing photograph here is not a defect: most of this history
   predates Plate holding the image. A dated frame, quiet, never a warning
   and never an invented picture. */
.tpost__ph--past span {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--ink-quiet);
}
.hist__more {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-5) 0 var(--s-2);
}
/* the one control that grows the page — a real target, not a hit area */
.hist__more .btn { min-height: 44px; }

/* the read-only record */
.postedview { display: grid; grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: var(--s-6); }
.postedview__ph { width: 100%; aspect-ratio: 3 / 2; border-radius: var(--r-md); }
.postedview__ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.postedview__hook {
  font-family: var(--font-display); font-size: var(--fs-xl);
  line-height: var(--lh-snug); margin-bottom: var(--s-4);
}
.postedview__lb { display: block; margin-bottom: var(--s-2); }
.postedview__cap {
  font-size: 16px; line-height: var(--lh-loose);
  white-space: pre-wrap;
  padding: var(--s-4);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.postedview__meta { margin-top: var(--s-3); font-size: var(--fs-sm); }
@media (max-width: 720px) {
  .postedview { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  /* ⛔ `.sechd` is a flex row, so the search box shrank to 69px on a phone
     — present, and useless. The header wraps and search takes the width. */
  .hist .sechd--cal { flex-wrap: wrap; }
  .hist .sechd__act.hist__search { min-width: 0; width: 100%; flex: 1 1 100%; }
  .hist__search .input { width: 100%; }
  .hist__more { flex-wrap: wrap; }
}

/* ============================================================
   POST IDEAS  ·  an idea is a decision about food
   ============================================================ */
/* A `.tpost` with a photograph big enough to decide on, and the controls
   that act on the idea. Today emits no `--idea`, so its rows are untouched. */
.idearows { display: grid; gap: 0; border-top: 1px solid var(--line); }
.tpost--idea {
  position: relative;
  align-items: flex-start;
  gap: var(--s-5);
  padding: var(--s-4) var(--s-1);
}
/* ⭐ Substantial, at the 3:2 the whole system uses. It was 38x38 at 1:1,
   below the words, between a button and three unlabelled icons. */
/* ⛔ Specific enough to beat Today's own `.tpost__ph { width: 108px }` --
   same class, later in the file, so a bare `.ph--idea` lost. */
.tpost--idea .tpost__ph.ph--idea { width: 208px; aspect-ratio: 3 / 2; }
.tpost--idea .tpost__bd { gap: var(--s-2); align-self: center; }

/* ⛔ The hook IS the control, and its ::after covers the row -- so the whole
   row opens the idea without an <article role="button"> illegally
   containing three buttons. */
.tpost__open {
  display: block; text-align: left; width: 100%;
  color: inherit;
}
.tpost__open::after { content: ""; position: absolute; inset: 0; z-index: 0; }
.tpost__open:focus-visible { outline: none; }
.tpost__open:focus-visible::after {
  outline: 2px solid var(--focus); outline-offset: -3px; border-radius: var(--r-md);
}
.tpost--idea .tpost__hook {
  font-size: var(--fs-lg); font-weight: 550; line-height: var(--lh-snug);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.tpost--idea:hover { background: var(--surface-2); }
.tpost__meta--failed { color: var(--bad); }
.tpost--idea.is-writing .tpost__hook { color: var(--ink-3); font-style: italic; }

/* Above the overlay, so they are their own targets. */
.idearow__acts {
  position: relative; z-index: 1;
  display: flex; flex-wrap: wrap; gap: var(--s-2);
  margin-top: var(--s-1);
}
/* ⭐ REAL 44px, not a hit area.

   These three are the controls that change what Plate writes, and the row
   they sit in is 156px tall -- there is no density to protect here, so the
   target is the button rather than a transparent overlay whose true
   geometry cannot be read back reliably. A measured 44 beats an argued one.

   ⛔ And a local `::after` override made it WORSE once: a more specific
   `inset: -6px` silently replaced the system's `-10px`. If a hit area is
   ever needed here, fix the system rule instead. */
.idearow__acts .btn { min-height: 44px; }
.idearow__acts .btn.is-saved { color: var(--accent-on-soft); border-color: var(--accent-line); }
/* the consequence, quieter than the label but on the screen at every width */
.idearow__what { color: var(--ink-3); font-weight: 400; margin-left: 4px; }
.idearow__acts .btn:hover .idearow__what { color: var(--ink-2); }
@media (max-width: 420px) {
  /* on the narrowest phone the labels stack rather than shrink away */
  .idearow__what { display: block; margin-left: 0; font-size: var(--fs-2xs); }
  .idearow__acts .btn { flex-direction: column; gap: 1px; padding-top: 6px; padding-bottom: 6px; }
}
.idearow__acts svg { width: 13px; height: 13px; }

/* ⛔ The family filter used the engine's taxonomy in uppercase mono --
   MENU, HERITAGE, DISH, TRIBE. Same words, said the way a person would.

   ⛔ This was scoped to `.home` in v192, so the identical strip on Saved
   kept shouting. It is the FILTER that should be quiet, wherever it is. */
.famfilter .chip--fam {
  font-family: var(--font-ui);
  text-transform: none;
  letter-spacing: normal;
}

/* ⭐ Saved is a LIBRARY, not a weekly plate: eighteen items rather than
   five. One column of rows put 4 above the fold where the old card grid put
   9, so the row language keeps its photograph and gains a second column
   where there is room. Post Ideas stays single-column -- five items do not
   need it. */
@media (min-width: 1100px) {
  .idearows--vault { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--s-6); }
  .idearows--vault > .tpost--idea:nth-child(2) { border-top: 0; }
}
.idearows--vault { border-top: 0; }
.idearows--vault > .tpost--idea:first-child { border-top: 1px solid var(--line); }

.sechd--ideas { margin-top: var(--s-6); }
/* one sentence, not a row of numbers */
.quiet--one { display: block; }

@media (max-width: 720px) {
  .tpost--idea { gap: var(--s-4); padding: var(--s-4) 0; }
  .tpost--idea .tpost__ph.ph--idea { width: 132px; }
  .tpost--idea .tpost__hook { font-size: var(--fs-md); }
  /* the labels stay -- they are the point -- but they wrap under the text */
  .idearow__acts .btn { flex: 1 1 auto; justify-content: center; }
}
@media (max-width: 420px) {
  .tpost--idea .tpost__ph.ph--idea { width: 108px; }
}

/* ============================================================
   WRITE A POST  ·  the compose screen
   ============================================================ */
/* The form was inside a `.card` whose spacing came from twelve inline
   `style=` attributes. One system, in one place. */
.compose { display: grid; gap: var(--s-5); max-width: 720px; }
/* The kind chips read as chips, so they stay 36px tall and carry their
   target in a transparent ::after -- the method used everywhere else. */
.compose .kind { position: relative; }
.compose .kind::after { content: ""; position: absolute; inset: -6px -2px; }
.compose .field { display: grid; gap: var(--s-2); }
.compose__tip {
  font-size: var(--fs-sm); color: var(--ink-2);
  padding-left: var(--s-4);
  border-left: 2px solid var(--line-strong);
}
.compose .btnrow { margin-top: var(--s-1); }
.compose__mine { margin-top: var(--s-8); }
/* ⛔ 16px, so iOS does not zoom the page when an owner taps into it. */
.textarea--write { font-size: 16px; line-height: var(--lh-loose); min-height: 128px; }
.drow__del {
  flex: none; margin-left: auto;
  width: 36px; height: 36px; display: grid; place-items: center;
  border-radius: var(--r-sm); color: var(--ink-3);
  position: relative;
}
.drow__del::after { content: ""; position: absolute; inset: -4px; }
.drow__del:hover { color: var(--bad); background: var(--surface-2); }
.drow__del svg { width: 15px; height: 15px; }

/* ============================================================
   TODAY  ·  food first, useful work second, system status third
   ============================================================ */
/* What was here: two stacked warning boxes, a setup card, five equal
   status cards and six shortcut buttons that all duplicated the sidebar --
   and not one photograph on the screen that opens the app for a
   restaurant. */

/* ⛔ NO TEXT OVER FOOD, AT ANY BREAKPOINT.
   The words are a SIBLING of the photograph, never a child. Two columns
   when there is room, stacked when there is not, and nothing is ever
   absolutely positioned over the frame -- so a busy photo and a calm one
   both work with nothing to tune. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: var(--s-6);
  align-items: center;
  margin-bottom: var(--s-7);
}
/* ⭐ 3:2 is the ratio the system uses everywhere, but at full column width
   that is 547px of a 900px screen for one photograph -- the food would push
   the work below the fold, which is the same mistake in the other
   direction. Capped, so it crops wider rather than growing taller. */
.hero__ph {
  width: 100%; aspect-ratio: 3 / 2; max-height: 340px;
  border-radius: var(--r-lg);
}
.hero__ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero.is-missing .hero__ph img { display: none; }
.hero.is-missing .hero__ph {
  display: grid; place-items: center;
  background: var(--surface-2); border: 1px dashed var(--line);
}
.hero.is-missing .hero__ph::after {
  content: "photo unavailable";
  font-family: var(--font-display); font-size: var(--fs-md); color: var(--ink-4);
}
.hero__say { display: grid; gap: var(--s-2); }
.hero__day {
  font-family: var(--font-display);
  font-size: var(--fs-3xl); line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}
.hero__state { font-size: var(--fs-md); color: var(--ink-2); }
.hero__promo { font-size: var(--fs-sm); color: var(--accent-on-soft); }
.hero__cap { font-size: var(--fs-sm); color: var(--ink-quiet); }
.hero__act { margin-top: var(--s-2); }
.hero--none .hero__ph { aspect-ratio: 3 / 2; }

/* ⭐ Attention: a quiet list on a rule. Error treatment is reserved for a
   genuine error -- a promotion ending on Friday is a date, not a fault,
   and dressing every one of them in red is how the block gets skipped. */
.needs { border-top: 1px solid var(--line); }
.need {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-3) var(--s-1);
  border-bottom: 1px solid var(--line);
}
.need__t { flex: 1; font-size: var(--fs-sm); color: var(--ink-2); }
.need--bad .need__t { color: var(--ink); }
.need--bad::before {
  content: ""; width: 3px; align-self: stretch; flex: none;
  background: var(--bad); border-radius: 2px; margin-right: calc(var(--s-4) * -1 + 6px);
}
.need__more {
  display: block; padding: var(--s-3) var(--s-1);
  font-size: var(--fs-sm); color: var(--ink-3);
}
.need__more:hover { color: var(--ink); }

/* ⭐ The product, as the product. */
.tsec__hd {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); margin-bottom: var(--s-3);
}
.tposts { display: grid; gap: 0; border-top: 1px solid var(--line); }
.tpost {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-2) var(--s-1);
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background var(--t-fast) var(--e-out);
}
.tpost:hover, .tpost:focus-visible { background: var(--surface-2); }
.tpost:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.tpost__ph { width: 108px; }
.tpost__ph img { width: 100%; height: 100%; object-fit: cover; }
.tpost__ph--none {
  display: grid; place-items: center;
  background: var(--surface-2); border: 1px solid var(--line); padding: 5px;
}
.tpost__ph--none span {
  font-family: var(--font-display); font-size: var(--fs-2xs);
  line-height: 1.15; color: var(--ink-quiet); text-align: center;
  display: grid; gap: 2px;
}
/* ⛔ --ink-4 at 9px measured 3.44:1 on the placeholder ground. It was never
   caught on Today because every idea there happened to have a photograph;
   Post Ideas has one that does not, and the probe found it immediately. */
.tpost__ph--none small { font-size: var(--fs-2xs); color: var(--ink-quiet); }
.tpost__bd { min-width: 0; display: grid; gap: 3px; }
/* ⛔ The HOOK, not the caption. Two lines at most -- Today shows enough to
   know what the idea is, never enough to become a text feed again. */
.tpost__hook {
  font-size: var(--fs-md); font-weight: 550; line-height: var(--lh-snug);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.tpost__meta { font-size: var(--fs-xs); color: var(--ink-3); }

/* Outcomes, quietly, at the bottom. ⛔ Never engine capacity. */
.quiet {
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-6);
  padding-top: var(--s-5); margin-top: var(--s-6);
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm); color: var(--ink-3);
}
.quiet b { color: var(--ink-2); font-weight: 600; }

/* ⛔ There is no six-shortcut block and no phone-only copy of the action
   either. The header's `Write a post` primary renders at every width,
   including behind the hamburger layout, so a second one at the foot of
   the page would be the same button twice -- which is the habit this
   screen was cleaned up to break. */

@media (max-width: 860px) {
  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-4);
    align-items: start;
    margin-bottom: var(--s-5);
  }
  .hero__day { font-size: var(--fs-2xl); }
  .hero__ph { max-height: 300px; }
}
@media (max-width: 560px) {
  .tpost__ph { width: 84px; }
  .tpost__hook { font-size: var(--fs-sm); }
}

/* ============================================================
   PHOTOS -- the head above the grid
   ============================================================ */
/* ⭐ What used to be here: a coverage CARD and a 525px dashed drop box,
   together 706px of chrome before the first photograph on desktop and
   1,294px on a phone. On a screen called Photos, zero photographs were
   visible without scrolling. This is the whole of it now. */
.lib__head {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--s-3) var(--s-5);
  padding-bottom: var(--s-3);
}
.covline {
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--fs-sm); color: var(--ink-3);
  margin: 0;
}
.covline .num { color: var(--ink-2); font-weight: 550; }
.covline__bar {
  display: block; width: 84px; height: 4px;
  border-radius: var(--r-full); background: var(--surface-3);
  overflow: hidden;
}
.covline__bar i { display: block; height: 100%; background: var(--ink-4); }
.covline__pct { color: var(--ink-3); }

/* Dragging still works everywhere; this is the feedback that says so. */
.lib.is-over { outline: 2px dashed var(--accent); outline-offset: 6px; border-radius: var(--r-lg); }

/* The Shoot it affordance on a Needs-a-photo row. */
.drow__go {
  display: inline-flex; align-items: center; gap: 6px;
  flex: none; margin-left: auto;
  font-size: var(--fs-xs); font-weight: 550; color: var(--ink-2);
  padding: 7px 11px;
  border: 1px solid var(--line); border-radius: var(--r-full);
}
.drow__go svg { width: 13px; height: 13px; }
.drow:hover .drow__go { border-color: var(--line-strong); color: var(--ink); }

/* ⭐ Eleven filter chips wrap to FIVE rows on a 390px phone -- 190px of
   chrome pushed in front of the photographs, which is the exact failure
   this screen was redesigned to remove. One row that scrolls sideways
   inside its own box; the page itself never scrolls horizontally. */
@media (max-width: 560px) {
  .lib .famfilter {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    margin: 0 calc(var(--s-4) * -1);
    padding: 2px var(--s-4);
  }
  .lib .famfilter::-webkit-scrollbar { display: none; }
  /* ⛔ 25px tall is a thumb-sized miss on a phone. The chip keeps its
     lightness — only the target grows. */
  .lib .famfilter .chip { flex: 0 0 auto; min-height: 36px; padding-inline: 12px; }
  .lib .seg > button { min-height: 36px; }
  .lib .libtools__q, .lib .libtools__sort .select { min-height: 40px; }
  /* The retry lives here too, and it is the one control an owner with a
     shaky upload actually needs to hit. */
  .lib .backupnote__a .btn { min-height: 36px; }
}

@media (max-width: 560px) {
  .lib__head { gap: var(--s-2) var(--s-4); }
  .covline__bar { width: 56px; }
  .drow__go { padding: 7px 9px; }
}

.pgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: var(--s-3);
  margin-top: var(--s-4);
}
/* ⭐ Two columns on a phone, deliberately. 390px of viewport leaves ~358 of
   content; at a 168px minimum plus the gap that is two, and two is the
   smallest number that still reads as a GRID of photographs rather than a
   stack of one. */
@media (max-width: 560px) {
  .pgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
}
.pthumb {
  position: relative;
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--e-out), transform var(--t-fast) var(--e-out);
}
.pthumb:hover { border-color: var(--line-strong); transform: translateY(-1px); }
.pthumb:focus-visible {
  outline: 2px solid var(--focus); outline-offset: 2px; border-color: var(--line-strong);
}
/* ⭐ The approved failed-image placeholder. A record whose picture will not
   load is not a broken browser glyph with alt text spilling across the tile;
   it is an empty frame that says so. */
.pthumb.is-missing img { display: none; }
.pthumb.is-missing::before {
  content: "photo unavailable";
  display: grid; place-items: center;
  width: 100%; aspect-ratio: 4 / 3;
  background: var(--surface-2);
  border-bottom: 1px dashed var(--line);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  color: var(--ink-4);
}
.pthumb.is-selected { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.pthumb img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  background: var(--dom, var(--surface-3));
}
.pthumb figcaption { padding: 7px 9px 9px; display: grid; gap: 1px; }
.pthumb__nm { font-size: var(--fs-xs); font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A photo nobody has tied to a dish yet. Stated, not flagged. */
.pthumb__meta { font-size: var(--fs-2xs); color: var(--ink-3); }
/* ⛔ Was a solid --bad red badge. Wanting a better picture of a dish is a
   recommendation, not a failure, and dressing it as an error taught owners
   to read the whole screen as a list of things they had done wrong. Quiet
   surface, readable ink, and it says what it means. */
.pthumb__flag {
  position: absolute; top: 7px; left: 7px;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--line-strong);
  font-size: var(--fs-2xs); font-weight: 550;
  padding: 2px 7px; border-radius: var(--r-full);
}
/* Where the photo lives: uploading now, or only on this device so far. */
.pthumb__state {
  position: absolute; top: 7px; right: 7px; z-index: 1;
  padding: 2px 7px; border-radius: var(--r-full);
  font-size: var(--fs-2xs); font-weight: 600;
  background: var(--warn-soft); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
}
.pthumb__state--gone { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink-2); font-weight: 500; }
.pthumb__state--up { background: var(--info-soft); border-color: color-mix(in srgb, var(--info) 45%, transparent); }
.pthumb__pick {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--bg) 62%, transparent);
  color: var(--ink);
  font-size: var(--fs-sm); font-weight: 600;
  opacity: 0; transition: opacity var(--t-fast) linear;
}
.pgrid--pick .pthumb:hover .pthumb__pick { opacity: 1; }

.tagrows { display: grid; gap: var(--s-3); }
.tagrow { display: flex; gap: var(--s-3); align-items: flex-start; }
.tagrow img {
  width: 92px; height: 92px; object-fit: cover; flex: 0 0 auto;
  border-radius: var(--r-md); border: 1px solid var(--line); background: var(--surface-3);
}
.tagrow__fields { flex: 1 1 auto; min-width: 0; display: grid; gap: 6px; }
.tagrow__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
@media (max-width: 640px) {
  .tagrow { flex-direction: column; }
  .tagrow img { width: 100%; height: 140px; }
  .tagrow__grid { grid-template-columns: 1fr; }
}

.editphoto { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: var(--s-5); }
.editphoto__img { width: 100%; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--surface-3); }
@media (max-width: 700px) { .editphoto { grid-template-columns: 1fr; } }

/* ============================================================
   MENU
   ============================================================ */
.menu__sec { margin-bottom: var(--s-7); }
.menu__sec .eyebrow { display: block; margin-bottom: var(--s-3); }
.dishes { display: grid; gap: var(--s-2); }
/* ⭐ C · The review note. A prompt, not warning chrome — no amber panel,
   no icon, no border box. It reads as a sentence the product is offering,
   and it can be put away. */
.reviewnote {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-4);
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s-6);
}
.reviewnote__t {
  flex: 1 1 320px; font-size: var(--fs-sm); color: var(--ink-2);
  line-height: var(--lh-body);
}
.reviewnote__t strong { color: var(--ink); font-weight: 600; }
.reviewnote__a { display: flex; gap: var(--s-2); flex: 0 0 auto; }
@media (max-width: 720px) { .reviewnote__a { width: 100%; } }

/* ============================================================
   ⭐ THE MENU ROW  (Menu redesign)

   This was `.dish`: a --surface card with a 1px border and a radius,
   repeated 71 times. Our own rule says a card means "a distinct object you
   can act on" -- and a menu line is a ROW. Seventy-one bordered boxes cost
   ~30px of chrome each and were the strongest cheap signal on the screen.

   Measured before: 88px per row, 10 visible, 8,048px of scroll. On a phone,
   240px per row and 3.5 visible -- twenty screens to find one price.
   ============================================================ */
.dishes { display: block; }
.drow {
  display: flex; align-items: center; gap: var(--s-4);
  /* ⛔ The photograph sets the row height, and that is the right trade.
     A 56px row would need a 40px-tall photo -- smaller than the 62px square
     this replaced -- which would win density by losing the thing the screen
     is about. The padding is trimmed instead. */
  padding: var(--s-1) var(--s-2);
  border-top: 1px solid var(--line);
  cursor: pointer;
  transition: background var(--t-fast) var(--e-out);
}
.dishes > .drow:first-child { border-top: 0; }
.drow:hover { background: var(--surface-2); }
.drow:focus-visible { background: var(--surface-2); }

/* The photograph at the ratio the system defines. */
.drow__ph { width: 96px; aspect-ratio: 3 / 2; border-radius: var(--r-sm); }
.drow__ph img { width: 100%; height: 100%; object-fit: cover; }

/* ⭐ A dish without a photograph is not missing content. Lighter than the
   row, framed like a mount, and it says which dish it is waiting for. */
.drow__ph--none {
  display: grid; place-items: center;
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 5px;
}
.drow__ph--none span {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  line-height: 1.15;
  color: var(--ink-quiet);
  text-align: center;
}

.drow__main { flex: 1 1 auto; min-width: 0; }
.drow__top { display: flex; align-items: baseline; gap: var(--s-3); }
.drow__nm { font-size: var(--fs-md); font-weight: 600; }
.drow__price {
  font-size: var(--fs-sm); color: var(--ink-2);
  margin-left: auto; flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}
.drow__desc {
  font-size: var(--fs-sm); color: var(--ink-3); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ⭐ D · the folded option ladder */
.drow__opts { font-size: var(--fs-xs); color: var(--ink-3); margin-top: 2px; }
.drow__more {
  background: none; border: 0; padding: 0 0 0 6px;
  font: inherit; color: var(--ink-quiet); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
  position: relative;
}
/* ⛔ -13px lands the target on 44.0 exactly, which rounds under. Clear it. */
.drow__more::after { content: ''; position: absolute; inset: -15px -8px; }
.drow__more:hover { color: var(--ink); }
.drow__tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }

/* The shoot affordance appears on hover, and is always there for keyboards
   and touch -- it just stops competing. */
/* ⛔ Was a fixed 30px column, so the reorder controls stacked on top of one
   another and spilled past the row. It sizes to what it holds now. */
.drow__acts { flex: 0 0 auto; display: flex; align-items: center; gap: 2px; }
.drow__acts .btn--icon { padding: 5px; }
/* Quiet where there is a pointer, always present where there is not —
   reordering must never be a hover-only action. */
@media (hover: hover) and (pointer: fine) {
  .drow__acts [data-act="dish-up"], .drow__acts [data-act="dish-down"] {
    opacity: 0; transition: opacity var(--t-fast) var(--e-out);
  }
  .drow:hover .drow__acts [data-act="dish-up"],
  .drow:hover .drow__acts [data-act="dish-down"],
  .drow:focus-within .drow__acts [data-act="dish-up"],
  .drow:focus-within .drow__acts [data-act="dish-down"] { opacity: 1; }
}
.drow__shoot { opacity: 0; transition: opacity var(--t-fast) var(--e-out); padding: 5px; }
.drow:hover .drow__shoot, .drow__shoot:focus-visible { opacity: 1; }
@media (hover: none) { .drow__shoot { opacity: 1; } }

.drow__check { flex: 0 0 auto; display: grid; place-items: center; padding: 0 2px; cursor: pointer; }
.drow__check input { width: 17px; height: 17px; accent-color: var(--accent); cursor: pointer; }
.drow.is-picked { background: var(--accent-soft); }
.drow.is-sus { box-shadow: inset 3px 0 0 var(--warn); }

/* ⭐ MOBILE · a real two-line row, not a reflowed desktop one.
   240px per dish becomes ~76px: 11 on a screen instead of 3.5. */
@media (max-width: 720px) {
  .drow { gap: var(--s-3); padding: var(--s-2) 0; align-items: center; }
  .drow__ph { width: 76px; }
  .drow__top { gap: var(--s-2); }
  .drow__nm { font-size: var(--fs-sm); }
  .drow__desc { display: none; }
  .drow__opts {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .drow__opts.is-folded { white-space: normal; }
  .drow__tags { display: none; }
}

/* ---- "is this a dish?" quick check ---- */
.check {
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  margin-bottom: var(--s-5);
}
.check__hd {
  display: flex; gap: var(--s-4); align-items: flex-start;
  margin-bottom: var(--s-4); flex-wrap: wrap;
}
.check__hd h3 { font-family: var(--font-display); font-size: var(--fs-xl); letter-spacing: var(--tracking-tight); }
.check__hd p { font-size: var(--fs-sm); color: var(--ink-2); margin-top: 4px; max-width: 62ch; line-height: 1.5; }
.check__hd > button { margin-left: auto; flex: 0 0 auto; }
.check__row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) 0;
  border-top: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  flex-wrap: wrap;
}
.check__nm {
  font-family: var(--font-display); font-size: var(--fs-lg);
  flex: 1 1 160px; min-width: 0;
}
.check__acts { display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; }
.check__acts .select { width: auto; max-width: 230px; }
@media (max-width: 640px) {
  .check__hd > button { margin-left: 0; width: 100%; }
  .check__acts { width: 100%; }
  .check__acts .select { flex: 1 1 auto; max-width: none; }
}

/* ---- bulk-select bar ---- */
.selbar {
  position: sticky; top: 70px; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-4);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-sm);
  flex-wrap: wrap;
}
.selbar__n { font-family: var(--font-mono); font-size: var(--fs-lg); font-weight: 600; }
.selbar__acts { margin-left: auto; display: flex; gap: var(--s-2); flex-wrap: wrap; }
@media (max-width: 700px) {
  .selbar { top: 56px; }
  .selbar__acts { margin-left: 0; width: 100%; }
}

/* ---- menu import: choose a method ---- */
.imp__tabs {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-2);
  margin-bottom: var(--s-5);
}
@media (max-width: 620px) { .imp__tabs { grid-template-columns: 1fr; } }
.imp__tab {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  text-align: left;
  transition: all var(--t-fast) var(--e-out);
}
.imp__tab:hover { border-color: var(--line-strong); }
.imp__tab[aria-pressed="true"] {
  border-color: var(--accent-on-soft); background: var(--accent-soft);
}
.imp__tab svg { width: 22px; height: 22px; flex: 0 0 auto; color: var(--ink-3); }
.imp__tab[aria-pressed="true"] svg { color: var(--accent); }
.imp__tab span { display: grid; gap: 1px; min-width: 0; }
.imp__tab b { font-size: var(--fs-sm); font-weight: 600; }
.imp__tab i { font-style: normal; font-size: var(--fs-2xs); color: var(--ink-3); }

.imp__thumbs {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--s-2); margin-top: var(--s-4);
}
.impthumb {
  position: relative; margin: 0;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  overflow: hidden; background: var(--surface-3);
}
.impthumb img { width: 100%; aspect-ratio: 3/4; object-fit: cover; }
.impthumb figcaption {
  position: absolute; left: 5px; bottom: 5px;
  background: var(--scrim); color: #fff;
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  padding: 1px 6px; border-radius: var(--r-full);
}
.impthumb__x {
  position: absolute; top: 4px; right: 4px;
  width: 22px; height: 22px; display: grid; place-items: center;
  background: var(--scrim); color: #fff; border-radius: 50%;
}
.impthumb__x svg { width: 12px; height: 12px; }
.impthumb--add {
  display: grid; place-items: center; gap: 4px;
  aspect-ratio: 3/4;
  border: 1px dashed var(--line-strong);
  color: var(--ink-3); font-size: var(--fs-2xs);
  background: transparent;
}
.impthumb--add svg { width: 20px; height: 20px; }

.imp__progress {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: var(--s-4); padding: var(--s-3) var(--s-4);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
}

.keycard {
  margin-top: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.keycard strong { font-size: var(--fs-sm); }
.keycard p { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.5; margin: 5px 0 var(--s-3); }
.keycard__row { display: flex; gap: var(--s-2); }
.keycard__row .input { flex: 1 1 auto; min-width: 0; }
.keycard__alt { margin: var(--s-3) 0 0 !important; }

.impthumb__pdf {
  display: grid; place-items: center; gap: 4px;
  aspect-ratio: 3/4; padding: var(--s-2);
  background: var(--surface-2); color: var(--ink-3);
  text-align: center;
}
.impthumb__pdf svg { width: 26px; height: 26px; }
.impthumb__pdf b { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.08em; }
.impthumb__pdf span {
  font-size: 9.5px; line-height: 1.25;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  word-break: break-word;
}

/* ---- #50 · a day you can click ----
   The cells were drop targets and nothing else, so nothing about them said
   "put something here". */
.cell { cursor: pointer; transition: background var(--t-fast) var(--e-out); }
.cell--muted { cursor: default; }
.cell:not(.cell--muted):hover { background: var(--surface-2); }
.cell:not(.cell--muted):hover .cell__hd::after {
  content: '+'; margin-left: auto;
  font-size: var(--fs-sm); color: var(--ink-3); line-height: 1;
}
.cell__hd { display: flex; align-items: center; gap: 6px; }
.ev, .anchor { cursor: pointer; }

.dayoffer { display: grid; gap: var(--s-2); }
.dayoffer__row {
  display: flex; align-items: center; gap: var(--s-3);
  width: 100%; text-align: left;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--e-out), background var(--t-fast) var(--e-out);
}
.dayoffer__row:hover { border-color: var(--line-strong); background: var(--surface-2); }
.dayoffer__hook { font-size: var(--fs-sm); flex: 1 1 auto; }
.dayoffer__subj { font-size: var(--fs-2xs); color: var(--ink-3); white-space: nowrap; }

/* ---- #23 · the dish, stated once ---- */
.tagctx {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunk);
  margin-bottom: var(--s-4);
}
.tagctx__lb { font-size: var(--fs-sm); }
.tagctx__pick { flex: 1 1 220px; }
.tagrows--known .tagrow__fields { gap: var(--s-2); }

/* #25 · one question per photo, as chips rather than a dropdown */
.shotchips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.shotchip {
  font-size: var(--fs-2xs);
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--e-out), background var(--t-fast) var(--e-out);
}
.shotchip:hover { border-color: var(--line-strong); }
.shotchip.is-on { border-color: var(--accent-on-soft); background: var(--accent-soft); color: var(--accent-on-soft); }

/* ---- #61 · what the page actually had ---- */
.grabfound { display: grid; gap: var(--s-2); margin-top: var(--s-4); }
.grabfound__row {
  display: grid; gap: 2px; text-align: left; width: 100%;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--e-out), background var(--t-fast) var(--e-out);
}
.grabfound__row:hover { border-color: var(--line-strong); background: var(--surface-2); }
.grabfound__lb { font-size: var(--fs-sm); font-weight: 600; }
.grabfound__sub { font-size: var(--fs-2xs); color: var(--ink-3); }

/* ---- #64 · the four voice inputs ---- */
.regrow { display: grid; gap: var(--s-2); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.regpick {
  display: grid; gap: 3px; text-align: left;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--e-out), background var(--t-fast) var(--e-out);
}
.regpick:hover { border-color: var(--line-strong); }
.regpick.is-on { border-color: var(--accent-on-soft); background: var(--accent-soft); }
.regpick b { font-size: var(--fs-sm); font-weight: 600; }
.regpick.is-on b { color: var(--accent); }
.regpick span { font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.4; }

/* ⭐ on a pasted post — the "posts that worked" input, in place */
.goldmarks { display: grid; gap: var(--s-2); margin-top: var(--s-2); }
.goldmark {
  display: flex; align-items: flex-start; gap: var(--s-3);
  width: 100%; text-align: left;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--e-out), background var(--t-fast) var(--e-out);
}
.goldmark:hover { border-color: var(--line-strong); }
.goldmark.is-on { border-color: var(--accent-on-soft); background: var(--accent-soft); }
.goldmark__star { font-size: var(--fs-md); line-height: 1.3; color: var(--ink-3); }
.goldmark.is-on .goldmark__star { color: var(--accent); }
.goldmark__t { font-size: var(--fs-2xs); line-height: 1.5; color: var(--ink-2); }

/* aspiration, folded away until wanted */
.raisebar { margin-top: var(--s-6); border-top: 1px solid var(--line); padding-top: var(--s-4); }
.raisebar > summary {
  cursor: pointer; font-size: var(--fs-sm); font-weight: 600;
  display: flex; align-items: center; gap: var(--s-2);
}
.raisebar__opt {
  font-size: var(--fs-2xs); font-weight: 400; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: .06em;
}
.raisebar__bd { padding-top: var(--s-4); }

/* ---- publish readiness (D4 · #73) ----
   Counted and named, with the calm line underneath. Not an error state:
   a website that is not ready is an ordinary thing. */
.readycard { border-color: var(--line-strong); }
.readycard__hd { margin: 0 0 var(--s-2); font-size: var(--fs-md); }
.readycard__names { font-size: var(--fs-sm); color: var(--ink-2); margin-bottom: var(--s-4); }
.readylist { display: grid; gap: var(--s-2); }
.readyrow {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--s-4);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunk);
}
.readyrow__lb { font-size: var(--fs-sm); }
.readycard__calm { margin-top: var(--s-4); }

/* ---- progressive setup card (D4 · #62) ----
   Quiet by design. It is a list of offers, not a scoreboard, and the way
   out of it is a visible button rather than a mystery. */
.setupcard {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: var(--s-5);
  display: grid; gap: var(--s-3);
}
.setupcard__hd {
  font-size: var(--fs-sm); font-weight: 600;
  margin-bottom: var(--s-1);
}
.setuprow {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--s-4);
  padding: var(--s-3) 0;
  border-top: 1px solid var(--line);
}
.setuprow:first-of-type { border-top: 0; padding-top: 0; }
.setuprow__lb { font-size: var(--fs-sm); }
.setuprow__why { font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.45; margin-top: 2px; }
.setupcard__x {
  justify-self: start;
  font-size: var(--fs-2xs); color: var(--ink-3);
  background: none; border: 0; cursor: pointer; padding: 0;
  margin-top: var(--s-1);
}
.setupcard__x:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 560px) {
  .setuprow { grid-template-columns: 1fr; }
  .setuprow .btn { justify-self: start; }
}

/* ---- list rows: promotions (D3) and special dates (D2) ----
   One shape for both. An owner reads down the left for what it is, and
   across for what happens on it. `.promorow` shipped in batch 4 with no
   styles at all -- it was rendering as stacked bare divs. */
.promolist, .exlist { display: grid; gap: var(--s-2); margin-top: var(--s-3); }
.promorow, .exrow {
  display: grid; align-items: center; gap: var(--s-3);
  grid-template-columns: 1fr auto auto;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
.promorow.is-off { opacity: .55; }
.promorow__nm, .exrow__nm { font-size: var(--fs-sm); font-weight: 600; }
.promorow__when, .promorow__dt, .exrow__dt {
  font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.45; margin-top: 2px;
}
.exrow__what {
  font-size: var(--fs-2xs); color: var(--ink-2);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.promorow__fx { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.promorow__act, .exrow__act { display: flex; gap: var(--s-1); }
/* Past dates stay listed. They are greyed, never deleted for you. */
.exlist__hd {
  font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
  margin-top: var(--s-3);
}
.exrow.is-past { opacity: .5; }
@media (max-width: 700px) {
  .promorow, .exrow { grid-template-columns: 1fr; align-items: start; }
  .promorow__act, .exrow__act { justify-content: flex-end; }
}

/* ---- three-way picker (slow-day promo) ---- */
.pickrow { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-2); }
.pickrow--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 700px) { .pickrow { grid-template-columns: 1fr; } }
.pick {
  display: grid; gap: 3px; text-align: left;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: all var(--t-fast) var(--e-out);
}
.pick:hover { border-color: var(--line-strong); }
.pick.is-on { border-color: var(--accent-on-soft); background: var(--accent-soft); }
.pick b { font-size: var(--fs-sm); font-weight: 600; }
.pick span { font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.4; }
.pick.is-on b { color: var(--accent); }

/* ---- numbered how-to (API key setup) ---- */
.howto { counter-reset: ht; display: grid; gap: var(--s-3); margin: var(--s-4) 0; }
.howto li {
  position: relative; padding-left: 30px;
  font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.5;
}
.howto li::before {
  counter-increment: ht; content: counter(ht);
  position: absolute; left: 0; top: 0;
  width: 21px; height: 21px; display: grid; place-items: center;
  border-radius: 50%; background: var(--surface-3); color: var(--ink-2);
  font-family: var(--font-mono); font-size: var(--fs-2xs);
}
.howto strong { color: var(--ink); }
.howto code {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  background: var(--surface-3); padding: 1px 5px; border-radius: var(--r-xs);
}

/* ---- learn-the-voice block ---- */
.vsamp__out {
  margin-top: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  border-radius: var(--r-md);
  animation: rise var(--t-mid) var(--e-out);
}
.vsamp__list { margin: var(--s-3) 0; display: grid; gap: 5px; }
.vsamp__list li {
  font-size: var(--fs-sm); color: var(--ink); line-height: 1.45;
  padding-left: 18px; position: relative;
}
.vsamp__list li::before {
  content: "→"; position: absolute; left: 0; color: var(--accent);
  font-family: var(--font-mono); font-size: var(--fs-xs);
}
.vsamp__note { font-size: var(--fs-2xs); color: var(--ink-3); margin-top: var(--s-3); }

/* ---- repeatable rows that wrap (multi-field addresses) ---- */
.rrow--wrap { flex-wrap: wrap; }
.rrow--wrap .input { flex: 1 1 140px; }
.rrow--wrap .input.is-wide { flex: 2 1 220px; }
.rrow--wrap .input.is-narrow { flex: 0 1 88px; }
.rrow--wrap .hrsbtn { flex: 1 1 200px; }

/* ---- menu import review table ---- */
.msum { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-4); }
.msum .chip b { font-weight: 700; }
.msum__note {
  flex: 1 1 100%;
  display: flex; gap: var(--s-2); align-items: flex-start;
  margin-top: var(--s-2); padding: var(--s-3);
  background: var(--info-soft);
  border: 1px solid color-mix(in srgb, var(--info) 30%, transparent);
  border-radius: var(--r-md);
  font-size: var(--fs-xs); line-height: 1.5; color: var(--ink-2);
}
.msum__note svg { width: 15px; height: 15px; flex: 0 0 auto; margin-top: 1px; }
.msum__note b { color: var(--ink); }
.mtablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-md); }
.mtable { width: 100%; border-collapse: collapse; min-width: 620px; }
.mtable th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--tracking-cap);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 500;
  padding: var(--s-3) var(--s-3) var(--s-2);
  background: var(--surface-2);
  position: sticky; top: 0; z-index: 1;
}
.mtable td { padding: 3px var(--s-2); border-top: 1px solid var(--line); }
.mrow__type { width: 210px; }
.mrow__price { width: 92px; }
/* the guessed type is legible at a glance, so a wrong row is easy to spot */
.mrow[data-type="dish"]        { background: color-mix(in srgb, var(--good) 9%, transparent); }
.mrow[data-type="option"]      { background: color-mix(in srgb, var(--info) 8%, transparent); }
.mrow[data-type="description"] { background: transparent; }
.mrow[data-type="section"]     { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.mrow[data-type="skip"],
.mrow[data-type="price"]       { opacity: 0.5; }
.mmode {
  margin-right: auto; display: flex; align-items: center; gap: 7px;
  font-size: var(--fs-sm); color: var(--ink-2); cursor: pointer;
}
.mmode input { width: 16px; height: 16px; accent-color: var(--bad); }
@media (max-width: 640px) { .mmode { width: 100%; margin-bottom: var(--s-2); } }
@media (max-width: 620px) {
  .dish { flex-wrap: wrap; }
  .dish__acts { width: 100%; }
  .dish__acts .btn { width: 100%; }
}

/* ============================================================
   PROFILE
   ============================================================ */
.prof { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: var(--s-7); align-items: start; }
/* ⛔ `1fr`, not `minmax(0, 1fr)`, was enough to push the whole screen sideways
   on a phone: a grid track's minimum is `auto`, so the horizontally-scrolling
   section nav refused to shrink below its content and took the body with it.
   The desktop rule above already knew this. */
@media (max-width: 900px) { .prof { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); } }

/* #10 · A `.prof` with no `.prof__nav` put its body in the 190px NAV
   column, so the Website screen rendered a full page of cards into a
   sidebar and hugged the left edge. The screen has no side nav and never
   did; it borrowed the class for the card spacing. Reading the DOM is what
   found this -- the inline `--read-max` cap was a real defect too, but
   removing it changed nothing, because the grid was doing the squeezing. */
.prof--single,
.prof:not(:has(.prof__nav)) { display: block; }

.prof__nav { position: sticky; top: 84px; display: grid; gap: 2px; }
@media (max-width: 900px) {
  .prof__nav { position: static; grid-auto-flow: column; grid-auto-columns: max-content; overflow-x: auto; padding-bottom: var(--s-2); }
  .prof__fresh { display: none; }
}
.prof__navitem {
  padding: 7px var(--s-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--ink-3);
  white-space: nowrap;
  transition: background var(--t-fast) var(--e-out), color var(--t-fast) var(--e-out);
}
.prof__navitem:hover { background: var(--surface-2); color: var(--ink); }
.prof__fresh {
  margin-top: var(--s-5);
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.prof__freshnum {
  font-family: var(--font-mono); font-size: var(--fs-2xl); font-weight: 600;
  line-height: 1.1; margin: 4px 0 2px;
}
.prof__sec { margin-bottom: var(--s-8); scroll-margin-top: 84px; }
.prof__body .card__bd .field:last-child { margin-bottom: 0; }

.tog__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s-2); }
.tog {
  align-items: flex-start;
  padding: 10px var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  text-align: left;
  width: 100%;
  transition: border-color var(--t-fast) var(--e-out);
}
.tog:hover { border-color: var(--line-strong); }
/* ⛔ A toggle sitting INLINE in a row, not stacked in a settings list. Without
   this the promotion row's two switches each took the full column width and
   the row read as three stacked cards. */
.tog--sm {
  width: auto;
  align-items: center;
  padding: 6px var(--s-3);
  gap: var(--s-2);
}
.tog--sm .tog__lab { font-size: var(--fs-sm); }
.tog__lab { display: grid; gap: 1px; }
.tog__lab > span:first-child { font-size: var(--fs-sm); font-weight: 550; }
.tog__hint { font-size: var(--fs-2xs); color: var(--ink-3); }

/* ---- hours editor ---- */
.hrs {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  padding: var(--s-4);
}
.hrs__quick {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--line);
}
.hrs__quicklb { font-size: var(--fs-sm); font-weight: 550; }
.hrs__quick .input { width: auto; flex: 0 0 auto; }
.hrs__help {
  font-size: var(--fs-xs); color: var(--ink-3);
  margin: var(--s-3) 0; line-height: 1.5;
}
.hrs__rows { display: grid; gap: 4px; }
.hrs__row {
  display: flex; align-items: center; gap: var(--s-2);
  padding: 3px 0;
}
.hrs__day {
  width: 42px; flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.hrs__t { width: auto; flex: 0 1 128px; min-width: 0; }
.hrs__to { font-size: var(--fs-xs); flex: 0 0 auto; }
/* ⛔ "next day" is a FACT about the hours you just typed, not an alert.
   It was carrying the accent -- the one colour reserved for action -- so a
   normal Friday closing time looked like something had gone wrong. Quiet
   treatment, per the three-status rule. */
.hrs__next {
  font-family: var(--font-ui); font-size: var(--fs-xs);
  color: var(--ink-3); background: transparent;
  padding: 1px 0; flex: 0 0 auto;
}
.hrs__closed {
  margin-left: auto; flex: 0 0 auto;
  display: flex; align-items: center; gap: 5px;
  font-size: var(--fs-xs); color: var(--ink-3); cursor: pointer;
}
/* A 15px checkbox is the smallest target in the product. The box stays
   15px -- a bigger one would look clumsy next to the time fields -- and the
   LABEL around it carries the hit area, which is what a label is for. */
.hrs__closed { position: relative; min-height: 44px; }
.hrs__closed input { width: 15px; height: 15px; accent-color: var(--ink-3); position: relative; }
.hrs__closed input::after { content: ''; position: absolute; inset: -15px; }
.hrs__row.is-closed .hrs__t, .hrs__row.is-closed .hrs__to { opacity: 0.4; }
.hrs__sum {
  margin-top: var(--s-4); padding-top: var(--s-3);
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm); font-weight: 550; color: var(--ink);
}
.hrs__sum.is-empty { color: var(--ink-4); font-weight: 400; font-style: italic; }
@media (max-width: 620px) {
  .hrs__row { flex-wrap: wrap; }
  .hrs__t { flex: 1 1 110px; }
  .hrs__closed { margin-left: 0; width: 100%; }
}

.hrsbtn { flex: 1 1 0; justify-content: flex-start; min-width: 0; }
.hrsbtn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ============================================================
   HISTORY
   ============================================================ */
.hist__top {
  display: flex; gap: var(--s-6); align-items: center; flex-wrap: wrap;
  padding: var(--s-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  margin-bottom: var(--s-7);
}
.hist__claim { display: flex; align-items: center; gap: var(--s-4); font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.35; }
.hist__big {
  font-family: var(--font-mono); font-size: var(--fs-4xl); font-weight: 600;
  letter-spacing: -0.03em; line-height: 1; color: var(--accent);
}
.hist__fams { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-left: auto; }
.histfam {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px; border-radius: var(--r-full);
  background: color-mix(in srgb, var(--fam) 12%, transparent);
  font-size: var(--fs-2xs);
}
.histfam__lab { color: var(--ink-2); }
.histfam__n { color: var(--fam); font-weight: 600; }

.histlist { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.histrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--surface);
}
.histrow:hover { background: var(--surface-2); }
.histrow__main { flex: 1 1 auto; min-width: 0; }
.histrow__hook { font-family: var(--font-display); font-size: var(--fs-md); line-height: 1.3; }
.histrow__meta { font-size: var(--fs-2xs); color: var(--ink-3); margin-top: 2px; }
.histrow__img { width: 34px; height: 34px; object-fit: cover; border-radius: var(--r-xs); flex: 0 0 auto; }
.histrow__date { font-size: var(--fs-xs); color: var(--ink-3); flex: 0 0 auto; }
@media (max-width: 600px) { .histrow__date { display: none; } }

/* ============================================================
   RESTAURANTS
   ============================================================ */
.rests { display: grid; gap: var(--s-3); }
.rest {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.rest.is-active { border-color: var(--accent-line); box-shadow: 0 0 0 2px var(--accent-soft); }
.rest__avatar {
  width: 46px; height: 46px; flex: 0 0 auto;
  border-radius: var(--r-md);
  display: grid; place-items: center;
  font-family: var(--font-mono); font-weight: 600; color: #fff;
}
.rest__main { flex: 1 1 auto; min-width: 0; }
.rest__nm { font-size: var(--fs-lg); font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rest__meta { font-size: var(--fs-sm); color: var(--ink-3); }
.rest__stats { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-top: 7px; font-size: var(--fs-xs); color: var(--ink-3); }
.rest__stats b { color: var(--ink); font-weight: 600; }
.rest__acts { display: flex; gap: var(--s-2); flex: 0 0 auto; }
@media (max-width: 620px) {
  .rest { flex-wrap: wrap; }
  .rest__acts { width: 100%; }
  .rest__acts .btn:first-child { flex: 1 1 auto; }
}

/* ============================================================
   SIDEBAR FOOT
   ============================================================ */
.sidefresh { display: flex; align-items: baseline; gap: 7px; margin-top: 3px; }
.sidefresh .num { font-family: var(--font-mono); font-size: var(--fs-xl); font-weight: 600; }
.sidefresh .muted { font-size: var(--fs-2xs); }

/* ============================================================
   SETTINGS
   ============================================================ */
.settings { display: grid; gap: var(--s-4); max-width: 720px; }

/* ============================================================
   ONBOARDING WIZARD
   ============================================================ */
.wiz {
  position: fixed; inset: 0;
  background: var(--bg);
  z-index: var(--z-modal);
  overflow-y: auto;
  animation: fade var(--t-mid) linear;
}
.wiz__shell {
  display: grid;
  grid-template-columns: 268px minmax(0, 1fr);
  min-height: 100vh;
}
.wiz__side {
  background: var(--bg-sunk);
  border-right: 1px solid var(--line);
  padding: var(--s-6) var(--s-5);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
}
.wiz__brand { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-7); }
.wiz__steps { display: grid; gap: 2px; }
.wiz__step {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 8px var(--s-3);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  color: var(--ink-3);
  cursor: pointer;
  transition: background var(--t-fast) var(--e-out), color var(--t-fast) var(--e-out);
}
.wiz__step:hover { background: var(--surface-2); color: var(--ink-2); }
.wiz__step.is-now { background: var(--surface-2); color: var(--ink); font-weight: 600; }
.wiz__step.is-done { color: var(--ink-2); }
.wiz__stepn {
  width: 21px; height: 21px; flex: 0 0 auto;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  font-size: var(--fs-2xs);
  color: var(--ink-3);
}
.wiz__step.is-now .wiz__stepn { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.wiz__step.is-done .wiz__stepn { background: var(--good); border-color: var(--good); color: #fff; }

.wiz__fresh {
  margin-top: auto;
  padding: var(--s-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.wiz__freshnum {
  font-family: var(--font-mono); font-size: var(--fs-3xl); font-weight: 600;
  line-height: 1; margin: 6px 0 var(--s-3); letter-spacing: -0.03em;
}
.wiz__freshcap { font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.45; margin-top: var(--s-3); }
.wiz__exit { margin-top: var(--s-4); }

.wiz__main {
  padding: var(--s-7) var(--s-8) var(--s-9);
  max-width: 760px;
  width: 100%;
}

/* ---- "You're set up." (D4 · #6) ----
   No rail, no step counter, no Continue. Setup is over and it should look
   over, so this shell is one centred column. */
.wiz__shell--done { grid-template-columns: minmax(0, 1fr); place-items: center; }
.wiz__shell--done .wiz__main { max-width: 620px; padding: var(--s-9) var(--s-6); }
.wiz__done { display: grid; gap: var(--s-5); text-align: center; }
.wiz__doneh { font-size: var(--fs-4xl); line-height: 1.05; }
.wiz__donesub { color: var(--ink-2); font-size: var(--fs-md); margin-top: calc(var(--s-4) * -1); }
.wiz__stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-3);
  margin-top: var(--s-2);
}
.wiz__stat {
  padding: var(--s-4) var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
.wiz__statn {
  font-family: var(--font-mono); font-size: var(--fs-2xl); font-weight: 600;
  line-height: 1; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.wiz__statl {
  font-size: var(--fs-2xs); color: var(--ink-3); margin-top: 6px;
  text-transform: uppercase; letter-spacing: .06em;
}
.wiz__donecap { font-size: var(--fs-sm); color: var(--ink-2); margin-top: calc(var(--s-3) * -1); }
.wiz__donesec { text-align: left; display: grid; gap: var(--s-2); }
.wiz__donesec--rule { border-top: 1px solid var(--line); padding-top: var(--s-5); }
.wiz__donesec p { font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.55; }
.wiz__donelist { display: grid; gap: var(--s-2); }
.wiz__donelist li {
  font-size: var(--fs-sm); line-height: 1.5;
  padding-left: var(--s-4); position: relative;
}
.wiz__donelist li::before {
  content: '•'; position: absolute; left: 0; color: var(--accent);
}
.wiz__doneact { margin-top: var(--s-3); }
.wiz__doneact .btn { min-width: 240px; }
.wiz__donemore {
  font-size: var(--fs-sm); color: var(--ink-3);
  background: none; border: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.wiz__donemore:hover { color: var(--ink); }
.wiz__donegaps { display: grid; gap: var(--s-3); text-align: left; margin-top: var(--s-2); }
.wiz__donegap { display: grid; gap: 2px; font-size: var(--fs-sm); }
.wiz__donegap span { font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.45; }
@media (max-width: 620px) {
  .wiz__stats { grid-template-columns: 1fr; }
  .wiz__doneact .btn { min-width: 0; width: 100%; }
}
.wiz__head { margin: var(--s-6) 0 var(--s-7); }
.wiz__h1 { font-size: var(--fs-3xl); margin: var(--s-2) 0 var(--s-3); }
.wiz__why { font-size: var(--fs-sm); color: var(--ink-3); max-width: 56ch; line-height: 1.55; }
.wiz__body { animation: rise var(--t-mid) var(--e-out); }
.wiz__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-8);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
.wizq { padding: var(--s-4); background: var(--surface-2); border-radius: var(--r-md); border: 1px solid var(--line); }

@media (max-width: 860px) {
  .wiz__shell { grid-template-columns: 1fr; }
  .wiz__side {
    position: static; height: auto;
    border-right: 0; border-bottom: 1px solid var(--line);
    padding: var(--s-4);
  }
  .wiz__steps { grid-auto-flow: column; grid-auto-columns: max-content; overflow-x: auto; gap: 4px; }
  .wiz__step span:not(.wiz__stepn) { display: none; }
  .wiz__step.is-now span:not(.wiz__stepn) { display: inline; }
  .wiz__fresh { margin-top: var(--s-4); }
  .wiz__brand { margin-bottom: var(--s-4); }
  .wiz__exit { margin-top: var(--s-3); }
  .wiz__main { padding: var(--s-5) var(--s-4) var(--s-9); }
  .wiz__h1 { font-size: var(--fs-2xl); }
  .wiz__foot { flex-wrap: wrap; }
  .wiz__foot .btnrow { flex: 1 1 auto; justify-content: flex-end; }
}

/* ---- "write this properly" ---- */
.writebar {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-5);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-md);
  flex-wrap: wrap;
}
.writebar .btn { flex: 0 0 auto; }
.writebar__note { font-size: var(--fs-xs); color: var(--ink-2); flex: 1 1 200px; line-height: 1.45; }
.writebar .spinner { display: inline-block; vertical-align: -2px; }

/* ---- like / dislike ---- */
.rate { display: inline-flex; gap: 2px; }
.rate__btn {
  width: 30px; height: 28px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--ink-3);
  background: var(--surface);
  transition: all var(--t-fast) var(--e-out);
}
.rate__btn svg { width: 15px; height: 15px; }
.rate__btn:hover { color: var(--good); border-color: var(--good); background: var(--good-soft); }
.rate__btn--down:hover { color: var(--bad); border-color: var(--bad); background: var(--bad-soft); }

.idea__rate {
  display: flex; align-items: center; gap: var(--s-2);
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm); flex-wrap: wrap;
}
.idea__rate .muted { margin-right: auto; }
.idea__rate .btn.is-on { border-color: var(--good); color: var(--good); background: var(--good-soft); }

.taste {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-4);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: var(--fs-sm); color: var(--ink-2);
}
.taste svg { width: 17px; height: 17px; flex: 0 0 auto; color: var(--accent); }
.taste > div { flex: 1 1 auto; }
.taste b { color: var(--ink); font-family: var(--font-mono); }
.taste strong { color: var(--ink); }

/* ---- editable caption box ---- */
.capbox {
  /* a field that looks like a field, so nothing has to explain that it is one */
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
  transition: border-color var(--t-fast) var(--e-out), box-shadow var(--t-fast) var(--e-out);
}
.capbox:hover { border-color: var(--ink-4); }
.capbox:focus-within { border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
/* ⭐ THE CAPTION IS THE PRODUCT.

   It was 13px UI sans -- the smallest text in the sheet, under a hook set
   at 34px in the display serif -- inside a box so quiet that a hint below
   it had to say "click into it and change anything you want". A hint
   explaining an affordance is the affordance failing.

   ⛔ And 13px is below 16px, so iOS Safari zoomed the page on every tap
   into the one long-form editor in the product. Never let this drop under
   16px at any breakpoint. */
.capedit {
  display: block; width: 100%;
  border: 0; background: transparent; resize: vertical;
  padding: var(--s-4);
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: var(--lh-loose);
  color: var(--ink);
  min-height: 200px;
}
.capedit:focus { outline: none; }
.capbox__bar {
  display: flex; align-items: center; gap: var(--s-2);
  padding: 6px var(--s-3);
  border-top: 1px solid var(--line);
  background: var(--surface);
}
.capbox__hint {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--fs-xs); color: var(--good);
}
.capbox__hint svg { width: 13px; height: 13px; }
/* hint (when shown) sits left; the two buttons sit right */
.capbox__bar > :last-child { margin-left: auto; }
.capbox__bar [data-reset-caption]:not([hidden]) ~ .btn:last-child { margin-left: 0; }

/* ---- save / vault ---- */
.rate__btn.is-saved { color: var(--accent-on-soft); border-color: var(--accent-line); background: var(--accent-soft); }
.btn--saved { color: var(--accent-on-soft); border-color: var(--accent-line); background: var(--accent-soft); }
.sechd h2 svg { width: 18px; height: 18px; vertical-align: -3px; margin-right: 4px; color: var(--accent); }

/* clickable calendar events */
.ev[role="button"] { cursor: pointer; }
.ev[role="button"]:hover { filter: brightness(1.08); }
.poolitem[role="button"] { cursor: pointer; }

/* ---- steer ("tell it what you want") ---- */
.steer {
  margin-bottom: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}
.steer > summary {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  font-size: var(--fs-sm); font-weight: 550;
  cursor: pointer; list-style: none;
}
.steer > summary::-webkit-details-marker { display: none; }
.steer > summary svg { width: 16px; height: 16px; color: var(--accent); flex: 0 0 auto; }
.steer__on {
  margin-left: auto;
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent-on-soft); background: var(--accent-soft);
  padding: 1px 8px; border-radius: var(--r-full);
}
.steer__body { padding: 0 var(--s-4) var(--s-4); }
.steer__hint { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.5; margin-bottom: var(--s-3); }
.steer__read {
  display: flex; gap: 7px; align-items: flex-start;
  margin-top: var(--s-3); padding: var(--s-3);
  background: var(--good-soft); border-radius: var(--r-sm);
  font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.5;
}
.steer__read svg { width: 14px; height: 14px; color: var(--good); flex: 0 0 auto; margin-top: 1px; }
.steer__read strong { color: var(--ink); }
.steer__read--miss { background: var(--info-soft); }
.steer__read--miss svg { color: var(--info); }

/* ---- per-post feedback box ---- */
.fbk {
  margin-top: var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
}
.fbk > summary {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  font-size: var(--fs-sm); font-weight: 550;
  cursor: pointer; list-style: none;
}
.fbk > summary::-webkit-details-marker { display: none; }
.fbk > summary svg { width: 15px; height: 15px; color: var(--accent); flex: 0 0 auto; }
.fbk__on {
  margin-left: auto;
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--good); background: var(--good-soft);
  padding: 1px 8px; border-radius: var(--r-full);
}
.fbk__body { padding: 0 var(--s-4) var(--s-4); }
.fbk__hint { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.5; margin-bottom: var(--s-3); }
.fbk__swap {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-top: var(--s-3); font-size: var(--fs-sm);
}

/* ---- runner-up caption versions ---- */
.alts { margin-top: var(--s-3); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface-2); }
.alts > summary {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  font-size: var(--fs-sm); cursor: pointer; list-style: none; color: var(--ink-2);
}
.alts > summary::-webkit-details-marker { display: none; }
.alts > summary svg { width: 15px; height: 15px; color: var(--accent); flex: 0 0 auto; }
.alts__body { padding: 0 var(--s-4) var(--s-4); }
.alts__why {
  font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.5;
  padding: var(--s-3); background: var(--surface); border-radius: var(--r-sm);
  margin-bottom: var(--s-3);
}
.alt { padding: var(--s-3) 0; border-top: 1px solid var(--line); }
.alt__approach {
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  text-transform: uppercase; letter-spacing: 0.07em; color: var(--accent); margin-bottom: 5px;
}
.alt__text { font-size: var(--fs-sm); line-height: var(--lh-loose); white-space: pre-wrap; margin-bottom: var(--s-2); }

/* ---- voice archetypes ---- */
.archrow {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--s-2);
}
.arch {
  display: grid; gap: 3px; text-align: left;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: all var(--t-fast) var(--e-out);
}
.arch:hover { border-color: var(--line-strong); transform: translateY(-1px); }
.arch.is-on { border-color: var(--accent-on-soft); background: var(--accent-soft); }
.arch b { font-size: var(--fs-sm); font-weight: 600; }
/* The selected archetype's name sits on the soft accent wash, where the
   accent itself measures 4.27:1. Same fix as every other soft-ground pair. */
.arch.is-on b { color: var(--accent-on-soft); }
.arch i {
  font-style: normal; font-family: var(--font-ui);
  font-size: var(--fs-xs); color: var(--ink-3);
  text-transform: none; letter-spacing: normal;
}
.arch span { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.4; margin-top: 3px; }
.arch__detail {
  margin-top: var(--s-3); padding: var(--s-3) var(--s-4);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md);
}
.arch__why { font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.6; }
.arch__warn {
  display: flex; gap: 6px; align-items: flex-start;
  margin-top: var(--s-2); font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.5;
}
.arch__warn svg { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 2px; color: var(--warn); }

/* ---- archetype blending feedback ---- */
.arch__blend { font-size: var(--fs-sm); color: var(--ink); margin-bottom: var(--s-3); }
.arch__good, .arch__clash {
  display: flex; gap: 7px; align-items: flex-start;
  margin-top: var(--s-2); padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm); font-size: var(--fs-xs); line-height: 1.5;
}
.arch__good { background: var(--good-soft); color: var(--ink-2); }
.arch__good svg { width: 13px; height: 13px; color: var(--good); flex: 0 0 auto; margin-top: 2px; }
.arch__clash { background: var(--warn-soft); color: var(--ink-2); }
.arch__clash svg { width: 14px; height: 14px; color: var(--warn); flex: 0 0 auto; margin-top: 1px; }
.arch__clash strong { color: var(--ink); }
.arch__why + .arch__why { margin-top: 5px; }
.arch.is-on::after {
  content: "✓"; position: absolute; top: 8px; right: 10px;
  color: var(--accent); font-size: var(--fs-xs);
}
.arch { position: relative; }

/* ---- "you haven't seen this yet" ---- */
.chip--new {
  background: var(--accent); color: var(--accent-ink);
  border-color: transparent; font-weight: 700;
  font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: 0.08em; padding: 2px 7px;
}
.side__ver {
  margin-top: var(--s-3); padding-top: var(--s-3);
  border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  color: var(--ink-quiet); letter-spacing: 0.04em;
}

/* ---- autowriter states on a ticket ---- */
.ticket__sub--writing,
.ticket__sub--failed { display: flex; align-items: center; gap: 7px; }
.ticket__sub--writing { color: var(--ink-3); font-style: italic; }
.ticket__sub--writing .spinner { flex: none; }
.ticket__sub--failed { color: var(--bad, var(--ink-3)); }

/* ---- quick post CTA on This Week (where the vault used to sprawl) ---- */
.quickcta {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-5); flex-wrap: wrap;
  margin-top: var(--s-7); padding: var(--s-5);
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  border-radius: var(--r-lg);
}
.quickcta h3 {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 4px; font-size: var(--fs-lg);
}
.quickcta h3 svg { color: var(--accent); flex: none; }
.quickcta p { margin: 0; color: var(--ink-2); font-size: var(--fs-sm); max-width: 62ch; }

/* one line, not a second queue */
.savedpeek {
  display: flex; align-items: center; gap: var(--s-3);
  width: 100%; margin-top: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: var(--fs-sm); cursor: pointer;
  transition: border-color .12s, color .12s;
}
.savedpeek:hover { border-color: var(--accent-line); color: var(--ink); }
.savedpeek svg { flex: none; color: var(--ink-3); }
.savedpeek__go {
  display: flex; align-items: center; gap: 4px;
  margin-left: auto; color: var(--accent); font-size: var(--fs-xs);
}

/* ---- quick post screen ---- */
.custom { max-width: 780px; }
.kinds { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.kind {
  padding: 7px 13px; border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--surface-2); color: var(--ink-2);
  font: inherit; font-size: var(--fs-sm); cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.kind:hover { border-color: var(--accent-line); color: var(--ink); }
.kind.is-on {
  background: var(--accent); border-color: transparent;
  color: var(--accent-ink); font-weight: 600;
}

/* ---- "what do you want on the next plate?" ---- */
.wants { width: 100%; max-width: 620px; margin: 0 auto; text-align: left; }
.wants__grp { margin-bottom: var(--s-4); }
.wants__lb {
  display: block; margin-bottom: var(--s-2);
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.wants__row { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.want {
  padding: 7px 13px; border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--surface-2); color: var(--ink-2);
  font: inherit; font-size: var(--fs-sm); cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.want:hover { border-color: var(--accent-line); color: var(--ink); }
.want.is-on {
  background: var(--accent); border-color: transparent;
  color: var(--accent-ink); font-weight: 600;
}
.wants__note {
  margin: 0 0 var(--s-4); text-align: center;
  font-size: var(--fs-xs); color: var(--ink-4);
}

/* ============================================================
   READ THEIR WEBSITE — the call to action, and the review sheet

   The visual job here is one thing: make "they published this"
   and "something guessed this" impossible to confuse. Once both
   are sitting in the profile as plain sentences they read the
   same, so the difference has to land while there is still a
   decision to make.
   ============================================================ */

.crawlcta {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-4);
  margin-top: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.crawlcta__bd { flex: 1; min-width: 0; }
.crawlcta__t { font-weight: 600; margin-bottom: 2px; }
.crawlcta__s { color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; }
.crawlcta .btn { flex: none; }
@media (max-width: 560px) {
  .crawlcta { flex-direction: column; align-items: stretch; }
}

.crawl__sum {
  padding: var(--s-3);
  background: var(--surface-2);
  border-radius: var(--r-md);
  margin-bottom: var(--s-3);
  line-height: 1.55;
}
.crawl__rule { font-size: var(--fs-xs); margin-bottom: var(--s-4); }
.crawl__hd { margin: var(--s-4) 0 var(--s-2); }
.crawl__gaps { margin: var(--s-2) 0 0; padding-left: 1.15em; color: var(--ink-2); }
.crawl__gaps li { margin-bottom: 4px; line-height: 1.5; }
.crawl__skipped { font-size: var(--fs-xs); margin-top: var(--s-4); }

.crawl__busy { text-align: center; padding: var(--s-7) var(--s-4); }
.crawl__busy .spinner { margin: 0 auto var(--s-4); }
.crawl__step { font-weight: 600; margin-bottom: 6px; }

/* One finding. Unticked rows are deliberately quieter than ticked
   ones — the tick is the decision, so it should be visible from
   across the room. */
.crawlrow {
  display: flex; gap: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  margin-bottom: var(--s-2);
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.crawlrow:hover { border-color: var(--line-strong); }
.crawlrow.is-on { border-color: var(--accent-line); background: var(--accent-soft); }
.crawlrow__ck { flex: none; margin-top: 3px; width: 16px; height: 16px; accent-color: var(--accent); }
.crawlrow__bd { flex: 1; min-width: 0; }
.crawlrow__top {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 6px; margin-bottom: 4px;
}
.crawlrow__label { font-weight: 600; }
.crawlrow__val { line-height: 1.5; }
.crawlrow__was {
  margin-top: 6px; font-size: var(--fs-xs); color: var(--warn);
}
.crawlrow__was s { opacity: .75; }
.crawlrow__src {
  margin-top: 6px; font-size: var(--fs-xs); color: var(--ink-4);
}

/* Provenance badges. */
.tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  line-height: 1.6;
  white-space: nowrap;
}
.tag--ok    { background: var(--good-soft); color: var(--good); }
.tag--warn  { background: var(--warn-soft); color: var(--warn); }
.tag--muted { background: var(--surface-3); color: var(--ink-3); }

/* Their photos — a grid you can actually judge. A photo library
   filled from a checklist nobody could see is how you end up with
   thirty copies of a logo and no food. */
.crawlcta__btns { display: flex; gap: var(--s-2); flex: none; }
@media (max-width: 560px) { .crawlcta__btns { flex-direction: column; } }

/* ⛔ This was a SECOND `.pgrid`. Same specificity as the photo library's,
   defined later, so it won everywhere -- and its 180px minimum against a
   358px phone (180+180+12 = 372) collapsed the library to one column. The
   crawl picker's grid has its own name now. Never fix this class of bug
   with another override; two rules for two components. */
.crawlgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--s-3);
}
.pcard {
  position: relative; display: block; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r-md);
  overflow: hidden; background: var(--surface-2);
  transition: border-color .12s;
}
.pcard:hover { border-color: var(--line-strong); }
.pcard.is-on { border-color: var(--accent-line); }
.pcard.is-dead { opacity: .35; pointer-events: none; }
.pcard.is-dead::after {
  content: 'could not load'; position: absolute; inset: auto 0 40% 0;
  text-align: center; font-size: var(--fs-xs); color: var(--ink-3);
}
.pcard__ck {
  position: absolute; top: 8px; left: 8px; z-index: 2;
  width: 18px; height: 18px; accent-color: var(--accent);
}
.pcard__img { aspect-ratio: 4 / 3; background: var(--surface-3); }
.pcard__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pcard__bd { padding: var(--s-2) var(--s-3) var(--s-3); }
.pcard__shows { font-size: var(--fs-xs); line-height: 1.45; margin-bottom: 6px; }
.pcard__meta { display: flex; flex-wrap: wrap; gap: 4px; }

/* The bookmarklet. It has to look draggable, because dragging it is
   the one instruction people skip. */
.grabbar {
  display: flex; align-items: center; gap: var(--s-3);
  margin: var(--s-3) 0 var(--s-2);
  padding: var(--s-3);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.grabbm { cursor: grab; text-decoration: none; white-space: nowrap; }
.grabbm:active { cursor: grabbing; }
.grabbar .muted { font-size: var(--fs-xs); }
kbd {
  font: inherit; font-size: var(--fs-xs);
  padding: 1px 5px; border: 1px solid var(--line-strong);
  border-bottom-width: 2px; border-radius: var(--r-xs);
  background: var(--surface-3);
}

/* Onboarding payoff screen — the moment the product either lands or
   doesn't, so the number gets to be big. */
.obwin { text-align: center; padding: var(--s-6) 0 var(--s-4); }
.obwin__num { font-size: 56px; line-height: 1; color: var(--accent); }
.obwin__cap { color: var(--ink-2); margin-top: 6px; }
.obideas { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--s-2); }
.obidea {
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: var(--s-3); background: var(--surface-2);
}
.obidea__fam { font-size: var(--fs-xs); color: var(--ink-3); margin-bottom: 4px; }
.obidea__label { font-weight: 600; line-height: 1.35; }
.obidea__sub { font-size: var(--fs-xs); color: var(--accent); margin-top: 4px; }

/* The register picker. Five cards, one tap, before anything is written.
   The EXAMPLE is the big text and the label is small underneath — an
   owner recognises their own voice by hearing it, not by reading an
   adjective they then have to translate. */
.regpick {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--s-3);
}
.regcard {
  display: flex; flex-direction: column; gap: 6px;
  text-align: left; cursor: pointer;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
  transition: border-color .12s ease, background .12s ease, transform .12s ease;
}
.regcard:hover { border-color: var(--line-strong); transform: translateY(-1px); }
.regcard[aria-pressed="true"] {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, var(--surface-2));
}
.regcard__ex {
  font-family: var(--font-display, Georgia, serif);
  font-size: var(--fs-md);
  line-height: 1.35;
  color: var(--ink);
}
.regcard__name {
  font-size: var(--fs-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--accent);
}
.regcard__blurb { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.45; }

/* The interview. One question per card, the SUBJECT above it so nobody
   loses track of which dish they are answering about, and the reason
   underneath in small text — an owner who knows why a question is being
   asked answers it better. */
.qlist { display: grid; gap: var(--s-3); }
.qcard {
  padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
  border-left: 3px solid var(--line);
  transition: border-color .15s ease;
}
.qcard.is-answered { border-left-color: var(--good); }
.qcard__subj {
  font-size: var(--fs-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--accent); margin-bottom: 4px;
}
.qcard__q {
  display: block; font-family: var(--font-display, Georgia, serif);
  font-size: var(--fs-md); line-height: 1.35;
  color: var(--ink); margin-bottom: var(--s-3);
}
.qcard__in { width: 100%; }
.qcard__why {
  margin-top: 6px; font-size: var(--fs-xs);
  color: var(--ink-3); line-height: 1.45;
}

/* Counts KNOWLEDGE, not ideas. The freshness meter climbs happily while
   Plate knows nothing true — this is the number that predicts whether the
   posts will be any good. */
.knowbar {
  margin-top: var(--s-6); padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  position: sticky; bottom: 0;
}
.knowbar__top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.knowbar__pct { font-size: var(--fs-lg); color: var(--ink); }
.knowbar__cap { margin-top: 8px; font-size: var(--fs-xs); color: var(--ink-3); }

.qcard.is-plain { opacity: .55; border-left-color: var(--line); }
.qcard.is-plain .qcard__q { font-family: inherit; font-size: var(--fs-sm); color: var(--ink-3); }
.qcard__skip { display: inline-block; margin-top: 8px; font-size: var(--fs-xs); color: var(--ink-3); }

/* What Plate heard, shown back before it counts. */
.heard { margin-top: var(--s-3); padding-top: var(--s-3); border-top: 1px dashed var(--line); }
.heard__hd { font-size: var(--fs-xs); color: var(--ink-3); margin-bottom: 6px; }
.heard__row { display: flex; gap: 8px; align-items: flex-start; padding: 4px 0; font-size: var(--fs-sm); color: var(--ink-2); cursor: pointer; }
.heard__row i { display: block; font-style: normal; font-size: var(--fs-xs); color: var(--ink-3); }

/* Ask, it answers, the box empties, you ask the next thing. */
.fbk__go { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-3); }
.fbk__gohint { font-size: var(--fs-xs); color: var(--ink-3); }
.fbk__ok { color: var(--good); font-size: var(--fs-sm); }
.ntrail { margin-top: var(--s-4); padding-top: var(--s-3); border-top: 1px dashed var(--line); }
.ntrail__hd { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); margin-bottom: 8px; }
.ntrail__row { display: flex; gap: 8px; align-items: flex-start; padding: 3px 0; font-size: var(--fs-sm); color: var(--ink-2); }
.ntrail__n { flex: none; width: 18px; height: 18px; border-radius: 50%; background: var(--surface-3); color: var(--ink-3); font-size: 11px; display: grid; place-items: center; }

/* Pinning your own rewrite: show the exact words that were saved, so
   "is it mine or Plate's?" is answerable by reading it. */
.golden__quote {
  margin: var(--s-3) 0; padding: var(--s-3) var(--s-4);
  border-left: 3px solid var(--good);
  background: var(--surface); border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: var(--fs-sm); color: var(--ink);
  white-space: pre-wrap; line-height: 1.55;
}
.golden__hint { margin-top: var(--s-3); font-size: var(--fs-xs); color: var(--accent); line-height: 1.5; }

/* The voice control gets its own line. Beside the thumbs it read as a
   third opinion button; it is a different question entirely. */
.idea__rate--voice { margin-top: var(--s-2); padding-top: var(--s-3); border-top: 1px dashed var(--line); }

/* The line that answers "will it keep MY version?" before the press,
   not after it. */
.idea__rateq { display: flex; flex-direction: column; gap: 2px; margin-right: auto; }
.idea__ratehint { font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.4; }
.idea__ratehint.is-mine { color: var(--accent); }

/* ⭐ The control a setup task sent you to. `.saved` only styles inputs, and
   half these targets are buttons -- a register chip, a staff row. This has
   to read on anything, and has to fade: a permanent ring is a new piece of
   furniture, not an answer to "which one did it mean?". */
.spotlit {
  animation: spotlit 2.2s ease-out;
  border-radius: var(--r-md);
}
@keyframes spotlit {
  0%, 55% { box-shadow: 0 0 0 3px var(--accent), 0 0 0 8px color-mix(in srgb, var(--accent) 28%, transparent); }
  100%    { box-shadow: 0 0 0 3px transparent, 0 0 0 8px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  /* Still unmistakable, just not animated. */
  .spotlit { animation: none; box-shadow: 0 0 0 3px var(--accent); }
}


/* ============================================================
   EMAIL & TEXT  (audiences, templates, campaign drafts)
   ============================================================
   Reuses the customer screen's segmented control and card shell; what is
   new here is the reusable-piece row and the two previews. Mobile first:
   every row collapses to a stack, and no horizontal scrolling anywhere. */
.mwrap { margin-top: var(--s-3); }
.mlist { display: flex; flex-direction: column; gap: var(--s-2); }

.mrow {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
}
.mrow__main { flex: 1 1 auto; min-width: 0; }
.mrow__nm { font-weight: 600; display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.mrow__sub { color: var(--ink-3); font-size: var(--fs-sm); margin-top: 2px;
             overflow-wrap: anywhere; }
.mrow__n { flex: 0 0 auto; text-align: right; line-height: 1.15; }
.mrow__n b { display: block; font-size: var(--fs-lg); }
.mrow__n span { color: var(--ink-3); font-size: var(--fs-xs); }
.mrow__do { flex: 0 0 auto; display: flex; gap: var(--s-2); flex-wrap: wrap; }

@media (max-width: 640px) {
  .mrow { flex-wrap: wrap; }
  .mrow__main { flex: 1 1 100%; }
  .mrow__n { text-align: left; }
  .mrow__n b { display: inline; }
  .mrow__do { flex: 1 1 100%; }
  .mrow__do .btn { flex: 1 1 auto; }
}

.mtag {
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .02em;
  padding: 2px 8px; border-radius: 999px;
  background: var(--surface-3); color: var(--ink-3); border: 1px solid var(--line);
}
/* Draft is the only state there is, so it reads as a fact rather than as a
   warning about something unfinished. */
.mtag--draft { background: transparent; }
.mwarn { color: var(--warn, var(--ink-3)); }

.mh { margin: 0 0 var(--s-3); font-size: var(--fs-lg); }

.mchips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.mchip {
  padding: 8px 14px; border-radius: 999px; cursor: pointer;
  background: var(--surface-3); color: var(--ink); border: 1px solid var(--line);
  font: inherit; font-size: var(--fs-sm);
}
.mchip.is-on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

.mclause {
  display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap;
  padding: var(--s-2); margin-bottom: var(--s-2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
.mclause__k { flex: 0 0 auto; width: auto; }
.mclause .input { flex: 1 1 10rem; min-width: 0; }
.mclause__u { color: var(--ink-3); font-size: var(--fs-sm); }

/* The count, and the sentence that stops it being read as a promise. */
.mpre {
  margin: var(--s-3) 0; padding: var(--s-3);
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface-3);
}
.mpre--go { border-color: var(--accent); }
.mpre__n { font-size: var(--fs-md); }
.mpre__n b { font-size: var(--fs-xl); }
.mpre__d { color: var(--ink-3); font-size: var(--fs-sm); margin-top: 2px; }
.mpre__c { color: var(--ink-3); font-size: var(--fs-xs); margin-top: var(--s-2); }

/* Exactly what the person receives, not a description of it. */
.mprev { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.mprev__sub { padding: var(--s-3); font-weight: 600; border-bottom: 1px solid var(--line); }
.mprev__pre { padding: 0 var(--s-3) var(--s-3); color: var(--ink-3); font-size: var(--fs-sm);
              margin-top: calc(-1 * var(--s-2)); }
.mprev__body { padding: var(--s-3); white-space: pre-wrap; overflow-wrap: anywhere; }
.mprev__cta {
  margin: 0 var(--s-3) var(--s-3); padding: 10px 16px; display: inline-block;
  border-radius: var(--r-sm); background: var(--accent); color: var(--accent-ink);
  font-weight: 600; font-size: var(--fs-sm);
}
.mprev--sms { border: none; }
.mprev__bub {
  padding: var(--s-3); border-radius: var(--r-md);
  background: var(--surface-3); border: 1px solid var(--line);
  white-space: pre-wrap; overflow-wrap: anywhere; max-width: 22rem;
}
.mrowf { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.mrowf .field { flex: 1 1 12rem; }
.mnote { margin-top: var(--s-3); display: flex; align-items: center; gap: var(--s-2); }
.mnote svg { flex: 0 0 auto; }

/* The final look: three facts, unmissable, before anything goes out. */
.mfact { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden;
         margin-bottom: var(--s-3); }
.mfact__r { display: flex; justify-content: space-between; align-items: baseline;
            gap: var(--s-3); padding: var(--s-3);
            border-bottom: 1px solid var(--line); }
.mfact__r:last-child { border-bottom: none; }
.mfact__r span { color: var(--ink-3); font-size: var(--fs-sm); }
.mfact__r b { font-size: var(--fs-md); text-align: right; overflow-wrap: anywhere; }

/* ============================================================
   OPERATOR SETUP — plain on purpose
   ============================================================
   ⛔ No progress bar and no celebration. This screen is read by somebody
   deciding whether Plate may contact thousands of people, and a design that
   rewards completion is a design that pushes toward it. Each state is shown
   in its own colour, including the one that matters most — `Set up,
   unproven` — which is deliberately as visible as `Verified` rather than a
   softer shade of it. */
.setup { display: flex; flex-direction: column; gap: 1px; background: var(--line);
         border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.setup__row { display: grid; grid-template-columns: 1fr auto; gap: 2px 12px;
              padding: 10px 12px; background: var(--surface); align-items: baseline; }
.setup__name { font-weight: 600; }
.setup__state { font-size: 13px; font-weight: 600; white-space: nowrap; }
.setup__why { grid-column: 1 / -1; font-size: 13px; color: var(--ink-3); line-height: 1.45; }
.setup__row--ok    .setup__state { color: var(--good); }
.setup__row--warn  .setup__state { color: var(--warn); }
.setup__row--bad   .setup__state { color: var(--bad); }
.setup__row--muted .setup__state { color: var(--ink-3); }

.setup__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
               gap: 12px; }
.setup__grid > div { display: flex; flex-direction: column; gap: 2px; }
.setup__grid b { font-size: 20px; font-variant-numeric: tabular-nums; }
.setup__grid span { font-size: 13px; color: var(--ink-3); }

.setup__dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; margin: 0; }
.setup__dl dt { color: var(--ink-3); font-size: 13px; }
.setup__dl dd { margin: 0; }
.setup__tag { font-size: 12px; color: var(--ink-3); }
.setup__ev { display: flex; flex-direction: column; gap: 8px; margin-top: 8px;
             padding: 10px 12px; background: var(--bg); border-radius: 8px; }
.setup__ev code { font-size: 12px; }
.setup__ev q { display: block; font-style: normal; line-height: 1.5; margin-top: 2px; }
.setup__ev i { color: var(--ink-3); }

/* ---------- Email & text: status, results, previews ---------- */
/* ⭐ Each execution state gets its own colour, including the two that mean
   "look at this": a campaign that stopped halfway must not be the same
   shade as one that went out. */
.mtag--ok    { background: var(--good-soft); color: var(--good); }
.mtag--sent  { background: var(--good-soft); color: var(--good); }
.mtag--warn  { background: var(--warn-soft); color: var(--warn); }
.mtag--bad   { background: var(--bad-soft); color: var(--bad); }

.mh--sub { font-size: var(--fs-md); margin-top: var(--s-4); }
/* ⛔ `grid-column` did nothing here — .mfact is not a grid — and without
   padding this note sat flush against the rounded border while every row
   above it was inset. */
.mfact__n { font-size: var(--fs-sm); color: var(--ink-3);
            line-height: 1.45; padding: 0 var(--s-3) var(--s-3); }
.num.tone--ok    { color: var(--good); }
.num.tone--warn  { color: var(--warn); }
.num.tone--bad   { color: var(--bad); }
.num.tone--muted { color: var(--ink-3); }

/* The compliance block, shown as part of the message because that is what
   it is — not as settings living somewhere else. */
.mprev__from  { font-size: 12px; color: var(--ink-3); margin-bottom: 6px; }
.mprev__legal { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line);
                font-size: 12px; color: var(--ink-3); line-height: 1.5; }
.mprev__legal--prov { text-decoration: underline; }
.mprev__legalnote { margin-top: 4px; font-size: 11px; opacity: .8; font-style: italic; }

.mrow--stack { display: block; }
.mrow__top   { display: flex; gap: var(--s-3); align-items: flex-start; }
.mrow__top .mrow__main { flex: 1; min-width: 0; }
.mrow__peek  { margin-top: var(--s-3); }
.mrow--tight { padding: 8px 0; }
.mlist--tight .mrow { border-bottom: 1px solid var(--line); }

/* ⛔ Narrow screens: the action row wraps under the name instead of
   squeezing it to nothing. An owner reads these on a phone behind the
   counter. */
@media (max-width: 640px) {
  .mrow, .mrow__top { flex-direction: column; align-items: stretch; }
  .mrow__main { min-width: 0; }
  /* ⛔ `flex: 1 1 auto` let a long label push the row past the card edge —
     "Duplicate" was cut off on a 390px screen. A basis of 0 with a floor
     makes them share the width instead of demanding it. */
  .mrow__do { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
  .mrow__do .btn { flex: 1 1 calc(50% - 3px); min-width: 0; }
  .mrow__n { text-align: left; margin-top: 4px; }
  .mfact__r { grid-template-columns: 1fr auto; }
  .setup__row { grid-template-columns: 1fr; }
  .setup__state { margin-top: 2px; }
}

/* ---------- Email & text: scheduling ---------- */
/* ⭐ The picker sits inside the review panel rather than in a dialog of its
   own: choosing a time is part of approving a send, not a separate act. */
.mschedule { border: 1px solid var(--line); border-radius: var(--r-md);
             padding: var(--s-4); margin-top: var(--s-4);
             background: var(--surface-2); }
.mschedule .mh--sub { margin-top: 0; }
.mschedule__row { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.mschedule__row .field { flex: 1 1 150px; min-width: 0; margin-bottom: var(--s-2); }
.mschedule__row .input { width: 100%; }
.mschedule .banner { margin: var(--s-3) 0 0; }
.mschedule .btnrow { margin-top: var(--s-4); }
.mschedule__say { margin: var(--s-3) 0 0; font-size: 14px; color: var(--ink); line-height: 1.5; }

/* A scheduled email or text on the content calendar. Same size and rhythm as
   a post pill so the day reads as one list — but no drag handle and no
   remove control, because neither is true here. */
.ev--send { display: flex; align-items: center; gap: 6px; width: 100%;
            text-align: left; background: var(--surface-2);
            border: 1px dashed var(--line); border-radius: var(--r-sm);
            padding: 3px 6px; margin-bottom: 3px; cursor: pointer;
            font: inherit; color: var(--ink-2); min-width: 0; }
.ev--send:hover { border-style: solid; color: var(--ink); }
.ev--send .ev__hook { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ev__send-ic { flex: none; display: inline-flex; }
.ev__send-ic svg { width: 12px; height: 12px; }
/* A send that already went out: still on its day, visibly finished rather
   than pending. A failure keeps the warning colour — that day needed
   attention and the calendar should not soften it. */
.ev--send-done { border-style: solid; opacity: .72; }
.ev--send-done .ev__send-ic svg { color: var(--good); }
.ev--send-failed { border-style: solid; border-color: var(--bad); color: var(--ink); }
.ev--send-failed .ev__send-ic svg { color: var(--bad); }

/* ---------- Photos: search and order ---------- */
/* Shown only once a library is big enough to need them. */
.libtools { display: flex; gap: var(--s-3); align-items: center;
            margin: var(--s-3) 0; flex-wrap: wrap; }
.libtools__q { flex: 1 1 220px; min-width: 0; }
.libtools__sort { flex: 0 0 auto; }
.libtools__sort .select { width: auto; }
.libmore { display: flex; align-items: center; justify-content: center;
           gap: var(--s-3); margin-top: var(--s-4); }

/* ---------- Menu: section header with its own controls ---------- */
.secbar { display: flex; align-items: baseline; justify-content: space-between;
          gap: var(--s-3); flex-wrap: wrap; }
.secbar__act { display: flex; gap: 2px; align-items: center; flex: 0 0 auto; }
/* The controls stay quiet until the section is hovered or focused within —
   but never hover-ONLY: they are always in the tab order and always visible
   on a touch screen, where there is no hover at all. */
@media (hover: hover) and (pointer: fine) {
  .secbar__act { opacity: .35; transition: opacity var(--t-fast) var(--e-out); }
  .menu__sec:hover .secbar__act,
  .menu__sec:focus-within .secbar__act { opacity: 1; }
}
@media (max-width: 560px) {
  /* ⛔ Height alone was not enough — an icon button with 5px of padding is
     36px tall and 25px wide, which is still a miss. Both axes. */
  .secbar__act .btn, .drow__acts .btn { min-height: 36px; min-width: 36px; }
  .readyrow .btn { min-height: 36px; }
}

/* ---------- Website: the feed, as a customer would read it ---------- */
.wprev { border: 1px solid var(--line); border-radius: var(--r-md);
         padding: var(--s-4); margin-top: var(--s-3); background: var(--surface-2); }
.wprev__sec + .wprev__sec { margin-top: var(--s-5); }
.wprev__sech { font-family: var(--font-display); font-size: var(--fs-lg);
               margin-bottom: var(--s-2); }
.wprev__item { padding: var(--s-2) 0; border-top: 1px solid var(--line); }
.wprev__sech + .wprev__item { border-top: 0; }
.wprev__itn { display: flex; justify-content: space-between; gap: var(--s-3);
              font-weight: 600; font-size: var(--fs-sm); }
.wprev__pr { flex: 0 0 auto; }
.wprev__itd { font-size: var(--fs-sm); color: var(--ink-3); margin-top: 1px; }
.wprev__opt { font-size: var(--fs-xs); color: var(--ink-3); margin-top: 2px; }
.wprev__has, .wprev__no { font-size: var(--fs-2xs); }
.wprev__has { color: var(--good); }
.wprev__no  { color: var(--ink-4); }
.wprev__locs { display: grid; gap: var(--s-3); margin-top: var(--s-3); }
.wprev__loc { border: 1px solid var(--line); border-radius: var(--r-md);
              padding: var(--s-3); background: var(--surface-2); }
.wprev__locn { font-weight: 600; font-size: var(--fs-sm); }
.wprev__locp { font-size: var(--fs-sm); color: var(--ink-3); }
.wprev__hrs { margin-top: var(--s-2); display: grid;
              grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); gap: 2px var(--s-3); }
.wprev__hr { display: flex; justify-content: space-between; gap: var(--s-2);
             font-size: var(--fs-xs); color: var(--ink-2); }
.wprev__hr span:first-child { color: var(--ink-3); }
.wprev__exc { margin-top: var(--s-2); font-size: var(--fs-xs); color: var(--warn); }

/* ---------- Settings → Connections (staff) ---------- */
.conn__sec { border-top: 1px solid var(--line); padding-top: var(--s-4); margin-top: var(--s-4); display: grid; gap: var(--s-3); }
.conn__h { font-size: 15px; font-weight: 600; margin: 0; }
.conn__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.conn__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 14px; }
.conn__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--s-3); }
.conn__add { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px; align-items: center; margin-top: var(--s-2); }
.conn__ck { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink-3); }
.chip[data-tone="good"] { color: var(--good); }
[data-conn-status][data-tone="bad"] { color: var(--bad); }
.setup__form { display: grid; gap: var(--s-2); border-top: 1px solid var(--line); padding-top: var(--s-3); margin-top: var(--s-3); }
