:root {
  color-scheme: light;

  --page:           #faf8f5;
  --surface-1:      #ffffff;
  --surface-2:      #f2ede6;
  --text-primary:   #241f1a;
  --text-secondary: #5c5349;
  --muted:          #8a8074;
  --border:         rgba(36, 31, 26, 0.12);
  --accent:         #b5541e;
  --accent-text:    #ffffff;
  --danger:         #b3261e;
  --danger-text:    #ffffff;
  --chip-category:  #dce9df;
  --chip-category-text: #2c5136;
  --chip-diet:      #f3ddc7;
  --chip-diet-text: #7a4a12;
  --chip-cuisine:   #ded7ee;
  --chip-cuisine-text: #4a3a72;
  --chip-protein:   #f2d7d7;
  --chip-protein-text: #7a2f2f;
  --star:           #d69a2d;
  --heart:          #c8484f;

  --radius:    12px;
  --radius-sm: 8px;
  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --page:           #16130f;
    --surface-1:      #211c17;
    --surface-2:      #2a2420;
    --text-primary:   #f4efe9;
    --text-secondary: #c9beb1;
    --muted:          #948977;
    --border:         rgba(244, 239, 233, 0.12);
    --accent:         #e08a4e;
    --accent-text:    #1a1109;
    --danger:         #f28b82;
    --danger-text:    #2a0d0b;
    --chip-category:  #24352a;
    --chip-category-text: #a9d3b6;
    --chip-diet:      #3a2c19;
    --chip-diet-text: #e7bf8b;
    --chip-cuisine:   #2c2740;
    --chip-cuisine-text: #c7bceb;
    --chip-protein:   #3a2323;
    --chip-protein-text: #e8b0b0;
    --star:           #e0a83e;
    --heart:          #ec6f76;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --page:           #16130f;
  --surface-1:      #211c17;
  --surface-2:      #2a2420;
  --text-primary:   #f4efe9;
  --text-secondary: #c9beb1;
  --muted:          #948977;
  --border:         rgba(244, 239, 233, 0.12);
  --accent:         #e08a4e;
  --accent-text:    #1a1109;
  --danger:         #f28b82;
  --danger-text:    #2a0d0b;
  --chip-category:  #24352a;
  --chip-category-text: #a9d3b6;
  --chip-diet:      #3a2c19;
  --chip-diet-text: #e7bf8b;
  --chip-cuisine:   #2c2740;
  --chip-cuisine-text: #c7bceb;
  --chip-protein:   #3a2323;
  --chip-protein-text: #e8b0b0;
  --star:           #e0a83e;
  --heart:          #ec6f76;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--page);
  color: var(--text-primary);
  font-family: var(--font);
  line-height: 1.45;
}

a { color: var(--accent); }

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  padding: 14px 20px;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
}

.topbar h1 { margin: 0; font-size: 1.25rem; }
.brand { text-decoration: none; color: var(--text-primary); }

.nav-links { display: flex; gap: 6px; }

.menu { position: relative; }

/* Inline SVG rather than emoji so both icons share one stroke weight and take
   their color from the theme — emoji render at whatever weight and palette the
   platform font happens to use, which differs per OS. */
.icon {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon-sm { width: 13px; height: 13px; stroke-width: 2.2; }

.menu-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 7px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
}
.menu-toggle:hover { background: var(--surface-2); color: var(--accent); }
.menu-toggle[aria-expanded="true"] {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--accent);
}

/* Each panel sets its own `display`, which would otherwise beat the browser's
   [hidden]{display:none} at equal specificity — hence the explicit override. */
.menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  min-width: 140px;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
}
.menu-panel[hidden] { display: none; }
.menu-panel a {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  text-decoration: none;
  white-space: nowrap;
  color: var(--text-secondary);
}
.menu-panel a:hover { background: var(--surface-2); color: var(--accent); }
.menu-panel .icon-sm { flex: none; color: var(--muted); }
.menu-panel a:hover .icon-sm { color: inherit; }

/* Controls that can only fail for this role. `!important` because every one of
   them has a class of its own that sets display (.btn, .shop-add, ...), and
   this has to win over all of them — the same fight as the [hidden] trap. The
   server refuses the write regardless; this only stops the page offering it.
   <html data-role> starts as "guest" in index.html, so nothing flashes up. */
/* Fails closed: an unknown role hides both. */
html:not([data-role='member']):not([data-role='admin']) .needs-member,
html:not([data-role='admin']) .needs-admin { display: none !important; }

/* Sign in / the account avatar, pushed to the far end of the topbar. */
.auth-control { margin-left: auto; display: flex; align-items: center; font-size: 0.9rem; }
.auth-control:empty { display: none; }

/* Light/dark switch (theme.js). It takes over pushing to the far end, so the
   avatar after it sits beside it rather than splitting the free space. Looks
   like a .menu-toggle, but isn't one — app.js's menu listener must not see it. */
