/* YAMP web client.
   Aesthetic: the working-tool half of the marketing site's Sunday market —
   warm cream paper, rounded friendly type, awning stripes, shelf-edge aisle
   labels, a weekly plan that looks like the menu card on the front of the
   site. Dark mode is the chalkboard after close: warm near-black, chalk text,
   the same accents turned up a notch.
   Hand-written, no build step, no external requests. */

:root {
  --cream:     #fbf5e9;
  --cream-2:   #f5edda;
  --card:      #fffdf6;
  --ink:       #33261a;
  --ink-soft:  #5f5142;
  --ink-mute:  #8d7f6d;
  --tomato:    #df4a2b;
  --tomato-dk: #c23c20;
  --leek:      #4f7d33;
  --butter:    #e8a53a;
  --butter-dk: #b57d20;
  --tint-red:    #f9e2d8;
  --tint-green:  #e6eed6;
  --tint-butter: #f8ecca;
  --line:      rgba(51, 38, 26, .14);
  --line-2:    rgba(51, 38, 26, .3);
  --shadow:    0 14px 34px rgba(51, 38, 26, .10);
  --shadow-sm: 0 3px 12px rgba(51, 38, 26, .07);

  --display: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --ease: cubic-bezier(.22, 1, .36, 1);
  --sidebar: 236px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --cream:     #211a12;
    --cream-2:   #1b150e;
    --card:      #2c231a;
    --ink:       #f1e8d9;
    --ink-soft:  #cdbfab;
    --ink-mute:  #9c8d7b;
    --tomato:    #f06a47;
    --tomato-dk: #d64f2e;
    --leek:      #8ab364;
    --butter:    #eebc59;
    --butter-dk: #d9a33e;
    --tint-red:    rgba(240, 106, 71, .16);
    --tint-green:  rgba(138, 179, 100, .16);
    --tint-butter: rgba(238, 188, 89, .15);
    --line:      rgba(241, 232, 217, .14);
    --line-2:    rgba(241, 232, 217, .32);
    --shadow:    0 14px 34px rgba(0, 0, 0, .35);
    --shadow-sm: 0 3px 12px rgba(0, 0, 0, .25);
  }
}

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1.1;
  margin: 0;
}

a { color: inherit; }
button { font: inherit; color: inherit; }
::placeholder { color: var(--ink-mute); opacity: .8; }
:focus-visible { outline: 2px solid var(--tomato); outline-offset: 2px; border-radius: 4px; }

/* ── awning ─────────────────────────────────────────────────────────── */

.awning {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  height: 10px;
  background: repeating-linear-gradient(90deg,
    var(--tomato) 0 28px, var(--card) 28px 56px);
}
.awning::after {
  content: "";
  position: absolute;
  top: 10px; left: 0; right: 0;
  height: 7px;
  background:
    radial-gradient(circle at 14px -4px, var(--tomato) 0 13px, transparent 13.5px) 0 0 / 56px 7px repeat-x,
    radial-gradient(circle at 14px -4px, var(--card) 0 13px, transparent 13.5px) 28px 0 / 56px 7px repeat-x;
}

/* ── shell ──────────────────────────────────────────────────────────── */

#shell { min-height: 100vh; }

.app {
  display: grid;
  grid-template-columns: var(--sidebar) minmax(0, 1fr);
  min-height: 100vh;
}

/* ── sidebar ────────────────────────────────────────────────────────── */

.side {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: .4rem;
  padding: 2.2rem 1rem 1.1rem;
  background: var(--cream-2);
  border-right: 1px solid var(--line);
}

.wordmark {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.9rem;
  letter-spacing: -.03em;
  text-decoration: none;
  padding: 0 .65rem;
  margin-bottom: 1.1rem;
}
.wordmark .dot { color: var(--tomato); }

.side nav { display: flex; flex-direction: column; gap: 2px; }

