/* ============================================================================
   Lazy Meal Planner — site chrome and home page styles
   ----------------------------------------------------------------------------
   Sections 1–3 (sticky nav, media placeholders, Play badge) and 11 (footer)
   are shared by every page, so the legal pages load this file too. Sections
   4–10 are the home page only. Everything here is built from the custom
   properties in tokens.css; no colour, space or type value is hardcoded if a
   token already exists for it. tokens.css is the shared foundation and is not
   edited from this file.

   Load order:
     fonts.css  →  tokens.css  →  site.css
   ========================================================================== */

/* ── Narrow-phone gutter ──────────────────────────────────────────────────
   Below 400px a 24px gutter each side spends 48px of a 320px viewport, which
   is what pushes the header row over the edge. 16px each side keeps the
   header on one line without touching tokens.css. */
@media (max-width: 399px) {
  :root { --gutter: var(--space-m); }
}

/* The sticky header covers the top of the viewport, so anchor targets must
   clear it. tokens.css sets a 64px default; these match the real header. */
html { scroll-padding-top: 5.5rem; }

@media (min-width: 900px) {
  html { scroll-padding-top: 6.5rem; }
}

/* ============================================================================
   1. Sticky nav
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background-color: var(--colour-page);
  /* A structural divider, not decoration: without it the header dissolves
     into whichever band scrolls beneath it. */
  border-bottom: 1px solid var(--colour-rule);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  padding-block: var(--space-s);
}

/* DM Sans loads with font-display: swap, so the fallback face paints first,
   and it sets "Lazy Meal Planner" 22px wider than DM Sans does. On a 320px
   phone that brief window was enough to push the row past the viewport edge
   and produce a horizontal scrollbar. Twelve pixels of gap instead of sixteen
   absorbs it, and costs nothing once the real font arrives. This has to sit
   after the rule above rather than with the other narrow-phone override at
   the top of the file: a media query adds no specificity, so on equal
   specificity it is source order that decides. */
@media (max-width: 399px) {
  .site-header__inner { gap: var(--space-s); }
}

/* ── Brand ── */

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--hit-target-min);
  margin-right: auto;
  color: var(--colour-text);
  text-decoration: none;
}

.brand:hover { color: var(--colour-text); }

/* The new mark is the bare mascot on a transparent ground — there is no tile,
   so nothing to round, and the artwork is taller than it is wide (508:590).
   Driving off height keeps it aligned with the wordmark beside it and lets the
   intrinsic ratio set the width. */
.brand__mark {
  width: auto;
  height: 2rem;
  flex-shrink: 0;
}

.brand__name {
  font-size: var(--text-small);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  white-space: nowrap;
}

/* ── Section links ──
   Hidden below 768px. A sticky header has to stay small on a phone, and
   three inline links plus the brand and the CTA cannot share a 320px row
   without the header growing to three stacked rows and eating a fifth of the
   screen. The same three anchors are in the footer, so nothing is lost — and
   the copy deck's one hard requirement, that the button stays visible at
   every width, still holds.

   From 768px they come back. The list measures 338px against a 432px gap
   between the brand and the button, so it fits with room to spare and fills
   what was otherwise dead space across the whole tablet range. */

.site-nav { display: none; }

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-l);
}

.site-nav__list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--hit-target-min);
  color: var(--colour-text);
  font-weight: var(--weight-medium);
  text-decoration: none;
  white-space: nowrap;
}

.site-nav__list a:hover {
  color: var(--colour-link);
  text-decoration: underline;
}

/* ── Header call to action ──
   Google's own badge artwork rather than a text button, so the one thing in
   the header that asks for a tap is the mark people already recognise.

   Two floors decide the size, and they nearly meet. Google's digital minimum
   is a 28px badge, which is a 42px image box once its baked-in clear space is
   counted (see --badge-height-nav). Our own floor is a 44px hit target. The
   link is therefore padded out to 44px while the artwork stays at 42px —
   padding the link, not scaling the badge, because a badge grown to 44px
   would be 113px wide and a 320px viewport has no room to spare.

   Selectors are compound (.play-badge.site-header__badge) on purpose. The
   shared badge rules in section 3 come later in this file, so a single class
   here would lose the cascade to them. */

.play-badge.site-header__badge {
  display: inline-flex;
  align-items: center;
  /* Never shrink. A flex item with an auto width can be squeezed, and a
     squeezed badge is a rescaled badge, which Google's guidelines forbid. */
  flex: 0 0 auto;
  min-height: var(--hit-target-min);
}