.theme-toggle {
  margin-left: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 7px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
}
.theme-toggle:hover { background: var(--surface-2); color: var(--accent); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-toggle + .auth-control { margin-left: 0; }
.auth-btn {
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-primary);
  font-weight: 600;
  text-decoration: none;
}
.auth-btn:hover { border-color: var(--accent); color: var(--accent); }

.menu-toggle.avatar-btn { padding: 0; border: none; border-radius: 50%; }
.menu-toggle.avatar-btn:hover,
.menu-toggle.avatar-btn[aria-expanded="true"] { box-shadow: 0 0 0 3px var(--surface-2); }
.menu-toggle.avatar-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The initial is always there; a photo, when there is one, covers it. If the
   photo fails to load, app.js removes the <img> and the initial shows. */
.avatar-circle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 700;
  line-height: 1;
}
.avatar-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.avatar-circle.large { width: 42px; height: 42px; font-size: 1.15rem; }

/* Anchored to the right: the avatar sits at the topbar's far end. */
.menu-panel.user-menu { left: auto; right: 0; width: max-content; max-width: min(20rem, calc(100vw - 32px)); }
.user-menu-who {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 8px 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.user-menu-id { min-width: 0; }
.user-menu-name { font-weight: 600; overflow-wrap: anywhere; }
.user-menu-name + .user-menu-email { font-weight: 400; font-size: 0.85rem; color: var(--text-secondary); }
.user-menu-email { font-weight: 600; overflow-wrap: anywhere; }
.user-menu-role { font-size: 0.8rem; color: var(--text-secondary); margin-top: 2px; }
.user-menu-item {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  font: inherit;
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
}
.user-menu-item:hover { background: var(--surface-2); color: var(--accent); }
.user-menu-item:disabled { color: var(--muted); cursor: default; }

/* The page a sign-in failure lands on (server.js sendAuthPage). */
.auth-message { max-width: 36rem; margin: 3rem auto; padding: 0 16px; }

.filters { display: flex; flex-wrap: wrap; gap: 8px; flex: 1; min-width: 0; }
.filters[hidden] { display: none; }

#search, select {
  font: inherit;
  font-size: 0.9rem;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
}
#search { flex: 1; min-width: 160px; }

main { max-width: 1100px; margin: 0 auto; padding: 20px; }

.loading, .empty, .error { color: var(--muted); padding: 40px 0; text-align: center; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 16px;
}

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.card:hover { transform: translateY(-2px); box-shadow: 0 4px 14px rgba(0,0,0,0.08); }

.card-link { display: block; text-decoration: none; color: inherit; }

.card-image {
  aspect-ratio: 4 / 3;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 0.8rem;
  overflow: hidden;
}
.card-image img { width: 100%; height: 100%; object-fit: cover; }

.card-body { padding: 12px 14px 6px; }
.card-title { font-weight: 600; margin: 0 0 4px; }
.card-meta { color: var(--text-secondary); font-size: 0.85rem; margin: 0 0 8px; }
.card-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.card-rating { padding: 0 14px 12px; display: flex; align-items: center; }

.chip {
  display: inline-block;
  font-size: 0.72rem;
  padding: 2px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.chip.category { background: var(--chip-category); color: var(--chip-category-text); }
.chip.diet     { background: var(--chip-diet); color: var(--chip-diet-text); }
.chip.cuisine  { background: var(--chip-cuisine); color: var(--chip-cuisine-text); }
.chip.protein  { background: var(--chip-protein); color: var(--chip-protein-text); }

.rating-control { display: inline-flex; align-items: center; gap: 1px; }
.rating-star {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px;
  font-size: 1rem;
  line-height: 1;
  color: var(--border);
}
.rating-star.filled { color: var(--star); }
.rating-star:hover { color: var(--star); }
.rating-star.static { cursor: default; }
.rating-star.static:not(.filled):hover { color: var(--border); }
.rating-clear {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px;
  margin-left: 4px;
  font-size: 0.7rem;
  color: var(--muted);
}
.rating-clear:hover { color: var(--text-primary); }
.detail-rating { margin: 4px 0 10px; display: flex; align-items: center; gap: 12px; }

/* A recipe's favorite heart. On a card it sits at the right end of the rating row. */
.card-rating .recipe-fav { margin-left: auto; }
.recipe-fav {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px 4px;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--muted);
}
.recipe-fav.on, .recipe-fav:hover { color: var(--heart); }
.recipe-fav.static { cursor: default; }

/* "♥ Favorites" in the filter bar — an on/off toggle, styled to sit with the selects. */
.filter-toggle {
  font: inherit;
  font-size: 0.9rem;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  cursor: pointer;
}
.filter-toggle[aria-pressed="true"] { color: var(--heart); border-color: var(--heart); }

/* --------------------------- detail view --------------------------- */

.back-link { display: inline-block; margin-bottom: 14px; font-size: 0.9rem; text-decoration: none; }

.detail-header {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.detail-image {
  width: 260px;
  max-width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--surface-2);
  border-radius: var(--radius);
  overflow: hidden;
  flex-shrink: 0;
}
.detail-image img { width: 100%; height: 100%; object-fit: cover; }
button.detail-image {
  display: block;
  padding: 0;
  border: none;
  position: relative;
}
button.detail-image:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ------------------------------ photo viewer ------------------------------ */