.nav-link {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .5rem .65rem;
  border-radius: 12px;
  text-decoration: none;
  font-weight: 600;
  color: var(--ink-soft);
  transition: background .15s var(--ease), color .15s;
}
.nav-link .n-emoji { font-size: 1.15rem; width: 1.5rem; text-align: center; }
.nav-link:hover { background: color-mix(in srgb, var(--card) 70%, transparent); color: var(--ink); }
.nav-link.active {
  background: var(--card);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.nav-link.active .n-label { color: var(--tomato); }

.side .spacer { flex: 1; }

.side-user {
  border-top: 1px dashed var(--line-2);
  padding: .85rem .65rem .2rem;
  font-size: .85rem;
  color: var(--ink-mute);
  line-height: 1.4;
}
.side-user b { color: var(--ink-soft); display: block; }

/* ── content ────────────────────────────────────────────────────────── */

.content {
  padding: 2.6rem 3rem 5rem;
  min-width: 0;
}
.page { max-width: 1120px; margin: 0 auto; }
.page.narrow { max-width: 780px; }

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.6rem;
}
.page-head h1 { font-size: 2rem; }
.page-head .sub { color: var(--ink-mute); margin: .3rem 0 0; font-size: .95rem; }
.page-actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }

/* staggered arrival */
.page > * { animation: rise .38s var(--ease) backwards; }
.page > *:nth-child(2) { animation-delay: .05s; }
.page > *:nth-child(3) { animation-delay: .1s; }
.page > *:nth-child(4) { animation-delay: .15s; }
.page > *:nth-child(5) { animation-delay: .2s; }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ── buttons ────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .5rem 1.05rem;
  border: 1.5px solid var(--tomato);
  border-radius: 999px;
  background: var(--tomato);
  color: #fff;
  font-family: var(--display);
  font-weight: 700;
  font-size: .92rem;
  letter-spacing: -.01em;
  cursor: pointer;
  text-decoration: none;
  transition: transform .12s var(--ease), background .15s, border-color .15s, box-shadow .15s;
}
.btn:hover { background: var(--tomato-dk); border-color: var(--tomato-dk); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.btn:active { transform: translateY(0); }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn.ghost:hover { background: var(--card); border-color: var(--ink-soft); }
.btn.leek { background: var(--leek); border-color: var(--leek); }
.btn.leek:hover { background: color-mix(in srgb, var(--leek) 85%, black); }
.btn.danger { background: transparent; color: var(--tomato); border-color: var(--tomato); }
.btn.danger:hover { background: var(--tomato); color: #fff; }
.btn.small { padding: .28rem .75rem; font-size: .82rem; }
.btn[disabled] { opacity: .45; pointer-events: none; }

.link-btn {
  background: none; border: 0; padding: 0;
  color: var(--tomato); font-weight: 600; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
  font-size: inherit;
}
.link-btn:hover { color: var(--tomato-dk); }

/* ── forms ──────────────────────────────────────────────────────────── */

label.field { display: block; margin-bottom: .9rem; }
/* The `hidden` attribute has to win over display rules like the one above,
   or a form field toggled with el.hidden stays on screen. */
[hidden] { display: none !important; }
label.field > span, .field-label {
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: .3rem;
}

input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="url"], input[type="search"], textarea, select {
  width: 100%;
  padding: .55rem .8rem;
  border: 1.5px solid var(--line);
  border-radius: 11px;
  background: var(--card);
  color: var(--ink);
  font: inherit;
  transition: border-color .15s, box-shadow .15s;
}
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--tomato);
  box-shadow: 0 0 0 3px var(--tint-red);
}
textarea { resize: vertical; min-height: 7.5rem; line-height: 1.6; }
select { cursor: pointer; }

/* A meal's slots: checkboxes worn as toggle chips. The box itself stays in
   the accessibility tree and takes focus; only its drawing is hidden. */
fieldset.slot-picker { border: 0; padding: 0; margin: 0 0 .9rem; display: flex; flex-wrap: wrap; gap: .45rem; }
fieldset.slot-picker legend { padding: 0; width: 100%; }
.slot-picker .chip { position: relative; font-size: .85rem; padding: .3rem .85rem; }
.slot-picker input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.slot-picker .chip:has(input:checked) { background: var(--ink); color: var(--cream); border-color: var(--ink); }
.slot-picker .chip:has(input:focus-visible) { outline: 2px solid var(--tomato); outline-offset: 2px; }
.form-row { display: flex; gap: .75rem; }
.form-row > * { flex: 1; }

.check-line { display: flex; align-items: center; gap: .5rem; font-size: .95rem; cursor: pointer; }
.check-line input { width: auto; }

/* ── cards & chips ──────────────────────────────────────────────────── */

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--shadow-sm);
  padding: 1.4rem 1.5rem;
}

