/* ==========================================================================
   Family gathering site — one stylesheet, all pages.

   HOW TO USE THIS FILE
   Everything below reads from the tokens in :root. To restyle the whole site,
   change tokens — not the rules underneath. Rules should never hardcode a
   colour, space, or radius.

   ORDER
     1. Tokens
     2. Reset & base
     3. Layout primitives
     4. Paper texture
     5. Components (nav, cards, pills, buttons, map, recipe)
     6. Utilities
     7. Motion & reduced-motion
   ========================================================================== */

/* 1. TOKENS =============================================================== */

:root {
  /* --- Surfaces: a real three-tier depth system, not everything on one plane */
  --desk:         #E4DACA;  /* the surface the notepad is lying on */
  --paper:        #FBF7F0;  /* the sheet itself */
  --paper-2:      #F4EEE3;  /* elevated — notes resting on the sheet */
  --paper-3:      #FFFFFF;  /* floating — the one thing that matters most */

  /* --- Notepad ruling. Deliberately faint: these sit BEHIND the cards, and
         are texture, not information. A ruled line loud enough to notice
         while reading is a ruled line that's too loud. */
  --rule:         rgba(116, 140, 170, 0.22);
  --rule-gap:     28px;
  --margin-rule:  rgba(198, 116, 96, 0.40);
  /* Where the red margin line sits. Tight on a phone — every pixel spent here
     comes straight out of the text column — and more generous once there's
     room to spare. */
  --margin-x:     28px;

  /* --- Ink */
  --ink:          #2B2A33;  /* body text, doodle lines. 12.9:1 on --paper */
  --ink-soft:     #5A5450;  /* secondary text.          6.5:1 on --paper */
  --ink-faint:    #8A827B;  /* decorative rules only — NOT for text */

  /* --- Accent: pen blue, a calmer cousin of the reference's #2222DD */
  --pen-blue:     #3A4795;  /* links & focus.           8.1:1 on --paper */
  --pen-blue-dk:  #2C3775;  /* hover */
  --pen-blue-wash:#E7E9F5;  /* tinted fill behind blue text */

  /* --- Character accents. Low saturation by intent: these are FILLS behind
         dark ink, never text colours. Contrast is checked against --ink. */
  --sage:         #A9C0A2;
  --clay:         #E0A98A;
  --butter:       #EFD79A;
  --sky:          #A6C4D6;
  --plum:         #C0AECB;

  /* --- Spacing: one scale. Never invent a value outside it. */
  --space-1: 0.25rem;  /*  4px */
  --space-2: 0.5rem;   /*  8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-7: 3rem;     /* 48px */
  --space-8: 4rem;     /* 64px */
  --space-9: 6rem;     /* 96px — the height of a drawing resting between two
                          days on the schedule. Nothing else uses it. */

  /* --- Type */
  --font-display: 'Gloria Hallelujah', 'Bradley Hand', cursive;
  --font-body: 'Atkinson Hyperlegible', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --text-xs:   0.8125rem;
  --text-sm:   0.9375rem;
  --text-base: 1.0625rem;  /* 17px — comfortable on mobile without zoom */
  --text-lg:   1.25rem;
  --text-xl:   1.5rem;
  --text-2xl:  1.875rem;
  --text-3xl:  2.25rem;

  --leading-body: 1.7;
  --leading-tight: 1.25;
  --tracking-display: -0.03em;

  /* --- Shape */
  --radius-card: 18px;
  --radius-pill: 999px;
  --radius-sm: 10px;

  /* --- Shadows: layered and warm-tinted. Never a flat grey drop. */
  --shadow-card:
    0 1px 2px rgba(74, 58, 42, 0.05),
    0 4px 12px rgba(74, 58, 42, 0.05);
  --shadow-float:
    0 1px 2px rgba(74, 58, 42, 0.06),
    0 8px 20px rgba(74, 58, 42, 0.07),
    0 16px 32px rgba(74, 58, 42, 0.04);

  /* --- Borders: the hand-drawn ink line */
  --line: 2px solid var(--ink);
  --line-soft: 1.5px solid rgba(43, 42, 51, 0.18);

  /* --- Motion */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur-fast: 120ms;
  --dur: 200ms;

  /* --- Layout */
  --measure: 65ch;         /* max line length for body copy */
  /* Where the red margin rule sits. It tracks the content column instead of the
     viewport edge, so it stays 8px to the left of the writing at every width
     rather than being stranded out in the margin on a desktop.
       narrow (390px): 195 − 480 + 28 = −257 → max() floors it at --margin-x
       wide (1920px):  960 − 480 + 28 = 508, and the column starts at 480
     max() is what lets one expression serve both. */
  --rule-x: max(
    var(--margin-x),
    calc(50% - var(--page-max) / 2 + var(--margin-x))
  );
  /* The sheet's width. 60rem, not the 44rem it was: at 44rem a 1920 monitor
     showed the page across a third of the screen and background across the
     rest. Body copy is capped at --measure independently, so widening the
     sheet gives the cards, timelines and grids more room without ever
     stretching a line of prose past 65ch. */
  --page-max: 60rem;
}