/* Drawn rather than the keywords: Windows renders the built-in zoom-in /
   zoom-out cursors as small, jagged bitmaps. The image-set line gives a
   high-DPI screen a 2x copy; a browser without it keeps the plain url line.
   Hotspot 13 13 is the lens centre. */
button.detail-image,
.zoom-btn {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8' stroke='white' stroke-width='5'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='white' stroke-width='6'/%3E%3Ccircle cx='13' cy='13' r='8' fill='white' fill-opacity='.85' stroke='%23222' stroke-width='2'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='%23222' stroke-width='3'/%3E%3Cpath d='M9.5 13h7M13 9.5v7' stroke='%23222' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 13 13, zoom-in;
  cursor: -webkit-image-set(url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8' stroke='white' stroke-width='5'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='white' stroke-width='6'/%3E%3Ccircle cx='13' cy='13' r='8' fill='white' fill-opacity='.85' stroke='%23222' stroke-width='2'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='%23222' stroke-width='3'/%3E%3Cpath d='M9.5 13h7M13 9.5v7' stroke='%23222' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 1x, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8' stroke='white' stroke-width='5'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='white' stroke-width='6'/%3E%3Ccircle cx='13' cy='13' r='8' fill='white' fill-opacity='.85' stroke='%23222' stroke-width='2'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='%23222' stroke-width='3'/%3E%3Cpath d='M9.5 13h7M13 9.5v7' stroke='%23222' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 2x) 13 13, zoom-in;
}
.image-viewer {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8' stroke='white' stroke-width='5'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='white' stroke-width='6'/%3E%3Ccircle cx='13' cy='13' r='8' fill='white' fill-opacity='.85' stroke='%23222' stroke-width='2'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='%23222' stroke-width='3'/%3E%3Cpath d='M9.5 13h7' stroke='%23222' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 13 13, zoom-out;
  cursor: -webkit-image-set(url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8' stroke='white' stroke-width='5'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='white' stroke-width='6'/%3E%3Ccircle cx='13' cy='13' r='8' fill='white' fill-opacity='.85' stroke='%23222' stroke-width='2'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='%23222' stroke-width='3'/%3E%3Cpath d='M9.5 13h7' stroke='%23222' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 1x, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8' stroke='white' stroke-width='5'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='white' stroke-width='6'/%3E%3Ccircle cx='13' cy='13' r='8' fill='white' fill-opacity='.85' stroke='%23222' stroke-width='2'/%3E%3Cpath d='M19.5 19.5l7.5 7.5' stroke='%23222' stroke-width='3'/%3E%3Cpath d='M9.5 13h7' stroke='%23222' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 2x) 13 13, zoom-out;
}

/* The magnifier over a photo that is already a link or a pick button. A dark
   translucent disc reads the same over any photo, in either theme. */
.zoom-btn {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
}
.zoom-btn:hover { background: rgba(0, 0, 0, 0.75); }
.zoom-btn:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }
.zoom-btn .icon { width: 18px; height: 18px; }

.card { position: relative; }
.card-zoom { top: 8px; right: 8px; }

/* The hit's 64px photo is centred vertically, and a hit grows with a wrapped
   title or an extra row of tags — so the magnifier is placed from the centre
   (50% - half the photo), not from the top, or it rides up off the photo on
   taller hits. The hit fills the wrap so both share one height when a
   neighbour in the grid row is taller. */
.picker-hit-wrap { position: relative; }
.picker-hit-wrap .picker-hit { height: 100%; }
.picker-zoom { top: calc(50% - 28px); left: 10px; width: 24px; height: 24px; }
.picker-zoom .icon { width: 14px; height: 14px; }

/* Clicking anywhere — photo, caption or backdrop — closes it, so there is no
   close button (one in the corner sat on top of the avatar). Escape too. */
