/* Pukki website. Two kinds of page share this file:

   - the home page, `.poster`: five pages on one screen, the app's onboarding story in the
     app's own order and words. Its reference frame is 1440 x 900 on a desktop and
     390 x 720 on a phone; every size in it is counted in that frame's pixels (--px), so
     the whole composition scales as one poster and never needs to scroll on a desktop;
   - the documents (privacy, terms, the support reply page): ordinary scrolling pages that
     take the colours, the nav and the footer from here and their own layout from
     legal.css or support-reply.css.

   Colours and typefaces are :root's and shared, with the documents' few sizes. The
   poster's whole scale is `.poster`'s own, so a document's type never follows the
   height of its window. */

:root {
  /* ------------------------------------------------------------------ colour
     Nothing neutral is warm; colour is an accent, never the canvas. The paper and every
     ink, rule and fill below are R == G == B, the same system as the app (Palette.swift).
     Hue lives only in the Puff, its glow, the drawn marks, the handwriting and the focus
     ring. Ratios against --paper are noted per line; 4.5 is the bar for text. */
  --paper: #FFFFFF;             /* page */
  --ink: #0E0E0E;               /* headlines                                 19.3:1 */
  --ink-strong: #202020;        /* body, titles, the wordmark                16.3:1 */
  --action: #232323;            /* primary buttons                           15.7:1 */
  --graphite: #2A2A2A;          /* the stage control, the signature          14.4:1 */
  --ink-mid: #363636;           /* the pencil                                12.1:1 */
  --ink-mid-2: #474747;         /* the cover's whys, letter text, hover       9.3:1 */
  --ink-soft: #6A6A6A;          /* subtitles, labels, small print             5.4:1 */
  --ink-faint: #6F6F6F;         /* sources, legal                             5.0:1 */
  /* The stage's "supportive" ink: a child's hesitation, the idle prompt. The app sets it
     at #8A8A8A, which only clears 3:1; here it also sets type under 24px on a small
     window, so it takes the lightest grey that still clears 4.5.              4.5:1 */
  --ink-supportive: #767676;
  --ink-faint-2: #C8C8C8;       /* an unvisited page's dash, a rule: a shape, not text */
  --hairline: rgba(32, 32, 32, .14);
  --card: #F5F5F5;              /* Home's cards, the week's bubbles                 */
  --fill: #EFEFEF;              /* the sheet's Close button                         */
  --fill-pressed: #E4E4E4;

  /* The authored accents, the app's own (Palette's accent family). A raw accent is for a
     drawn mark or a glyph; type set in an accent takes its darker label counterpart,
     which keeps the hue and clears AA. */
  --accent-gold: #F5B94A;
  --accent-violet: #A78BF0;
  --accent-sky: #7FA6F0;
  --label-gold: #90671D;        /*                                            5.2:1 */
  --label-violet: #7860B7;      /*                                            5.0:1 */
  --label-sky: #436CC1;         /* also links and the focus ring              5.0:1 */
  --wash-gold: rgba(245, 185, 74, .16);

  /* -------------------------------------------------------------------- type
     The platform's own UI face: SF on the Apple devices that walk to the App Store, so
     the site sets in the app's typeface. Self-hosting SF Pro would breach Apple's
     licence; don't. The wordmark is a logotype in the rounded face. Handwriting is
     Caveat, the face the app bundles for its margin notes (SIL OFL, assets/fonts): a
     note from the people who made Pukki, pointing at something real, plus the
     signature. Never a heading, never a control. */
  --font: -apple-system, system-ui, 'Helvetica Neue', 'Segoe UI Variable', 'Segoe UI', Roboto, Arial, sans-serif;
  --font-rounded: ui-rounded, 'SF Pro Rounded', -apple-system, system-ui, sans-serif;
  --font-hand: 'Caveat', 'Bradley Hand', 'Segoe Print', cursive;

  /* ------------------------------------------------------------- documents
     What the scrolling pages size themselves with: one small type step, one spacing
     unit and its multiples, a measure. The poster has a scale of its own, below. */
  --ink-quiet: var(--ink-soft);
  --ink-quiet-3: #858585;       /* a list marker: a shape, not text           3.7:1 */
  --t-small: clamp(.8125rem, .5rem + .5vw, .875rem);                     /* 13-14 */
  --tr-soft: -.004em;
  /* Height-capped, as it has always been: a short window gets a little less air. */
  --u: clamp(4px, min(.56vw, .8dvh), 8px);
  --s2: calc(var(--u) * 2);
  --s3: calc(var(--u) * 3);
  --s5: calc(var(--u) * 5);
  --s6: calc(var(--u) * 6);
  --s8: calc(var(--u) * 8);
  --s10: calc(var(--u) * 10);
  --inset: clamp(20px, 5vw, 72px);
  --measure: 1180px;

  /* motion */
  --ease-lift: cubic-bezier(.2, .7, .2, 1);
}