/* 2. RESET & BASE ========================================================= */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background-color: var(--desk);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  min-height: 100vh;
}

/* Ambient warmth, fixed to the viewport so it stays put while the page scrolls
   — a light source in the room, not a mark on the paper. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 80% 60% at 15% 0%, rgba(239, 215, 154, 0.28), transparent 60%),
    radial-gradient(ellipse 70% 50% at 95% 15%, rgba(166, 196, 214, 0.20), transparent 55%),
    radial-gradient(ellipse 90% 70% at 50% 100%, rgba(169, 192, 162, 0.18), transparent 60%);
}

/* THE SHEET — the notepad page everything is written on. It rules the whole
   viewport, edge to edge, at every width.
   The old objection to ruling the viewport was that the red margin rule ends up
   stranded 400px from the text on a desktop. That's answered below: --rule-x
   tracks the content column, so the rule sits beside the writing at any width,
   and the space it opens up is where the doodles live. */
.sheet {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  /* Clips the doodle layer at the viewport. That layer deliberately overflows
     (see .doodles) so drawings can hang past the content column into the
     margins; this is what stops them causing a sideways scrollbar. */
  overflow: hidden;
  background-color: var(--paper);
  /* The ruling scrolls WITH the page — it's printed on the paper. */
  background-image:
    /* the red margin rule */
    linear-gradient(to right,
      transparent 0 var(--rule-x),
      var(--margin-rule) var(--rule-x) calc(var(--rule-x) + 1.5px),
      transparent calc(var(--rule-x) + 1.5px)),
    /* the blue ruled lines */
    repeating-linear-gradient(to bottom,
      transparent 0 calc(var(--rule-gap) - 1.5px),
      var(--rule) calc(var(--rule-gap) - 1.5px) var(--rule-gap));
  box-shadow:
    0 0 0 1px rgba(74, 58, 42, 0.08),
    0 2px 8px rgba(74, 58, 42, 0.06),
    0 12px 40px rgba(74, 58, 42, 0.08);
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  margin: 0 0 var(--space-3);
  /* Stops short display headings breaking with one orphaned word. */
  text-wrap: balance;
}

/* Fluid so a long title doesn't crowd the character beside it on a 390px
   screen, while still landing at full size on desktop. */
h1 { font-size: clamp(1.75rem, 6.5vw, 2.25rem); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }

