:root {
  --paper:#F4F4F1; --card:#FFFFFF; --ink:#22252A; --ink-2:#5F645D; --ink-3:#8E938A;
  --line:#E2E2DC; --moss:#586B51; --moss-soft:#EDF1EA; --clay:#9E5F49; --clay-soft:#F7ECE7;
  --slate:#4A6076;
  /* Text that sits ON the moss fill. White works on the dark green of the
     light theme; in dark mode moss inverts to a light green and white on it
     measures 2.47:1, so the ink flips too. */
  --on-moss:#FFFFFF;
  /* Aliased, not a new colour. Four rules referenced --muted and nothing ever
     defined it, so `color: var(--muted)` was invalid at computed-value time
     and those elements silently inherited full-strength ink — comment authors
     and the sign-in lede rendered louder than everything around them.
     Mapped to ink-2 rather than ink-3 so it stays above 4.5:1 on card. */
  --muted:#5F645D;
}
@media (prefers-color-scheme: dark) {
  :root {
    --paper:#15171A; --card:#1D2024; --ink:#E4E6E1; --ink-2:#A6ABA2; --ink-3:#767B72;
    --line:#2E3239; --moss:#93AC8A; --moss-soft:#1F251F; --clay:#C98A70; --clay-soft:#2A211E;
    --slate:#8FA8BE; --muted:#A6ABA2; --on-moss:#15171A;
  }
}

* { box-sizing:border-box; }

/* The `hidden` attribute must actually hide things.
   The browser's own rule is [hidden]{display:none}, but ANY author rule that
   sets `display` beats it — .sheet{display:flex} left the modal permanently
   open as a full-viewport overlay that swallowed every click on every screen.
   This is declared once, here, rather than per-element, because the next
   component with a display property would reintroduce the same bug. */
[hidden] { display: none !important; }
html,body { margin:0; padding:0; }
body {
  background:var(--paper); color:var(--ink);
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  font-size:15.5px; line-height:1.55; -webkit-font-smoothing:antialiased;
}

.top {
  position:sticky; top:0; z-index:20; background:var(--paper);
  border-bottom:1px solid var(--line); padding:.7rem 1rem .4rem;
  display:flex; flex-wrap:wrap; align-items:baseline; gap:.4rem 1.2rem;
}
.top h1 {
  font-family:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  font-size:1.15rem; font-weight:600; margin:0; letter-spacing:-.01em;
}
nav { display:flex; gap:.15rem; flex-wrap:wrap; }
nav button {
  background:none; border:0; padding:.35rem .6rem; border-radius:4px; cursor:pointer;
  color:var(--ink-2); font:inherit; font-size:.87rem;
}
nav button:hover { background:var(--card); color:var(--ink); }
nav button.on { background:var(--moss-soft); color:var(--moss); font-weight:600; }

main { max-width:940px; margin:0 auto; padding:1.2rem 1rem 5rem; }

h2 {
  font-family:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  font-size:1.3rem; font-weight:600; margin:0 0 .2rem;
}
h3 { font-size:.72rem; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2);
     font-weight:700; margin:1.4rem 0 .5rem; }
p.sub { color:var(--ink-2); margin:.1rem 0 1rem; font-size:.9rem; }

/* ---- plan ---- */
.day { margin-bottom:1.1rem; }
.day-head { display:flex; align-items:baseline; gap:.6rem; margin-bottom:.35rem; }
.day-name { font-weight:650; font-size:.95rem; }
.day-date { color:var(--ink-3); font-size:.8rem; }
.day.today .day-name { color:var(--moss); }

.slot {
  background:var(--card); border:1px solid var(--line); border-radius:6px;
  padding:.6rem .75rem; margin-bottom:.35rem;
  display:grid; grid-template-columns:88px 1fr auto; gap:.7rem; align-items:center;
  /* the changed-row decay lives here too, so .slot is declared exactly once */
  transition: background-color 480ms linear;
}
.slot-name { color:var(--ink-3); font-size:.78rem; text-transform:uppercase; letter-spacing:.07em; }
.slot-main { min-width:0; }
.slot-title { font-weight:600; }
.slot-title.empty { color:var(--ink-3); font-weight:400; font-style:italic; }
.slot-why { font-size:.78rem; color:var(--ink-3); margin-top:.05rem; }