@font-face {
  font-family: 'Caveat';
  /* One variable font: semibold is a point on its weight axis, as in the app. The WOFF2
     is the same font cut down to Latin (73 KB against the full TTF's 404 KB) and is what
     every current browser takes; the TTF stays as the fallback and as the source to
     cut it from again (README, "Type, colour and the hand"). */
  src: url('assets/fonts/Caveat-latin.woff2') format('woff2'),
       url('assets/fonts/Caveat.ttf') format('truetype');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

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

/* The UA rule for [hidden] is a bare `display: none`, so any class that sets a display
   value beats it. Hidden must mean hidden. */
[hidden] { display: none !important; }

html {
  /* Safari on a phone inflates text on its own when turned to landscape, which would
     undo the scale above. 100%, not none: none also blocks the visitor's zoom. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-strong);
  font-family: var(--font);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

h1, h2, h3, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: var(--ink-strong); text-decoration: none; }
button { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--label-sky);
  outline-offset: 3px;
}

/* A headline takes the focus when its page arrives, so a keyboard or a screen reader
   lands on the new page rather than on a link that has just been hidden. It is not a
   control, so it draws no ring. */
[tabindex="-1"]:focus { outline: none; }

.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ------------------------------------------------------------- drawn glyphs
   One stroke family, the app's: round caps, round joins, no fills. Stroke weights are
   in each glyph's own grid, as in the app, so a glyph's ink scales with its size. */

.icon,
.mark {
  display: block;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}

.icon { width: 1.25em; height: 1.25em; stroke-width: 1.5; }
.mark { stroke-width: 2; }

.mark--gold { color: var(--accent-gold); }
.mark--violet { color: var(--accent-violet); }
.mark--sky { color: var(--accent-sky); }

/* A few words written beside what they are about. Broken by hand where they break at
   all: a note that wraps has become a paragraph. */
.hand {
  font: 600 var(--t-hand)/1 var(--font-hand);
  white-space: nowrap;
}

.hand--gold { color: var(--label-gold); }
.hand--violet { color: var(--label-violet); }
.hand--sky { color: var(--label-sky); }

/* The word with a coloured-pencil line under it. inline-block, so the word and its line
   are one box that never straddles a wrap; the line is positioned, so it costs the
   headline no height. */
.marked {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}

.marked__line {
  position: absolute;
  left: -.02em;
  right: -.02em;
  bottom: -.11em;
  width: auto;
  height: .16em;
  overflow: visible;
  pointer-events: none;
}

/* A pencil, not a rule: the stroke is one weight whatever the word's width, and it is
   drawn once, after the headline has landed. */
.marked__line path {
  fill: none;
  stroke: var(--accent-gold);
  stroke-linecap: round;
  stroke-width: max(2px, .05em);
  vector-effect: non-scaling-stroke;
  opacity: .9;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: drawMark .42s ease-out .55s forwards;
}

@keyframes drawMark {
  to { stroke-dashoffset: 0; }
}

/* ---------------------------------------------------------------- page
   What every page shares: a column the height of the window at least, the nav, the
   wordmark, and (on the documents) the footer. */

.page {
  min-height: 100vh;
  /* dvh, so the phone's collapsing URL bar is part of the budget rather than a
     surprise 90px the page overflows by. */
  min-height: 100dvh;
  padding: var(--s5) var(--inset) var(--s5);
  display: flex;
  flex-direction: column;
  overflow-x: clip;
}

.nav {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  position: relative;
  z-index: 2;
}

.wordmark {
  display: inline-flex;
  flex-direction: column;
  /* The swash sits under the word, inset a touch from the left so its drawn start
     lines up optically with the p's stem rather than with the glyph box. */
  align-items: flex-start;
  gap: 4px;
  /* A 44pt target around a 36px lockup: padding grows the hit area and the negative
     margin gives the same amount back, so the nav's height does not move. */
  padding-block: 4px;
  margin-block: -4px;
}

.wordmark__text {
  /* A logotype, not a step on any type scale: it keeps the rounded face and a weight
     the interface never uses, at one size on every page and every window. */
  font: 600 23px/1 var(--font-rounded);
  letter-spacing: -.02em;
  color: var(--ink-strong);
}

/* The wordmark's swash is drawn in the same pencil as the Puff's marks. */
.wordmark__underline {
  display: block;
  width: 53px;
  height: 9px;
  margin-left: 1px;
  color: var(--ink-mid);
}

.wordmark:hover .wordmark__text { color: var(--ink-mid-2); }

/* ---- the documents' footer ---------------------------------------------------- */

.footer {
  margin-top: var(--s10);
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-top: var(--s3);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--u) var(--s3);
}

/* The whole footer is one size. The claim is told apart by weight and ink, not by
   being a step bigger than the small print beside it. */
.footer__claim {
  font: 500 var(--t-small)/1.4 var(--font);
  letter-spacing: var(--tr-soft);
  color: var(--ink-strong);
}

.footer__claim-soft { font-weight: 400; color: var(--ink-faint); }

.footer__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--u) var(--s2);
  font: 400 var(--t-small)/1.4 var(--font);
  letter-spacing: var(--tr-soft);
  color: var(--ink-quiet);
}

.footer__legal { display: flex; justify-content: flex-end; }

.footer__link { color: var(--ink-quiet); }
.footer__link:hover { color: var(--ink-strong); }

@media (max-width: 899px) {
  /* Stacked: the statement, then the small print. */
  .footer {
    margin-top: var(--s6);
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    gap: var(--u);
  }

  .footer__legal { justify-content: flex-start; }
  .footer__link { min-height: 24px; }
}

/* ============================================================== the poster
   The home page. One full-viewport composition: the nav, the page that is up, and a
   bottom line shared by that page's buttons (right) and the pager and legal links (left). */

.poster {
  /* One unit: a pixel of the 1440 x 900 reference frame. It takes the smaller of the
     window's width and height shares, so a wide-but-short laptop (1512 x 810) shrinks
     the whole poster rather than scrolling it. Under .62 (a window shorter than about
     560px) the page stops shrinking and scrolls instead; over 1.15 it stops growing. */
  --px: clamp(.62px, min(100vw / 1440, 100vh / 900), 1.15px);

  /* A visitor's own text-size setting still moves the type: each step adds the
     difference between their root size and the default 16px, in proportion. At the
     default this term is zero. */
  --rem-delta: calc(1rem - 16px);

  /* Sizes in frame pixels. The small steps carry a floor so a short window does not
     take them under what can be read; the large ones scale freely. */
  --t-display: calc(76 * var(--px) + var(--rem-delta) * 4.75);              /* the cover's headline */
  --t-chapter: calc(64 * var(--px) + var(--rem-delta) * 4);                 /* a page's headline */
  --t-chapter-long: calc(56 * var(--px) + var(--rem-delta) * 3.5);          /* page 04's two full sentences */
  --t-title: calc(max(17px, 24 * var(--px)) + var(--rem-delta) * 1.5);      /* a finding, a card's question */
  --t-lead: calc(max(15px, 21 * var(--px)) + var(--rem-delta) * 1.3125);    /* subtitles */
  --t-why: calc(max(14px, 20 * var(--px)) + var(--rem-delta) * 1.25);       /* the whys around the cloud */
  --t-body: calc(max(15px, 19 * var(--px)) + var(--rem-delta) * 1.1875);    /* the letter */
  --t-text: calc(max(14px, 17 * var(--px)) + var(--rem-delta) * 1.0625);    /* findings, buttons */
  --t-label: calc(max(13px, 15 * var(--px)) + var(--rem-delta) * .9375);    /* eyebrows, footnotes */
  --t-small: calc(max(12px, 14 * var(--px)) + var(--rem-delta) * .875);     /* nav, small print */
  --t-legal: calc(max(12px, 13 * var(--px)) + var(--rem-delta) * .8125);    /* sources, legal */
  --t-hand: calc(max(21px, 34 * var(--px)) + var(--rem-delta) * 2.125);     /* a margin note */
  --t-hand-small: calc(max(20px, 30 * var(--px)) + var(--rem-delta) * 1.875);

  /* layout */
  --inset: 20px;                              /* the least the poster keeps from a window's edge */
  --measure: calc(1180 * var(--px));          /* nav, pages and footer share one width */
  --text-col: calc(540 * var(--px));
  --col-gap: calc(70 * var(--px));
  --button-h: max(44px, calc(60 * var(--px)));

  /* The week map is the app's WeekMap, drawn on the app's own 322 x 232 points: one map
     point is --m, so its coordinates below are the app's coordinates. */
  --m: calc(1.35 * var(--px));
  padding: calc(44 * var(--px)) var(--inset) calc(40 * var(--px));
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  /* `1fr`, not `minmax(0, 1fr)`: a page taller than the window has to push the
     buttons down and scroll, not shrink its row and draw over them. */
  grid-template-rows: auto 1fr;
  justify-items: center;
}