p { margin: 0 0 var(--space-4); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

img { max-width: 100%; height: auto; display: block; }

a {
  color: var(--pen-blue);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
a:hover { color: var(--pen-blue-dk); }

/* One focus style, everywhere. Visible against every surface token. */
:focus-visible {
  outline: 3px solid var(--pen-blue);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* 3. LAYOUT PRIMITIVES ==================================================== */

/* Header, main and footer are the content column. They each carry the same
   width and side padding, so their edges line up by construction — the sheet
   itself is now full-bleed and can't do it for them.
   The left padding must clear --margin-x or the text sits on the red rule.
   Every page is one width; there used to be a `class="wide"` opt-out. */
.site-header, .page, .site-footer {
  max-width: var(--page-max);
  margin-inline: auto;
  padding-left: calc(var(--margin-x) + var(--space-2));
  padding-right: var(--space-3);
}

.page { padding-bottom: var(--space-8); }

/* The home page's day view: the day, then the food that hangs off it, at the
   full width of the sheet. There's no side column — the day card carries a
   whole timeline and the meals sit four across beneath it, and both want the
   room. */
.dashboard > * + * { margin-top: var(--space-5); }

/* The day's meals. One per line on a phone, two across once there's room, then
   all four side by side on a wide screen — breakfast, lunch, dinner, dessert,
   the order you'd eat them in.
   Explicit column counts rather than auto-fit: the meals are a set of four and
   should read as one row, not reflow to whatever happens to fit. Days with a
   second dinner or dessert simply wrap onto another row. */
.meal-grid { display: grid; gap: var(--space-4); }

@media (min-width: 40rem) {
  .meal-grid { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 58rem) {
  .meal-grid { grid-template-columns: repeat(4, 1fr); }
}

/* Panel headings sit on the sheet, not on a card, so they need to be quieter
   than a page heading or they compete with the day's own title. */
.panel-heading {
  font-size: var(--text-lg);
  margin: 0 0 var(--space-3);
}

.stack > * + * { margin-top: var(--space-4); }
.stack-lg > * + * { margin-top: var(--space-6); }

/* The schedule's day list only. Its children alternate day / drawing / day, so
   this is the breathing room on EACH side of a drawing, not the whole gap —
   the .gap-doodle supplies the rest of it. Card to card works out at roughly
   24 + 96 + 24. Not shared with the meals or recipe pages. */
.stack-days > * + * { margin-top: var(--space-5); }

/* A drawing resting in the gap between two days.
   Unlike .doodle this sits in normal flow inside .page, which is only possible
   because the art carries real alpha — see convert-characters.mjs. Give these
   images back a white background and every one of these gets a white rectangle
   punched through the ruled lines. */
.gap-doodle {
  display: block;
  width: 100%;
  height: var(--space-9);
  pointer-events: none;   /* never swallow a tap meant for a card */
  user-select: none;
}

.gap-doodle img {
  display: block;
  height: 100%;
  width: auto;
  margin-inline: auto;
  opacity: 0.5;             /* matches the scattered layer */
  transform: rotate(var(--rot, 0deg)) scaleX(var(--flip, 1));
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--paper-3);
  border: var(--line);
  border-radius: var(--radius-sm);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-150%);
}
.skip-link:focus { transform: translateY(0); }

/* 4. PAPER TEXTURE ======================================================== */
/* Subtle grain for warmth. Low opacity by intent — texture, not visual noise
   (a busy field is exactly what makes an interface feel overwhelming). */

.grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0.35;
  mix-blend-mode: multiply;
}

/* 5. COMPONENTS =========================================================== */

/* --- Site header + nav -------------------------------------------------- */

.site-header {
  /* padding-block, not the shorthand: the inline padding comes from the
     content-column rule above and the shorthand would wipe it, dropping the
     title onto the red margin rule. */
  padding-block: var(--space-5) var(--space-3);
}

.site-title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  letter-spacing: var(--tracking-display);
  color: var(--ink);
  text-decoration: none;
  display: inline-block;
}
.site-title:hover { color: var(--ink); }

/* Four items will not fit one row at 390px, and a 3-then-1 wrap reads as a
   mistake. A 2x2 grid is deliberate, keeps every target full width, and hides
   nothing — which matters more here than saving a row. */
.nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
  padding: 0;
  margin: var(--space-3) 0 0;
  list-style: none;
}