.play-badge.site-header__badge img { height: var(--badge-height-nav); }

@media (min-width: 768px) {
  .site-nav {
    display: block;
    margin-inline-start: auto;
  }

  /* The badge brings roughly 8px of transparent margin of its own, so the
     16px flex gap reads optically as 24px — precisely the gap between the nav
     links themselves, which leaves the badge looking like a fourth link
     rather than the thing the header is asking you to tap. This pushes the
     optical separation to about 40px, so the nav reads as a group and the
     badge reads as the call to action. */
  .play-badge.site-header__badge { margin-inline-start: var(--space-m); }
}

@media (min-width: 900px) {
  .brand__name { font-size: var(--text-body); }

  .play-badge.site-header__badge {
    min-height: var(--control-min-height);
  }

  .play-badge.site-header__badge img { height: var(--badge-height-nav-lg); }
}

/* ============================================================================
   2. Media placeholders
   ----------------------------------------------------------------------------
   Deliberately unlike finished content: muted ground, dashed outline, and a
   written description of the asset that belongs here. Each holds its final
   aspect ratio via `aspect-ratio`, so dropping the real screenshot in changes
   no layout. The intended alt text rides along in `data-alt` on each block.
   ========================================================================== */

.placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  width: 100%;
  padding: var(--space-l);
  background-color: var(--colour-surface-muted);
  border: 2px dashed var(--colour-text-muted);
  border-radius: var(--radius-m);
  text-align: center;
}

/* A white card band would leave the muted placeholder barely separated, so it
   swaps to the cream page ground for contrast against the white. */
.section--alt .placeholder { background-color: var(--colour-page); }

.placeholder--portrait { aspect-ratio: 4 / 5; }

.placeholder--phone {
  aspect-ratio: 9 / 19.5;
  max-width: 17.5rem;      /* 280px — a tall 9:19.5 block would otherwise
                              dominate the hero on a wide screen */
  margin-inline: auto;
}

.placeholder__desc {
  max-width: 22ch;
  font-size: var(--text-small);
  line-height: var(--leading-small);
  color: var(--colour-text);
}

.placeholder__note {
  max-width: 24ch;
  font-size: var(--text-eyebrow);
  line-height: var(--leading-small);
  color: var(--colour-text-muted);
}

/* ── App screenshots ──────────────────────────────────────────────────────
   Real captures from the app, in public/assets/img/app/. They take over the
   placeholder's slot at the same aspect ratio, so swapping one in moves
   nothing. The 4:5 shots are crops of the screen with no device frame drawn
   round them; the hero is the whole screen, so it gets the larger card
   radius to read as a phone without pretending to be one.
   ─────────────────────────────────────────────────────────────────────── */
.shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-card);
}

.shot--portrait { aspect-ratio: 4 / 5; }

.shot--phone {
  aspect-ratio: 9 / 19.5;
  max-width: 17.5rem;       /* same cap as .placeholder--phone */
  margin-inline: auto;
  border-radius: var(--radius-card);
}

/* Pause/play for the hero video. Compact, but .btn's min-height keeps the
   44px hit target. [hidden] has to be restated because display beats it. */
.reel-toggle {
  display: flex;
  margin: var(--space-s) auto 0;
  padding: var(--space-xs) var(--space-l);
  font-size: var(--text-small);
}

.reel-toggle[hidden] { display: none; }

/* The whole screen below the status bar, for animations where the action
   happens in a bottom sheet or dialog that a 4:5 crop would cut off. The
   ratio comes from the image's width/height attributes rather than a fixed
   value, and the cap keeps it level with the copy beside it. */
.shot--screen {
  max-width: 18rem;
  margin-inline: auto;
  border-radius: var(--radius-card);
}

/* ============================================================================
   2b. Pill
   ----------------------------------------------------------------------------
   The app's own badge pattern (STYLE.md §1): a filled tonal background with
   contrasting ink, never an outline. Charcoal rather than sage-dark for the
   ink — sage-dark on sage-light is 4.55:1, which passes but leaves no
   headroom at all, and charcoal gives 12.05:1 for the same silhouette.
   ========================================================================== */