/* A row of plain links: the About card's pages, and anywhere else a card
   ends in "here is where to read more" rather than in a button. */
.links {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1.1rem;
  margin: .9rem 0 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .12rem .6rem;
  border-radius: 999px;
  font-size: .76rem;
  font-weight: 700;
  font-family: var(--display);
  letter-spacing: 0;
  white-space: nowrap;
  background: var(--cream-2);
  color: var(--ink-soft);
  border: 1px solid var(--line);
}
.chip.red    { background: var(--tint-red);    color: var(--tomato-dk); border-color: transparent; }
.chip.green  { background: var(--tint-green);  color: var(--leek);      border-color: transparent; }
.chip.butter { background: var(--tint-butter); color: var(--butter-dk); border-color: transparent; }
.chip.click { cursor: pointer; border: 1px solid var(--line); background: var(--card); }
.chip.click:hover { border-color: var(--ink-soft); }
.chip.click.on { background: var(--ink); color: var(--cream); border-color: var(--ink); }

/* ── toolbar ────────────────────────────────────────────────────────── */

.toolbar {
  display: flex;
  gap: .6rem;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 1.3rem;
}
.toolbar input[type="search"] { max-width: 300px; }
.toolbar select { width: auto; }
.toolbar .gap { flex: 1; }
/* Data-derived chip sets (recipe tags, meal slots) refresh with the results
   while the toolbar around them stays put; the wrapper must not disturb the
   toolbar's own flex flow. */
.toolbar .facet-chips { display: contents; }
.chip.click.more { border-style: dashed; color: var(--ink-soft); }

/* ── menu card (the plan) ───────────────────────────────────────────── */

.menu-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 20px;
  box-shadow: var(--shadow);
  padding: 1.9rem 2.1rem 1.6rem;
  overflow: hidden;
}
.menu-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 9px;
  background: repeating-linear-gradient(90deg,
    var(--tomato) 0 22px, transparent 22px 44px);
  opacity: .9;
}
.menu-title-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.menu-title { font-family: var(--display); font-weight: 800; font-size: 1.55rem; letter-spacing: -.02em; }
.menu-sub { color: var(--ink-mute); font-size: .92rem; margin: .15rem 0 0; }

.menu-section { margin-top: 1.5rem; }
.menu-section-head {
  font-family: var(--display);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--tomato);
  margin: 0;
  padding-bottom: .35rem;
  border-bottom: 1px solid var(--line);
}
.menu-list { list-style: none; margin: .2rem 0 0; padding: 0; }
.menu-item {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding: .8rem .35rem;
  border-top: 1px dashed var(--line-2);
}
.menu-item:first-child { border-top: 0; }
/* A meal's picture in a row: its first recipe photo, or its emoji on the same
   cream tile the recipe and meal cards use when there is no photo. */
.m-thumb {
  width: 3rem;
  height: 3rem;
  flex: none;
  border-radius: 10px;
  overflow: hidden;
  background: var(--cream-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
}
.m-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.m-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.08rem;
  letter-spacing: -.01em;
  text-decoration: none;
}
.m-name:hover { color: var(--tomato); }
.menu-item .m-main { flex: 1; min-width: 0; }
.m-meta { display: flex; gap: .4rem; margin-top: .15rem; flex-wrap: wrap; }
.menu-item .m-actions { display: flex; gap: .4rem; opacity: 0; transition: opacity .15s; }
.menu-item:hover .m-actions, .menu-item:focus-within .m-actions { opacity: 1; }
.menu-item.cooked .m-name { color: var(--ink-mute); }
.menu-item.cooked .m-thumb { filter: grayscale(.6); opacity: .7; }
.menu-foot {
  text-align: center;
  color: var(--ink-mute);
  font-size: .85rem;
  margin: 1.3rem 0 0;
  font-style: italic;
}

/* ── shopping list ──────────────────────────────────────────────────── */