@media (min-width: 34rem) {
  .nav {
    display: flex;
    flex-wrap: wrap;
  }
}

.nav__link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* min-height 44px: WCAG 2.5.8 target size */
  min-height: 44px;
  padding: var(--space-2) var(--space-4);
  border: var(--line);
  border-radius: var(--radius-pill);
  background: var(--paper-2);
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 700;
  text-decoration: none;
  transition: transform var(--dur) var(--ease-spring),
              background-color var(--dur) var(--ease-out);
}
.nav__link:hover {
  background: var(--paper-3);
  color: var(--ink);
  transform: translateY(-2px);
}
.nav__link:active { transform: translateY(0); }

/* Current page marked by fill AND a leading dot — never colour alone. */
.nav__link[aria-current='page'] {
  background: var(--ink);
  color: var(--paper);
}
.nav__link[aria-current='page']::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--butter);
  flex: none;
}

.noscript-note {
  padding: var(--space-4);
  border: var(--line);
  border-radius: var(--radius-card);
  background: var(--butter);
  margin: var(--space-4) 0;
}

/* --- Cards -------------------------------------------------------------- */

/* Opaque on purpose — this is what lets the doodle layer beneath be playful
   without ever risking readability. */
.card {
  background: var(--paper-2);
  border: var(--line);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  /* Tighter side padding on a phone: the sheet's margin rule already eats into
     the width, and text wrapping every three words is a worse problem than a
     snug card. */
  padding: var(--space-4);
}

/* The one card that matters most on the page — floats above the rest. */
.card--feature {
  background: var(--paper-3);
  box-shadow: var(--shadow-float);
  padding: var(--space-5) var(--space-4);
}

@media (min-width: 30rem) {
  .card { padding: var(--space-5); }
  .card--feature { padding: var(--space-6) var(--space-5); }
}

.card--link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: transform var(--dur) var(--ease-spring),
              box-shadow var(--dur) var(--ease-out);
}
.card--link:hover {
  color: inherit;
  transform: translateY(-3px);
  box-shadow: var(--shadow-float);
}
.card--link:active { transform: translateY(-1px); }

.card__label {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 var(--space-2);
}

/* Accent strip — set --accent per instance from the palette tokens. */
.card--accent { border-left: 6px solid var(--accent, var(--sage)); }

/* --- Pills / meta ------------------------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--accent, var(--butter));
  border: var(--line-soft);
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--ink);
}

.meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

/* --- Meal extras ---------------------------------------------------------
   The side dishes that ride along with a recipe, listed under the day's cards
   on the meal plan. Deliberately NOT a card: a card here promises a recipe to
   tap, and these have nothing behind them — that dead card is the whole reason
   they were pulled out of the grid. A quiet rule and a slot column instead, so
   they read as a footnote to the meals above rather than more of them.
   ------------------------------------------------------------------------- */

.meal-extras {
  margin-top: var(--space-4);
  padding-left: var(--space-4);
  border-left: var(--line-soft);
}

.meal-extras__label {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 var(--space-2);
}

.meal-extras__list { list-style: none; padding: 0; margin: 0; }
.meal-extras__list > li + li { margin-top: var(--space-2); }

/* Same 5rem slot column the timeline uses, so the names line up with each other
   and a long dish wraps against its own edge instead of under its label. */
.meal-extras__list > li {
  display: grid;
  grid-template-columns: 5rem 1fr;
  gap: var(--space-2);
}

.meal-extras__slot {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-top: 0.25em;
}

/* --- Buttons ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  min-width: 44px;
  padding: var(--space-3) var(--space-5);
  border: var(--line);
  border-radius: var(--radius-pill);
  background: var(--paper-3);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--dur) var(--ease-spring),
              background-color var(--dur) var(--ease-out);
}
.btn:hover { background: var(--butter); color: var(--ink); transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

.btn--primary { background: var(--ink); color: var(--paper); }
.btn--primary:hover { background: var(--pen-blue); color: var(--paper); }

/* --- Day switcher ------------------------------------------------------- */