.pill {
  display: inline-block;
  padding: var(--space-xxs) var(--space-s);
  border-radius: var(--radius-pill);
  font-size: var(--text-small);
  font-weight: var(--weight-bold);
  line-height: var(--leading-small);
}

.pill--accent {
  background-color: var(--colour-sage-light);
  color: var(--colour-text);
}

/* ============================================================================
   3. Google Play badge
   ----------------------------------------------------------------------------
   Google's official artwork, used unmodified and with its own built-in clear
   space. Only the rendered height is set; the width follows the intrinsic
   ratio so the badge is never distorted.
   ========================================================================== */

.play-badge {
  display: inline-block;
  line-height: 0;              /* kills the inline-image descender gap, so the
                                  link box matches the badge exactly */
  text-decoration: none;
  border-radius: var(--radius-m);
}

.play-badge img {
  width: auto;
  height: var(--badge-height);  /* 60px image box → a 40.3px badge */
}

.play-badge:hover { filter: brightness(0.93); }

/* ============================================================================
   4. Hero
   ========================================================================== */

.hero__grid {
  display: grid;
  gap: var(--space-2xl);
  align-items: center;
}

/* The standfirst under any h1 or h2 — the hero and the intro of a section
   both use it. Declared here, ahead of .hero__subhead, so the hero's wider
   gap wins the tie. */
.lede {
  margin-top: var(--space-m);
  font-size: var(--text-h3);
  line-height: 1.45;
  color: var(--colour-text-muted);
}

.hero__subhead { margin-top: var(--space-l); }

.hero__actions { margin-top: var(--space-xl); }

/* ── Hero terms ──
   Three unrelated facts — an offer, a price and a platform qualifier — that
   were previously one 17px sentence with full stops doing all the work. They
   now carry three different weights: the trial leads because it is the most
   attractive of the three, the price supports it with the amounts picked out,
   and the platform constraint sits underneath as small print. Small print
   here still means 14px at 5.70:1 — it is a qualifier, and it is there for
   honesty, so it stays legible. */

.hero__terms { margin-top: var(--space-l); }

.hero__price {
  margin-top: var(--space-s);
  color: var(--colour-text);          /* 14.74:1 on cream */
}

.hero__price strong { font-weight: var(--weight-bold); }

.hero__platform {
  margin-top: var(--space-xs);
  font-size: var(--text-small);
  line-height: var(--leading-small);
  color: var(--colour-text-muted);    /* 5.70:1 on cream */
}

@media (min-width: 900px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: var(--space-3xl);
  }
}

/* ============================================================================
   5. Prose sections
   ========================================================================== */

.prose-block > * { max-width: var(--measure); }

/* The "what it doesn't do" paragraph. Set apart and smaller, as the copy deck
   asks, while staying on a 5.70:1 pairing rather than dropping to grey. */
.honest-line {
  margin-top: var(--space-xl);
  padding-left: var(--space-m);
  border-left: 3px solid var(--colour-blush);
  font-size: var(--text-small);
  line-height: var(--leading-small);
  color: var(--colour-text-muted);
}

/* ── Sample questions ──
   Things you might say to the assistant, not quotations from anybody. The
   first treatment — a muted panel with a terracotta left rule — was pull-quote
   language, and a quoted sentence in a ruled block on a marketing page reads
   as a testimonial. CLAUDE.md forbids those outright, so the risk is not worth
   running even accidentally.

   These are chat bubbles instead: filled blush (the app's own chip colour,
   STYLE.md §1), squared at the bottom-left like a speech tail, and sized to
   fit their own text rather than spanning the column. The ragged right edge
   across the three is the point — it reads as someone talking, not as three
   formatted panels. Charcoal on blush is 11.30:1. */
.ask-example {
  width: fit-content;
  max-width: var(--measure);
  margin-top: var(--space-m);
  padding: var(--space-s) var(--space-m);
  background-color: var(--colour-blush);
  border-radius: var(--radius-card) var(--radius-card) var(--radius-card) var(--space-xxs);
  line-height: var(--leading-small);
  color: var(--colour-text);
}

/* Stacked examples tighten up, so consecutive ones read as one set. */
.ask-example + .ask-example { margin-top: var(--space-xs); }

/* Returning to prose after an example gets the full paragraph step back. */
.ask-example + p { margin-top: var(--space-m); }