.aisle-group { margin-bottom: 1.7rem; break-inside: avoid; }
.aisle-head {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding-bottom: .45rem;
  border-bottom: 2px solid var(--line);
  margin-bottom: .3rem;
}
.aisle-head .a-emoji {
  font-size: 1.25rem;
  background: var(--cream-2);
  border-radius: 10px;
  padding: .18rem .4rem;
}
.aisle-head .a-label {
  font-family: var(--display);
  font-weight: 800;
  font-size: .82rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.aisle-head .a-count { margin-left: auto; color: var(--ink-mute); font-size: .8rem; font-variant-numeric: tabular-nums; }

.shop-item {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem .3rem;
  border-bottom: 1px dashed var(--line);
}
.shop-item:last-child { border-bottom: 0; }

.tick {
  flex: none;
  width: 23px; height: 23px;
  border: 2px solid var(--line-2);
  border-radius: 50%;
  background: var(--card);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background .18s var(--ease), border-color .18s;
}
.tick::after {
  content: "✓";
  font-size: .8rem;
  font-weight: 900;
  color: #fff;
  transform: scale(0);
  transition: transform .18s var(--ease);
}
.tick[aria-pressed="true"] { background: var(--leek); border-color: var(--leek); }
.tick[aria-pressed="true"]::after { transform: scale(1); }

.shop-item .qty {
  font-family: var(--mono);
  font-size: .82rem;
  color: var(--ink-soft);
  min-width: 4.2rem;
  text-align: right;
  flex: none;
  font-variant-numeric: tabular-nums;
}
.shop-item .i-main { flex: 1; min-width: 0; }
.i-name {
  font-weight: 600;
  background-image: linear-gradient(var(--ink-mute), var(--ink-mute));
  background-size: 0% 1.5px;
  background-position: 0 58%;
  background-repeat: no-repeat;
  transition: background-size .3s var(--ease), color .3s;
}
.shop-item.done .i-name { background-size: 100% 1.5px; color: var(--ink-mute); }
.shop-item.done .qty { opacity: .5; }
.i-why { font-size: .78rem; color: var(--ink-mute); margin-top: .05rem; }
.shop-item .i-actions { display: flex; gap: .35rem; opacity: 0; transition: opacity .15s; }
.shop-item:hover .i-actions, .shop-item:focus-within .i-actions { opacity: 1; }

/* "Hide ticked" walks the list down to what is still to get. The rows stay in
   the DOM so the tallies and the untick are one toggle away, and an aisle whose
   every line is done goes with them (JS sets .all-ticked). The "already have
   it" pile is left alone — it answers a different question. */
.hide-ticked .aisle-columns .shop-item.done,
.hide-ticked .aisle-group.all-ticked { display: none; }

.icon-btn {
  border: 1px solid var(--line);
  background: var(--card);
  border-radius: 9px;
  padding: .2rem .5rem;
  font-size: .78rem;
  cursor: pointer;
  color: var(--ink-soft);
  white-space: nowrap;
}
.icon-btn:hover { border-color: var(--ink-soft); color: var(--ink); }
.icon-btn.warm:hover { border-color: var(--tomato); color: var(--tomato); }

.quick-add {
  display: flex;
  gap: .6rem;
  margin-bottom: 1.6rem;
}
.quick-add input { flex: 1; font-size: 1rem; padding: .7rem 1rem; border-radius: 999px; }

.staples-banner {
  background: var(--tint-butter);
  border: 1px dashed var(--butter-dk);
  color: var(--butter-dk);
  border-radius: 14px;
  padding: .7rem 1rem;
  font-size: .92rem;
  margin-bottom: 1.2rem;
}

@media (min-width: 1240px) {
  .aisle-columns { columns: 2; column-gap: 3rem; }
}

/* ── recipe grid ────────────────────────────────────────────────────── */

.recipe-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1.1rem;
}
.recipe-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: transform .16s var(--ease), box-shadow .16s;
  display: flex;
  flex-direction: column;
}
.recipe-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.recipe-card .r-img {
  aspect-ratio: 5 / 3;
  background: var(--cream-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.4rem;
  overflow: hidden;
}
.recipe-card .r-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.recipe-card .r-sub { font-size: .82rem; color: var(--ink-mute); line-height: 1.35; }
/* A meal card's picture is up to four of its recipes' photos: 1 fills it,
   2 split it, 3 is one tall and two stacked, 4 is a 2×2. The gaps show the
   cream behind, so a dead link is a blank cell rather than a broken card. */
.recipe-card .photo-mosaic { display: grid; grid-template-columns: 1fr; place-items: stretch; place-content: stretch; gap: 2px; }
.recipe-card .photo-mosaic img { min-width: 0; min-height: 0; }
.recipe-card .photo-mosaic[data-n="2"] { grid-template-columns: 1fr 1fr; }
.recipe-card .photo-mosaic[data-n="3"],
.recipe-card .photo-mosaic[data-n="4"] { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.recipe-card .photo-mosaic[data-n="3"] img:first-child { grid-row: span 2; }
.recipe-card .r-body { padding: .85rem 1rem 1rem; display: flex; flex-direction: column; gap: .4rem; flex: 1; }
.recipe-card .r-title { font-family: var(--display); font-weight: 700; font-size: 1.05rem; letter-spacing: -.01em; line-height: 1.25; }
.recipe-card .r-meta { display: flex; gap: .55rem; flex-wrap: wrap; color: var(--ink-mute); font-size: .8rem; margin-top: auto; }

/* ── detail pages ───────────────────────────────────────────────────── */

.crumb { font-size: .88rem; color: var(--ink-mute); margin-bottom: 1rem; }
.crumb a { text-decoration: none; color: var(--ink-soft); }
.crumb a:hover { color: var(--tomato); }

.detail-cols {
  display: grid;
  grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
  gap: 1.6rem;
  align-items: start;
}
@media (max-width: 980px) { .detail-cols { grid-template-columns: 1fr; } }

.hero-img {
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  margin-bottom: 1.4rem;
  max-height: 340px;
}
.hero-img img { width: 100%; height: 100%; max-height: 340px; object-fit: cover; display: block; }

.ing-list { list-style: none; margin: 0; padding: 0; }
.ing-list li {
  display: flex;
  gap: .6rem;
  align-items: baseline;
  padding: .45rem 0;
  border-bottom: 1px dashed var(--line);
}
.ing-list li:last-child { border-bottom: 0; }
.ing-list .qty { font-family: var(--mono); font-size: .82rem; color: var(--ink-soft); min-width: 4.5rem; text-align: right; flex: none; font-variant-numeric: tabular-nums; }
.ing-list li { flex-direction: column; align-items: stretch; gap: .1rem; padding: 0; }
.ing-line {
  display: flex;
  flex-wrap: wrap; /* on a phone the chips take their own row, not the name's room */
  gap: .25rem .6rem;
  align-items: baseline;
  width: 100%;
  padding: .45rem .35rem;
  border: 0;
  border-radius: 8px;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ing-line:hover, .ing-line:focus-visible { background: var(--cream-2); }
.ing-line .ing-name { flex: 1 1 9rem; min-width: 0; }
.ing-line .ing-tags { display: flex; flex-wrap: wrap; gap: .3rem; margin-left: auto; }
.ing-note { font-size: .8rem; color: var(--ink-soft); padding: 0 .35rem .45rem 5.45rem; font-style: italic; }
.ing-hint { margin: .6rem 0 0; font-size: .78rem; }
.staple-check { margin-bottom: .9rem; align-items: flex-start; }
.staple-check input { margin-top: .2rem; }

.prose { line-height: 1.7; }
.prose p { margin: 0 0 .9rem; }
.prose ol { margin: 0; padding-left: 1.3rem; }
.prose ol li { margin-bottom: .7rem; padding-left: .3rem; }
.prose ol li::marker { font-family: var(--display); font-weight: 800; color: var(--tomato); }

.meta-chips { display: flex; gap: .45rem; flex-wrap: wrap; margin: .6rem 0 0; }

/* ── plain rows (meals, ingredients, settings tables) ───────────────── */

.row-list { list-style: none; margin: 0; padding: 0; }
.row-card {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .85rem 1.1rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  margin-bottom: .55rem;
  text-decoration: none;
  transition: transform .14s var(--ease), box-shadow .14s;
}
a.row-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.row-card .rc-emoji { font-size: 1.4rem; flex: none; }
.row-card .rc-main { flex: 1; min-width: 0; }
.row-card .rc-title { font-family: var(--display); font-weight: 700; font-size: 1.02rem; }
.row-card .rc-sub { font-size: .82rem; color: var(--ink-mute); margin-top: .1rem; }
.row-card .rc-side { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }

table.plain {
  width: 100%;
  border-collapse: collapse;
  font-size: .92rem;
}
table.plain th {
  text-align: left;
  font-size: .72rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-mute);
  font-weight: 700;
  padding: .4rem .6rem;
  border-bottom: 2px solid var(--line);
}
table.plain td { padding: .55rem .6rem; border-bottom: 1px dashed var(--line); vertical-align: middle; }
table.plain tr:last-child td { border-bottom: 0; }

/* ── ingredient manager rows ────────────────────────────────────────── */

.ing-row { display: grid; grid-template-columns: minmax(140px, 1.4fr) auto minmax(110px, 1fr) auto minmax(120px, 1fr) minmax(160px, 1.4fr) auto; gap: .6rem; align-items: center; padding: .5rem 0; border-bottom: 1px dashed var(--line); }
.ing-row.ing-head { border-bottom: 2px solid var(--line); }
.ing-row .name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.ing-row .name:hover, .ing-row .name:focus-visible { text-decoration: underline dotted; }
.ing-row select, .ing-row input { padding: .32rem .55rem; font-size: .88rem; border-radius: 9px; }
.ing-row .flash { animation: saved .8s var(--ease); }
@keyframes saved { 0% { background: var(--tint-green); } 100% { background: transparent; } }
.row-actions { display: flex; gap: .35rem; align-items: center; justify-content: flex-end; }
.ing-row select, .ing-row input[type="text"] { min-width: 0; }
.ing-row .staple { display: flex; align-items: center; gap: .35rem; cursor: pointer; }
.ing-row .staple .field-label { display: none; margin: 0; }

/* Seven columns need ~760px, and the card is narrower than that on a laptop
   with the sidebar open, so the row spilled merge…/✕ out of the card (#146).
   Below that the "why" note and the actions drop to a second line, and on a
   phone to a third. It keys on the card, not the viewport, because the
   sidebar decides how wide the card is. */
.ing-table { container-type: inline-size; }
@container (max-width: 780px) {
  .ing-row { grid-template-columns: minmax(0, 1.4fr) auto minmax(0, 1fr) minmax(0, 1fr); row-gap: .45rem; }
  .ing-row.ing-head { display: none; }
  .ing-row > span:empty { display: none; }
  .ing-row .staple .field-label { display: inline; } /* the header is gone */
  .ing-row [data-k="value_note"] { grid-column: 1 / 4; }
}
/* A phone's worth: name and staple, then aisle and verdict, then note. */
@container (max-width: 520px) {
  .ing-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
  .ing-row .name, .ing-row .rename { grid-column: 1 / 3; }
  .ing-row .staple { justify-self: end; }
  .ing-row [data-k="value_tier"] { grid-column: 2 / 4; }
  .ing-row [data-k="value_note"] { grid-column: 1 / 3; }
}

.scale-input { width: 4.4rem; padding: .3rem .5rem; font-size: .88rem; }

/* ── editor line rows ───────────────────────────────────────────────── */

.line-row { display: grid; grid-template-columns: 6.5rem 7.5rem minmax(0, 1fr) auto; gap: .55rem; margin-bottom: .5rem; }
.line-row input { padding: .45rem .65rem; }

/* ── login ──────────────────────────────────────────────────────────── */

.login-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 3rem 1.2rem;
}
.login-card {
  width: min(430px, 100%);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 22px;
  box-shadow: var(--shadow);
  padding: 2.1rem 2.2rem 1.9rem;
  position: relative;
  overflow: hidden;
}
.login-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 9px;
  background: repeating-linear-gradient(90deg, var(--tomato) 0 22px, transparent 22px 44px);
}
.login-card .wordmark { display: block; text-align: center; font-size: 2.3rem; padding: 0; margin: .4rem 0 .1rem; }
.login-card .strap { text-align: center; color: var(--ink-mute); font-size: .92rem; margin: 0 0 1.5rem; }
.login-tabs { display: flex; gap: .3rem; background: var(--cream-2); border-radius: 999px; padding: .25rem; margin-bottom: 1.4rem; }
.login-tabs button {
  flex: 1;
  border: 0;
  background: none;
  padding: .45rem .5rem;
  border-radius: 999px;
  font-family: var(--display);
  font-weight: 700;
  font-size: .9rem;
  color: var(--ink-mute);
  cursor: pointer;
}
.login-tabs button.on { background: var(--card); color: var(--ink); box-shadow: var(--shadow-sm); }
.login-card .btn { width: 100%; justify-content: center; padding: .65rem 1rem; font-size: 1rem; margin-top: .4rem; }
.login-foot { text-align: center; margin-top: 1.1rem; font-size: .85rem; color: var(--ink-mute); }
/* A server with no SMTP has no reset link to offer, so the foot can be empty
   on the sign-in tab — don't leave its margin behind. */