/* dvh, so a phone's collapsing URL bar is part of the budget rather than a surprise the
   page overflows by. Declared again rather than in place: a browser without dvh keeps
   the vh line above. */
@supports (height: 100dvh) {
  .poster { --px: clamp(.62px, min(100vw / 1440, 100dvh / 900), 1.15px); }
}

.deck,
.meta {
  width: 100%;
  max-width: var(--measure);
}

/* ----------------------------------------------------------------- nav */

.poster .nav {
  gap: calc(24 * var(--px));
  min-height: calc(44 * var(--px));
}

.nav__links {
  display: flex;
  align-items: center;
  gap: calc(28 * var(--px));
}

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  color: var(--ink-soft);
  font: 400 var(--t-small)/1 var(--font);
  letter-spacing: -.004em;
  transition: color 200ms;
}

.nav__link .icon { width: 17px; height: 17px; stroke-width: 1.9; }
.nav__link:hover { color: var(--ink-strong); }

/* The App Store, on every page: the pages turn with their own button, so the way out to
   the store stays in one place above them. */
.store {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: max(40px, calc(44 * var(--px)));
  padding: 0 calc(max(14px, 16 * var(--px))) 0 calc(max(12px, 14 * var(--px)));
  border-radius: calc(max(12px, 13 * var(--px)));
  background: var(--action);
  color: var(--paper);
  font: 600 var(--t-small)/1 var(--font);
  transition: background 200ms;
}

.store__logo { display: block; width: 13px; height: 16px; }
.store:hover { background: var(--ink-mid-2); }
.store:active { background: var(--ink); }

/* ---------------------------------------------------------------- deck
   Which page is up is the URL's fragment, and the pages' own links are plain fragment
   links. With the script running, main.js marks the page the fragment names
   (`data-current`) and the stylesheet shows that one. Without it, the stylesheet shows
   the `:target` page itself, and the first when nothing is targeted.

   The script path exists because the second rule cannot be relied on while pages turn:
   Chrome does not re-evaluate `:has(:target)` when the fragment changes, so the pager
   kept its dash on the first page and a page could be left standing. */

.deck {
  grid-row: 2;
  grid-column: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  /* A page turn by swipe is horizontal; the page's own scroll, where it has one, stays
     vertical and stays the browser's. */
  touch-action: pan-y pinch-zoom;
}

.slide {
  display: none;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: 1fr auto;
  /* A fragment link scrolls its target into view. Where the page is taller than the
     window (a phone on its side) that should mean the top of the page, nav included. */
  scroll-margin-top: 100vh;
}

.js .slide[data-current],
html:not(.js) .slide:target,
html:not(.js) .deck:not(:has(> .slide:target)) > .slide:first-child {
  display: grid;
}

/* A browser without :has() cannot tell that nothing is targeted, so it would show no
   page at all. It gets the story as one long page instead. */
@supports not selector(:has(*)) {
  .slide { display: grid; padding-block: calc(40 * var(--px)); }
}

.slide__body { align-self: center; }

/* Text left, picture right. The text column is one width on every page so the
   headline does not jump sideways as the pages turn. */
.split {
  display: grid;
  grid-template-columns: var(--text-col) minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: var(--col-gap);
  align-content: center;
  align-items: center;
}

.split__text {
  grid-column: 1;
  grid-row: 1 / span 2;
  display: flex;
  flex-direction: column;
  gap: calc(22 * var(--px));
}

.split__picture {
  grid-column: 2;
  grid-row: 1 / span 2;
}

/* Small print under the text column, where a page has some. */
.split:has(> .split__aside) > .split__text { grid-row: 1; align-self: end; }
.split__aside { grid-column: 1; grid-row: 2; align-self: start; margin-top: calc(48 * var(--px)); }

/* A page arrives rather than switching on: its text, then its picture, then its small
   print. `backwards` only, so nothing here holds a value after it has run. */
.slide__body > .split__text,
.slide__body > .split__picture,
.slide__body > .split__aside,
.slide > .actions {
  animation: arrive .5s var(--ease-lift) backwards;
}

.slide__body > .split__picture { animation-delay: 80ms; }
.slide__body > .split__aside { animation-delay: 160ms; }
.slide > .actions { animation-delay: 200ms; animation-name: appear; }

@keyframes arrive {
  from { opacity: 0; translate: 0 10px; }
}

@keyframes appear {
  from { opacity: 0; }
}

/* ---- headings ---------------------------------------------------------------- */

.display,
.chapter {
  font-family: var(--font);
  font-weight: 600;
  letter-spacing: -.022em;
  color: var(--ink);
}

.display { font-size: var(--t-display); line-height: 1.02; }
.chapter { font-size: var(--t-chapter); line-height: 1.04; }
.chapter--long { font-size: var(--t-chapter-long); line-height: 1.06; }