.image-viewer {
  padding: 0;
  border: none;
  background: transparent;
  max-width: 94vw;
  max-height: 94vh;
  overflow: visible;
  outline: none;
}
.image-viewer::backdrop { background: rgba(0, 0, 0, 0.8); }
.image-viewer figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.image-viewer img {
  display: block;
  max-width: 94vw;
  max-height: calc(94vh - 48px);
  object-fit: contain;
  border-radius: var(--radius-sm);
}
.image-viewer figcaption { color: #fff; font-size: 0.95rem; text-align: center; }
.image-viewer figcaption:empty { display: none; }

.detail-info { flex: 1; min-width: 220px; }
.detail-info h2 { margin: 0 0 6px; }
.detail-source { color: var(--muted); font-size: 0.85rem; margin: 0 0 10px; }
.detail-meta { display: flex; flex-wrap: wrap; gap: 14px; color: var(--text-secondary); font-size: 0.9rem; margin: 0 0 10px; }
.detail-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.detail-description { color: var(--text-secondary); }

.panels {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}
@media (max-width: 700px) {
  .panels { grid-template-columns: 1fr; }
}

.panel h3 { margin: 0 0 10px; font-size: 1rem; }

.ingredient-list { list-style: none; margin: 0; padding: 0; }
.ingredient-list li {
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  display: flex;
  gap: 8px;
}
.ingredient-list li:last-child { border-bottom: none; }
.ingredient-qty { color: var(--text-secondary); min-width: 90px; flex-shrink: 0; }
.ingredient-optional { color: var(--muted); font-style: italic; font-size: 0.8rem; }

.instructions { padding-left: 22px; }
.instructions li { padding: 4px 0; }

.nutrition-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.nutrition-table td { padding: 5px 0; border-bottom: 1px solid var(--border); }
.nutrition-table td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.nutrition-source { color: var(--muted); font-size: 0.78rem; margin-top: 8px; }

.notes {
  margin-top: 20px;
  padding: 12px 14px;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
}

/* ---------------------------- meal plan view ---------------------------- */

.plan-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-bottom: 16px;
}
.plan-header h2 { margin: 0; font-size: 1.15rem; }

.plan-week-title { margin: 20px 0 8px; font-size: 0.95rem; color: var(--text-secondary); }
.plan-week-title:first-of-type { margin-top: 0; }

.plan-grid-wrap { overflow-x: auto; }

.plan-grid {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  /* Wide enough that a day column still fits a legible thumbnail; .plan-grid-wrap
     scrolls horizontally on a narrow screen rather than squeezing the photos. */
  min-width: 880px;
}

.plan-day-header, .plan-slot-label, .plan-cell {
  background: var(--surface-1);
  padding: 8px 10px;
}
.plan-day-header {
  background: var(--surface-2);
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
}
.plan-slot-label {
  background: var(--surface-2);
  font-size: 0.78rem;
  color: var(--text-secondary);
  text-transform: capitalize;
  display: flex;
  align-items: center;
}
.plan-cell {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 44px;
}
.plan-item {
  font-size: 0.82rem;
  text-decoration: none;
  color: var(--text-primary);
  line-height: 1.3;
}
.plan-item:hover { color: var(--accent); }
.plan-servings { color: var(--muted); font-size: 0.75rem; }
.plan-leftover {
  color: var(--muted);
  font-size: 0.7rem;
  font-style: italic;
  display: block;
}
.plan-empty { color: var(--muted); font-size: 0.8rem; }
/* A banner across the cell rather than a square beside the title: the column is
   only ~90px of content wide, so a side-by-side thumbnail leaves the title in a
   two-character-wide gutter. Shorter in the builder, where the cell also carries
   a time input and a servings stepper. */
.meal-photo {
  display: block;
  width: 100%;
  height: 52px;
  object-fit: cover;
  border-radius: 4px;
  margin-bottom: 4px;
  background: var(--surface-2);
}
.cell-item .meal-photo { height: 40px; }
.plan-time { color: var(--muted); font-size: 0.7rem; font-variant-numeric: tabular-nums; }

/* ------------------------------- buttons ------------------------------- */

.btn {
  font: inherit;
  font-size: 0.85rem;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: var(--accent);
  color: var(--accent-text);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { filter: brightness(1.08); }
.btn:disabled { opacity: 0.5; cursor: default; filter: none; }
.btn.subtle {
  background: var(--surface-2);
  color: var(--text-secondary);
  border-color: var(--border);
}
.btn.subtle:hover { color: var(--text-primary); filter: none; }
.btn.danger { background: var(--danger); color: var(--danger-text); }
.btn.subtle.danger { background: var(--surface-2); color: var(--danger); }
.btn.subtle.danger:hover { border-color: var(--danger); color: var(--danger); }

/* ----------------------------- saved plan list ----------------------------- */

.plan-fav {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--border);
}
.plan-fav.on { color: var(--star); }
.plan-fav:hover { color: var(--star); }
.plan-fav.plan-fav-static { cursor: default; }

.plan-list { list-style: none; margin: 0; padding: 0; }
.plan-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 8px;
}
.plan-row-main { flex: 1; min-width: 0; }
.plan-row-name { font-weight: 600; text-decoration: none; color: var(--text-primary); }
.plan-row-name:hover { color: var(--accent); }
.plan-row-meta { margin: 2px 0 0; color: var(--text-secondary); font-size: 0.82rem; }

/* -------------------------------- builder -------------------------------- */