/* On the sage-light accent band the blush fill is 1.07:1 against the ground —
   the same luminance, so the bubble shape all but disappears and only a hue
   shift is left, which is no help to anyone reading in greyscale or with a
   colour vision deficiency. Every light tone in the palette sits within
   1.31:1 of sage-light, so no light fill can work here. Sage-dark does: it is
   4.55:1 against the ground and stays in the band's own colour family, which
   is what tonal contrast means. Cream on it is 5.56:1. */
.section--accent .ask-example {
  background-color: var(--colour-sage-dark);
  color: var(--colour-text-inverse);
}

/* Same problem, same cause: the blush rule is invisible on this ground.
   Warm brown reads at 4.66:1 and matches the line's own text colour. */
.section--accent .honest-line {
  border-left-color: var(--colour-warm-brown);
}

/* ============================================================================
   6. Three steps
   ========================================================================== */

.steps {
  display: grid;
  gap: var(--space-2xl);
  margin-top: var(--space-2xl);
}

/* Capped so a single-column step cannot blow the 4:5 block up to 704×880px
   and swamp the copy it belongs to. In the three-up grid the column is
   narrower than this anyway, so the cap only bites on the stacked layouts. */
.step__media {
  margin-bottom: var(--space-l);
  max-width: 20rem;
}

.step .eyebrow { margin-bottom: var(--space-xxs); }

.step h3 + p { margin-top: var(--space-xs); }

/* Two across from 768px. Two-up any earlier is a false economy: at 600px it
   halves the copy to 33 characters a line, against the 68 the stacked layout
   gives at the same width. Three across at 768px was worse still — a third of
   the container is 213px, which set step one in a 27-character column 13 lines
   deep. */
@media (min-width: 768px) {
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-xl) var(--space-l);
  }
}

/* Three across only once the container has reached its 1120px maximum, so the
   three-up columns are always at their widest: 42 characters rather than the
   38 a 1024px breakpoint would give. One number, not two. */
@media (min-width: 1120px) {
  .steps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-xl);
  }
}

/* ============================================================================
   7. Split sections — copy beside a media block
   ========================================================================== */

.split {
  display: grid;
  gap: var(--space-2xl);
  align-items: center;
}

.split__media { max-width: 24rem; }

@media (min-width: 900px) {
  .split {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.7fr);
    gap: var(--space-3xl);
  }

  /* Alternating the media side stops two consecutive split sections reading
     as the same block twice. The DOM order is unchanged, so the reading
     order stays copy-then-media either way. */
  .split--reverse .split__copy { order: 2; }
  .split--reverse .split__media { order: 1; }
}

/* ============================================================================
   8. Free vs paid
   ========================================================================== */

.tiers {
  display: grid;
  gap: var(--space-l);
  margin-top: var(--space-2xl);
}

.tier { padding: var(--space-xl); }

.tier h3 { margin-bottom: var(--space-m); }

.ticks li {
  position: relative;
  padding-left: var(--space-l);
  line-height: var(--leading-small);
}

.ticks li + li { margin-top: var(--space-s); }

/* A CSS-drawn tick rather than a glyph, so no screen reader announces a
   stray character and no icon font is loaded. */