/* Set apart in the softer ink: it is an admission, not a third line of the sentence. */
.chapter__turn { color: var(--ink-soft); }

.lead {
  max-width: calc(440 * var(--px));
  font: 400 var(--t-lead)/1.4 var(--font);
  letter-spacing: -.01em;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.label {
  font: 600 var(--t-label)/1.3 var(--font);
  color: var(--ink-soft);
}

.source {
  font: 400 var(--t-legal, .8125rem)/1.4 var(--font);
  color: var(--ink-faint);
}

/* A source that leads to its paper keeps the source's ink; the line under it says it is a link. */
.source a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--ink-faint-2);
  text-underline-offset: .18em;
}

.source a:hover { color: var(--ink-strong); text-decoration-color: currentColor; }

.footnote {
  font: 400 var(--t-small)/1.4 var(--font);
  color: var(--ink-soft);
}

/* ------------------------------------------------------------- buttons
   The app's primary: filled, one height, one radius. Each page has exactly one. */

.actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: calc(12 * var(--px));
  min-height: var(--button-h);
  position: relative;
  z-index: 1;
}

.actions__aside {
  margin-right: calc(8 * var(--px));
  font: 400 var(--t-small)/1.4 var(--font);
  color: var(--ink-soft);
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(10 * var(--px));
  height: var(--button-h);
  padding: 0 calc(28 * var(--px));
  border: 0;
  border-radius: calc(max(14px, 17 * var(--px)));
  font: 600 var(--t-text)/1 var(--font);
  letter-spacing: -.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: background 200ms, transform 200ms var(--ease-lift);
}


.button--primary {
  min-width: calc(196 * var(--px));
  background: var(--action);
  color: var(--paper);
}

.button--primary:hover { background: var(--ink-mid-2); transform: translateY(-1px); }

/* Under a finger it settles rather than lifts, and darkens to the headline's ink. */
.button--primary:active { background: var(--ink); transform: none; transition-duration: 80ms; }

/* The store's lockup: the small kicker over the store's name, as on the official badge. */
.badge { gap: calc(12 * var(--px)); padding: 0 calc(24 * var(--px)) 0 calc(22 * var(--px)); text-align: left; }
.badge__logo { display: block; flex: none; width: calc(max(16px, 20 * var(--px))); height: calc(max(19px, 24 * var(--px))); }
.badge__stack { display: flex; flex-direction: column; gap: 3px; }
.badge__kicker { font: 400 calc(max(10px, 11 * var(--px)))/1 var(--font); letter-spacing: .012em; opacity: .78; }
.badge__name { font: 500 var(--t-text)/1.1 var(--font); letter-spacing: -.01em; }

.textlink {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--label-sky);
  font: 500 var(--t-label)/1 var(--font);
  cursor: pointer;
}

.textlink:hover { text-decoration: underline; text-underline-offset: .2em; }

/* -------------------------------------------------------------- footer
   The pager and the legal links share the buttons' line: they sit in the deck's own
   grid cell, at its bottom left, across from the page's buttons. */

.meta {
  grid-row: 2;
  grid-column: 1;
  align-self: end;
  display: flex;
  align-items: center;
  gap: calc(28 * var(--px));
  min-height: var(--button-h);
  /* The row spans the measure, over the buttons; only its own contents take a click. */
  pointer-events: none;
  position: relative;
  z-index: 1;
}

.meta > * { pointer-events: auto; }

/* Five dashes, one per page. A dash is a link like any other; the hit area is the
   anchor, the drawn mark is the line inside it. */
.pager {
  display: flex;
  gap: calc(8 * var(--px));
}

.pager a {
  display: flex;
  align-items: center;
  width: calc(max(22px, 32 * var(--px)));
  height: 44px;
}

.pager i {
  display: block;
  width: 100%;
  height: 3px;
  border-radius: 2px;
  background: var(--ink-faint-2);
  transition: background 200ms;
}

.pager a:hover i { background: var(--ink-soft); }

/* The page that is up: the dash main.js marks `aria-current`, or without the script the
   one whose page is targeted. */