.setup-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  max-width: 520px;
}
.setup-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 14px; }
.setup-field { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem; color: var(--text-secondary); }
.setup-hint { color: var(--muted); font-size: 0.82rem; margin: 0 0 8px; }
.setup-slots { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.setup-slot { display: flex; align-items: center; gap: 10px; font-size: 0.9rem; }
.setup-slot-name { text-transform: capitalize; flex: 1; }

input[type="date"], input[type="time"], input[type="text"] {
  font: inherit;
  font-size: 0.85rem;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
}

.save-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  margin-bottom: 14px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.save-bar input[type="text"] { flex: 1; min-width: 180px; }
.save-status { color: var(--muted); font-size: 0.82rem; }

.plan-day-header .add-meal {
  display: block;
  width: 100%;
  margin-top: 4px;
  font-size: 0.7rem;
  padding: 2px 4px;
  text-transform: capitalize;
}

.plan-cell.not-scheduled { background: var(--surface-2); }
.plan-day-empty { display: none; }

.cell-head { display: flex; align-items: center; gap: 4px; }
.cell-head input[type="time"] {
  flex: 1;
  min-width: 0;
  font-size: 0.7rem;
  padding: 2px 4px;
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}
.cell-head input[type="time"]:hover,
.cell-head input[type="time"]:focus { border-color: var(--border); background: var(--surface-2); }

.cell-x {
  background: none;
  border: none;
  cursor: pointer;
  padding: 1px 3px;
  font-size: 0.7rem;
  line-height: 1;
  color: var(--muted);
}
.cell-x:hover { color: var(--accent); }

.cell-item {
  border-top: 1px solid var(--border);
  padding-top: 4px;
}
.cell-item:first-of-type { border-top: none; }
.cell-item-title {
  display: block;
  font-size: 0.8rem;
  text-decoration: none;
  color: var(--text-primary);
  line-height: 1.25;
}
.cell-item-title:hover { color: var(--accent); }
.cell-item-controls { display: flex; align-items: center; gap: 2px; margin-top: 2px; }
.step {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  cursor: pointer;
  width: 18px;
  height: 18px;
  line-height: 1;
  font-size: 0.75rem;
  color: var(--text-secondary);
  padding: 0;
}
.step:hover { color: var(--accent); }
.cell-servings {
  font-size: 0.75rem;
  color: var(--text-secondary);
  min-width: 14px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.cell-item-controls .cell-x { margin-left: auto; }

.cell-add {
  align-self: flex-start;
  margin-top: 2px;
  background: none;
  border: 1px dashed var(--border);
  border-radius: 4px;
  cursor: pointer;
  padding: 0 6px;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--muted);
}
.cell-add:hover { color: var(--accent); border-color: var(--accent); }

/* ------------------------------ leftovers ------------------------------ */

.leftovers-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.leftovers-label { font-size: 0.8rem; font-weight: 600; color: var(--text-secondary); }
.leftovers-hint { font-size: 0.78rem; color: var(--muted); margin-left: auto; }
.leftovers-note { font-size: 0.8rem; color: var(--muted); margin: 0 0 14px; }

.leftover-chip {
  font: inherit;
  font-size: 0.8rem;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
  cursor: pointer;
}
.leftover-chip:hover { border-color: var(--accent); }
.leftover-chip.armed {
  background: var(--accent);
  color: var(--accent-text);
  border-color: var(--accent);
}
.leftover-count { opacity: 0.75; font-size: 0.75rem; }

/* With a batch armed, the cells themselves are the drop target. */
#builder-grids.arming .plan-cell[data-date] { cursor: copy; }
#builder-grids.arming .plan-cell[data-date]:hover { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ----------------------------- recipe picker ----------------------------- */

#recipe-picker {
  width: min(760px, 94vw);
  max-height: 86vh;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-1);
  color: var(--text-primary);
  overflow: hidden;
}
#recipe-picker::backdrop { background: rgba(0, 0, 0, 0.45); }

.picker-head {
  display: flex;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
#picker-search {
  flex: 1;
  font: inherit;
  font-size: 0.9rem;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
}

.picker-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.picker-filters select {
  font: inherit;
  font-size: 0.85rem;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
}
/* Pushed to the far end so the filter row reads left-to-right as
   "narrow it down … and here's what's left". */
.picker-count {
  margin-left: auto;
  font-size: 0.8rem;
  color: var(--text-secondary);
}

.picker-results {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 4px;
  max-height: 62vh;
  overflow-y: auto;
  padding: 8px;
}
.picker-results .empty,
.picker-results .error { grid-column: 1 / -1; }

.picker-hit {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  padding: 6px;
  color: inherit;
  font: inherit;
}
.picker-hit:hover { background: var(--surface-2); }

.picker-hit-photo {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
}
.picker-hit-photo img { width: 100%; height: 100%; object-fit: cover; }
.picker-hit-nophoto { font-size: 0.65rem; color: var(--muted); }

.picker-hit-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.picker-hit-title { font-size: 0.9rem; font-weight: 500; }
.picker-hit-meta { font-size: 0.78rem; color: var(--text-secondary); }
.picker-hit-tags { display: flex; flex-wrap: wrap; gap: 4px; }

/* ----------------------------- shopping list ----------------------------- */

.shop-meta { margin: -8px 0 14px; color: var(--text-secondary); font-size: 0.85rem; }

.shop-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.78rem;
}
.shop-badge.active { background: var(--chip-category); color: var(--chip-category-text); }
.shop-badge.heb {
  background: var(--chip-diet);
  color: var(--chip-diet-text);
  margin-bottom: 14px;
}
.shop-badge-clear {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0 2px;
  font-size: 0.7rem;
  color: inherit;
  opacity: 0.7;
}
.shop-badge-clear:hover { opacity: 1; }

