/* ═══════════════════════════════════════════════════════════════
   Sift — siftapp.me
   Values come from DESIGN.md, which comes from sift/brand/BRAND.md.
   Do not introduce a colour, a radius or a curve that is not below.
   ═══════════════════════════════════════════════════════════════ */

:root {
  --surface-1: #f1f1f3;
  --surface-2: #f8f8fa;
  --surface-3: #fcfcfd;
  --night:     #0a0a0c;

  --ink:        #101014;
  --ink-muted:  #5b5b66;
  --ink-faint:  #6a6a76;
  --rule:       #e4e4e7;
  --rule-strong:#71717a;

  --ember:      #c2181d;
  --ember-deep: #9c1216;
  /* the app's own control tokens, so a ported component is not guessing */
  --ember-fill: #c2181d;
  --on-ember:   #ffffff;
  --ember-wash: #fdf2f2;
  --surface-4:  #ffffff;
  --sage-wash:  #eff8f3;
  --on-ember:   #ffffff;
  --sage:       #0a6e47;

  /* the junk ramp: light enough to read as noise, never as content */
  --junk-fill:  #e7e7ea;
  --junk-fill-2:#ededf0;
  --junk-ink:   #a3a3ad;
  --junk-ink-2: #b9b9c2;

  --radius: 14px;
  --radius-phone: 44px;

  --feedback: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  --entrance: 420ms cubic-bezier(0.16, 1, 0.3, 1);

  /* the mark's fall vector, normalised. Nothing on this page moves
     straight down: vertical gravity would cross the mark instead of
     becoming it. 133deg is the same vector as a CSS gradient angle. */
  --fx: 0.7305;
  --fy: 0.6828;

  --sans: "Bricolage Grotesque", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --serif: "Newsreader", ui-serif, Georgia, "Times New Roman", serif;
  --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

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

/* the transport icons toggle with the hidden attribute, and SVG children do
   not honour it without this */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  background: var(--surface-1);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  font-variation-settings: "opsz" 14;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

a { color: inherit; }

::selection { background: #d9d9de; color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--surface-1);
  padding: 12px 20px; border-radius: var(--radius);
  text-decoration: none; font-weight: 600;
}
.skip:focus { left: 16px; top: 16px; }

.num { font-family: var(--mono); font-feature-settings: "tnum"; letter-spacing: -0.01em; }

/* ─────────────────────────── type scale ───────────────────────────
   1.333, editorial. 13 · 14 · 17 · 22 · 30 · 40 · 53 · 71 · 95     */

h1, h2, h3 { text-wrap: balance; }
p, li, dd, summary { text-wrap: pretty; }

h1 {
  font-size: clamp(2.6rem, 6.6vw, 5.2rem);
  line-height: 0.96;
  letter-spacing: -0.035em;
  font-weight: 600;
  font-variation-settings: "opsz" 48;
  margin: 0 0 24px;
}

h2 {
  font-size: clamp(1.9rem, 3.5vw, 2.75rem);
  line-height: 1.08;
  letter-spacing: -0.028em;
  font-weight: 600;
  font-variation-settings: "opsz" 40;
  margin: 0 0 20px;
  max-width: 18ch;
}

h2.big {
  font-size: clamp(2.4rem, 5.4vw, 4rem);
  max-width: 16ch;
  margin-inline: auto;
}

h3 {
  font-size: 22px;
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 600;
  font-variation-settings: "opsz" 24;
  margin: 0 0 10px;
}

p { margin: 0 0 18px; max-width: 62ch; color: var(--ink-muted); }

.kicker {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 14px;
}

.eyebrow {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-faint);
  margin: 0 0 20px;
  letter-spacing: -0.005em;
}

.lede {
  font-size: clamp(18px, 1.55vw, 21px);
  line-height: 1.5;
  color: var(--ink-muted);
  max-width: 46ch;
}

.lede-sm { font-size: 19px; line-height: 1.55; max-width: 56ch; }

.caption {
  font-size: 14px;
  color: var(--ink-faint);
  margin: 20px 0 0;
  max-width: 34ch;
}
.caption-dark { color: #8e8e99; }

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

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 24px;
  border-radius: var(--radius);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
  transition: background var(--feedback), transform var(--feedback), color var(--feedback);
}

/* Ember appears once per band, on the thing you can act on. On this page
   that is App Store buttons and nothing else. */
.btn-ember { background: var(--ember); color: var(--on-ember); }
.btn-ember:hover { background: var(--ember-deep); }
.btn-ember:active { transform: translateY(1px); }

.btn-ghost { background: transparent; color: var(--ink); box-shadow: inset 0 0 0 1px var(--rule-strong); }
.btn-ghost:hover { background: #e7e7ea; }

/* The nav button is ink, not ember. Ember appears once per screen and in the
   hero that one place is the App Store button, which must win. */
.btn-ink { background: var(--ink); color: var(--surface-2); }
.btn-ink:hover { background: #26262c; }
.btn-ink:active { transform: translateY(1px); }

.btn-sm { min-height: 44px; padding: 10px 16px; font-size: 14px; }

.cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin: 32px 0 20px; }
.cta-center { justify-content: center; }

.hero-foot { font-size: 14px; color: var(--ink-faint); margin: 0; max-width: 44ch; }
.center .hero-foot { margin-inline: auto; }

/* ─────────────────────────── nav ─────────────────────────── */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: transparent;
  transition: background var(--feedback), box-shadow var(--feedback);
}
/* Solid once it lifts off, not translucent. A blurred light bar passing over
   the night band turned into a grey slab, which is worse than either state. */
.nav.is-stuck {
  background: var(--surface-1);
  box-shadow: inset 0 -1px 0 var(--rule);
}

.nav-inner {
  width: min(1180px, 92vw);
  margin: 0 auto;
  height: 68px;
  display: flex;
  align-items: center;
  gap: 26px;
}

.nav-mark { color: var(--ink); display: flex; align-items: center;
  min-height: 44px; line-height: 0; }

.nav-links { display: flex; gap: 22px; margin-left: auto; }
.nav-links a {
  font-size: 14px; font-weight: 500; color: var(--ink-muted);
  text-decoration: none; transition: color var(--feedback);
}
.nav-links a:hover { color: var(--ink); }
/* where you are on a long page. The underline sits on the text baseline
   rather than boxing the link, so it stays quiet. */
.nav-links a {
  position: relative;
  display: inline-flex; align-items: center; min-height: 44px;
  padding-bottom: 3px;
  box-shadow: inset 0 -1.5px 0 transparent;
  transition: color var(--feedback), box-shadow var(--feedback);
}
.nav-links a[aria-current="true"] {
  color: var(--ink);
  box-shadow: inset 0 -1.5px 0 var(--ink);
}

/* ═══════════════════════════ HERO ═══════════════════════════
   The one committed move. The page performs the sift before it
   describes it: recipe-page debris falls out of frame along the
   mark's vector, shrinking and never fading, while three grains
   fall in and the recipe is wiped into view on the same diagonal.
   ═══════════════════════════════════════════════════════════ */

.hero { position: relative; height: 220vh; height: 220svh; }

.hero-stage {
  position: sticky; top: 0;
  height: 100vh;
  height: 100svh;
  min-height: 680px;
  overflow: hidden;
  display: grid;
  place-items: center;
}

.hero-grid {
  position: relative;
  z-index: 2;
  /* deliberately narrower than every other band on the page. The debris
     needs a gutter to live in, and the reserved centre channel is what
     keeps the headline legible over a full field. */
  width: min(1000px, 88vw);
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: clamp(24px, 4vw, 48px);
  align-items: center;
}

.hero-copy { max-width: 486px; }
.hero-copy h1 { font-size: clamp(2.4rem, 4.9vw, 4.2rem); }
.hero-copy .lede { max-width: 440px; }
.hero-copy .cta-row .btn { padding-inline: 21px; }

/* ── the kept column: grains land, then the card is wiped in ── */

.hero-kept { position: relative; justify-self: end; width: 100%; max-width: 300px; }

.grains { position: absolute; top: -78px; left: -22px; color: var(--ink); }
.grains .g { fill: var(--ink); will-change: transform; }

.recipe-card {
  /* revealed by a band travelling on the fall vector, 133deg.
     Position and size, never opacity. */
  --reveal: 1;
  -webkit-mask-image: linear-gradient(133deg,
      #000 0%,
      #000 calc(var(--reveal) * 150% - 26%),
      transparent calc(var(--reveal) * 150%));
  mask-image: linear-gradient(133deg,
      #000 0%,
      #000 calc(var(--reveal) * 150% - 26%),
      transparent calc(var(--reveal) * 150%));
  will-change: transform;
}

.card {
  background: var(--surface-3);
  border-radius: var(--radius);
  padding: 26px 26px 22px;
  box-shadow: 0 1px 2px rgba(16, 16, 20, 0.05),
              0 12px 32px -12px rgba(16, 16, 20, 0.16);
}

.card-kicker {
  font-size: 10px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-faint); margin: 0 0 10px;
}

.card-title {
  font-family: var(--sans);
  font-size: 22px; line-height: 1.1; letter-spacing: -0.026em;
  font-weight: 600; font-variation-settings: "opsz" 32;
  margin: 0 0 8px; max-width: none;
}

.card-meta { font-size: 14px; color: var(--ink-faint); margin: 0 0 20px; }

/* Newsreader is restricted to the recipe itself, here and in the
   compare columns. The furniture around it stays Bricolage. */