/* Capped and centred: at full page width the two buttons fly to opposite
   edges and stop reading as one control. */
.switcher {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  max-width: 26rem;
  margin-inline: auto;
}

/* Tighter than a standard .btn: the sheet's margin rule has already taken a
   bite out of the width, and the default padding leaves the label too little
   room — it wraps to two lines and stops reading as one control. */
.switcher .btn { padding-inline: var(--space-2); }

.switcher__label {
  font-family: var(--font-display);
  font-size: var(--text-xs);
  text-align: center;
  flex: 1;
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}
@media (min-width: 30rem) {
  .switcher .btn { padding-inline: var(--space-4); }
  .switcher__label { font-size: var(--text-sm); }
}

/* --- Schedule items ----------------------------------------------------- */

.timeline { list-style: none; padding: 0; margin: 0; }

.timeline__item {
  display: grid;
  /* 5rem fits the real vocabulary — "12–12:30pm", "10:30–2:30", "Post-game" —
     without wrapping, and hands the rest back to the description, which is the
     part that should wrap. It was 4rem when the times were all placeholder
     HH:MMs; the real plan needed more room. Keep `time` in data.js to roughly
     11 characters and this holds. */
  grid-template-columns: 5rem 1fr;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  border-bottom: var(--line-soft);
}
@media (min-width: 30rem) {
  .timeline__item { grid-template-columns: 5.5rem 1fr; gap: var(--space-3); }
}
.timeline__item:last-child { border-bottom: none; }

.timeline__time {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  font-size: var(--text-sm);
  padding-top: 0.15em;
}
.timeline__what { font-weight: 700; }
.timeline__where {
  color: var(--ink-soft);
  font-size: var(--text-sm);
  display: block;
}

/* --- Grids -------------------------------------------------------------- */

.grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
}

/* --- Scattered doodles -------------------------------------------------- */
/* Marginalia: the drawings repeated around the sheet at odd angles, as if
   someone doodled on the pad while thinking.
 *
 * THE IMPORTANT PART: this layer sits BEHIND the cards (z-index 1 vs 2), and
 * the cards are opaque. So a doodle can never land on top of text and hurt
 * readability — where a card covers one, it's simply hidden, which reads as
 * the doodle being on the paper underneath. That's what lets the placement be
 * playful without being a risk: the worst case is a doodle you don't see.
 *
 * They are decoration and carry no information, so the layer is aria-hidden
 * and the drawings are repeats of what's already shown elsewhere. Nothing is
 * lost by not seeing them.
 */
.doodles {
  position: absolute;
  inset: 0;
  /* Tracks the CONTENT COLUMN, not the viewport, and is allowed to overflow.
     That's the whole trick: SCATTER offsets are percentages, so anchoring this
     to the column keeps `left: -9%` meaning the same distance at every width.
     Anchored to the viewport instead, -9% grows with the screen and the
     drawings walk off the edge — at 1920 that's -173px, and a 90px drawing is
     simply gone. Overflowing here is what lets them hang past the column into
     the margins on a desktop; .sheet clips them at the viewport. */
  max-width: var(--page-max);
  margin-inline: auto;
  overflow: visible;
  pointer-events: none;   /* never swallow a tap meant for a card */
  user-select: none;
  /* The viewport's edges, in this layer's coordinates. The layer sits centred
     at --page-max wide, so its left edge is (100vw − page-max) / 2 from the
     viewport's; stepping back by that lands on the viewport edge. Doodles with
     { edge, x } in SCATTER use these to fill the outer margins, which no
     percentage of the column can reach reliably. */
  --edge-l: calc(-50vw + var(--page-max) / 2);
  --edge-r: calc(-50vw + var(--page-max) / 2);
  /* DO NOT add a z-index here. Ordering depends on it being absent: this is
     positioned but z-index:auto, so it paints below .page / .site-header /
     .site-footer, which carry z-index 2. Give it a z-index and the doodles
     start landing on top of the text.
     (This used to carry a second warning about mix-blend-mode isolation. The
     drawings now have a real alpha channel — see convert-characters.mjs — so
     no blending is involved and that hazard is gone.) */
}