.shop-recipes { margin-bottom: 20px; }
.shop-recipes h3 { margin: 0 0 8px; font-size: 0.95rem; }
.shop-recipe-row { display: flex; flex-wrap: wrap; gap: 8px; }
.shop-recipe {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 150px;
  padding: 8px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}
.shop-recipe:hover { border-color: var(--accent); }
.shop-recipe img {
  width: 100%;
  height: 64px;
  object-fit: cover;
  border-radius: 4px;
  margin-bottom: 4px;
  background: var(--surface-2);
}
.shop-recipe-title { font-size: 0.82rem; font-weight: 500; line-height: 1.25; }
.shop-recipe-meta { font-size: 0.74rem; color: var(--muted); }

.shop-group { margin-bottom: 18px; }
.shop-group h3 {
  margin: 0 0 6px;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
}

.shop-list { list-style: none; margin: 0; padding: 0; }
.shop-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 4px;
}
/* Crossed out, not gone: the line stays exactly where it was so "I already have
   that" is still readable in the store. */
.shop-item.checked .shop-name,
.shop-item.checked .shop-qty { text-decoration: line-through; color: var(--muted); }
.shop-item.checked { opacity: 0.6; }

.shop-item-main {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  cursor: pointer;
}
.shop-check { width: 16px; height: 16px; accent-color: var(--accent); flex: none; }
.shop-qty {
  flex: none;
  width: 74px;
  font-size: 0.82rem;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.shop-name { font-size: 0.9rem; }
.shop-flag {
  font-size: 0.68rem;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  white-space: nowrap;
}
.shop-flag.added { background: var(--chip-cuisine); color: var(--chip-cuisine-text); }
/* HEB's own red, so it reads as "the HEB one" at a glance. Exempt from the
   checked row's dimming: it's the point of the line once it's crossed out. */
.shop-heb {
  flex: none;
  font-size: 0.64rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  padding: 1px 6px;
  border-radius: 4px;
  background: #dc291e;
  color: #fff;
  white-space: nowrap;
}
.shop-item.checked:has(.shop-heb) { opacity: 0.8; }
.shop-note { font-size: 0.75rem; color: var(--muted); }

.shop-delete {
  background: none;
  border: none;
  cursor: pointer;
  padding: 2px 4px;
  font-size: 0.8rem;
  color: var(--muted);
  flex: none;
}
.shop-delete:hover { color: var(--text-primary); }

.shop-add {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 12px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-top: 18px;
}
#shop-add-name { flex: 1; min-width: 180px; }
.shop-add-error { color: var(--accent); font-size: 0.8rem; }

#shop-gen-dialog,
.confirm-dialog {
  width: min(420px, 92vw);
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-1);
  color: var(--text-primary);
}
#shop-gen-dialog::backdrop,
.confirm-dialog::backdrop { background: rgba(0, 0, 0, 0.45); }
.shop-gen-message,
.confirm-message { margin: 0 0 16px; font-size: 0.9rem; }
.shop-gen-actions,
.confirm-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }

/* -------------------------------- settings -------------------------------- */

a.user-menu-item { text-decoration: none; box-sizing: border-box; }

.settings { max-width: 44rem; }
.settings h2 { margin: 0 0 16px; }
.settings-section {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
}
.settings-section h3 { margin: 0 0 6px; font-size: 1.05rem; }
.settings-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.settings-help { margin: 0; color: var(--text-secondary); font-size: 0.92rem; }
.settings-facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 8px 14px;
  margin: 16px 0 0;
  font-size: 0.9rem;
}
.settings-facts dt { font-weight: 600; }
.settings-facts dd { margin: 0; color: var(--text-secondary); }
.settings-facts select { max-width: 100%; }
.settings-warning {
  margin: 14px 0 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--danger);
  font-size: 0.88rem;
}
.settings-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 16px; }
.settings-status { font-size: 0.88rem; color: var(--text-secondary); }
.settings-status.error { color: var(--danger); }
@media (max-width: 520px) {
  .settings-facts { grid-template-columns: 1fr; gap: 2px; }
  .settings-facts dd { margin-bottom: 8px; }
}