.pill {
  border:1px solid var(--line); background:var(--card); color:var(--ink-2);
  border-radius:99px; display:inline-flex; align-items:center; padding:.5rem .8rem; min-height:44px; font-size:.78rem; cursor:pointer; font:inherit;
  font-size:.78rem; white-space:nowrap;
}
.pill:hover { border-color:var(--moss); color:var(--moss); }
.pill.primary { background:var(--moss-soft); border-color:var(--moss-soft); color:var(--moss); font-weight:600; }
.pill.warn:hover { border-color:var(--clay); color:var(--clay); }
.badge { font-size:.68rem; padding:.1rem .4rem; border-radius:3px; background:var(--moss-soft); color:var(--moss); }
.badge.stale { background:var(--clay-soft); color:var(--clay); }
.badge.lock { background:var(--line); color:var(--ink-2); }

/* ---- generic ---- */
.card { background:var(--card); border:1px solid var(--line); border-radius:6px; padding:.85rem 1rem; margin-bottom:.6rem; }
.row { display:flex; gap:.5rem; align-items:center; flex-wrap:wrap; }
.row.between { justify-content:space-between; }
.grow { flex:1 1 auto; min-width:0; }
.muted { color:var(--ink-3); font-size:.85rem; }
.mono { font-family:ui-monospace,Menlo,Consolas,monospace; font-size:.82rem; }

input, select, textarea, button.btn {
  font:inherit; font-size:.9rem; padding:.6rem .75rem; min-height:44px; border:1px solid var(--line);
  border-radius:5px; background:var(--card); color:var(--ink);
}
input:focus, select:focus, textarea:focus { outline:2px solid var(--moss); outline-offset:1px; }
input[type=text], input[type=url], input[type=number], textarea { width:100%; }
textarea { min-height:5rem; resize:vertical; }
button.btn { cursor:pointer; }
button.btn.primary { background:var(--moss); border-color:var(--moss);
                     color:var(--on-moss); font-weight:600; }
button.btn.primary:hover { filter:brightness(1.08); }
label.field { display:block; margin-bottom:.6rem; }
label.field > span { display:block; font-size:.75rem; letter-spacing:.08em; text-transform:uppercase;
                     color:var(--ink-2); font-weight:700; margin-bottom:.2rem; }

table { width:100%; border-collapse:collapse; font-size:.9rem; }
th { text-align:left; font-size:.68rem; letter-spacing:.1em; text-transform:uppercase;
     color:var(--ink-2); border-bottom:1.5px solid var(--ink); padding:.4rem .5rem .4rem 0; }
td { border-bottom:1px solid var(--line); padding:.4rem .5rem .4rem 0; vertical-align:middle; }

ul.list { list-style:none; padding:0; margin:0; }
ul.list li { padding:.35rem 0; border-bottom:1px solid var(--line); display:flex; gap:.5rem; align-items:center; }

.note { border-left:3px solid var(--moss); background:var(--moss-soft); padding:.6rem .8rem; border-radius:4px; font-size:.88rem; }
.note.warn { border-left-color:var(--clay); background:var(--clay-soft); }

/* ---- sheet ---- */
.sheet { position:fixed; inset:0; background:rgba(0,0,0,.35); z-index:50; display:flex;
         align-items:flex-start; justify-content:center; overflow-y:auto; padding:2rem 1rem; }
.sheet-inner { background:var(--paper); border-radius:8px; max-width:760px; width:100%;
               padding:1.2rem 1.3rem 2rem; position:relative; border:1px solid var(--line); }
.sheet-close { position:absolute; top:.5rem; right:.7rem; background:none; border:0;
               font-size:1.5rem; line-height:1; cursor:pointer; color:var(--ink-3); }

/* ---- toast ---- */
.toast { position:fixed; bottom:1.2rem; left:50%; transform:translateX(-50%);
         background:var(--ink); color:var(--paper); padding:.5rem .9rem; border-radius:5px;
         font-size:.88rem; z-index:60; }

.ing-row { display:grid; grid-template-columns:70px 80px 1fr auto; gap:.4rem; align-items:center; margin-bottom:.3rem; }
.ing-row input { padding:.25rem .4rem; font-size:.85rem; }
.match { font-size:.72rem; padding:.1rem .35rem; border-radius:3px; white-space:nowrap; }
.match.exact { background:var(--moss-soft); color:var(--moss); }
.match.suggest { background:var(--clay-soft); color:var(--clay); }
.match.new { background:var(--line); color:var(--ink-2); }