.ing, .steps {
  font-family: var(--serif);
  font-size: 17px; line-height: 1.45;
  color: var(--ink);
  margin: 0; padding: 0; list-style: none;
}
.ing li {
  display: flex; gap: 7px; align-items: center;
  padding: 7px 0;
  box-shadow: inset 0 -1px 0 var(--rule);
}
.ing-t { flex: 1; min-width: 0; }
/* ticked by the hero's own scroll: you sift the page, then you start cooking */
.ing-box {
  flex: 0 0 auto; width: 19px; height: 19px; border-radius: 6px;
  box-shadow: inset 0 0 0 1.5px var(--rule);
  position: relative;
  transition: background var(--feedback), box-shadow var(--feedback);
}
.ing-box::after {
  content: ""; position: absolute; left: 31%; top: 17%;
  width: 27%; height: 50%;
  border-right: 2px solid #fff; border-bottom: 2px solid #fff;
  transform: rotate(42deg) scale(0.4); opacity: 0;
  transition: opacity 140ms ease, transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.ing li.got .ing-box { background: var(--sage); box-shadow: inset 0 0 0 1.5px var(--sage); }
.ing li.got .ing-box::after { opacity: 1; transform: rotate(42deg) scale(1); }
.ing li.got .ing-t, .ing li.got .num, .ing li.got .unit { color: var(--ink-faint); }
.ing li .ing-t, .ing li .num, .ing li .unit { transition: color var(--feedback); }
.ing li:last-child { box-shadow: none; }
.ing .num { font-size: 14px; color: var(--ink); }
.ing .unit { font-family: var(--mono); font-size: 14px; color: var(--ink-faint); }

.steps { margin-top: 16px; counter-reset: s; }
.steps li { color: var(--ink-muted); }

.card-src {
  font-size: 13px; color: var(--ink-faint);
  margin: 18px 0 0; padding-top: 14px;
  box-shadow: inset 0 1px 0 var(--rule);
}

.scroll-hint {
  position: absolute; bottom: 26px; left: 50%;
  transform: translateX(-50%);
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0;
  transition: opacity var(--feedback);
}

/* ── the debris field ──
   This was originally drawn in Sift's own cold neutrals, on the theory that
   colour would compete with the CTA. That was the wrong call and it showed:
   the first reaction to the page was that something had failed to load. Grey
   debris does not read as somebody else's website. It reads as a broken
   version of this one.

   So the debris wears the aesthetic Sift deliberately refused. Warm creams,
   an orange call to action, a coral subscribe bar, gold stars, that food-blog
   navy: the exact palette DESIGN-V3 named as the reason the product once read
   as a craft-market blog. Colour falling out of frame and leaving a cold, quiet
   card behind is the argument the hero is making, made in one more dimension.

   None of it names a real publication. It is generic blog furniture. */

.junk {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  --b-navy:   #2c3757;
  --b-orange: #f0703a;
  --b-coral:  #e8543f;
  --b-green:  #3fa46a;
  --b-gold:   #e8b34a;
  --b-teal:   #2b9aa4;
  --b-cream:  #fdf5ea;
  --b-ink:    #3b4152;
  --b-mute:   #8e93a1;
  --b-line:   #e6e2da;
}

.j {
  position: absolute;
  will-change: transform;
  font-size: 13px;
  line-height: 1.4;
  color: var(--b-ink);
  border-radius: 10px;
  font-family: var(--sans);
}

.j img { border-radius: 0; }

.j-btn {
  display: inline-block; border-radius: 6px; padding: 7px 13px;
  font-size: 13px; font-weight: 700; white-space: nowrap; letter-spacing: 0.01em;
}
.j-orange  { background: var(--b-orange); color: #fff; }
.j-coral   { background: var(--b-coral);  color: #fff; }
.j-green   { background: var(--b-green);  color: #fff; }
.j-white   { background: #fff; color: var(--b-ink); }
.j-outline { background: transparent; color: #cfd4e0; box-shadow: inset 0 0 0 1px #59637f; }

.j-tag {
  position: absolute; top: 7px; left: 8px;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: rgba(255,255,255,0.72); font-weight: 700;
}
.j-tag-dark { color: rgba(59,65,82,0.5); }

.j-label {
  display: block;
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--b-mute); font-weight: 700; margin-bottom: 8px;
}
.j-line { display: block; height: 6px; border-radius: 3px; background: var(--b-line); margin-top: 7px; }
.j-line.short { width: 56%; }
.j-field { display: block; height: 28px; border-radius: 6px; background: #fff; box-shadow: inset 0 0 0 1px var(--b-line); margin: 9px 0; }

/* the newsletter popup, the single most recognisable thing on a recipe page */
.j-modal {
  width: 226px; padding: 0; overflow: hidden;
  background: #fff; border-radius: 12px;
  box-shadow: 0 18px 44px -14px rgba(24, 20, 14, 0.4), 0 2px 6px rgba(24, 20, 14, 0.1);
}
.j-modal img { width: 100%; height: 104px; object-fit: cover; display: block; }
.j-modal-b { display: block; padding: 13px 15px 15px; background: var(--b-cream); }
.j-modal-h {
  display: block; font-size: 22px; line-height: 1.1; font-weight: 700;
  letter-spacing: -0.02em; color: var(--b-navy);
}
.j-no { display: block; margin-top: 9px; font-size: 10px; color: var(--b-mute); text-decoration: underline; }
.j-x {
  position: absolute; right: 9px; top: 7px; z-index: 2;
  width: 20px; height: 20px; border-radius: 50%;
  background: rgba(0,0,0,0.45); color: #fff;
  font-size: 13px; line-height: 20px; text-align: center;
}

.j-cookie {
  width: 306px; padding: 12px 14px;
  background: var(--b-navy); color: #cfd4e0;
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  box-shadow: 0 10px 24px -12px rgba(20, 26, 44, 0.6);
}
.j-cookie .j-t { flex: 1 1 100%; font-size: 13px; margin-bottom: 2px; }

.j-ad-a {
  width: 182px; height: 146px; padding: 14px;
  background: linear-gradient(150deg, var(--b-teal), #1d7f92 62%, #17636f);
  color: #fff; display: flex; flex-direction: column; justify-content: flex-end;
  border-radius: 8px;
}
.j-ad-big { font-size: 30px; line-height: 0.92; font-weight: 700; letter-spacing: -0.03em; margin-bottom: 10px; }
.j-ad-a .j-btn { align-self: flex-start; }

.j-ad-b {
  width: 134px; height: 232px; padding: 22px 13px 13px;
  background: var(--b-cream); border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--b-line);
}
.j-blob {
  display: block; height: 96px; border-radius: 6px;
  background: linear-gradient(140deg, var(--b-gold), var(--b-orange));
  margin-bottom: 11px;
}

.j-video {
  width: 224px; height: 126px;
  background: #16181f; border-radius: 8px;
  display: grid; place-items: center;
  /* stays absolute. It was set to relative so the skip chip and the progress
     bar would anchor to it, which silently cancelled its own bottom/left
     placement and dropped it at the top of the stage. Absolute is a containing
     block too, so the children were never the problem. */
  box-shadow: 0 12px 28px -14px rgba(0,0,0,0.6);
}
.j-play {
  width: 0; height: 0;
  border-left: 20px solid rgba(255,255,255,0.94);
  border-top: 13px solid transparent; border-bottom: 13px solid transparent;
  margin-left: 5px;
}
.j-skip {
  position: absolute; right: 8px; bottom: 14px;
  background: rgba(255,255,255,0.16); color: #fff;
  font-size: 10px; padding: 4px 8px; border-radius: 4px;
}
.j-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(255,255,255,0.2); }
.j-bar i { display: block; width: 38%; height: 100%; background: var(--b-orange); }

.j-related { width: 254px; }
.j-cards { display: flex; gap: 7px; }
.j-card { flex: 1; }
.j-card img { width: 100%; height: 52px; object-fit: cover; border-radius: 6px; display: block; }
.j-card em {
  display: block; font-style: normal; font-size: 10px; line-height: 1.3;
  color: var(--b-ink); font-weight: 600; margin-top: 5px;
}

.j-author {
  width: 236px; display: flex; gap: 11px; align-items: flex-start;
  font-size: 13px; color: var(--b-mute); line-height: 1.45;
}
.j-author img { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; flex: 0 0 46px; }
.j-author b { display: block; color: var(--b-navy); font-size: 17px; margin-bottom: 3px; }

.j-rating { white-space: nowrap; font-size: 13px; color: var(--b-mute); }
.j-stars { color: var(--b-gold); letter-spacing: 2px; font-size: 14px; }

.j-social { display: flex; gap: 6px; }
.j-social span {
  padding: 6px 12px; border-radius: 5px; font-size: 13px;
  font-weight: 700; color: #fff;
}
.j-social .c1 { background: var(--b-coral); }
.j-social .c2 { background: var(--b-teal); }
.j-social .c3 { background: var(--b-mute); }
.j-social .c4 { background: var(--b-green); }

.j-jump {
  background: var(--b-green); color: #fff;
  padding: 9px 16px; border-radius: 999px;
  font-weight: 700; white-space: nowrap; font-size: 14px;
  letter-spacing: 0.01em;
  box-shadow: 0 6px 16px -8px rgba(63, 164, 106, 0.9);
}

.j-para { width: 226px; font-size: 13px; }
.j-para p { margin: 0; color: var(--b-mute); max-width: none; font-size: 13px; line-height: 1.5; }

.j-crumb { width: 214px; font-size: 10px; color: var(--b-mute); }
.j-comments { white-space: nowrap; font-size: 13px; color: var(--b-mute); background: var(--b-cream); padding: 6px 11px; border-radius: 999px; }

.j-sticky {
  width: 330px; padding: 11px 13px;
  background: #fff; border-radius: 10px;
  box-shadow: 0 -6px 24px -10px rgba(24, 20, 14, 0.3), inset 0 0 0 1px var(--b-line);
  display: flex; align-items: center; gap: 9px;
}
.j-sticky .j-t { font-size: 13px; font-weight: 700; color: var(--b-navy); white-space: nowrap; }
.j-field-sm { flex: 1; height: 26px; border-radius: 5px; background: #f4f1eb; }

/* ── placement ──
   Anchored to the centre line, not to viewport percentages, so the reserved
   channel holds its width at any viewport. The hero content box is 1000px, so
   its edges sit at calc(50% ± 500px).

   The newsletter popup sits exactly where the recipe card is wiped in. That is
   the argument staged literally: the thing in the way leaves, and the recipe
   takes its place. */

/* top strip, above the copy */
.j-crumb   { left: calc(50% - 486px); top: 24px; }
.j-cookie  { left: calc(50% - 172px); top: 10px; }
.j-jump    { left: calc(50% - 366px); top: 78px; }
.j-rating  { left: calc(50% - 362px); top: 122px; }

/* the card's own footprint: what is standing in the recipe's place */
.j-modal   { left: calc(50% + 208px); top: 15%; }
.j-related { left: calc(50% + 216px); bottom: 118px; }

/* right outer rail, bleeding off */
.j-comments{ left: calc(50% + 516px); top: 16%; }
.j-ad-b    { left: calc(50% + 516px); top: 28%; }
.j-author  { left: calc(50% + 516px); top: 66%; }

/* left outer rail */
.j-para    { right: calc(50% + 512px); top: 46%; }

/* the band under the copy. The brightest pieces live here rather than on the
   outer rails, because on a 1280 screen the rails are only ~130px wide and the
   ad that is meant to catch the eye was 60% off the edge. */
.j-ad-a    { left: calc(50% - 496px); bottom: 56px; }
.j-video   { left: calc(50% - 288px); bottom: 56px; }
.j-social  { left: calc(50% - 30px);  bottom: 56px; }
.j-sticky  { left: calc(50% + 206px); bottom: 8px; }

/* ─────────────────────────── bands ───────────────────────────
   Section rhythm is deliberately uneven. See DESIGN.md.       */

.band { padding: 160px 0; position: relative; }
.band-1 { background: var(--surface-1); }
.band-2 { background: var(--surface-2); }
.band-3 { background: var(--surface-3); }
.band-tight { padding: 128px 0; }
.band-narrow { padding: 96px 0; }
.band-air { padding: 224px 0; }
.band-faq { padding: 112px 0 128px; }

.band-night {
  background: var(--night);
  color: #fafafa;
  padding: 200px 0;
}
.band-night h2 { color: #fafafa; }
.band-night p { color: #a1a1aa; }
.band-night .kicker { color: #8e8e99; }

.wrap { width: min(1180px, 92vw); margin: 0 auto; }
.wrap-narrow { width: min(760px, 92vw); }
.center { text-align: center; }
.center p { margin-inline: auto; }

/* ── split: text one side, device the other, alternating ── */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.82fr);
  gap: clamp(40px, 7vw, 110px);
  align-items: center;
}
.split-flip .split-text { order: 2; }
.split-flip .split-shot { order: 1; }

/* ── the phone ──
   The only elevated object on the page, because it is the only one
   that is a physical thing. */

/* The caption is a label for the picture, so it starts where the picture
   starts. It used to sit at the column's left edge while the phone was
   centred inside that column, which read as a misalignment because it was
   one. Everything in the column now shares one width. */
.split-shot {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.split-shot > * { width: 100%; max-width: 340px; }
.split-shot > .phone-pair { max-width: 400px; }
.split-shot .caption { max-width: 340px; }
.night-shot .caption { max-width: none; }

.phone {
  position: relative;
  border-radius: var(--radius-phone);
  padding: 8px;
  background: linear-gradient(158deg, #2a2a30, #131317 42%, #26262c);
  box-shadow:
    0 2px 4px rgba(16, 16, 20, 0.10),
    0 28px 60px -20px rgba(16, 16, 20, 0.34),
    0 60px 120px -50px rgba(16, 16, 20, 0.26);
  max-width: 340px;
  margin-inline: auto;
}
.split-shot .phone { margin-inline: 0; }
.phone img {
  border-radius: 36px;
  display: block;
  width: 100%;
  height: auto;
}

.phone-pair { position: relative; padding-bottom: 54px; max-width: 400px; margin-inline: auto; }
.split-shot .phone-pair { margin-inline: 0; }
.phone-back { max-width: 268px; margin: 0; transform: translate(0, 0) scale(0.92); transform-origin: top left; }
.phone-front {
  max-width: 268px; margin: 0;
  position: absolute;
  /* offset on the fall vector rather than straight across */
  right: 0; top: 74px;
}

/* ── night band ── */

.night-head { margin-bottom: 64px; }
.night-head h2 { max-width: 20ch; }

.night-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
  gap: clamp(40px, 6vw, 88px);
  align-items: start;
}

.night-aside {
  margin-top: 28px; padding-top: 24px;
  box-shadow: inset 0 1px 0 #27272a;
  color: #8e8e99 !important;
  font-size: 17px;
}

.island-plate {
  border-radius: 20px;
  overflow: hidden;
  background: #16161a;
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.9);
}
.island-plate img { width: 100%; height: auto; }

/* ══════════════════════════ LIVE PHONE SCENES ══════════════════════════
   These are ports of the app's own components, not impressions of them. Every
   value below was read out of the product: radii from tailwind.config.ts
   (xs 4, card 8, panel 12, pill 8), control heights from the same file
   (touch 56, control 48, control-sm 44), the type scale from its fontSize
   block, the control classes from the @layer components block in globals.css,
   and the Safari bar from the extension's own content.css, which is why it is
   dark and why its button is #FF6166 with dark text.

   The rule is one sentence: nobody should meet a preview here and then open
   the app to something different.

   Sized in container units against a 428pt reference, so a scene renders at
   any frame size and calc(var(--s) * 17) is 17pt on a phone.
   ═══════════════════════════════════════════════════════════════════════ */

.phone, .island-plate, .tile-shot, .tile-strip { container-type: inline-size; }

.scene {
  --ref: 428;
  --s: calc(100cqw / var(--ref));
  /* the product's own radii */
  --r-xs: calc(var(--s) * 4);
  --r-card: calc(var(--s) * 8);
  --r-panel: calc(var(--s) * 12);
  position: relative;
  aspect-ratio: 428 / 926;
  overflow: hidden;
  border-radius: 36px;
  background: var(--surface-1);
  font-family: var(--sans);
  color: var(--ink);
  font-size: calc(var(--s) * 17);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
.scene * { box-sizing: border-box; }

/* the app's type steps */
.s-micro { font-size: calc(var(--s) * 12); line-height: 1.3; letter-spacing: 0.08em; }
.s-meta  { font-size: calc(var(--s) * 15); line-height: 1.4; letter-spacing: 0.01em; }
.s-ui    { font-size: calc(var(--s) * 17); line-height: 1.45; }
.s-head  { font-size: calc(var(--s) * 20); line-height: 1.3; letter-spacing: -0.01em; }
.s-title { font-size: calc(var(--s) * 30); line-height: 1.2; letter-spacing: -0.02em; }
.qty     { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.s-body  { font-family: var(--serif); }

/* .pill / .chip, ported */
.s-chip {
  display: inline-flex; align-items: center; justify-content: center;
  gap: calc(var(--s) * 10);
  min-height: calc(var(--s) * 44);
  border-radius: var(--r-card);
  padding: 0 calc(var(--s) * 18);
  font-size: calc(var(--s) * 15); line-height: 1.4; letter-spacing: 0.01em;
  font-weight: 500; white-space: nowrap;
}
.s-chip-solid { background: var(--ink); color: var(--surface-2); }
.s-chip-quiet { background: var(--surface-3); color: var(--ink-muted);
  box-shadow: inset 0 0 0 1px var(--rule-strong); }
.s-chip-danger { background: var(--ember-wash); color: var(--ember);
  box-shadow: inset 0 0 0 1px var(--ember); }
.s-pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: calc(var(--s) * 48); border-radius: var(--r-card);
  padding: 0 calc(var(--s) * 16);
  font-size: calc(var(--s) * 17); font-weight: 500;
}
.s-pill-primary { background: var(--ember-fill); color: var(--on-ember); width: 100%; }

/* iOS furniture */
.sc-status {
  position: absolute; inset: 0 0 auto 0; z-index: 6;
  height: calc(var(--s) * 54);
  display: flex; align-items: center; justify-content: space-between;
  padding: calc(var(--s) * 14) calc(var(--s) * 30) 0;
  font-size: calc(var(--s) * 15); font-weight: 600;
}
.sc-status i { display: flex; gap: calc(var(--s) * 5); align-items: center; font-style: normal; }
.sc-bars { display:inline-block; width: calc(var(--s) * 17); height: calc(var(--s) * 11);
  background: currentColor;
  -webkit-mask: linear-gradient(#000 0 0) 0 100%/18% 40% no-repeat, linear-gradient(#000 0 0) 29% 100%/18% 62% no-repeat, linear-gradient(#000 0 0) 58% 100%/18% 82% no-repeat, linear-gradient(#000 0 0) 87% 100%/18% 100% no-repeat;
          mask: linear-gradient(#000 0 0) 0 100%/18% 40% no-repeat, linear-gradient(#000 0 0) 29% 100%/18% 62% no-repeat, linear-gradient(#000 0 0) 58% 100%/18% 82% no-repeat, linear-gradient(#000 0 0) 87% 100%/18% 100% no-repeat;
}
.sc-batt { width: calc(var(--s) * 25); height: calc(var(--s) * 12); border-radius: calc(var(--s) * 3);
  box-shadow: inset 0 0 0 calc(var(--s) * 1.2) currentColor; position: relative; opacity: .5; }
.sc-batt::after { content:""; position:absolute; inset: calc(var(--s) * 2); width: 62%;
  background: currentColor; border-radius: calc(var(--s) * 1); }

/* TopNav: h-14, border-b border-rule, bg-surface-2, wordmark centred */
.sc-nav {
  position: relative; z-index: 3;
  height: calc(var(--s) * 56);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--rule);
}
.sc-nav svg { height: calc(var(--s) * 26); width: auto; display: block; color: var(--ink); }

/* TabBar: 4 tabs, 24px glyph over a 12px label */
.sc-tabs {
  position:absolute; inset:auto 0 0 0; z-index:5;
  display:grid; grid-template-columns: repeat(4, 1fr);
  background: var(--surface-2); box-shadow: inset 0 1px 0 var(--rule);
  padding-bottom: calc(var(--s) * 8);
}
.sc-tab { display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap: calc(var(--s) * 4); min-height: calc(var(--s) * 56);
  font-size: calc(var(--s) * 12); line-height:1.3; color: var(--ink-muted); font-weight: 500; }
.sc-tab svg { width: calc(var(--s) * 24); height: calc(var(--s) * 24); display:block; }
.sc-tab.on { color: var(--ink); font-weight: 600; }
/* Account is the fourth tab and it is drawn as the face, not as a glyph, so
   the tab is a person and not a category. 24 to match the three beside it,
   so the row reads as one row and not as three icons and a photograph. The
   ring is the active state only: a permanent one competes with the weight
   change the other three use. */
.sc-avatar { width: calc(var(--s) * 24); height: calc(var(--s) * 24); display:block;
  border-radius: 50%; object-fit: cover; }
.sc-tab.on .sc-avatar { box-shadow: 0 0 0 calc(var(--s) * 2) var(--surface-2),
  0 0 0 calc(var(--s) * 4) var(--ink); }

.sc-body { position:absolute; inset: calc(var(--s) * 54) 0 0 0; overflow:hidden;
  display:flex; flex-direction:column; }
/* the scroller lives below the nav in its own clipped band, so scrolled content
   cannot ride up over the wordmark */
.sc-scroller { position:relative; flex:1; min-height:0; overflow:hidden; }
.sc-pad { padding: calc(var(--s) * 24) calc(var(--s) * 20); }

/* recipe screen */
.sc-title { font-size: calc(var(--s) * 30); line-height:1.2; letter-spacing:-.02em;
  font-weight:600; font-variation-settings:"opsz" 32; margin: 0 0 calc(var(--s) * 8); }
.sc-meta { font-size: calc(var(--s) * 15); line-height:1.4; color: var(--ink-muted); margin:0; }
.sc-photo { width:100%; aspect-ratio:16/10; object-fit:cover; border-radius: var(--r-card);
  display:block; margin: calc(var(--s) * 16) 0; }
.sc-chips { display:flex; gap: calc(var(--s) * 12); margin-top: calc(var(--s) * 16); }
.sc-chip2 { flex:1; background: var(--surface-3); border-radius: var(--r-card);
  padding: calc(var(--s) * 10) calc(var(--s) * 14); }
.sc-chip2 span { display:block; font-size: calc(var(--s) * 12); line-height:1.3; letter-spacing:.08em;
  text-transform:uppercase; color: var(--ink-faint); }
.sc-chip2 b { font-family: var(--mono); font-size: calc(var(--s) * 17); font-weight:500;
  font-variant-numeric: tabular-nums; }
.sc-note { margin: calc(var(--s) * 14) 0 0; font-size: calc(var(--s) * 15); line-height:1.4;
  color: var(--ink-muted); }

/* IngredientList: rounded-card bg-surface-3, px-3 py-2.5, 28px box, border-2 */
.sc-row {
  display:flex; align-items:flex-start; gap: calc(var(--s) * 12);
  background: var(--surface-3); border-radius: var(--r-card);
  padding: calc(var(--s) * 10) calc(var(--s) * 12);
  margin-bottom: calc(var(--s) * 4);
  font-family: var(--serif); font-size: calc(var(--s) * 22); line-height:1.4; letter-spacing:-.005em;
  transition: background var(--feedback);
}
.sc-row .n { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: calc(var(--s) * 19); flex:0 0 auto; letter-spacing:-.01em; }
.sc-row .u { color: var(--ink-muted); }
.sc-row .t { flex:1; min-width:0; }
.sc-box {
  flex:0 0 auto; margin-top: calc(var(--s) * 2);
  width: calc(var(--s) * 28); height: calc(var(--s) * 28);
  /* round, and sage when it is ticked. It shipped as a black rounded square,
     which is neither: the product draws this as `rounded-pill border-2` and
     fills it `bg-sage`, and sage is reserved for done so it never competes
     with ember for the eye. */
  border-radius: 50%;
  background: var(--surface-4);
  border: calc(var(--s) * 2) solid var(--rule-strong);
  position:relative;
  transition: background var(--feedback), border-color var(--feedback);
}
.sc-box::after { content:""; position:absolute; left:29%; top:16%;
  width:30%; height:52%; border-right: calc(var(--s) * 2.4) solid var(--surface-2);
  border-bottom: calc(var(--s) * 2.4) solid var(--surface-2);
  transform: rotate(42deg) scale(.4); opacity:0;
  transition: opacity 140ms ease, transform 260ms cubic-bezier(0.34,1.56,0.64,1); }
.sc-row.done .sc-box { background: var(--sage); border-color: var(--sage); }
.sc-row.done .sc-box::after { opacity:1; transform: rotate(42deg) scale(1); }
.sc-row.done .t, .sc-row.done .n, .sc-row.done .u { color: var(--ink-faint); }
.sc-swap { margin-left:auto; display:flex; align-items:center; gap: calc(var(--s) * 4);
  font-family: var(--sans); font-size: calc(var(--s) * 15); color: var(--ink-muted); flex:0 0 auto; }

/* StepList, cook size: space-y-step 32, 28px tick, Newsreader body at 25 */
.sc-step { display:flex; gap: calc(var(--s) * 16); margin-bottom: calc(var(--s) * 32); }
.sc-tick { flex:0 0 auto; width: calc(var(--s) * 30); height: calc(var(--s) * 30);
  /* round and sage, same as the ingredient box and for the same reason */
  border-radius: 50%; background: var(--surface-4);
  border: calc(var(--s) * 2) solid var(--rule-strong);
  display:grid; place-items:center; font-family: var(--mono);
  font-size: calc(var(--s) * 15); color: var(--ink-muted);
  transition: background var(--feedback), border-color var(--feedback), color var(--feedback); }
.sc-step p { font-family: var(--serif); font-size: calc(var(--s) * 25); line-height:1.5;
  letter-spacing:-.01em; margin:0; max-width:none; }
.sc-step.done .sc-tick { background: var(--sage); border-color: var(--sage); color: var(--surface-4); }
.sc-step.done p { color: var(--ink-faint); }

/* CookBar: border-b border-rule, ember pulse dot, qty timer, chip-solid Done */
.sc-cookbar { display:flex; align-items:center; gap: calc(var(--s) * 8);
  padding: calc(var(--s) * 8) calc(var(--s) * 8) calc(var(--s) * 8) calc(var(--s) * 16);
  background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--rule); }
/* CookStatus, ported line for line. It is ONE row: an ember clock, the step's
   own verb at s-meta medium, then the countdown in mono at the same size and
   in full ink. It shipped here as a pulsing red dot over a stacked label and a
   12px muted clock, which is a different component wearing this one's name,
   and the size drop made the countdown the smallest thing in the bar when it
   is the only thing in the bar you look up to read. */
.sc-clock { flex:0 0 auto; width: calc(var(--s) * 16); height: calc(var(--s) * 16);
  color: var(--ember); animation: scAwake 2s ease-in-out infinite; }
@keyframes scAwake { 0%,100%{opacity:1} 50%{opacity:.55} }
.sc-cookbar .lab { font-size: calc(var(--s) * 15); line-height:1.4; font-weight:500;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sc-cookbar .clock { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: calc(var(--s) * 15); line-height:1.4; letter-spacing:0; color: var(--ink);
  flex:0 0 auto; }
.sc-cookbar .s-chip { margin-left:auto; }

.sc-h { font-size: calc(var(--s) * 20); line-height:1.3; letter-spacing:-.01em;
  font-weight:600; margin: calc(var(--s) * 20) 0 calc(var(--s) * 4); }
.sc-hint { font-size: calc(var(--s) * 15); color: var(--ink-faint); margin: 0 0 calc(var(--s) * 10); }
.kicker-s { font-size: calc(var(--s) * 12); line-height:1.3; letter-spacing:.08em;
  text-transform:uppercase; color: var(--ink-faint); margin:0; }

/* ── the Safari detection bar, ported from the extension's content.css ──
   Values are that file's, not approximations of it: #0F0F12 ground with a
   #27272A hairline, 8px radius, 12/12/12/20 padding, a 44px #FF6166 button
   with dark text and 20px of side padding, and the 240ms rise it ships with.
   The bar is dark while the app is light, deliberately: it lands on somebody
   else's page and a light bar disappears into the average recipe site. */

.sc-bar {
  position:absolute; left: calc(var(--s) * 12); right: calc(var(--s) * 12);
  bottom: calc(var(--s) * 12); z-index: 6;
  display:flex; align-items:center; gap: calc(var(--s) * 12);
  padding: calc(var(--s) * 12) calc(var(--s) * 12) calc(var(--s) * 12) calc(var(--s) * 20);
  background: #0f0f12; color: #fafafa;
  border: 1px solid #27272a; border-radius: var(--r-card);
  box-shadow: 0 calc(var(--s) * 8) calc(var(--s) * 32) rgba(0,0,0,.32);
  transform: translateY(calc(var(--s) * 8)); opacity: 0;
  transition: transform 240ms cubic-bezier(0.2,0,0,1), opacity 240ms cubic-bezier(0.2,0,0,1);
}
.sc-bar.up { transform: none; opacity: 1; }
.sc-bar-l { flex:1; min-width:0; }
.sc-bar-k { display:block; font-size: calc(var(--s) * 12); line-height:1.3;
  letter-spacing:.08em; text-transform:uppercase; color:#a1a1aa; }
.sc-bar-t { display:block; margin-top: calc(var(--s) * 4);
  font-size: calc(var(--s) * 15); line-height:1.4; font-weight:500; color:#fafafa;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sc-bar-save { flex:none; display:inline-flex; align-items:center; justify-content:center;
  min-height: calc(var(--s) * 44); padding: 0 calc(var(--s) * 20);
  background:#ff6166; color:#0f0f12; border-radius: var(--r-card);
  font-size: calc(var(--s) * 15); font-weight:500; line-height:1; }
.sc-bar-x { flex:none; display:inline-flex; align-items:center; justify-content:center;
  min-width: calc(var(--s) * 44); min-height: calc(var(--s) * 44);
  color:#a1a1aa; font-size: calc(var(--s) * 15); }

/* ── a recipe page that looks like a recipe page ── */
.sc-blog { position:absolute; inset:0; background:#fff; overflow:hidden; }
.sc-blog-scroll { position:absolute; inset: calc(var(--s) * 54) 0 auto 0; will-change:transform;
  transform: translateY(0); transition: transform 2600ms cubic-bezier(0.33,0,0.2,1); }
.sc-blog-scroll.go { transform: translateY(calc(var(--s) * -420)); }
.sc-blog-top { background:#2c3757; color:#fff; display:flex; align-items:center;
  justify-content:space-between; padding: calc(var(--s)*12) calc(var(--s)*16); }
.sc-blog-top b { font-size: calc(var(--s)*19); font-weight:800; letter-spacing:-.01em; }
.sc-blog-top i { font-style:normal; letter-spacing:.2em; font-size: calc(var(--s)*15); }
.sc-blog-band { background:#f0703a; color:#fff; text-align:center; font-weight:700;
  font-size: calc(var(--s)*12); padding: calc(var(--s)*8); }
.sc-blog-crumb { font-size: calc(var(--s)*11); color:#8e93a1; padding: calc(var(--s)*10) calc(var(--s)*16) 0; }
.sc-blog-title { font-size: calc(var(--s)*27); line-height:1.15; font-weight:800; color:#22263a;
  margin: calc(var(--s)*6) calc(var(--s)*16) calc(var(--s)*8); letter-spacing:-.02em; }
.sc-blog-stars { display:flex; gap: calc(var(--s)*8); align-items:center;
  padding: 0 calc(var(--s)*16) calc(var(--s)*10); font-size: calc(var(--s)*12); color:#8e93a1; }
.sc-blog-stars em { color:#e8b34a; font-style:normal; letter-spacing:1px; }
.sc-blog-acts { display:flex; gap: calc(var(--s)*8); padding: 0 calc(var(--s)*16) calc(var(--s)*12); }
.sc-blog-acts span { flex:1; text-align:center; border:1px solid #d8dae2; border-radius: calc(var(--s)*6);
  padding: calc(var(--s)*8) 0; font-size: calc(var(--s)*12); font-weight:600; color:#3b4152; }
.sc-blog-acts span.pin { background:#e8543f; color:#fff; border-color:#e8543f; }
.sc-blog-by { display:flex; align-items:center; gap: calc(var(--s)*9);
  padding: 0 calc(var(--s)*16) calc(var(--s)*12); font-size: calc(var(--s)*12); color:#8e93a1; }
.sc-blog-by img { width: calc(var(--s)*30); height: calc(var(--s)*30); border-radius:50%; object-fit:cover; }
.sc-blog p { font-size: calc(var(--s)*15); line-height:1.55; color:#3b4152;
  margin: 0 0 calc(var(--s)*11); padding: 0 calc(var(--s)*16); max-width:none; }
.sc-blog img.hero { width: calc(100% - var(--s)*32); margin: 0 calc(var(--s)*16) calc(var(--s)*12);
  aspect-ratio:16/10; object-fit:cover; border-radius: calc(var(--s)*6); display:block; }
.sc-blog-ad { margin: calc(var(--s)*14) calc(var(--s)*16); height: calc(var(--s)*104);
  border-radius: calc(var(--s)*6); background: linear-gradient(150deg,#2b9aa4,#17636f);
  display:grid; place-items:center; color:rgba(255,255,255,.85);
  font-size: calc(var(--s)*10); letter-spacing:.16em; text-transform:uppercase; }
.sc-blog-jump { display:block; margin: calc(var(--s)*4) calc(var(--s)*16) calc(var(--s)*14);
  background:#3fa46a; color:#fff; text-align:center; font-weight:800;
  font-size: calc(var(--s)*13); padding: calc(var(--s)*11); border-radius: calc(var(--s)*999); }
.sc-safaribar { position:absolute; inset:auto 0 0 0; height: calc(var(--s)*64);
  background:#f2f2f4; box-shadow: inset 0 1px 0 rgba(0,0,0,.12);
  display:flex; align-items:center; justify-content:center; z-index:4; }
.sc-url { background:#e2e2e6; border-radius: calc(var(--s)*999); color:#3b4152;
  font-size: calc(var(--s)*13); padding: calc(var(--s)*7) calc(var(--s)*24); }

.sc-screens { position:absolute; inset:0; }
.sc-screen { position:absolute; inset:0;
  transition: transform 620ms cubic-bezier(0.16,1,0.3,1), opacity 260ms ease; }
.sc-screen[data-out] { transform: translateY(calc(var(--s) * -26)); opacity:0; }
.sc-screen[data-in]  { transform: translateY(calc(var(--s) * 26)); opacity:0; }
/* the recipe screen scrolls a little once it opens, the way you would */
.sc-scrolls { transition: transform 1800ms cubic-bezier(0.33,0,0.2,1); transform: translateY(0); }
.sc-scrolls.down { transform: translateY(calc(var(--s) * -150)); }

/* ── ported: .field, .section-head, .kicker ── */
.s-field { display:flex; align-items:center; gap: calc(var(--s) * 10);
  height: calc(var(--s) * 48); border-radius: var(--r-card);
  border: 1px solid var(--rule-strong); background: var(--surface-3);
  padding: 0 calc(var(--s) * 16); font-size: calc(var(--s) * 17); color: var(--ink); }
.s-field svg { width: calc(var(--s) * 18); height: calc(var(--s) * 18); flex:0 0 auto; color: var(--ink-faint); }
.s-caret { display:inline-block; width: calc(var(--s) * 2); height: calc(var(--s) * 20);
  background: var(--ember); animation: scBlink 1s steps(2,start) infinite; }
@keyframes scBlink { to { opacity:0 } }
.s-sec { display:flex; align-items:center; gap: calc(var(--s) * 16);
  font-size: calc(var(--s) * 20); line-height:1.3; letter-spacing:-.01em; font-weight:600;
  margin: calc(var(--s) * 24) 0 calc(var(--s) * 12); }
.s-sec::after { content:""; height:1px; flex:1; background: var(--rule); }

/* ── Compare, as the app actually draws it: a summary panel whose differing
      values go ember, then the two recipes side by side ── */
.sc-sum { margin: calc(var(--s) * 16) calc(var(--s) * 20) 0;
  border-radius: var(--r-panel); border: 1px solid var(--rule);
  background: var(--surface-4); padding: calc(var(--s) * 18); }
.sc-sum-r { display:flex; align-items:baseline; gap: calc(var(--s) * 12);
  padding: calc(var(--s) * 11) 0; box-shadow: inset 0 -1px 0 var(--rule); }
.sc-sum-r:last-child { box-shadow:none; }
.sc-sum-r .k { flex:1; font-size: calc(var(--s) * 15); color: var(--ink-muted); }
.sc-sum-r .v { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: calc(var(--s) * 20); line-height:1.3; letter-spacing:-.01em;
  min-width: calc(var(--s) * 82); text-align:right;
  transition: color var(--feedback); }
.sc-sum-r.differs .v { color: var(--ember); }
.sc-sum-r.differs .k { color: var(--ink); }

.sc-sxs { display:grid; grid-template-columns:1fr 1fr; gap: calc(var(--s) * 12);
  margin: calc(var(--s) * 4) calc(var(--s) * 20) 0; }
.sc-panel { border-radius: var(--r-card); border: 1px solid var(--rule);
  background: var(--surface-3); overflow:hidden; height: calc(var(--s) * 300); position:relative; }
.sc-panel-h { position:absolute; inset:0 0 auto 0; z-index:2; background: var(--surface-3);
  box-shadow: inset 0 -1px 0 var(--rule); padding: calc(var(--s) * 8) calc(var(--s) * 12); }
.sc-panel-h b { display:block; font-size: calc(var(--s) * 15); font-weight:600;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sc-panel-h span { display:block; font-size: calc(var(--s) * 12); line-height:1.3;
  color: var(--ink-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sc-panel-b { position:absolute; inset: calc(var(--s) * 52) 0 auto 0;
  padding: 0 calc(var(--s) * 12) calc(var(--s) * 12);
  will-change:transform; transition: transform 900ms cubic-bezier(0.16,1,0.3,1); }
.sc-panel-b li { list-style:none; font-family: var(--serif);
  font-size: calc(var(--s) * 15); line-height:1.35; padding: calc(var(--s) * 4) 0; }
.sc-panel-b li .q { font-family: var(--mono); font-size: calc(var(--s) * 12);
  letter-spacing:0; color: var(--ink-muted); }

/* ── Library, ported: rounded-card bg-surface-3 p-3, 64px rounded-xs photo ── */
.sc-lib { position:absolute; inset:0 0 auto 0; padding: calc(var(--s)*8) calc(var(--s)*20) 0;
  will-change:transform; transition: transform 1200ms cubic-bezier(0.33,0,0.2,1); }
.sc-libcard { display:flex; align-items:center; gap: calc(var(--s) * 16);
  background: var(--surface-3); border-radius: var(--r-card);
  padding: calc(var(--s) * 12); margin-bottom: calc(var(--s) * 12); }
.sc-libcard img { width: calc(var(--s) * 64); height: calc(var(--s) * 64); flex:0 0 auto;
  border-radius: var(--r-xs); object-fit:cover; }
.sc-libcard b { display:block; font-size: calc(var(--s) * 17); line-height:1.35; font-weight:600;
  letter-spacing:-.01em; }
.sc-libcard span { display:block; font-size: calc(var(--s) * 15); color: var(--ink-muted);
  margin-top: calc(var(--s) * 2); }
.sc-star { margin-left:auto; color: var(--ink-faint); flex:0 0 auto; }
.sc-star.on { color: var(--ember); }

/* ── Find, ported ── */
.sc-field-top { position:relative; z-index:2; background: var(--surface-1);
  padding: calc(var(--s)*10) calc(var(--s)*20) calc(var(--s)*8);
  box-shadow: 0 calc(var(--s)*6) calc(var(--s)*8) calc(var(--s)*-6) rgba(16,16,20,.10); }
.sc-hits { position:absolute; inset: calc(var(--s)*128) 0 auto 0; z-index:1; padding: 0 calc(var(--s)*20);
  will-change:transform; transition: transform 1100ms cubic-bezier(0.33,0,0.2,1); }
.sc-hit { display:flex; gap: calc(var(--s) * 12); align-items:center;
  background: var(--surface-3); border-radius: var(--r-card);
  padding: calc(var(--s) * 10); margin-bottom: calc(var(--s) * 10);
  opacity:0; transform: translateY(calc(var(--s) * 10));
  transition: opacity 260ms ease, transform var(--entrance); }
.sc-hit.in { opacity:1; transform:none; }
.sc-hit img { width: calc(var(--s) * 52); height: calc(var(--s) * 52); border-radius: var(--r-xs);
  object-fit:cover; flex:0 0 auto; }
.sc-hit b { display:block; font-size: calc(var(--s) * 15); font-weight:600; line-height:1.3; }
.sc-hit span { display:block; font-size: calc(var(--s) * 12); line-height:1.3;
  color: var(--ink-muted); margin-top: calc(var(--s) * 3); }

/* ── the three quiet ones ──
   The page already moves a lot, so these hold still and change one thing
   each. They sit inside .tile-well-panel, which centres them and gives them
   the air they were missing when each was pinned to the top of a card its
   neighbour had stretched. */
.mini { position: relative; }
.mini-row { display: flex; align-items: center; gap: 10px; }
.mini-t { font-size: 14px; color: var(--ink-muted); min-width: 0; }
.mini-b { margin-left: auto; font-size: 13px; font-weight: 600; color: var(--sage); flex: 0 0 auto; }
.mini-status { justify-content: space-between; padding: 0 4px; }
.mini-status .mini-clock { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 13px; color: var(--ink-muted); }
.mini-status > span:last-child { display: flex; align-items: center; gap: 8px; }

/* the saved recipe that opens anyway, drawn as a library row so the claim is
   made by the thing itself rather than by a line of text about it */
/* wraps rather than squeezes. On the narrow card the badge and the 40px
   photo left the title 22 pixels, and a title in 22 pixels is a column of
   broken letters. Given a basis it takes the line, and the badge drops under
   it when there is genuinely no room. */
.mini-row-card { margin-top: 14px; padding: 10px 12px; gap: 10px 12px;
  flex-wrap: wrap;
  background: var(--surface-4); border-radius: var(--radius);
  box-shadow: 0 1px 2px rgba(16,16,20,.05); }
.mini-row-card img { width: 40px; height: 40px; flex: 0 0 auto;
  border-radius: 8px; object-fit: cover; }
/* the title wraps rather than truncates. At the narrowest card it was
   ellipsing to "Creamy Baked ...", which makes the one concrete thing in the
   panel look like a rendering fault. */
.mini-row-card .mini-t { flex: 1 1 130px; min-width: 0; color: var(--ink);
  font-weight: 600; font-size: 14px; line-height: 1.35; }

/* undo: the toast, with six seconds draining */
.mini-toast { display:flex; align-items:center; gap: 12px;
  background: var(--surface-4); color: var(--ink); border-radius: var(--radius);
  padding: 14px 16px; box-shadow: 0 8px 32px rgba(16,16,20,.12); }
.mini-toast p { flex:1; min-width:0; margin:0; font-size: 15px; color: var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.mini-toast b { color: var(--ember); font-size: 15px; font-weight: 600; }
.mini-ring { width: 20px; height: 20px; flex:0 0 auto; transform: rotate(-90deg); }
.mini-ring circle { fill:none; stroke-width: 2.4; }
.mini-ring .bg { stroke: var(--rule); }
.mini-ring .fg { stroke: var(--ember); stroke-linecap: round; stroke-dashoffset: 0;
  stroke-dasharray: 50.3; transition: stroke-dashoffset 1s linear; }

/* no signal: the bars go, the recipe stays */
.mini-sig { display:flex; align-items:center; gap: 4px; }
.mini-sig i { display:block; width: 3px; border-radius: 2px; background: var(--ink-faint);
  transition: background var(--feedback), opacity var(--feedback); }
.mini-sig i:nth-child(1){height:5px} .mini-sig i:nth-child(2){height:8px}
.mini-sig i:nth-child(3){height:11px} .mini-sig i:nth-child(4){height:14px}
.mini-sig.off i { background: var(--rule); }
.mini-plane { font-size: 13px; color: var(--ink-faint); }

/* share: the sheet */
.mini-sheet { border-radius: var(--radius); background: var(--surface-4);
  box-shadow: 0 8px 32px rgba(16,16,20,.10); overflow:hidden; }
.mini-sheet div { display:flex; align-items:center; gap: 10px; padding: 13px 14px;
  font-size: 14px; box-shadow: inset 0 -1px 0 var(--rule);
  transition: background var(--feedback); }
.mini-sheet div:last-child { box-shadow:none; }
.mini-sheet div.on { background: var(--sage-wash); font-weight: 600; }
.mini-sheet em { margin-left:auto; font-style:normal; font-size: 12px; color: var(--ink-faint); }

/* ── scene: Dynamic Island, a brisket running with the app closed ── */
.sc-island-wall { position:absolute; inset:0;
  background: linear-gradient(152deg,#3f6ea8 0%,#8d7f63 44%,#c9a06a 66%,#4a6f9e 100%); }
.sc-island-wall::after { content:""; position:absolute; inset:0;
  background: radial-gradient(120% 80% at 30% 20%, rgba(255,255,255,.18), transparent 60%); }
.sc-island { position:absolute; top: calc(var(--s) * 13); left:50%; transform: translateX(-50%);
  z-index:7; display:flex; align-items:center; gap: calc(var(--s) * 10);
  background:#000; border-radius: calc(var(--s) * 999);
  height: calc(var(--s) * 38); padding: 0 calc(var(--s) * 14);
  min-width: calc(var(--s) * 236);
  box-shadow: 0 calc(var(--s)*3) calc(var(--s)*10) rgba(0,0,0,.4); }
.sc-ring { width: calc(var(--s) * 17); height: calc(var(--s) * 17); border-radius:50%;
  box-shadow: inset 0 0 0 calc(var(--s) * 2) var(--ember); position:relative; flex:0 0 auto; }
.sc-ring::after { content:""; position:absolute; left:50%; top: calc(var(--s) * 3);
  width: calc(var(--s) * 1.6); height: calc(var(--s) * 6); background: var(--ember);
  border-radius: calc(var(--s) * 1); transform: translateX(-50%); }
.sc-island .lbl { color:#fafafa; font-size: calc(var(--s) * 15); font-weight:500; }
.sc-island .cd { margin-left:auto; color:#fafafa; font-family: var(--mono);
  font-size: calc(var(--s) * 15); font-variant-numeric: tabular-nums; }
.sc-icon { position:absolute; left: calc(var(--s) * 34); top: calc(var(--s) * 120); text-align:center; }
.sc-icon img { width: calc(var(--s) * 62); height: calc(var(--s) * 62);
  border-radius: calc(var(--s) * 14); display:block;
  box-shadow: 0 calc(var(--s)*6) calc(var(--s)*14) rgba(0,0,0,.3); }
.sc-icon span { display:block; color:#fff; font-size: calc(var(--s) * 12);
  margin-top: calc(var(--s) * 6); text-shadow: 0 1px 2px rgba(0,0,0,.5); }
.sc-live { position:absolute; left: calc(var(--s) * 16); right: calc(var(--s) * 16);
  bottom: calc(var(--s) * 40); border-radius: calc(var(--s) * 20);
  background: rgba(22,22,26,.72); backdrop-filter: blur(calc(var(--s)*18));
  padding: calc(var(--s) * 15) calc(var(--s) * 17); color:#fafafa; }
.sc-live .top { display:flex; align-items:center; gap: calc(var(--s) * 8);
  font-size: calc(var(--s) * 12); color:#a1a1aa; margin: 0 0 calc(var(--s) * 9); }
.sc-live .top b { color:#a1a1aa; font-weight:500; letter-spacing:.08em; }
.sc-livemark { display:inline-flex; color:#fafafa; }
.sc-livemark svg { width: calc(var(--s) * 15); height: calc(var(--s) * 15); display:block; }
.sc-live .row { display:flex; align-items:baseline; justify-content:space-between;
  gap: calc(var(--s) * 10); }
.sc-live .name { font-size: calc(var(--s) * 19); font-weight:600; letter-spacing:-.02em; }
.sc-live .big { font-family: var(--mono); font-size: calc(var(--s) * 24);
  font-variant-numeric: tabular-nums; }
.sc-live .bar { height: calc(var(--s) * 4); border-radius: calc(var(--s)*2);
  background: rgba(255,255,255,.18); margin-top: calc(var(--s) * 12); overflow:hidden; }
.sc-live .bar i { display:block; height:100%; background: var(--ember);
  border-radius: calc(var(--s)*2); transition: width 1s linear; }

/* ── the disagreement card, one row lit at a time ── */
.diff-row { transition: background var(--feedback), color var(--feedback); border-radius: 8px; }
.diff-row.lit { background: var(--ember-wash); }
.diff-row.lit .num { color: var(--ember); font-weight: 600; }
.diff-row.lit .diff-k { color: color-mix(in srgb, var(--ember) 72%, var(--ink-faint)); }

/* ── the debris is dismissible, a quiet easter egg ── */
.junk { pointer-events: none; }
.j [data-dismiss] { pointer-events: auto; cursor: pointer; }
.j.swept { transition: transform 620ms cubic-bezier(0.33, 0, 0.2, 1); }

/* ── the preview ──
   The video's own burned-in captions were cropped out, because inside a phone
   frame they pushed the app screen down and the phone stopped looking like a
   phone. They live next to it now as a chapter list that follows playback and
   that you can click to jump. That is better than a caption anyway: it makes
   the whole thirty seconds scannable without watching them. */

.band-watch { padding: 128px 0; }

.watch-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 296px;
  column-gap: clamp(40px, 6vw, 88px);
  align-items: start;
}
.watch-head { grid-column: 1; grid-row: 1; }
.chaps      { grid-column: 1; grid-row: 2; }
.watch-note { grid-column: 1; grid-row: 3; }
.watch-shot { grid-column: 2; grid-row: 1 / 4; align-self: center; }

.watch-head h2 { margin-bottom: 34px; }
.watch-note {
  color: #767680 !important; font-size: 14px;
  margin: 26px 0 0; padding-top: 20px; box-shadow: inset 0 1px 0 #27272a;
}

/* the chapters */
.chaps { list-style: none; margin: 0; padding: 0; max-width: 30em; }
.chaps li { box-shadow: inset 0 -1px 0 #1e1e24; }
.chaps li:last-child { box-shadow: none; }

.chaps button {
  position: relative;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  align-items: baseline;
  gap: 4px;
  width: 100%;
  padding: 13px 0 14px;
  background: none; border: 0; cursor: pointer;
  font: inherit; text-align: left;
  color: #8e8e99;
  transition: color var(--feedback);
}
.chaps button:hover { color: #c4c4cc; }
.ch-n { font-size: 13px; color: #6f6f79; transition: color var(--feedback); }
.ch-t { font-size: 17px; letter-spacing: -0.012em; }

.chaps [aria-current="true"] { color: #fafafa; }
.chaps [aria-current="true"] .ch-n { color: #fafafa; }
.chaps [aria-current="true"] .ch-t { font-weight: 600; }

/* a rule that fills across the chapter as it plays, so the list is also the
   scrubber */
.ch-bar {
  position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; grid-column: 1 / -1;
  overflow: hidden;
}
.ch-bar i { display: block; height: 100%; width: 0%; background: #fafafa; }
.chaps [aria-current="true"] .ch-bar i { transition: width 120ms linear; }

/* the phone */
.phone-video {
  max-width: 296px;
  margin-inline: 0;
  background: linear-gradient(158deg, #34343c, #17171c 42%, #2c2c34);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.5),
    0 40px 90px -30px rgba(0, 0, 0, 0.95),
    0 0 0 1px rgba(255, 255, 255, 0.06);
}
.watch-video {
  display: block; width: 100%; height: auto;
  border-radius: 34px; background: #0f0f12;
}

.watch-bar {
  display: flex; align-items: center; gap: 14px;
  margin-top: 22px; max-width: 296px;
}
.watch-btn {
  flex: 0 0 auto;
  width: 44px; height: 44px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: #fafafa; color: #101014;
  display: grid; place-items: center;
  transition: transform var(--feedback), background var(--feedback);
}
.watch-btn:hover { background: #fff; }
.watch-btn:active { transform: scale(0.94); }
.watch-btn svg { margin-left: 1px; }
.watch-btn.is-playing svg { margin-left: 0; }

.watch-track { flex: 1; height: 3px; border-radius: 2px; background: #2a2a30; overflow: hidden; }
.watch-track i { display: block; height: 100%; width: 0%; background: #fafafa; border-radius: 2px; }
.watch-time { flex: 0 0 auto; font-size: 13px; color: #8e8e99; }

.band-night :focus-visible { outline-color: #fafafa; }

@media (max-width: 900px) {
  .band-watch { padding: 96px 0; }
  /* the phone comes before the chapters on a phone, because a list of
     chapters for a video you have not seen yet is backwards */
  .watch-grid { grid-template-columns: 1fr; row-gap: 0; }
  .watch-head { grid-column: 1; grid-row: 1; margin-bottom: 30px; }
  .watch-shot { grid-column: 1; grid-row: 2; margin-bottom: 34px; }
  .chaps      { grid-column: 1; grid-row: 3; max-width: none; }
  .watch-note { grid-column: 1; grid-row: 4; }
  .phone-video, .watch-bar { max-width: 288px; }
}

/* ── compare's disagreement card ── */

.diff { margin-top: 34px; padding: 22px 24px; max-width: 420px; }
.diff-head {
  font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 14px;
}
.diff-list { margin: 0; }
.diff-list dt, .diff-list dd { margin: 0; }

.diff-row {
  display: flex; align-items: baseline; gap: 8px;
  padding: 10px 0; font-size: 17px;
  box-shadow: inset 0 -1px 0 var(--rule);
  color: var(--ink);
}
.diff-row:last-child { box-shadow: none; }
.diff-k { flex: 0 0 84px; color: var(--ink-faint); font-size: 14px; }
.diff-v { color: var(--ink-faint); font-size: 13px; }
/* the consequence, in prose. The card lists what differs; this says why you
   would care, which is the sentence a table cannot carry. */
.diff-foot { margin: 14px 0 0; font-size: 14px; line-height: 1.55;
  color: var(--ink-muted); max-width: 42ch; }

/* ── the extraction cascade ── */

.cascade { list-style: none; margin: 48px 0 0; padding: 0; counter-reset: none; }
.cascade li {
  display: flex; gap: 22px; align-items: baseline;
  padding: 22px 0;
  box-shadow: inset 0 -1px 0 var(--rule);
  /* each rung steps in along the fall vector, so the list reads as a
     descent rather than a stack */
  padding-left: calc(var(--i, 0) * 26px);
}
.cascade li:nth-child(1) { --i: 0; }
.cascade li:nth-child(2) { --i: 1; }
.cascade li:nth-child(3) { --i: 2; }
.cascade li:nth-child(4) { --i: 3; }
.cascade li:last-child { box-shadow: none; }

.cas-n { flex: 0 0 auto; font-size: 14px; color: var(--ink-faint); font-weight: 500; }
.cas-b { display: block; }
.cas-b strong {
  display: block; font-size: 19px; font-weight: 600; letter-spacing: -0.02em;
  margin-bottom: 4px;
}
.cas-b span { color: var(--ink-muted); font-size: 17px; }
.cas-b code {
  font-family: var(--mono); font-size: 14px;
  background: #eeeef1; padding: 1px 6px; border-radius: 5px;
}

.cascade-out {
  display: flex; align-items: center; gap: 16px;
  margin: 26px 0 0; padding-left: 104px; max-width: none;
}
.cas-arrow {
  width: 30px; height: 30px; flex: 0 0 auto;
  border-left: 2px solid var(--sage);
  border-bottom: 2px solid var(--sage);
  border-bottom-left-radius: 10px;
  margin-top: -16px;
}
/* sage means done and gathered, and it appears exactly once on this page */
.cas-land { color: var(--sage); font-weight: 600; font-size: 17px; }

/* ── Pro, later ──
   No spec row and no price card. There is nothing to buy yet, so a price card
   would be writing a cheque the page cannot cash, and the spec row that used to
   stand in for one was a labelled restatement of the two sentences above it. */

#pro h2 { max-width: 20ch; }
#pro p { font-size: 17px; }

.pro-note {
  margin: 28px 0 0;
  padding-top: 22px;
  box-shadow: inset 0 1px 0 var(--rule);
  font-size: 17px;
  color: var(--ink-faint);
}

/* ── everything else: the bento ──

   The grid is six columns and the spans are explicit, 4+2 / 3+3 / 2+4. They
   have to sum to a multiple of six or a row ends in a hole, which is exactly
   what happened when the interactive pieces went in and the spans stayed at
   4+2+2+3+3+3. Seventeen columns over six.

   The wide card changes sides between the first row and the last, and no row
   is three across.

   Card anatomy, one shape for all six: a body that sizes to its own text,
   then a WELL that takes every pixel of height the body did not. The well
   bleeds to the card's left, right and bottom edges. Precedent is Apple's
   product feature grid: the media is cropped by the card rather than fitted
   inside it, which is what makes two cards of different heights read as a
   composition instead of as a fitting accident. Stripe's docs cards are the
   precedent for the other well: one real UI fragment at its real size, with
   air around it, centred rather than pinned to the top of the box.

   Two wells and no third:
     .tile-well-stage  a recessed ground a device screen stands on
     .tile-well-panel  a flat ground holding one piece of product UI
*/

.more-head { margin-bottom: 56px; }
.more-head h2 { max-width: 21ch; }

.more-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 24px;
}

.tile {
  display: flex;
  flex-direction: column;
  background: var(--surface-3);
  border-radius: var(--radius);
  padding: 30px 28px;
  box-shadow: 0 1px 2px rgba(16, 16, 20, 0.04);
  overflow: hidden;
}
.tile p { font-size: 17px; margin-bottom: 0; }
.tile-body { flex: 0 0 auto; padding-bottom: 28px; }
.tile-2 { grid-column: span 2; }
.tile-3 { grid-column: span 3; }
.tile-4 { grid-column: span 4; }

/* ── the footer band ──
   Every card ends in a band of a FIXED height that bleeds to its left, right
   and bottom edges: 320 for a card carrying a device, 200 for one carrying a
   piece of UI. `margin-top: auto` puts the slack above the band, as card
   surface, rather than inside it.

   The first attempt let the band stretch to whatever height the row happened
   to be, which is how a 90px fragment ended up floating in the middle of a
   380px tray on a card its neighbour had made tall. A band of a known height
   means a card gains air and never gains emptiness, and it means the six
   cards share a baseline you can see across a row. */
.tile-well {
  flex: 0 0 auto;
  margin: auto -28px -30px;
  padding: 0 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* A device stands here. No tint and no tray: the screen is an object on the
   card's own surface, the same relationship the hero shot has, and a tinted
   ground behind it only ever read as the card having ended early.

   The window is shorter than the screen it holds, so the card crops the phone
   rather than the phone fitting the card. That is the whole difference between
   a composition and a fitting accident, and it is why Apple's product grid
   cuts its devices at the cell edge instead of scaling them down. */
.tile-well-stage {
  height: 320px;
  align-items: flex-end;
}
.tile-well-stage .tile-strip {
  width: min(100%, 348px);
  height: 320px;
  overflow: hidden;
  border-radius: 20px 20px 0 0;
  box-shadow: 0 22px 48px -26px rgba(16, 16, 20, 0.42);
}
/* the scene keeps its real phone proportion and runs off the bottom of the
   window. Overriding the aspect here rather than per-scene means the two
   cards crop identically, which is what makes the pair read as a pair. */
.tile-well-stage .scene {
  aspect-ratio: 428 / 926;
  border-radius: 20px 20px 0 0;
}

/* No device, so no shadow and no crop: one piece of product UI at its real
   size on a recessed tray. Stripe's docs cards are the precedent, and the
   thing they get right is the air around the fragment rather than under it.

   This one does NOT bleed, where the stage does. A recess is surface-1, which
   is also the colour of the band behind the whole grid, so a tray running to
   the card's edge dissolved into the page and read as the card having stopped
   early with a fragment loose beneath it. Inset, with its own radius, the card
   keeps its outline and the recess is unmistakably inside it.

   Surface-1 in a surface-3 card is a 4% step, which is the separation order in
   DESIGN.md doing its job before any border is reached. */
.tile-well-panel {
  height: 200px;
  margin: auto 0 0;
  padding: 0 20px;
  border-radius: 12px;
  background: var(--surface-1);
  box-shadow: inset 0 0 0 1px var(--rule);
}
.tile-well-panel .mini { width: 100%; max-width: 420px; }

/* The hero. Two columns inside the card rather than stacked, because it is
   the only one carrying a full-height phone and the only one that should
   read differently from the other five. */
.tile-wide {
  grid-column: span 4;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 196px;
  gap: 28px;
  align-items: center;
  padding-bottom: 0;
}
/* The shot is bottom-anchored; the prose is not. Letting both sit at the
   bottom left a band of dead space above every heading. */
.tile-wide .tile-body { align-self: center; padding-bottom: 0; }

/* A fixed window on the shot rather than a free-floating image. Left to size
   itself the phone stretched to whatever height the grid row happened to be
   and the screenshot came out visibly distorted. */
.tile-shot {
  align-self: end;
  height: 320px;
  overflow: hidden;
  border-radius: 18px 18px 0 0;
  box-shadow: 0 18px 40px -22px rgba(16, 16, 20, 0.34);
}
.tile-shot img {
  width: 100%;
  height: auto;
  border-radius: 18px 18px 0 0;
}

/* ── FAQ ──
   GOV.UK's disclosure pattern: a real <details>, no icon library,
   the question always visible and never truncated. */

.band-faq h2 { max-width: 22ch; margin-bottom: 40px; }

.qa {
  box-shadow: inset 0 -1px 0 var(--rule);
}
.qa summary {
  cursor: pointer;
  list-style: none;
  padding: 22px 44px 22px 0;
  font-size: 19px; font-weight: 600; letter-spacing: -0.018em;
  position: relative;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: "";
  position: absolute; right: 6px; top: 50%;
  width: 11px; height: 11px;
  border-right: 2px solid var(--ink-faint);
  border-bottom: 2px solid var(--ink-faint);
  transform: translateY(-70%) rotate(45deg);
  transition: transform var(--feedback);
}
.qa[open] summary::after { transform: translateY(-20%) rotate(-135deg); }
.qa p { padding: 0 0 24px; margin: 0; font-size: 17px; }
.qa a, .guide-body a, .foot-fine a {
  color: var(--ink); text-decoration-color: #c4c4cc; text-underline-offset: 3px;
  position: relative;
}
/* ported from the app's .tap-safe: a hit area big enough to hit, on a link
   that has to stay inline. The pseudo-element grows the target without
   touching the line box, so the sentence does not reflow. */
.qa a::after, .guide-body a::after {
  content: ""; position: absolute; inset: -12px -8px;
}

/* ── the conversion dock ──
   Phones only. It arrives once the hero has been read and stands down as
   soon as the page's own App Store button reaches the viewport, so there is
   never more than one ember element on screen. */

.dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: var(--surface-2);
  box-shadow: inset 0 1px 0 var(--rule), 0 -12px 28px -18px rgba(16, 16, 20, 0.34);
  transform: translateY(110%);
  transition: transform var(--entrance);
}
.dock.is-up { transform: none; }
.dock-t { margin: 0; font-size: 14px; font-weight: 500; color: var(--ink); max-width: none; }
.dock .btn-sm { flex: 0 0 auto; }

@media (max-width: 680px) {
  .dock { display: flex; }
  /* the footer would otherwise sit under the dock */
  .foot { padding-bottom: 108px; }
}

/* ── guides ──
   Standalone pages, each aimed at one question people actually type. Same
   tokens, same faces, no hero: these are documents, so they get a document's
   measure and rhythm. */

.guide { padding: 88px 0 120px; background: var(--surface-1); }
.guide-wrap { width: min(680px, 90vw); margin: 0 auto; }

.guide-head { margin-bottom: 48px; }
.guide-head h1 {
  font-size: clamp(2.1rem, 4.4vw, 3.1rem);
  line-height: 1.04; margin-bottom: 20px;
}
.guide-head .lede { max-width: none; font-size: 19px; }
.guide-meta {
  font-size: 13px; color: var(--ink-faint); margin: 24px 0 0;
  padding-top: 18px; box-shadow: inset 0 1px 0 var(--rule);
}

.guide-body h2 {
  font-size: 25px; max-width: 26ch;
  margin: 52px 0 16px; letter-spacing: -0.022em;
}
.guide-body h2:first-child { margin-top: 0; }
.guide-body p { font-size: 17px; max-width: none; }
.guide-body ul, .guide-body ol { margin: 0 0 18px; padding-left: 22px; color: var(--ink-muted); }
.guide-body li { margin-bottom: 9px; font-size: 17px; }
.guide-body li::marker { color: var(--ink-faint); }
.guide-body strong { color: var(--ink); font-weight: 600; }
.guide-body a { color: var(--ink); text-decoration-color: #c4c4cc; text-underline-offset: 3px; }
.guide-body code {
  font-family: var(--mono); font-size: 14px;
  background: #eeeef1; padding: 1px 6px; border-radius: 5px;
}

/* a table that scrolls on its own rather than pushing the page sideways */
.tbl-wrap {
  overflow-x: auto;
  margin: 0 0 22px;
  /* Scroll shadows that hide themselves at each end. The two `local` covers
     scroll with the content and paint over the two `scroll` shadows, so the
     hint only shows when there is genuinely more table to reach. */
  background:
    linear-gradient(to right, var(--surface-1) 60%, rgba(241,241,243,0)) left / 34px 100% no-repeat local,
    linear-gradient(to left,  var(--surface-1) 60%, rgba(241,241,243,0)) right / 34px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgba(16,16,20,.13), rgba(16,16,20,0)) left / 12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(16,16,20,.13), rgba(16,16,20,0)) right / 12px 100% no-repeat scroll;
}
.tbl-wrap:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; border-radius: 4px; }
.guide-body table { border-collapse: collapse; width: 100%; min-width: 460px; font-size: 15px; }
.guide-body th, .guide-body td {
  text-align: left; padding: 11px 14px 11px 0;
  box-shadow: inset 0 -1px 0 var(--rule);
}
.guide-body th {
  font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 600;
}
.guide-body td { color: var(--ink-muted); }
.guide-body td:first-child { color: var(--ink); font-weight: 500; }
.guide-body tbody tr:last-child td { box-shadow: none; }

.guide-cta {
  background: var(--surface-3); border-radius: var(--radius);
  padding: 28px; margin: 44px 0;
  box-shadow: 0 1px 2px rgba(16, 16, 20, 0.04);
}
.guide-cta p { margin-bottom: 20px; font-size: 17px; }
.guide-cta .btn { margin: 0; }

.related { margin-top: 64px; padding-top: 30px; box-shadow: inset 0 1px 0 var(--rule); }
.related h2 { font-size: 19px; margin: 0 0 16px; max-width: none; }
.related ul { list-style: none; margin: 0; padding: 0; }
.related li { box-shadow: inset 0 -1px 0 var(--rule); }
.related li:last-child { box-shadow: none; }
.related a {
  display: block; padding: 14px 0; font-size: 17px; font-weight: 500;
  color: var(--ink); text-decoration: none;
  transition: color var(--feedback);
}
.related a:hover { color: var(--ink-muted); }
.related span { display: block; font-size: 14px; color: var(--ink-faint); font-weight: 400; margin-top: 3px; }

@media (max-width: 680px) {
  .guide { padding: 56px 0 88px; }
  .guide-body h2 { font-size: 22px; margin-top: 40px; }
  .guide-cta { padding: 22px; }
}

/* ─────────────────────────── footer ─────────────────────────── */

.foot { background: var(--surface-1); padding: 72px 0 44px; box-shadow: inset 0 1px 0 var(--rule); }
.foot-inner {
  display: flex; flex-wrap: wrap; gap: 40px;
  align-items: flex-start; justify-content: space-between;
}
.foot-brand { color: var(--ink); }
.foot-brand p { font-size: 14px; color: var(--ink-faint); margin: 14px 0 0; }
.foot-guides { display: flex; flex-direction: column; gap: 8px; }
.foot-h {
  font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 4px;
}
.foot-guides a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 14px; color: var(--ink-muted); text-decoration: none;
  transition: color var(--feedback);
}
.foot-guides a:hover { color: var(--ink); }

.foot-links { display: flex; flex-wrap: wrap; gap: 8px 28px; align-content: flex-start; }
.foot-links a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 14px; color: var(--ink-muted); text-decoration: none;
  transition: color var(--feedback);
}
.foot-links a:hover { color: var(--ink); }
.foot-fine {
  width: min(1180px, 92vw); margin: 56px auto 0;
  font-size: 14px; line-height: 1.6; color: var(--ink-muted);
  padding-top: 24px; box-shadow: inset 0 1px 0 var(--rule);
  max-width: min(1180px, 92vw);
}
/* the legal line sits under the product line and below it in weight, so the
   two are not read as one paragraph of small print */
.foot-legal {
  width: min(1180px, 92vw); margin: 12px auto 0;
  max-width: min(1180px, 92vw);
  font-size: 13px; color: var(--ink-faint);
}

/* ─────────────────────────── scroll reveal ───────────────────────────
   entrance: 420ms, the house curve. A hard expo-out with no overshoot. */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--entrance), transform var(--entrance);
}
.reveal.in { opacity: 1; transform: none; }

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

/* As the gutters close, the field thins from the outside in. The popup and the
   "you may also like" grid are the last two to go, because they are the two
   pieces everybody recognises. */
@media (max-width: 1300px) {
  .j-comments, .j-author { display: none; }
}
@media (max-width: 1180px) {
  .j-rating, .j-social, .j-crumb { display: none; }
}
@media (max-width: 1040px) {
  .j-ad-b, .j-para { display: none; }
}
@media (max-height: 780px) {
  .j-jump { display: none; }
}

@media (max-width: 900px) {
  .hero { height: 200vh; height: 200svh; }
  .hero-stage { min-height: 620px; }
  .hero-grid { grid-template-columns: 1fr; gap: 28px; }
  /* One column, but a tablet is not a phone. The measure stays readable and
     the buttons stay side by side until there is genuinely no room, which is
     the 680px block below. */
  .hero-copy { max-width: 560px; }
  .hero-copy h1 { font-size: clamp(2.3rem, 7.4vw, 3.4rem); }
  .hero-copy .lede { max-width: 100%; font-size: 17px; }
  .hero-copy .eyebrow { margin-bottom: 14px; }
  .cta-row { margin: 26px 0 16px; gap: 10px; }

  /* One column has to hold the copy and the card inside one viewport, and the
     full card does not fit: at 430px the grid ran 978px tall inside an 843px
     stage and the bottom was simply clipped away. The card is an illustration
     of what Sift keeps, not a data table, so it shows three ingredients here
     and drops the method. The source line stays, because the link back to
     whoever wrote the recipe is the part that matters. */
  .hero-kept { justify-self: start; max-width: 320px; }
  .recipe-card { padding: 20px 20px 16px; }
  .card-title { font-size: 19px; }
  .card-meta { margin-bottom: 14px; }
  .ing li { padding: 5px 0; }
  .ing li:nth-child(n+4) { display: none; }
  .steps { display: none; }
  .card-src { margin-top: 14px; padding-top: 11px; }
  /* One column puts the card under the copy, so the grains land on top of the
     footnote if they stay on the left. They move to the card's other corner. */
  .grains { top: -64px; left: auto; right: 4px; width: 54px; height: 54px; }

  /* One column, so the rails move to the outer viewport edges and most of each
     piece hangs off the screen. The popup keeps a corner on screen because it
     is the piece that makes the joke land. */
  .j-modal   { left: auto; right: -96px; top: 8px; }
  .j-cookie  { left: auto; right: -140px; top: auto; bottom: 128px; }
  .j-ad-a    { right: auto; left: -92px; top: 46%; }
  .j-video   { right: auto; left: -104px; bottom: 84px; }
  .j-related { left: auto; right: -132px; bottom: 210px; }
  .j-sticky  { left: 50%; }
  .j-para, .j-rating, .j-social, .j-jump, .j-crumb,
  .j-comments, .j-ad-b, .j-author { display: none; }

  .split, .night-grid { grid-template-columns: 1fr; gap: 48px; }
  .split-flip .split-text { order: 1; }
  .split-flip .split-shot { order: 2; }
  /* wide enough for the compare pair; the single phone still caps at 340 */
  .split-shot { max-width: 400px; }
  .phone { margin-inline: 0; }
  .phone-pair { margin-inline: 0; }

  /* Two columns. The wide hero and the undo toast both take the full width,
     which keeps the count of half-width cards at four and the last row full.
     With undo at half width the grid ends on five halves and a hole. */
  .more-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tile-2, .tile-3 { grid-column: span 1; }
  .tile-4, .tile-wide { grid-column: span 2; }
  .tile-wide { grid-template-columns: minmax(0, 1fr) 200px; }
}

@media (max-width: 680px) {
  /* 17 is the documented floor and it holds on a phone too */
  /* At 390pt the breadcrumb wrapped to three lines and landed on top of the
     eyebrow. Four pieces bleeding off the edges still read as page debris;
     text-shaped junk in the copy's lane does not. */
  .j-modal   { right: -118px; top: 4px; }
  .j-cookie  { right: -168px; bottom: 116px; }
  .j-ad-a    { left: -108px; top: 44%; }
  .j-video   { left: -120px; bottom: 62px; }
  .j-related { display: none; }
  .hero-copy { max-width: 100%; }
  .hero-copy h1 { font-size: clamp(2.2rem, 9.4vw, 3rem); }
  .hero-copy .cta-row .btn { width: 100%; justify-content: center; }
  /* every tap target clears 44px */
  .nav-inner { height: 60px; }
  .band { padding: 96px 0; }
  .band-tight, .band-narrow, .band-faq { padding: 88px 0; }
  .band-night, .band-air { padding: 120px 0; }
  .nav-links { display: none; }
  .nav-inner { gap: 16px; }
  .btn-sm { margin-left: auto; }
  .hero { height: 190vh; }
  .hero-stage { min-height: 560px; }
  .cascade li { padding-left: 0; }
  .cascade-out { padding-left: 0; }
  .more-grid { grid-template-columns: minmax(0, 1fr); }
  .tile-2, .tile-3, .tile-4, .tile-wide { grid-column: span 1; }
  /* one column: the hero stacks like every other card, prose then shot */
  .tile-wide { grid-template-columns: minmax(0, 1fr); padding-bottom: 0; }
  .tile-wide .tile-body { padding-bottom: 24px; }
  /* justify-self, not margin-inline:auto. On a stretched grid item auto side
     margins make the box shrink-to-fit, and its only child is width:100% of
     that box, so the whole shot resolved to zero wide and the card rendered
     as a tall empty rectangle on every phone. */
  .tile-shot { height: 260px; width: 100%; max-width: 240px;
    justify-self: center; align-self: center; }
  .tile-well-stage, .tile-well-stage .tile-strip { height: 280px; }
  .tile-well-panel { height: 184px; }
  .foot-inner { flex-direction: column; gap: 28px; }
}

/* ─────────────────────────── reduced motion ───────────────────────────
   The pin is dropped entirely. The hero becomes one static screen with
   the debris at rest and the recipe already resolved, and the page still
   makes its point without anything moving. */

/* The pin is dropped whenever the composition cannot fit the viewport it is
   given. On a short phone the copy and the card together ran taller than the
   stage and the bottom of the card was silently clipped; main.js measures for
   that on load and on resize and sets .is-static, which is the same layout
   reduced motion gets. */
.hero.is-static { height: auto; }
.hero.is-static .hero-stage {
  /* relative, not static. Unpinning it to static moved the debris field's
     containing block up to .hero, and overflow:hidden here stopped clipping
     it: the page grew a 104px horizontal scroll. */
  position: relative; height: auto; min-height: 0; padding: 72px 0 104px;
}
.hero.is-static .recipe-card { -webkit-mask-image: none; mask-image: none; }
.hero.is-static .scroll-hint { display: none; }
.hero.is-static .ing li:nth-child(n+4),
.hero.is-static .steps { display: revert; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero { height: auto; }
  .hero-stage { position: relative; height: auto; min-height: 0; padding: 80px 0 110px; }
  .recipe-card { -webkit-mask-image: none; mask-image: none; }
  .scroll-hint { display: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .btn, .nav-links a, .qa summary::after { transition: none; }
}