.login-foot:empty { display: none; }

.seg { display: flex; gap: .3rem; background: var(--cream-2); border-radius: 999px; padding: .22rem; margin-bottom: 1rem; }
.seg button { flex: 1; border: 0; background: none; padding: .35rem .5rem; border-radius: 999px; font-weight: 600; font-size: .85rem; color: var(--ink-mute); cursor: pointer; }
.seg button.on { background: var(--card); color: var(--ink); box-shadow: var(--shadow-sm); }

/* ── dialogs ────────────────────────────────────────────────────────── */

dialog {
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--card);
  color: var(--ink);
  box-shadow: var(--shadow);
  padding: 1.6rem 1.7rem;
  width: min(520px, calc(100vw - 2rem));
  max-height: min(84vh, 720px);
  overflow: auto;
}
dialog::backdrop { background: rgba(30, 20, 12, .45); backdrop-filter: blur(2px); }
dialog h2 { font-size: 1.3rem; margin-bottom: .9rem; }
.dialog-actions { display: flex; justify-content: flex-end; gap: .6rem; margin-top: 1.3rem; }

.code-reveal {
  font-family: var(--mono);
  font-size: 1.05rem;
  background: var(--cream-2);
  border: 1px dashed var(--line-2);
  border-radius: 12px;
  padding: .8rem 1rem;
  text-align: center;
  letter-spacing: .06em;
  word-break: break-all;
  user-select: all;
}