@media (max-width:620px) {
  .slot { grid-template-columns:1fr; gap:.35rem; }
  .slot-actions { justify-content:flex-start; }
  .ing-row { grid-template-columns:60px 70px 1fr; }
}
@media (prefers-reduced-motion:reduce) { * { transition:none !important; animation:none !important; } }

/* ---- sign-in ------------------------------------------------------------
   The only screen a signed-out person sees. Deliberately plain: one decision
   to make, and the provider buttons are the only affordance on it. */
.signin { max-width: 26rem; margin: 3rem auto; }
.signin h1 { margin-bottom: .25rem; }
.signin .lead { color: var(--muted); margin-bottom: 1.4rem; }
.signin .card { display: flex; flex-direction: column; gap: .5rem; }
.signin .muted { font-size: .82rem; margin-top: 1rem; }
.btn.block { display: block; width: 100%; text-align: center; text-decoration: none; }
/* (the global [hidden] rule near the top covers #nav too) */

/* ---- destructive actions ------------------------------------------------
   Set apart and coloured like a warning, not like the rest of settings.
   The confirm button only exists once the word has been typed. */
.danger { margin-top: 1.2rem; }
.danger h4 { margin: 0 0 .35rem; }
.danger p { margin: .25rem 0; font-size: .88rem; }
.danger .row { margin-top: .6rem; align-items: center; gap: .5rem; }
.danger input { padding: .4rem .6rem; border: 1px solid var(--line); border-radius: 4px; }
.btn.danger-btn { background: var(--clay); color: #fff; border-color: var(--clay); }
.btn.danger-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ---- sharing ------------------------------------------------------------
   The switcher only appears when more than one plan is reachable, so a
   solo user never sees a control for a thing they do not have. */
#space-switcher { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.space-select { padding: .3rem .5rem; border: 1px solid var(--line); border-radius: 4px;
                background: var(--card); font: inherit; }
.role-badge { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em;
              color: var(--muted); border: 1px solid var(--line);
              border-radius: 999px; padding: .1rem .5rem; }

/* Notes on a meal. Quiet by default — they sit under the row they belong to
   and should not compete with the meal itself. */
.comments { padding: .1rem 0 .4rem 1rem; border-left: 2px solid var(--line); margin-left: .6rem; }
.comment { display: flex; gap: .5rem; align-items: baseline; font-size: .85rem;
           padding: .15rem 0; }
.comment-who { color: var(--muted); font-weight: 600; white-space: nowrap; }
.comment-add { margin-top: .25rem; gap: .4rem; }
.comment-input { padding: .3rem .5rem; border: 1px solid var(--line);
                 border-radius: 4px; font: inherit; font-size: .85rem; }
.link-btn { background: none; border: 0; color: var(--muted); cursor: pointer;
            font-size: .78rem; text-decoration: underline; padding: 0 .2rem; }

/* A role that cannot edit does not get shown edit affordances. This is a
   courtesy for the reader, NOT a control — the server refuses regardless. */
body.read-only .slot-actions,
body.read-only .proposal-card { display: none; }
body.no-comment .comment-add { display: none; }

/* ---- shopping list ------------------------------------------------------
   Used one-handed, in bad light, with a trolley. The whole row is the tap
   target; the checkbox is only the indicator. Ticked rows stay in place —
   never reorder a list somebody is reading while walking. */
.shop-row { cursor: pointer; min-height: 44px; padding: .5rem 0; gap: .6rem; }
.shop-row input[type=checkbox] { width: 20px; height: 20px; flex: none; margin: 0; }
.shop-row strong { font-size: 1rem; }
.shop-row.done strong { text-decoration: line-through; }
.shop-row.done { opacity: .45; }
.shop-row .src { font-size: .75rem; }
.shop-foot { justify-content: space-between; margin-top: 1rem;
             padding-top: .7rem; border-top: 1px solid var(--line); }

/* ---- the changed row ----------------------------------------------------
   A slow, quiet decay marking which cell changed, for the case where the eye
   was somewhere else when it happened. It says "this one", never "well done":
   no bounce, no scale, no colour that reads as success. */
.slot.changed { background: var(--moss-soft); transition: background-color 120ms linear; }
.undo-bar:empty { display: none; }
.undo-bar { margin-bottom: .6rem; }