/* An on/off switch: a real checkbox, visually hidden, driving a track. */
.switch { position: relative; flex: none; display: inline-block; width: 46px; height: 26px; cursor: pointer; }
.switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: inherit; }
.switch-track {
  position: absolute;
  inset: 0;
  border-radius: 13px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: background 0.15s;
}
.switch-track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text-secondary);
  transition: transform 0.15s, background 0.15s;
}
.switch input:checked + .switch-track { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .switch-track::after { transform: translateX(20px); background: var(--accent-text); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch input:disabled + .switch-track { opacity: 0.5; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ------------------------- recipe versions + notes ------------------------- */

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

.version-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 8px 12px;
  margin: 0 0 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 0.88rem;
}
.version-bar > span:first-child { flex: 1; min-width: 200px; }
.version-bar.quiet { background: none; color: var(--text-secondary); }
.version-actions { display: flex; gap: 8px; }

.change-mark {
  font-size: 0.7rem;
  padding: 1px 6px;
  border-radius: 999px;
  margin-left: 6px;
  white-space: nowrap;
  vertical-align: 1px;
  background: var(--chip-diet);
  color: var(--chip-diet-text);
}
.change-mark.new { background: var(--chip-category); color: var(--chip-category-text); }
.removed-heading { color: var(--muted); font-size: 0.8rem; margin: 14px 0 4px; }
.ingredient-list.removed li { color: var(--muted); text-decoration: line-through; }

.nutrition-warning {
  font-size: 0.82rem;
  color: var(--chip-diet-text);
  background: var(--chip-diet);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
}

.my-notes h3 { margin-top: 0; }
.note-list { list-style: none; margin: 0 0 12px; padding: 0; }
.note { padding: 8px 0; border-bottom: 1px solid var(--border); }
.note-body { margin: 0 0 4px; white-space: pre-wrap; overflow-wrap: anywhere; }
.note-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; color: var(--muted); font-size: 0.78rem; }
.note-empty { color: var(--muted); font-size: 0.88rem; padding: 4px 0; }
.note-empty.is-error, .note-status, .editor-status.is-error { color: var(--danger); font-size: 0.82rem; }
.note-form-actions { display: flex; align-items: center; gap: 8px; margin-top: 6px; }

.link-btn {
  font: inherit;
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  cursor: pointer;
}
.link-btn.danger { color: var(--danger); }
.link-btn:hover { text-decoration: underline; }

.my-notes textarea, .recipe-editor textarea, .note-edit textarea,
.recipe-editor input[type="number"] {
  font: inherit;
  font-size: 0.9rem;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  box-sizing: border-box;
}
.my-notes textarea, .note-edit textarea { width: 100%; resize: vertical; }

/* The editor */
.editor-title { margin: 0 0 4px; }
.recipe-editor { max-width: 760px; }
.recipe-editor h3 { margin: 22px 0 8px; font-size: 1rem; }
.recipe-editor .setup-field.grow { flex: 1; }
.recipe-editor .setup-field.grow input { width: 100%; box-sizing: border-box; font-size: 1rem; }
.recipe-editor input[type="number"] { width: 90px; }

.edit-head, .ingredient-row {
  display: grid;
  grid-template-columns: minmax(80px, 9rem) minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
}
.edit-head { color: var(--muted); font-size: 0.78rem; margin-bottom: 4px; padding-right: 108px; }
.edit-head span:nth-child(2) { grid-column: 2; }
.edit-rows { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.edit-rows input[type="text"] { width: 100%; box-sizing: border-box; font-size: 0.9rem; }
.step-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: start; }
.step-row textarea { width: 100%; resize: vertical; }

.row-tools { display: flex; gap: 4px; }
.icon-btn {
  font: inherit;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  cursor: pointer;
  line-height: 1;
}
.icon-btn:hover:not(:disabled) { color: var(--text-primary); border-color: var(--text-secondary); }
.icon-btn:disabled { opacity: 0.35; cursor: default; }
.icon-btn.danger:hover:not(:disabled) { color: var(--danger); border-color: var(--danger); }

.editor-actions { display: flex; align-items: center; gap: 10px; margin-top: 24px; }

@media (max-width: 560px) {
  /* Amount and ingredient share a line; the tools drop below them. */
  .ingredient-row { grid-template-columns: minmax(70px, 7rem) minmax(0, 1fr); }
  .ingredient-row .row-tools, .step-row .row-tools { grid-column: 1 / -1; justify-content: flex-end; }
  .step-row { grid-template-columns: 1fr; }
  .edit-head { padding-right: 0; grid-template-columns: minmax(70px, 7rem) minmax(0, 1fr); }
}

/* ------------------------------ narrow screens ------------------------------ */

/* The recipe filters take a row of their own below the brand/nav/avatar row
   once they no longer fit beside it. Without this the flex row squeezed them
   into a column between the nav and the theme toggle, overlapping both. One
   row needs ~1150px with the avatar showing (measured); below that the theme
   toggle and avatar would otherwise wrap onto a line of their own. */
@media (max-width: 1180px) {
  .filters { order: 1; flex: 1 1 100%; }
}

@media (max-width: 640px) {
  .topbar { padding: 10px 16px; gap: 10px 12px; }
  /* Four rows of filters are too much to pin over the list on a phone; the
     other views keep a one-row sticky bar. */
  .topbar:has(.filters:not([hidden])) { position: static; }
  #search { flex: 1 1 100%; min-width: 0; }
  .filters select, .filter-toggle { flex: 1 1 calc(50% - 4px); min-width: 0; }

  main { padding: 16px; }

  /* iOS Safari zooms the page into any focused field under 16px. */
  input:not([type="checkbox"]):not([type="radio"]), select, textarea { font-size: 16px !important; }

  .detail-image { width: 100%; }

  /* Two recipes per row rather than one screen-wide card each: browsing is
     scanning photos, and one per row meant a screenful showed about two. */
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .card-body { padding: 8px 10px 4px; }
  .card-title { font-size: 0.92rem; line-height: 1.25; }
  .card-meta { font-size: 0.78rem; }
  .card-rating { padding: 0 6px 6px; flex-wrap: wrap; }
  /* Tighter than the finger-sized block below, so five stars, ✕ and the heart
     still share one line in a half-width card. */
  .card-rating .rating-star { padding: 6px 1px; }
  .card-rating .rating-clear { padding: 8px 4px; }
  .card-rating .recipe-fav { padding: 6px 4px; }


  /* Plan week → a day-by-day agenda. The grid's markup is row-major (every
     day's breakfast, then every day's lunch …); `order` re-sorts it into day
     order using the --d/--s indices app.js and builder.js put on each cell,
     so there is still one set of markup and no horizontal scrolling. */
  .plan-grid-wrap { overflow-x: visible; }
  .plan-grid { min-width: 0; grid-template-columns: 1fr !important; }
  .plan-grid > :first-child, .plan-slot-label, .plan-cell.not-scheduled { display: none; }
  .plan-day-header {
    order: calc(var(--d) * 100);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    font-size: 0.85rem;
    text-align: left;
  }
  .plan-day-header .add-meal { width: auto; margin-top: 0; }
  .plan-cell { order: calc(var(--d) * 100 + var(--s) + 1); padding: 10px 12px; }
  .plan-day-empty {
    display: block;
    order: calc(var(--d) * 100 + 99);
    background: var(--surface-1);
    padding: 10px 12px;
    color: var(--muted);
    font-size: 0.85rem;
  }
  .plan-cell::before {
    content: attr(data-slot);
    text-transform: capitalize;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-secondary);
  }
  /* A thumbnail beside the title instead of a banner above it: the cell is now
     the full width of the screen, not a ninth of it. */
  .plan-item, .cell-item-title { display: flow-root; font-size: 0.9rem; }
  .plan-item .meal-photo, .cell-item-title .meal-photo {
    float: left;
    width: 52px;
    height: 52px;
    margin: 0 10px 0 0;
  }

  .plan-row { flex-wrap: wrap; }
  .plan-row-main { flex: 1 1 calc(100% - 44px); }

  /* The recipes a list was made from scroll sideways, so the list itself — the
     thing you need in the store — starts on the first screen. */
  .shop-recipe-row { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 4px; }
  .shop-recipe { flex: 0 0 132px; width: auto; }

  #recipe-picker { width: calc(100vw - 16px); max-height: calc(100dvh - 16px); }
  .picker-results { max-height: calc(100dvh - 200px); }
}