.picker-list { list-style: none; margin: .8rem 0 0; padding: 0; max-height: 320px; overflow: auto; }
.picker-list li { display: flex; align-items: center; gap: .6rem; padding: .5rem .2rem; border-bottom: 1px dashed var(--line); }
.picker-list li:last-child { border-bottom: 0; }
.picker-list .p-main { flex: 1; min-width: 0; }
.picker-list .p-title { font-weight: 600; }
.picker-list .p-sub { font-size: .78rem; color: var(--ink-mute); }

dialog .sub { color: var(--ink-mute); font-size: .9rem; margin: .2rem 0 .9rem; }

/* duplicate groups: one radio per spelling picks the survivor */
.merge-group { padding: .65rem 0; border-bottom: 1px dashed var(--line); }
.merge-group:last-child { border-bottom: 0; }
.unfolded { margin-top: 1.2rem; }
.unfolded .merge-section-head { font-size: 1.05rem; margin-bottom: .2rem; }
.unfolded .picker-list { margin-top: .2rem; }
.merge-member { display: flex; align-items: center; gap: .55rem; padding: .28rem 0; cursor: pointer; }
.merge-member input { accent-color: var(--ink); }
.merge-member .m-name { font-weight: 600; white-space: nowrap; }
.merge-member .m-meta { font-size: .78rem; color: var(--ink-mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.merge-group-foot { display: flex; align-items: center; justify-content: flex-end; gap: .8rem; margin-top: .4rem; }
.merge-group-foot .m-hint { font-size: .78rem; color: var(--butter-dk); flex: 1; }
.merge-group-foot .btn { flex-shrink: 0; }

/* ── toast ──────────────────────────────────────────────────────────── */

#toast-rack {
  position: fixed;
  bottom: 1.4rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  z-index: 100;
  width: min(560px, calc(100vw - 2rem));
  pointer-events: none;
}
.toast {
  background: var(--ink);
  color: var(--cream);
  border-radius: 14px;
  padding: .7rem 1.1rem;
  font-size: .92rem;
  box-shadow: var(--shadow);
  animation: rise .25s var(--ease);
  pointer-events: auto;
  max-width: 100%;
}
.toast.error { background: var(--tomato-dk); color: #fff; }
.toast.ok { background: var(--leek); color: #fff; }
.toast.leaving { opacity: 0; transition: opacity .3s; }

/* ── empty states & skeletons ───────────────────────────────────────── */

.empty {
  text-align: center;
  padding: 3.5rem 1rem;
  color: var(--ink-mute);
}
.empty .e-emoji { font-size: 2.6rem; display: block; margin-bottom: .7rem; }
.empty h2 { color: var(--ink-soft); font-size: 1.25rem; margin-bottom: .4rem; }
.empty p { margin: 0 0 1.2rem; }

.skeleton { display: flex; flex-direction: column; gap: .7rem; padding: .5rem 0; }
.skeleton .bone {
  height: 1.15rem;
  border-radius: 8px;
  background: var(--cream-2);
  animation: pulse 1.2s ease-in-out infinite;
}
.skeleton .bone:nth-child(2) { width: 82%; animation-delay: .12s; }
.skeleton .bone:nth-child(3) { width: 64%; animation-delay: .24s; }
@keyframes pulse { 50% { opacity: .45; } }

.danger-zone { border-color: color-mix(in srgb, var(--tomato) 45%, var(--line)); }
.danger-zone h2 { color: var(--tomato); }

.section { margin-bottom: 1.9rem; }
.section > h2 { font-size: 1.25rem; margin-bottom: .8rem; }

.noscript-card { max-width: 30rem; margin: 18vh auto; text-align: center; }

.value-badge { cursor: help; font-size: .85rem; }

.copy-row { display: flex; gap: .5rem; align-items: center; margin-top: .8rem; }
.copy-row .code-reveal { flex: 1; }

/* ── supermarkets: settings rows + the shopping-page switcher ───────── */

.market-row { display: flex; align-items: center; gap: .6rem; padding: .55rem .1rem; border-bottom: 1px dashed var(--line); }
.market-row:last-child { border-bottom: 0; }
.market-row .m-pick { display: flex; align-items: center; gap: .7rem; flex: 1; min-width: 0; cursor: pointer; }
.market-row .m-main { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.market-row .aisle-mini { letter-spacing: .22em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.market-row .m-actions { display: flex; gap: .35rem; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }

.order-rows { margin: .6rem 0 .2rem; max-height: 55vh; overflow-y: auto; }
.order-row { display: flex; align-items: center; gap: .7rem; padding: .35rem .15rem; border-bottom: 1px dashed var(--line); }
.order-row:last-child { border-bottom: 0; }
.order-row .o-label { flex: 1; }
.order-row .icon-btn[disabled] { opacity: .3; cursor: default; }
.order-row .icon-btn[disabled]:hover { border-color: var(--line); color: var(--ink-soft); }

.market-pick { width: auto; font: inherit; font-size: inherit; color: inherit; background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: .05rem .35rem; }

/* ── allowances: what this server allows, and the signup note ───────── */

.allow-list { margin-top: .3rem; }
.allow-row { display: flex; align-items: center; gap: 1rem; padding: .55rem .1rem; border-bottom: 1px dashed var(--line); }
.allow-row:last-child { border-bottom: 0; }
.allow-row .a-main { display: flex; flex-direction: column; gap: .1rem; flex: 1; min-width: 0; }
.allow-row .a-main b { font-family: var(--display); font-size: .98rem; }
.allow-row .a-cap { font-family: var(--mono); font-size: .82rem; color: var(--ink-mute); flex: none; }
.allow-row .a-bar {
  flex: none;
  width: 140px;
  height: 8px;
  border-radius: 999px;
  background: var(--cream-2);
  overflow: hidden;
}
/* The width of the fill is set through the CSSOM in settings.js — a style
   attribute would need 'unsafe-inline' in the CSP, which is not a trade worth
   making for a progress bar. */
.allow-row .a-bar span { display: block; height: 100%; background: var(--leek); border-radius: 999px; }
.allow-row .a-bar.full span { background: var(--tomato); }

.allow-note {
  margin-top: 1.1rem;
  padding: .85rem 1rem;
  background: var(--cream-2);
  border-radius: 14px;
  font-size: .85rem;
  color: var(--ink-soft);
}
.allow-note b { font-family: var(--display); display: block; margin-bottom: .35rem; }
.allow-note ul { margin: 0; padding-left: 1.1rem; }
.allow-note li { margin: .12rem 0; }

/* ── responsive ─────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  .side {
    position: static;
    height: auto;
    flex-direction: row;
    align-items: center;
    padding: 1rem 1.2rem;
    gap: .3rem;
    overflow-x: auto;
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }
  .wordmark { margin-bottom: 0; font-size: 1.4rem; }
  .side nav { flex-direction: row; }
  .nav-link { padding: .4rem .55rem; }
  .nav-link .n-label { display: none; }
  .side-user { display: none; }
  .side .spacer { display: none; }
  .content { padding: 1.6rem 1.2rem 4rem; }
  .detail-cols { grid-template-columns: 1fr; }
}