@media (prefers-reduced-motion: reduce) {
  /* Movement removed, the state change kept. A blanket transition:none would
     leave an instant unexplained swap, which is worse for the reader this is
     meant to help, not better. */
  .slot { transition: background-color 200ms linear; }
}

/* ---- meal cell ----------------------------------------------------------
   One promoted action, everything else behind More. Seven identical pills per
   row meant 294 controls on a fourteen-day plan, each about half the size a
   thumb needs - the worst possible density for people who came here to make
   fewer decisions. */
.cell { margin-bottom: .35rem; }
.cell .slot { margin-bottom: 0; }

.slot-actions { display: flex; gap: .5rem; align-items: center; }  /* >=8px between adjacent targets */

/* 44px minimum on both. Visual weight and hit area are separate problems:
   solve density by de-emphasising, never by shrinking the target. */
.slot .swap, .slot .more {
  font: inherit; cursor: pointer; border-radius: 6px;
  min-height: 44px; min-width: 44px; padding: .5rem .85rem;
  white-space: nowrap; line-height: 1;
}
.slot .swap {
  background: var(--moss-soft); border: 1px solid var(--moss-soft);
  color: var(--moss); font-weight: 600;
}
.slot .swap:hover { filter: brightness(.96); }
.slot .more {
  background: none; border: 1px solid var(--line); color: var(--ink-3);
  font-size: .82rem;
}
.slot .more:hover { border-color: var(--moss); color: var(--moss); }
.slot .more[aria-expanded="true"] { border-color: var(--moss); color: var(--moss); }
.slot .swap:focus-visible, .slot .more:focus-visible,
.drawer-btn:focus-visible { outline: 2px solid var(--moss); outline-offset: 2px; }

/* The drawer. One open at a time, and it pushes rather than overlays - an
   overlay would cover the meal you are deciding about. */
.drawer {
  display: grid; grid-template-columns: 1fr 1fr; gap: .3rem;
  padding: .45rem; margin: .3rem 0 0;
  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
}
.drawer-btn {
  font: inherit; font-size: .85rem; cursor: pointer; text-align: left;
  min-height: 44px; padding: .5rem .7rem;
  background: none; border: 1px solid var(--line); border-radius: 5px;
  color: var(--ink-2);
}
.drawer-btn:hover { border-color: var(--moss); color: var(--moss); }
.drawer-btn.warn:hover { border-color: var(--clay); color: var(--clay); }
/* Destructive actions sit apart from the rest, never adjacent to a routine one. */
.drawer-btn.warn { grid-column: 1 / -1; }

.tag-filter { gap: .35rem; margin-bottom: .6rem; flex-wrap: wrap; }

@media (max-width: 620px) {
  .drawer { grid-template-columns: 1fr; }
  .slot-actions { justify-content: flex-start; }
}

/* ---- sign out -----------------------------------------------------------
   Always in the header, never hunted for. Quiet by default - it is a safety
   control, not something to invite - but a full 44px target and a visible
   focus ring, because the person reaching for it is often in a hurry on a
   device that is not theirs. */
.signout { margin: 0; }
.signout button {
  font: inherit; font-size: .82rem; cursor: pointer;
  min-height: 44px; padding: .4rem .7rem;
  background: none; border: 1px solid transparent; border-radius: 5px;
  color: var(--ink-3);
}
.signout button:hover { border-color: var(--line); color: var(--ink); }
.signout button:focus-visible { outline: 2px solid var(--moss); outline-offset: 2px; }

/* On a phone the header wraps, and adding a third line to it costs 44px of a
   812px viewport. So the nav is forced onto its own row and sign out sits
   beside the title, using space that was already empty. */
@media (max-width: 620px) {
  .top { align-items: center; }
  .top h1 { flex: 0 1 auto; }
  nav { order: 2; flex-basis: 100%; }
  #space-switcher { order: 1; }
  .signout { order: 1; margin-left: auto; }
  .signout button { padding: .4rem .5rem; }
}

/* Recipe titles are links and measured 42px against a 44 minimum. Two
   pixels, but it is the control people tap most on that screen. They sit
   in a table rather than a list, which the first version of this rule
   missed entirely — the browser said 42px and the CSS looked correct. */
ul.list a, td a {
  display: inline-flex; align-items: center;
  min-height: 44px; text-decoration: none; color: inherit;
}
ul.list a:hover, td a:hover { text-decoration: underline; }
ul.list a:focus-visible, td a:focus-visible { outline: 2px solid var(--moss); outline-offset: 2px; }