.pager a[aria-current] i,
html:not(.js) .page:has(#how-it-works:target) .pager [href="#how-it-works"] i,
html:not(.js) .page:has(#why-it-matters:target) .pager [href="#why-it-matters"] i,
html:not(.js) .page:has(#your-role:target) .pager [href="#your-role"] i,
html:not(.js) .page:has(#why-we-built-it:target) .pager [href="#why-we-built-it"] i,
html:not(.js) .page:not(:has(.slide:target:not(#top))) .pager [href="#top"] i {
  background: var(--ink-strong);
}

.meta__list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px calc(20 * var(--px));
  font: 400 var(--t-legal)/1.4 var(--font);
  color: var(--ink-faint);
}

.meta__link { color: var(--ink-faint); }
.meta__link:hover { color: var(--ink-strong); }

/* The year gives way to the links. With About and Questions in the row, five links are what
   fits across from a page's buttons: the row lies over the buttons' line, and with the year
   as well it ran under page 5's small print at 900 and 1024 wide. The year is in every
   document's footer. (Measured 2026-10-05 with _src/fit.html; README, "Responsive".) */
.meta__list [data-copyright] { display: none; }

/* =============================================================== 01 · cover
   The cover's own composition rather than the template: the artwork owns the picture
   column, a child's questions sit around it, and nothing prints an answer. Positions
   are the reference frame's, in a 670 x 640 box. */

.split--cover {
  grid-template-columns: calc(470 * var(--px)) minmax(0, 1fr);
  column-gap: calc(40 * var(--px));
  position: relative;
}

.cover__title { gap: calc(24 * var(--px)); }
.cover__title .lead { max-width: calc(430 * var(--px)); }

.scene {
  grid-column: 2;
  grid-row: 1 / span 2;
  justify-self: end;
  position: relative;
  width: calc(670 * var(--px));
  height: calc(640 * var(--px));
}

/* ---- the cloud --------------------------------------------------------------- */

/* The frame the Puff is drawn in. */
.cloud {
  position: absolute;
  left: calc(55 * var(--px));
  top: calc(40 * var(--px));
  width: calc(560 * var(--px));
  height: calc(560 * var(--px));
}

/* On white the Puff's own glow is a near-white wash that vanishes into the ground. The
   Puff's violet and sky, faint, give the silhouette back: the app's light-mode halo.
   A plain gradient, no blur filter. */
.cloud__glow {
  position: absolute;
  inset: -5.4%;
  border-radius: 50%;
  background: radial-gradient(circle closest-side,
    rgba(167, 139, 240, .30) 0%,
    rgba(127, 166, 240, .18) 55%,
    rgba(127, 166, 240, 0) 100%);
  opacity: .85;
}

.cloud__puff,
.cloud__motes {
  position: absolute;
  inset: 0;
}

.puff,
.puff-motes {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* ---- the whys ---------------------------------------------------------------- */

.whys {
  position: absolute;
  inset: 0;
}

/* Soft primary rather than secondary: they float over the cloud's glow, not the ground. */
.why {
  position: absolute;
  font: 400 var(--t-why)/1.35 var(--font);
  color: var(--ink-mid-2);
}

.why--first { left: 0; top: calc(34 * var(--px)); }
.why--left { left: 0; top: calc(548 * var(--px)); }
/* Right-aligned at the opposite corner, so the questions read around the cloud rather
   than as a column of captions. */
.why--right { right: 0; top: calc(548 * var(--px)); text-align: right; }

/* Names the cloud, which a parent otherwise meets as an unexplained picture. The arrow
   hangs down and back from the note's first letter into the cloud's top lobe. */
.whys__note {
  position: absolute;
  right: calc(6 * var(--px));
  top: calc(12 * var(--px));
  rotate: 5deg;
}

.whys__arrow {
  position: absolute;
  left: calc(456 * var(--px));
  top: calc(52 * var(--px));
  width: calc(58 * var(--px));
  height: calc(58 * var(--px));
}

/* =============================================================== 02 · the stage
   The child's own screen, annotated: a still of one moment, drawn on the app's 402pt
   canvas. One canvas point is --s, so the positions below are the design's own. An
   illustration: nothing in it is a control. */

.stagepic {
  --s: calc(1.4 * var(--px));
  position: relative;
  justify-self: center;
  width: calc(402 * var(--s));
  height: calc(381 * var(--s));
}

.stagepic__halo {
  position: absolute;
  left: calc(76 * var(--s));
  top: 0;
  width: calc(250 * var(--s));
  height: calc(210 * var(--s));
  border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(167, 139, 240, .16),
    rgba(127, 166, 240, .08) 55%,
    rgba(127, 166, 240, 0) 100%);
}

.stagepic__cloud {
  position: absolute;
  left: calc(121 * var(--s));
  top: calc(22 * var(--s));
  width: calc(160 * var(--s));
  height: calc(160 * var(--s));
}

/* The child's words as they say them, in the stage's supportive ink: paler than
   anything Pukki says, because it is a half-finished sentence. */
.stagepic__caption {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(200 * var(--s));
  font: 500 calc(max(18px, 22 * var(--s)) + var(--rem-delta) * 1.375)/1.27 var(--font);
  text-align: center;
  color: var(--ink-supportive);
}

.stagepic__note {
  position: absolute;
  font-size: calc(max(19px, 22 * var(--s)) + var(--rem-delta) * 1.375);
  line-height: .92;
}

.stagepic__arrow { position: absolute; }

.stagepic__note--waits { left: calc(252 * var(--s)); top: calc(138 * var(--s)); rotate: -5deg; }
.stagepic__arrow--waits { left: calc(272 * var(--s)); top: calc(178 * var(--s)); width: calc(40 * var(--s)); height: calc(30 * var(--s)); }

.stagepic__note--button { left: calc(34 * var(--s)); top: calc(304 * var(--s)); rotate: -4deg; }
.stagepic__arrow--button { left: calc(96 * var(--s)); top: calc(344 * var(--s)); width: calc(52 * var(--s)); height: calc(28 * var(--s)); }

.stagepic__control {
  position: absolute;
  left: calc(150 * var(--s));
  top: calc(279 * var(--s));
  width: calc(102 * var(--s));
  height: calc(102 * var(--s));
}

/* A pencil ring in Wonder Blue around the control means the microphone is live. */
.stagepic__ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: var(--accent-sky);
  stroke-width: 2.2;
  stroke-linecap: round;
  overflow: visible;
}

/* The fill never takes a colour: the glyph reads because it is knocked out of near-black. */
.stagepic__button {
  position: absolute;
  inset: 11.76%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--graphite);
  box-shadow: 0 calc(10 * var(--s)) calc(12 * var(--s)) rgba(0, 0, 0, .18);
}

.stagepic__mic {
  width: 43.6%;
  height: auto;
  aspect-ratio: 1;
  fill: none;
  stroke: var(--paper);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.readalong {
  display: flex;
  align-items: flex-start;
  gap: calc(14 * var(--px));
  max-width: calc(390 * var(--px));
  font: 400 var(--t-label)/1.45 var(--font);
  color: var(--ink-soft);
}

.readalong .icon { width: 1.6em; height: 1.6em; color: var(--ink-faint); }

/* =============================================================== 03 · the research
   Titles to skim, each finding cited on its own row. */

.findings {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(18 * var(--px));
}

.findings__list { width: 100%; }

.finding {
  display: flex;
  flex-direction: column;
  gap: calc(6 * var(--px));
  padding: calc(22 * var(--px)) 0;
}

/* Ruled between the rows only: the list's own top and bottom edges are the text's. */
.finding + .finding { border-top: 1px solid var(--hairline); }
.finding:first-child { padding-top: 0; }
.finding:last-child { padding-bottom: 0; }

.finding__title {
  font: 600 var(--t-title)/1.2 var(--font);
  letter-spacing: -.015em;
  color: var(--ink-strong);
}

.finding__text {
  font: 400 var(--t-text)/1.45 var(--font);
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* =============================================================== 04 · Home
   One child's week as the subjects Home groups her questions under, the most asked
   about largest; then one of her questions opened as its own page opens it. An illustration:
   Home lists these subjects rather than drawing them. */

.home {
  display: flex;
  flex-direction: column;
  width: calc(520 * var(--px));
  justify-self: start;
}

.week {
  position: relative;
  width: calc(322 * var(--m));
  height: calc(232 * var(--m));
}

/* Hand-placed, the app's own centres: a loose cluster, not a grid. Each floats three
   points on a cycle of its own, so the week reads as alive rather than moving. */
.bubble {
  position: absolute;
  left: calc((var(--x) - var(--d) / 2) * var(--m));
  top: calc((var(--y) - var(--d) / 2) * var(--m));
  width: calc(var(--d) * var(--m));
  height: calc(var(--d) * var(--m));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(4 * var(--m));
  border-radius: 50%;
  background: var(--card);
  color: var(--ink-strong);
  font: 500 calc(max(11px, 12 * var(--m)))/1.1 var(--font);
  animation: float var(--drift) ease-in-out infinite alternate;
}

.bubble .icon {
  width: calc(var(--glyph) * var(--m));
  height: calc(var(--glyph) * var(--m));
  stroke-width: 1.75;
  color: #292929;
}

/* The opened topic keeps its accent wash; the rest sit on the quiet card grey. */
.bubble--moon   { --x: 80;  --y: 92;  --d: 132; --glyph: 30; --drift: 4.2s; background: var(--wash-gold); font-size: calc(17 * var(--m)); font-weight: 600; letter-spacing: -.01em; }
.bubble--dogs   { --x: 200; --y: 52;  --d: 92;  --glyph: 26; --drift: 3.4s; font-size: calc(max(12px, 15 * var(--m))); font-weight: 600; }
.bubble--stars  { --x: 286; --y: 96;  --d: 76;  --glyph: 24; --drift: 3.8s; font-size: calc(max(12px, 15 * var(--m))); font-weight: 600; }
.bubble--rain   { --x: 180; --y: 146; --d: 60;  --glyph: 21; --drift: 3.1s; gap: calc(2 * var(--m)); }
.bubble--plants { --x: 258; --y: 172; --d: 54;  --glyph: 19; --drift: 3.6s; gap: calc(1 * var(--m)); }

.bubble--moon .icon { color: var(--accent-gold); }
.bubble--dogs .icon { color: var(--accent-violet); }
.bubble--stars .icon { color: var(--accent-sky); }

@keyframes float {
  from { translate: 0 3px; }
  to { translate: 0 -3px; }
}

.week__note {
  position: absolute;
  left: calc(244 * var(--m));
  top: 0;
  font-size: var(--t-hand-small);
  rotate: -6deg;
}

/* From just under the first bubble down to the question, which starts where the map ends. */
.week__arrow {
  position: absolute;
  left: calc(72 * var(--m));
  top: calc(162 * var(--m));
  width: calc(38.4 * var(--m));
  height: calc(64 * var(--m));
  stroke-width: 2.2;
}

/* One of the week's questions opened as its own page opens it: the day, the question
   over Home's pencil stroke, then what a parent can do with it. No card: every page a
   parent opens from Home sits on the page. */
.asked {
  display: flex;
  flex-direction: column;
  margin-top: calc(4 * var(--px));
}

.asked__day {
  font: 600 var(--t-small)/1.3 var(--font);
  color: var(--ink-soft);
}

.asked__question {
  margin-top: calc(6 * var(--px));
  font: 600 var(--t-title)/1.25 var(--font);
  letter-spacing: -.015em;
  color: var(--ink-strong);
}

.asked__rule {
  margin-top: calc(8 * var(--px));
  width: calc(56 * var(--px));
  height: calc(9.8 * var(--px));
  stroke-width: 1.5;
}

.asked__rows {
  --lead: calc(28 * var(--px));       /* the glyph's column */
  --gap: calc(16 * var(--px));
  margin-top: calc(10 * var(--px));
}

.asked__rows li {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gap);
  min-height: calc(60 * var(--px));
}

/* A rule between rows only, from where the words start. */
.asked__rows li + li::before {
  content: "";
  position: absolute;
  inset: 0 0 auto calc(var(--lead) + var(--gap));
  height: 1px;
  background: var(--hairline);
}

.asked__rows .icon {
  width: var(--lead);
  height: calc(24 * var(--px));
  stroke-width: 1.75;
  color: #292929;
}

.asked__rows p {
  flex: 1;
  display: flex;
  flex-direction: column;
  font: 400 var(--t-text)/1.3 var(--font);
  color: var(--ink-strong);
}

.asked__detail {
  font-size: var(--t-small);
  color: var(--ink-soft);
}

/* The empty ring a parent ticks once they have tried the idea. */
.ring {
  flex: none;
  width: calc(max(22px, 28 * var(--px)));
  height: calc(max(22px, 28 * var(--px)));
  border: 1.5px solid rgba(32, 32, 32, .2);
  border-radius: 50%;
}

.home .footnote { margin-top: calc(14 * var(--px)); }

/* =============================================================== 05 · the letter
   The one page that is a letter, and the only one that argues by refusing something. */

.letter {
  display: flex;
  flex-direction: column;
  gap: calc(24 * var(--px));
  max-width: calc(520 * var(--px));
  font: 400 var(--t-body)/1.5 var(--font);
  color: var(--ink-mid-2);
}

.letter > p { text-wrap: pretty; }

/* The letter's anchor, and so the one block set in full ink. Home's gold, drawn as a tick. */
.promises li {
  display: flex;
  align-items: flex-start;
  gap: calc(14 * var(--px));
  padding: calc(16 * var(--px)) 0;
  border-top: 1px solid var(--hairline);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink-strong);
}

.promises li:last-child { border-bottom: 1px solid var(--hairline); }

.promises .mark {
  width: 1.2em;
  height: 1.2em;
  margin-top: .08em;
  stroke-width: 2;
}

/* The founder's name in her own hand, and what she is, in type under it. Signed by hand,
   because an unsigned letter is a marketing block wearing a letter's clothes. */
.signature {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.signature__name {
  font-size: calc(max(34px, 54 * var(--px)) + var(--rem-delta) * 3.375);
  color: var(--graphite);
  rotate: -3deg;
  transform-origin: left center;
}

.signature__role {
  font: 400 var(--t-small)/1.4 var(--font);
  color: var(--ink-soft);
}

/* =============================================================== the research sheet
   A reference, allowed to scroll, and set in rem so it grows with the reader. Close
   leads the bar and the title sits beside it, as on every sheet in the app. */

.sheet {
  width: min(35rem, calc(100vw - 32px));
  max-height: min(45rem, calc(100vh - 48px));
  padding: 0;
  border: 0;
  border-radius: 28px;
  background: var(--paper);
  color: var(--ink-strong);
  box-shadow: 0 30px 80px rgba(0, 0, 0, .18), 0 2px 8px rgba(0, 0, 0, .06);
  overflow: hidden;
}

.sheet[open] {
  display: flex;
  flex-direction: column;
  animation: sheetIn .32s var(--ease-lift);
}

.sheet::backdrop {
  background: rgba(0, 0, 0, .32);
  animation: appear .24s ease-out;
}

@keyframes sheetIn {
  from { opacity: 0; translate: 0 16px; }
}

.sheet__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 24px 8px 16px;
}

.sheet__close {
  order: -1;
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--fill);
  color: var(--action);
  cursor: pointer;
  transition: background 200ms;
}

.sheet__close:hover { background: var(--fill-pressed); }
.sheet__close .icon { width: 16px; height: 16px; stroke-width: 2.75; }

.sheet__title {
  font: 600 1.25rem/1.2 var(--font);
  letter-spacing: -.01em;
}

.sheet__body {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  padding: 12px 28px 32px;
  overflow-y: auto;
  overscroll-behavior: contain;
  font: 400 1rem/1.5 var(--font);
  color: var(--ink-mid-2);
}

.sheet__heading {
  margin-bottom: .375rem;
  font: 600 .8125rem/1.3 var(--font);
  color: var(--ink-soft);
}

.sheet__claim {
  margin-bottom: .5rem;
  font: 500 1.1875rem/1.35 var(--font);
  letter-spacing: -.01em;
  color: var(--ink-strong);
}

.sheet__studies {
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
}

.sheet .source { margin-top: .25rem; font: 400 .8125rem/1.4 var(--font); }

/* ================================================================= Puff
   Ported from the design system's Puff component, but rendered *once*.

   The app animates a dozen groups inside this SVG. On the web that is ruinous: an
   SVG <g> transform is not a composited layer, so every animated frame re-rasterises
   the whole subtree, and this artwork carries 20-odd filters, including two
   feTurbulence displacement passes. Measured in Mobile Safari at dpr 3 that was
   ~3-5fps (200-350ms per frame). Filters alone cost nothing; animation alone costs
   nothing; the product of the two is what kills it.

   So nothing inside the SVG animates. The artwork rasterises once, and the only motion
   is `breathe` on the wrapper div: a composited transform, promoted so the compositor
   reuses one texture. The motes are a layer of their own outside the body's transform.
   If the cloud ever needs states again, pose it out here too (scale, rotate, opacity on
   these wrappers), never inside the SVG. */

.cloud__breath {
  width: 100%;
  height: 100%;
  animation: breathe 7s ease-in-out infinite;
  will-change: transform;
}

.cloud__motes {
  opacity: .70;
  pointer-events: none;
}

/* Nothing animates while the page is in the background. Browsers throttle a hidden
   tab, but they do not all stop compositing it. */
[data-hidden] .cloud__breath,
[data-hidden] .bubble { animation-play-state: paused; }

@keyframes breathe {
  0%, 100% { transform: scale(1) rotate(0deg); }
  50% { transform: scale(1.035) rotate(-.6deg); }
}

/* Nothing inside the SVG is state-dependent, so after the first paint the artwork never
   changes and its filters are never re-run. */
.puff {
  --pf-glow-opacity: .28;
  --pf-current-opacity: .95;
  --pf-current2-opacity: .85;
  --pf-graphite-opacity: .55;
  --pf-pencil-color: var(--ink-mid);
  --pf-particles-opacity: .8;
}

.pf-glow { opacity: var(--pf-glow-opacity); }
.pf-current { opacity: var(--pf-current-opacity); }
.pf-current--b { opacity: var(--pf-current2-opacity); }
.pf-graphite { opacity: var(--pf-graphite-opacity); }
.pf-pencil { stroke: var(--pf-pencil-color); }
.pf-particles { opacity: var(--pf-particles-opacity); }

/* ======================================================== the narrow tier
   Under 900 wide the poster is the app's own screen: one column, 390 x 720 in the
   reference frame, the picture under the headline and the buttons along the bottom.
   A tablet held upright gets the same column, larger and centred. The unit takes the
   smaller of the width and height shares here too, so a common phone viewport holds a
   whole page; a short one (a phone on its side, a large text size) scrolls. */

@media (max-width: 899px) {
  .poster {
    --px: clamp(.82px, min(100vw / 390, 100vh / 720), 1.3px);

    --t-display: calc(40 * var(--px) + var(--rem-delta) * 2.5);
    --t-chapter: calc(34 * var(--px) + var(--rem-delta) * 2.125);
    --t-chapter-long: calc(30 * var(--px) + var(--rem-delta) * 1.875);
    --t-title: calc(17 * var(--px) + var(--rem-delta) * 1.0625);
    --t-lead: calc(16 * var(--px) + var(--rem-delta) * 1);
    --t-why: calc(15 * var(--px) + var(--rem-delta) * .9375);
    --t-body: calc(16 * var(--px) + var(--rem-delta) * 1);
    --t-text: calc(15 * var(--px) + var(--rem-delta) * .9375);
    --t-label: calc(13 * var(--px) + var(--rem-delta) * .8125);
    --t-small: calc(13 * var(--px) + var(--rem-delta) * .8125);
    --t-legal: calc(max(11px, 12 * var(--px)) + var(--rem-delta) * .75);
    --t-hand: calc(24 * var(--px) + var(--rem-delta) * 1.5);
    --t-hand-small: calc(23 * var(--px) + var(--rem-delta) * 1.4375);

    --measure: calc(342 * var(--px));
    --button-h: max(44px, calc(52 * var(--px)));
    --m: calc(.8 * var(--px));

    grid-template-rows: auto 1fr auto;
    padding: calc(12 * var(--px)) var(--inset) calc(12 * var(--px));
  }

  .poster .nav { min-height: 44px; }
  /* The accounts are their glyphs here, without the words: the footer's one line has no
     room for them beside the pager, and the nav has room for a glyph each. */
  .nav__links { gap: calc(4 * var(--px)); }
  .nav__link { justify-content: center; min-width: clamp(32px, 11vw, 44px); }
  .nav__link span { display: none; }
  /* The glyphs give way before the button's label breaks in two. */
  .store { flex: none; white-space: nowrap; }

  .slide__body { align-self: start; padding-top: calc(16 * var(--px)); }

  .split,
  .split--cover {
    display: flex;
    flex-direction: column;
    /* The desktop grid centres its two columns on each other; in a column that would
       centre every block sideways. */
    align-items: stretch;
    gap: calc(20 * var(--px));
  }

  .split__text { gap: calc(10 * var(--px)); }
  .split__aside { margin-top: 0; }
  /* The desktop grid seats these against a row's edge; in a column that is the right
     edge of the screen. */
  .split:has(> .split__aside) > .split__text,
  .split__aside { align-self: auto; }
  .lead { max-width: none; }

  /* The button along the bottom, at the right, as on the app's own screens. The last
     page sets the Google Play line beside it. */
  .actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: calc(10 * var(--px));
    margin-top: calc(8 * var(--px));
  }

  .actions > :only-child { grid-column: 2; }
  .actions__aside { margin: 0; text-align: center; }

  .button { padding: 0 calc(12 * var(--px)); }
  .button--primary { min-width: 0; }
  .badge { padding: 0 calc(12 * var(--px)); gap: calc(10 * var(--px)); }

  .meta {
    grid-row: 3;
    align-self: auto;
    justify-content: space-between;
    gap: calc(12 * var(--px));
    min-height: 0;
    margin-top: calc(4 * var(--px));
    pointer-events: auto;
  }

  .pager { gap: calc(6 * var(--px)); }
  .pager a { width: calc(22 * var(--px)); height: calc(max(28px, 32 * var(--px))); }
  .meta__list { gap: 2px calc(14 * var(--px)); justify-content: flex-end; }
  /* A phone's one line holds three links: a fourth wraps, and a second line overflows every
     page. About and Questions are the way into the site, and Privacy stays in reach on a
     children's product. The FAQ and the Terms are in every other page's footer. */
  .meta__wide { display: none; }
  .meta__link { display: inline-flex; align-items: center; min-height: 24px; }

  /* ---- 01 -------------------------------------------------------------------
     The app's cover: the artwork owns the top, the title lands under it. */
  .slide#top .slide__body { padding-top: 0; }

  .scene {
    order: -1;
    justify-self: auto;
    width: 100%;
    height: calc(380 * var(--px));
  }

  .cloud {
    left: calc(-14 * var(--px));
    top: calc(10 * var(--px));
    width: calc(370 * var(--px));
    height: calc(370 * var(--px));
  }

  .why--first { top: calc(6 * var(--px)); }
  .why--left,
  .why--right { top: calc(338 * var(--px)); }

  .whys__note { right: calc(2 * var(--px)); top: calc(2 * var(--px)); }

  .whys__arrow {
    left: calc(206 * var(--px));
    top: calc(28 * var(--px));
    width: calc(42 * var(--px));
    height: calc(42 * var(--px));
  }

  .cover__title { gap: calc(12 * var(--px)); }
  .cover__title .lead { max-width: none; }
  /* The eyebrow sits close on its headline, on one tight line, and the artwork gives
     up most of its gap to it, so the cover still fits the phones it fitted without
     the line (360 x 640 has the least room: check it after any change here). */
  .split--cover { gap: calc(8 * var(--px)); }
  .cover__title .label { margin-bottom: calc(-8 * var(--px)); line-height: 1.15; }

  /* ---- 02 -------------------------------------------------------------------
     The stage at the width of the column: 342 of the canvas's 402 points. */
  .stagepic { --s: calc(.85 * var(--px)); align-self: center; }
  .readalong { max-width: none; gap: calc(12 * var(--px)); }

  /* ---- 03 ------------------------------------------------------------------- */
  .findings { gap: calc(6 * var(--px)); }
  .finding { padding: calc(10 * var(--px)) 0; gap: calc(3 * var(--px)); }

  /* ---- 04 ------------------------------------------------------------------- */
  .home { width: 100%; }
  .asked { margin-top: 0; }
  .asked__question { margin-top: calc(4 * var(--px)); }
  .asked__rule { margin-top: calc(6 * var(--px)); width: calc(44 * var(--px)); height: calc(7.7 * var(--px)); }
  .asked__rows { --lead: calc(24 * var(--px)); --gap: calc(12 * var(--px)); margin-top: calc(6 * var(--px)); }
  .asked__rows li { min-height: calc(40 * var(--px)); }
  .asked__rows .icon { height: calc(20 * var(--px)); }
  /* A phone's page has room for the rows' names, not for the line under each. */
  .asked__detail { display: none; }
  .ring { width: calc(24 * var(--px)); height: calc(24 * var(--px)); }
  .home .footnote { margin-top: calc(6 * var(--px)); }

  /* ---- 05 ------------------------------------------------------------------- */
  .letter { gap: calc(14 * var(--px)); max-width: none; line-height: 1.45; }
  .promises li { padding: calc(11 * var(--px)) 0; gap: calc(12 * var(--px)); }
  .signature__name { font-size: calc(36 * var(--px) + var(--rem-delta) * 2.25); }

  /* ---- the sheet rises from the bottom edge ---------------------------------- */
  .sheet {
    width: 100vw;
    max-width: 100vw;
    max-height: 88vh;
    margin: auto 0 0;
    border-radius: 28px 28px 0 0;
  }

  .sheet__body { padding: 12px 24px calc(28px + env(safe-area-inset-bottom)); }
}

@supports (height: 100dvh) {
  @media (max-width: 899px) {
    .poster { --px: clamp(.82px, min(100vw / 390, 100dvh / 720), 1.3px); }
    .sheet { max-height: 88dvh; }
  }
}

/* ------------------------------------------------------ reduced motion */

/* Every loop stops and nothing arrives by moving. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }

  .marked__line path { animation: none; stroke-dashoffset: 0; }
  .bubble,
  .cloud__breath { animation: none; }
}