/* Finger-sized hit areas, on any touch screen and any narrow one. Most of these
   controls were sized for a mouse at ~15–20px. */
@media (max-width: 640px), (pointer: coarse) {
  .menu-panel a, .user-menu-item { padding: 10px 12px; }
  .btn { padding: 8px 14px; }
  .rating-star { padding: 6px 3px; font-size: 1.15rem; }
  .rating-clear { padding: 8px; }
  .recipe-fav, .plan-fav { padding: 6px 8px; }
  .step { width: 32px; height: 32px; font-size: 1rem; }
  .cell-servings { min-width: 24px; font-size: 0.85rem; }
  .cell-x { padding: 8px 10px; font-size: 0.85rem; }
  .cell-add { padding: 4px 16px; font-size: 1rem; }
  .shop-item { padding: 10px 12px; }
  .shop-check { width: 22px; height: 22px; }
  .shop-delete { padding: 8px 10px; }
  .shop-badge-clear { padding: 4px 6px; }
  .icon-btn { width: 40px; height: 40px; }
}

/* Lifting a card on hover is a mouse affordance; on touch it sticks after a tap. */
@media (hover: none) {
  .card:hover { transform: none; box-shadow: none; }
}

/* Access requests: the count on the avatar and on the menu's People link, and
   the #/admin page (admin.js), which borrows the Settings page's sections. */
.menu-toggle.avatar-btn { position: relative; }
.pending-badge {
  display: inline-block;
  min-width: 1.2em;
  padding: 0 0.35em;
  border-radius: 999px;
  background: var(--danger);
  color: var(--danger-text);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
}
.pending-badge[hidden] { display: none; }
.avatar-badge { position: absolute; top: -4px; right: -6px; }
.admin-intro { margin-bottom: 16px; }
.access-count { color: var(--muted); font-weight: 400; }
.access-list { list-style: none; margin: 0; padding: 0; }
.access-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
.access-row:first-child { border-top: none; }
.access-who { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.access-email { color: var(--text-secondary); font-size: 0.9rem; }
.access-dates { color: var(--muted); font-size: 0.8rem; margin-top: 2px; }
.access-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.access-admin { color: var(--accent); font-weight: 600; font-size: 0.85rem; }
.error-banner { color: var(--danger); margin: 0 0 12px; }