.doodle {
  position: absolute;
  display: block;
  opacity: 0.5;
  width: var(--w, 90px);
  transform: rotate(var(--rot, 0deg)) scaleX(var(--flip, 1));
}

/* Outer-margin doodles. Below this there is no margin for them to sit in and
   they'd land on the content, so they simply aren't there.
   80rem = 1280px, where the margin either side reaches 160px. The widest of
   these is 84px at 44px in, and rotation grows a bounding box by ~20% — so 160
   is the point where the biggest one clears the column with room to spare. At
   75rem (120px of margin) one of them brushed it.
   MUST come after .doodle: both are single classes, so they carry equal
   specificity and the later one wins. Ordered the other way round, .doodle's
   `display: block` quietly re-enables every one of these on a phone. */
.doodle--wide { display: none; }

@media (min-width: 80rem) {
  .doodle--wide { display: block; }
}

/* --- The drawings ------------------------------------------------------- */
/* Coen's line art, shown inline beside the heading.
 *
 * NO dark gradient overlay — that rule is for photographs; over line art it
 * destroys the drawing.
 *
 * `mix-blend-mode: multiply` DOES earn its place: the drawings are black ink
 * on a white canvas, and multiply lets the card colour show through the white
 * while leaving the ink alone. It knocks the background out optically — no
 * pixel editing, and no transparency needed in the source files (their alpha
 * channel is fully opaque, so there is none to rely on). */
.character {
  width: clamp(112px, 30vw, 156px);
  height: auto;
  flex: none;
}

/* The base reset makes images display:block, so text-align can't centre them. */
.text-center > .character { margin-inline: auto; }

.character-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
/* Without this the text column refuses to shrink below its longest word and
   shoves the character off the edge. */
.character-row > *:not(.character) { min-width: 0; }

/* --- The day card's body -------------------------------------------------
   The plan on one side, the drawing and the day's note on the other.

   Grid with named areas rather than the .character-row flex the recipe page
   uses: the drawing and the note share a column while the title and timeline
   share the other, and those two rows have to line up. Flex would need a
   wrapper per column, and the wrapper is exactly what breaks the phone layout
   — there the drawing belongs BESIDE the title, not stacked above the note.
   Areas let the same four elements re-flow without touching the markup.
   ------------------------------------------------------------------------- */

.day-body {
  display: grid;
  grid-template-columns: 1fr auto;
  column-gap: var(--space-4);
  align-items: start;
  /* Phone: drawing beside the title, then the plan, then the note. */
  grid-template-areas:
    "head char"
    "time time"
    "note note";
}

.day-body__head { grid-area: head; align-self: center; min-width: 0; }
.day-body > .character { grid-area: char; align-self: center; }
.day-body > .timeline { grid-area: time; }
.day-body > .day-quote { grid-area: note; margin-top: var(--space-4); }

/* Wide, and only when there IS a note: the timeline gives up the right-hand
   third so the note can sit under the drawing. Without a note the timeline
   keeps spanning both columns — see the phone areas above — so a day with no
   quote in data.js doesn't get a column of dead space instead.
   `minmax` rather than a fixed width: the note should give room back to the
   timeline on a narrower sheet, not hold 20rem it hasn't earned. */
@media (min-width: 58rem) {
  .day-body--noted {
    grid-template-columns: 1fr minmax(15rem, 20rem);
    grid-template-areas:
      "head char"
      "time note";
  }
  /* The drawing is narrower than the note column it now sits over. Centred, it
     reads as the note's picture; left in place it just floats. */
  .day-body--noted > .character { justify-self: center; }
  .day-body--noted > .day-quote { margin-top: 0; }
}