.ticks li::before {
  content: '';
  position: absolute;
  top: 0.34em;
  left: var(--space-xxs);
  width: 0.4em;
  height: 0.72em;
  border: solid var(--colour-text-accent);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.tiers__closing {
  margin-top: var(--space-xl);
  font-weight: var(--weight-bold);
}

@media (min-width: 768px) {
  .tiers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ============================================================================
   9. Pricing
   ========================================================================== */

.prices {
  display: grid;
  gap: var(--space-l);
  margin-top: var(--space-2xl);
}

.price { padding: var(--space-xl); }

.price--highlight {
  /* Marked as the better value with a tonal step and a flag, not with a
     popularity claim we have no data for. */
  background-color: var(--colour-sage-light);
}

/* An .eyebrow--strong; only the colour and the gap below are its own. */
.price__flag {
  margin-bottom: var(--space-xs);
  color: var(--colour-text-accent);
}

/* The flag is a label for the plan name, so 8px belongs between them. Without
   this the prose rule `p + h3` puts 32px there when the cards are stacked,
   against the 8px the subgrid gives them side by side. */
.price h3 { margin-top: 0; }

.price__figure {
  margin-top: var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-h2);
}

.price__note {
  margin-top: var(--space-xs);
  color: var(--colour-text-muted);
}

.trial {
  max-width: var(--measure);
  margin-top: var(--space-xl);
}

.trial p + p { margin-top: var(--space-m); }

.pricing__actions { margin-top: var(--space-xl); }

/* The same qualifier as the hero's "Android only", so it reads the same way:
   small print, not body copy. 14px warm brown on cream is 5.70:1. */
.pricing__platform {
  margin-top: var(--space-m);
  font-size: var(--text-small);
  line-height: var(--leading-small);
  color: var(--colour-text-muted);
}

@media (min-width: 768px) {
  .prices {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* No align-items: start. The cards stretch to a common height — that was
       the setting letting them run 90px apart. */
  }
}

/* ── Card rows shared across both cards ──────────────────────────────────
   Equal height on its own is not enough: it leaves one card with dead space
   and still sits the plan names and the price figures 53px apart, because
   the Yearly card carries a flag above its name and the Monthly card does
   not. Subgrid hands both cards the same four rows — flag, plan name, price
   figure, note — so each row shares one baseline across the pair.

   The Monthly card simply has nothing in rows 1 and 4. Those rows stay
   reserved and empty, which is why this needs no placeholder markup: there
   is no element to hide from a screen reader because there is no element.

   Only from 768px, where the cards sit side by side. Stacked, there is
   nothing to align against, so the rules are scoped inside the media query
   and each card returns to its natural height.
   ─────────────────────────────────────────────────────────────────────── */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 768px) {
    .prices { grid-template-rows: auto auto auto auto; }

    .price {
      display: grid;
      grid-row: span 4;
      grid-template-rows: subgrid;
      /* Its own gap, not the 24px the parent uses between cards. */
      row-gap: var(--space-xs);
    }

    /* Row spacing is the grid's job now, so the margins that used to do it
       would double up. */
    .price h3,
    .price__flag,
    .price__figure,
    .price__note { margin: 0; }

    .price__flag   { grid-row: 1; }
    .price h3      { grid-row: 2; }
    .price__figure { grid-row: 3; }
    .price__note   { grid-row: 4; }
  }
}

/* ============================================================================
   10. FAQ
   ========================================================================== */

.faq {
  display: grid;
  gap: var(--space-xl);
  margin-top: var(--space-2xl);
}

.faq__item h3 + p { margin-top: var(--space-xs); }

@media (min-width: 900px) {
  .faq {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-xl) var(--space-2xl);
  }
}

/* ============================================================================
   11. Footer
   ========================================================================== */

.site-footer__grid {
  display: grid;
  gap: var(--space-xl);
}

/* The cream mark, for the charcoal footer band: 14.74:1, against 3.82:1 for the
   terracotta mark the header uses on cream. Slightly larger than the header
   mark because the footer has the room and nothing competes with it there. */
.site-footer__mark {
  width: auto;
  height: 2.5rem;
  margin-bottom: var(--space-s);
}

.site-footer__name {
  font-family: var(--font-display);
  font-size: var(--text-h3);
}

.site-footer__tagline {
  margin-top: var(--space-xxs);
  color: var(--colour-text-inverse-muted);
}

.site-footer__col a {
  display: inline-flex;
  align-items: center;
  min-height: var(--hit-target-min);
  text-decoration: none;
}

.site-footer__col a:hover { text-decoration: underline; }

.site-footer__base {
  margin-top: var(--space-2xl);
  padding-top: var(--space-l);
  border-top: 1px solid var(--colour-rule);
}

/* Blush on charcoal is 11.30:1, so the small print clears 4.5:1 with room
   to spare. */
.site-footer__legal {
  font-size: var(--text-small);
  line-height: var(--leading-small);
  color: var(--colour-text-inverse-muted);
}

.site-footer__legal + .site-footer__legal { margin-top: var(--space-s); }

@media (min-width: 768px) {
  .site-footer__grid {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-2xl);
  }
}

/* ============================================================================
   Reduced motion
   ----------------------------------------------------------------------------
   tokens.css already flattens transitions and disables smooth scrolling
   globally, which covers everything currently on this page.

   The "Saying no is how it learns" section's asset is a looping GIF. A GIF
   cannot be paused by CSS, so when the real asset lands it must ship as a
   <picture> with the still frame in a `media="(prefers-reduced-motion:
   reduce)"` source, ahead of the animated one. That is a markup change at
   drop-in time, not a style this file can pre-empt — the placeholder in
   index.html carries the same note.
   ========================================================================== */