/* The note itself. A scrap in the day's own colour, tucked under the drawing.
   The accent is a fill behind ink here, the same job it does in a .pill — but
   mixed back toward the paper, because a pill is two words and this is a
   paragraph, and at full strength a block that size shouts down the timeline
   beside it. */
.day-quote {
  margin: 0;
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--accent, var(--sage)) 38%, var(--paper));
}

/* Handwritten, because it's the one thing on the card nobody has to read — the
   plan is typed, the aside is scribbled. */
.day-quote__text {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-sm);
  line-height: 1.65;
  color: var(--ink);
}

.day-quote__by {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  color: var(--ink-soft);
}
/* The dash is punctuation the design adds, so it lives here and not in the
   name that data.js stores. */
.day-quote__by::before { content: '\2014\00a0'; }

/* --- Nav tiles ----------------------------------------------------------
   THE navigation. Sits in the header; the .nav pills above are now only the
   <noscript> fallback. Given room for the art on purpose — the line work is too
   detailed to read at pill size.
   ------------------------------------------------------------------------- */

.nav-tiles {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-2);
  padding: 0;
  margin: var(--space-4) 0 0;
  list-style: none;
}

.nav-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  height: 100%;
  padding: var(--space-3) var(--space-2);
  border: var(--line);
  border-radius: var(--radius-card);
  background: var(--paper-2);
  color: var(--ink);
  text-decoration: none;
  text-align: center;
  transition: transform var(--dur) var(--ease-spring);
}

.nav-tile:hover, .nav-tile:focus-visible {
  color: var(--ink);
  transform: translateY(-3px);
}

/* The current page. Deliberately NOT the dark ink fill .nav__link uses when
   active — these drawings are near-black ink, so on a dark ground they'd be a
   solid blob. A light accent fill marks the page and keeps the drawing legible. */
.nav-tile[aria-current='page'] {
  background: var(--butter);
  border-width: 2px;
}

.nav-tile__art {
  display: block;
  width: 56px;
  height: 56px;
  object-fit: contain;
}

.nav-tile__label {
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: 1.2;
}

@media (min-width: 34rem) {
  .nav-tile__art { width: 84px; height: 84px; }
  .nav-tile { padding: var(--space-4) var(--space-3); }
}

/* --- Recipe ------------------------------------------------------------- */

.recipe-list { padding-left: var(--space-5); margin: 0; }
.recipe-list li { margin-bottom: var(--space-2); max-width: var(--measure); }
.recipe-steps li { margin-bottom: var(--space-4); }

/* What changes when you cook the thing at this size — batches, pan space, the
   marinade that has to start last night. Marked with the pen rule rather than a
   card, so it reads as something written in the margin, not another section. */
.recipe-note {
  border-left: 3px solid var(--clay);
  padding-left: var(--space-4);
  color: var(--ink-soft);
  font-style: italic;
  max-width: var(--measure);
}

/* --- Footer ------------------------------------------------------------- */

.site-footer {
  margin: var(--space-8) auto 0;   /* auto keeps it in the content column */
  padding-block: var(--space-5) var(--space-6);
  border-top: var(--line-soft);
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

/* 6. UTILITIES ============================================================ */

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

.lede { font-size: var(--text-lg); color: var(--ink-soft); }
.text-soft { color: var(--ink-soft); }
.text-center { text-align: center; }

/* Content sits above the fixed grain layer. */
.site-header, .page, .site-footer { position: relative; z-index: 2; }

/* 7. MOTION =============================================================== */
/* Only transform and opacity are animated anywhere in this file — never
   `transition-all`, never layout-triggering properties. */

@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.rise { animation: rise var(--dur) var(--ease-out) both; }

/* Honour the OS setting completely. Not a reduction — a full stop.
   `prefers-reduced-motion` is a genuine accessibility need, not a preference:
   motion triggers nausea and migraine for vestibular-disorder users. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto; }
}
