/* Warmest Regards / After Tea Media / Ruby Pemberton — the one stylesheet.
 *
 * One canonical copy. The deploy step copies this file to the root of every
 * bucket, so the sites cannot drift apart. See web/README.md.
 *
 * ── The idea ──────────────────────────────────────────────────────────────
 *
 * The app is a dark green room lit by one ember. A website is not a room, and
 * a full-bleed dark green page reads as a landing page for something loud,
 * which this is not. So the sites are paper: warm off-white, deep ink, hairline
 * rules, a great deal of air, and exactly one accent.
 *
 * The green is not gone — it is quoted. On warmestregards.app it appears where
 * the product appears: inside the phone screens, and in the single deep band
 * that carries the privacy claim, which is the one place the page should feel
 * like being inside the app. afterteamedia.com has no green ground at all; the
 * only green on it is 72 pixels of app icon, which is a product mark rather
 * than a background.
 *
 * Nothing is separated by elevation. Sections are divided by 1px rules and by
 * changes of ground, never by cards with shadows — the same discipline the app
 * holds to, and the reason the pages look composed rather than assembled.
 *
 * ── The palette ───────────────────────────────────────────────────────────
 *
 * The deep family is transcribed from the app's own Design_Tokens in
 * core/src/commonMain/kotlin/.../theme/Theme.kt. They are literals here because
 * a stylesheet cannot resolve a Kotlin token, which is the same compromise
 * docs/store-listing.md records for the Android launcher icon. If Theme.kt
 * changes, these change with it.
 *
 * The paper family is the site's own, and it is After Tea Media's: the paper
 * #FBF7F0 for the page and the cream #F6EFE3 for a tinted band, so the
 * publisher and its product stand on the same ground. It could not be
 * transcribed from the app, because the app has no light appearance to transcribe — `Theme.color` takes no appearance
 * parameter and there is no light branch anywhere in it. `--ember-ink` is the
 * one value that had to be invented rather than borrowed: the app's ember
 * (#FF7A2F) measures 2.43:1 on this page ground, so it cannot set text. It is
 * kept for rules, marks and boundaries, and text that wants to be ember is set
 * in #9A3A0F instead, which is the same hue taken down to 6.59:1.
 *
 * Every pair web/check.py lists is computed from these values. Change one here
 * and change it there, or the build fails — which is the point.
 *
 * No webfonts, no analytics, no third-party requests of any kind. That is
 * deliberate: an app whose whole claim is that it transmits nothing should not
 * have a tracker on its privacy policy, and a CDN font request is a request.
 * Everything here is served from your own bucket or is a system font.
 */

:root {
  /* ── Paper: the site's own ground ─────────────────────────────────── */
  --page: #fbf7f0;
  --page-tint: #f6efe3;
  --ink: #1c1b18;
  --ink-muted: #57534a;

  /* Two rules, for two jobs. `--rule` is decoration, where WCAG 1.4.11
   * does not apply. `--rule-strong` is the edge of anything that groups
   * content or bounds a control, and is held to the 3:1 non-text floor:
   * 3.30:1 on the page ground where the hairline is 1.27:1. */
  --rule: #e3ddd1;
  --rule-strong: #8f8878;

  /* The ember, twice. `--ember-ink` sets text; `--ember-mark` is for rules,
   * dots and boundaries, where 3:1 is the floor. */
  --ember-ink: #9a3a0f;
  --ember-ink-deep: #5e230a;
  --ember-mark: #c86a2e;

  /* ── Role aliases ─────────────────────────────────────────────────────
   * Components reference these, never a brand's own colour names, which is
   * what lets one stylesheet carry two identities. Warmest Regards fills
   * them from the ember family above; After Tea Media fills them from its
   * terracotta in `.brand-atm` below.
   *
   * `--accent-ink` sets text and is held to 4.5:1. `--accent-mark` is for
   * decoration only — an eyebrow's dot, a short ornamental rule — and is
   * explicitly *not* for a control boundary or the edge of anything that
   * groups content. On the cream band After Tea Media's terracotta
   * measures 2.95:1, below even 1.4.11's non-text floor, so that
   * distinction is load-bearing rather than tidy. */
  --accent-ink: var(--ember-ink);
  --accent-ink-strong: var(--ember-ink-deep);
  --accent-mark: var(--ember-mark);
  --deep-accent: var(--ember);
  --deep-accent-ink: var(--ember-text);
  --deep-accent-ink-strong: var(--ember-core);

  /* ── Deep: the app's own ground, quoted ───────────────────────────── */
  --deep: #1d3a2d;
  --deep-still: #112219;
  --deep-rule: #3a6650;
  --deep-ink: #f2ede4;
  --deep-ink-muted: #a9bbaf;
  --deep-boundary: #7e9a8a;
  --ember: #ff7a2f;
  --ember-text: #ffa35f;
  --ember-core: #ffd8a8;

  /* ── Type ─────────────────────────────────────────────────────────────
   * The app's own faces first, self-hosted from this bucket, with system
   * stacks behind them for the moment before they arrive. These were system
   * stacks only until the subsetting pipeline existed; now that it does,
   * there is no reason for the product's site not to be set in the product.
   * See the @font-face block below for why "Warmest Serif" is one family
   * holding two typefaces. */
  --serif: "Warmest Serif", ui-serif, "Iowan Old Style", "Palatino Linotype",
    Palatino, Georgia, "Times New Roman", serif;
  --sans: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;

  /* Three roles rather than two families, because the two sites divide the
   * work differently. Warmest Regards sets its prose in the serif, the way
   * the app does. After Tea Media sets display type in its brand serif and
   * everything else in its brand sans — see `.brand-atm`. */
  --font-display: var(--serif);
  /* Inter, not the serif, and that follows the app rather than taste: its
   * Body role — Menu rows, the How-to-use prose, every long passage it has —
   * is Inter. The serif is reserved for what the app calls authored voice,
   * which on these pages is the headings, the lede and the statements. */
  --font-body: var(--sans);
  --font-ui: var(--sans);

  /* ── Measures ─────────────────────────────────────────────────────── */
  --measure: 34rem;      /* prose. ~72 characters at this size */
  --measure-wide: 46rem; /* the widest prose goes, ~90 characters */
  --wrap: 69rem;         /* the widest a section's content goes */
  --gutter: 1.5rem;
}

@media (min-width: 40em) {
  :root {
    --gutter: 2.5rem;
  }
}

/* ── The Warmest Regards faces ────────────────────────────────────────────
 *
 * The app's own typefaces, self-hosted, so the site is set in the product
 * rather than in an approximation of it. Subset to Latin plus the punctuation
 * this copy uses: 84KB for all four, from 1.2MB of source TTFs.
 *
 * ── "Warmest Serif" is a family of two faces, and that is deliberate ────
 *
 * It mirrors `WarmestFonts.serif` in androidApp/.../theme/WarmestFonts.kt
 * exactly. There, one FontFamily registers Fraunces 72pt Italic under
 * `FontStyle.Normal` and EB Garamond Italic under `FontStyle.Italic` — so the
 * app's *upright* serif is a slanted display italic, chosen on purpose, and the
 * roles that ask for italic get a true text italic instead. The two @font-face
 * rules below are that same construction in CSS, which is why the family is
 * named for the app rather than for either typeface.
 *
 * The practical consequence: every heading on this site slants, because every
 * heading in the app does. `.lede` and `.statement` ask for italic and so land
 * on EB Garamond, which is the app's Subtitle and Annotation voice.
 *
 * Inter carries everything functional, at 400 and 600 — the only two weights
 * this site asks for. The app also bundles Inter Medium; nothing here needs it,
 * so it is not shipped.
 *
 * Fraunces, EB Garamond and Inter are all under the SIL Open Font License,
 * which permits self-hosting and subsetting. See fonts/OFL.txt.
 */
@font-face {
  font-family: "Warmest Serif";
  src: url("fonts/fraunces-72pt-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Warmest Serif";
  src: url("fonts/eb-garamond-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: Inter;
  src: url("fonts/inter-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: Inter;
  src: url("fonts/inter-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* ── The two After Tea Media faces ────────────────────────────────────────
 *
 * Self-hosted, not fetched from a CDN. That is the whole point: a site whose
 * privacy policy says it makes no third-party requests cannot have a font
 * request in its head. These come from the same bucket as the page.
 *
 * Both are **variable** fonts with the weight axis kept, so two files per
 * family cover every weight the pages ask for — 300 to 700 of Cormorant, 100
 * to 900 of Jost — rather than one file per weight. Subset to Latin plus the
 * punctuation this copy actually uses: the curly apostrophe, both dashes, the
 * ellipsis, the middot and the copyright sign. The Cormorant Garamond variable
 * font is 999KB as shipped; this is 30KB. All four together are 124KB.
 *
 * Licensed under the SIL Open Font License, which permits self-hosting. The
 * licence text belongs beside the files — see brand/fonts/OFL.txt.
 *
 * `font-display: swap` deliberately: the fallback stacks are chosen to be
 * metrically close, so the reflow when these arrive is small, and showing the
 * words immediately beats showing nothing. `src` is relative, so it resolves
 * against the stylesheet's own location and works both deployed and opened
 * from disk — the same reason the pages' own stylesheet href is relative.
 *
 * Warmest Regards never names these families, so its copy of this stylesheet
 * declares fonts it never requests. A browser only fetches a face something
 * actually renders in, so that costs nothing and 404s nothing.
 */
@font-face {
  font-family: "Cormorant Garamond";
  src: url("brand/fonts/cormorant-garamond-var.woff2") format("woff2-variations");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("brand/fonts/cormorant-garamond-italic-var.woff2") format("woff2-variations");
  font-weight: 300 700;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: Jost;
  src: url("brand/fonts/jost-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: Jost;
  src: url("brand/fonts/jost-italic-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

/* ── After Tea Media ──────────────────────────────────────────────────────
 *
 * The company's own identity, taken from its brand sheet, and applied by
 * `<body class="brand-atm">`. Warmest Regards keeps the values above, which
 * are the app's; a publisher and one of its products are allowed to look
 * like themselves. Only the tokens change — not one component is
 * duplicated, which is the whole reason the roles exist.
 *
 * ── The three brand colours, and what each may do ──────────────────────
 *
 *   Paper        #FBF7F0   The ground.
 *   Cream        #F6EFE3   The tinted band, the inset and inline code.
 *   Emerald      #2E4030   10.39:1 on the paper, 9.71:1 on the cream. Sets
 *                          every word of body copy, which is why the page
 *                          reads green-black rather than black.
 *   Terracotta   #C07A68   3.16:1 on the paper and 2.95:1 on the cream —
 *                          below 4.5:1 for text, and on the cream below even
 *                          1.4.11's 3:1 non-text floor. So it is
 *                          **decoration only** here: the eyebrow's dot, a
 *                          short ornamental rule, the tea in the cup. It
 *                          must never be a control boundary or the edge of
 *                          anything that groups content.
 *
 * Text that wants to be terracotta is set in #A04B38 instead — the same hue
 * taken down to 5.53:1 on the paper and 5.16:1 on the cream — exactly the
 * compromise the ember needed on the other site. On the emerald band the relationship inverts and terracotta
 * lightens to #E3A392 at 5.24:1.
 *
 * ── Type ───────────────────────────────────────────────────────────────
 *
 * Cormorant Garamond for display, Jost for everything functional, which is
 * the pairing on the brand sheet and the division the logo already makes —
 * "After Tea" in the garamond, "MEDIA" in tracked geometric caps.
 *
 * **Both are named first and neither is served.** The faces are listed
 * ahead of the closest system fallbacks, so anyone with them installed sees
 * the brand properly and everyone else gets Palatino-or-similar and
 * Futura-or-similar. Self-hosting them would be the fix and would keep the
 * no-third-party-request rule intact, since they would come from this
 * bucket — but the Cormorant Garamond variable font is 999KB unsubsetted,
 * which is a poor trade on a page this size. Subset woff2 files are the
 * thing to add; see README's SEO and typography notes.
 *
 * Prose is set in Jost rather than in Cormorant deliberately. Cormorant is a
 * high-contrast display face with a small x-height and it is too delicate
 * below about 20px; Jost also has far closer metric cousins in its fallback
 * chain, so the page degrades gracefully instead of resizing itself.
 */
.brand-atm {
  --page: #fbf7f0;
  --page-tint: #f6efe3;
  --ink: #2e4030;
  --ink-muted: #4f5e50;

  --rule: #ddd1bc;
  --rule-strong: #7f8273;

  --accent-ink: #a04b38;
  --accent-ink-strong: #7e3526;
  --accent-mark: #c07a68;

  --deep: #2e4030;
  --deep-still: #243324;
  --deep-rule: #4c5f4b;
  --deep-ink: #f6efe3;
  --deep-ink-muted: #b9c6b6;
  --deep-boundary: #8ca088;
  --deep-accent: #c07a68;
  --deep-accent-ink: #e3a392;
  --deep-accent-ink-strong: #f0cbc0;

  /* Narrower than the other site, which is not a preference but a consequence.
   * Warmest Regards fills 69rem because it has a device beside the hero text
   * and three steps abreast; this page is prose end to end, so at that width the
   * masthead spanned a third further than anything beneath it and the right of
   * every band read as missing rather than as margin. */
  --wrap: 56rem;

  --font-display: "Cormorant Garamond", Cormorant, "EB Garamond", Garamond,
    "Apple Garamond", "Palatino Linotype", Palatino, ui-serif, Georgia, serif;
  --font-body: Jost, Futura, "Futura PT", "Century Gothic", "Avenir Next",
    Avenir, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    sans-serif;
  --font-ui: var(--font-body);
}

/* Cormorant runs small and light for its nominal size, so the display scale
 * is lifted and weighted where the brand face is in play. Held to a modest
 * bump rather than a large one: the same rules apply when a visitor falls
 * back to Palatino, and a figure tuned hard for Cormorant looks overblown
 * there. */
.brand-atm h1,
.brand-atm .display {
  font-size: clamp(2.75rem, 7vw, 4.75rem);
  font-weight: 500;
  letter-spacing: -0.012em;
}

.brand-atm h2 {
  font-size: clamp(2rem, 4.2vw, 2.875rem);
  font-weight: 500;
  letter-spacing: -0.008em;
}

/* Cormorant at 23px sat too quietly against prose set in Jost — a subheading
 * that reads as lighter than the paragraph under it is not a subheading. Up to
 * 26px, which is the smallest size this face carries authority at. */
.brand-atm h3 {
  font-family: var(--font-display);
  font-size: 1.625rem;
  font-weight: 500;
  letter-spacing: -0.005em;
}

.brand-atm .lede {
  font-size: clamp(1.25rem, 2.3vw, 1.5625rem);
  font-weight: 400;
}

.brand-atm .statement {
  font-size: clamp(1.5rem, 3.2vw, 2.125rem);
  font-weight: 500;
}

/* Cormorant's x-height is small enough that the answer sat lighter here than
 * its equivalent on the other site, against a statement that is also larger.
 * Up a step, and at the same 500 the rest of the display type carries. */
.brand-atm .statement-answer {
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 2.5vw, 1.6875rem);
  font-weight: 500;
}

/* Jost's lowercase is a touch smaller than the system sans it replaces, and
 * geometric faces want a little more air between lines. */
.brand-atm {
  font-size: 1.09375rem;
  line-height: 1.72;
}

/* The brand sets "MEDIA" in widely tracked caps, so the eyebrow follows the
 * logo rather than the other site's tighter setting. */
.brand-atm .eyebrow {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.26em;
}

/* ── Ruby Pemberton ───────────────────────────────────────────────────────
 *
 * rubypemberton.com is After Tea Media's identity with one colour and one
 * typeface added, and nothing else. Its pages carry both classes —
 * `<body class="brand-atm brand-rp">` — so every token and type lift above
 * applies, and this block states only the difference. Her books are published
 * by the company, so her site stands on its paper, in its emerald and its
 * Cormorant. If it ever needs to diverge, this is where that happens.
 *
 * ── Burgundy #7A1F2B, and what it may do ───────────────────────────────
 *
 * Small accents only: the signature, the eyebrow's dot, a button or link under
 * the pointer, the focus ring. Never a ground and never a block.
 *
 * Unlike the terracotta it is dark — 9.55:1 on the paper, 8.93:1 on the
 * cream — so it is legitimate as text, as a boundary and as a focus ring. That
 * is why it takes `--accent-mark` here, where the terracotta can only ever be
 * decoration, and the hover end of the link colour. On the emerald it measures
 * 1.09:1 and vanishes, so it never goes there.
 *
 * The terracotta keeps the job the brief gives it, the boldest buttons, at its
 * text-safe #A04B38: cream on it is 5.53:1, where cream on #C07A68 would be
 * 3.16:1 and fail for the small line under each button.
 *
 * ── Parisienne ─────────────────────────────────────────────────────────
 *
 * The name and the signature, and never anything someone has to read. Both
 * are fixed strings, so both are outlined SVGs in brand/ and no script face is
 * ever requested — see og/rubypemberton-art.py.
 *
 * ── Size ───────────────────────────────────────────────────────────────
 *
 * Body copy at 18px rather than 17.5px, as a floor: most of Ruby's readers are
 * over forty and arrive on a phone, from Instagram or Pinterest.
 */
.brand-rp {
  --rp-burgundy: #7a1f2b;
  --accent-mark: var(--rp-burgundy);
  --accent-ink-strong: var(--rp-burgundy);

  /* One centred column on every screen, because the home page is a link page
   * first and a link page that spreads into columns is harder to scan. But not
   * phone-width on a desktop: at 30rem the page was a 480px strip in the middle
   * of the screen. 40rem is the widest the About text reads well at this size,
   * about 70 characters a line, and still a stack of buttons the eye takes in at
   * once. On a phone nothing changes, as the screen is narrower than either. */
  --wrap: 40rem;

  font-size: 1.125rem;
}

.brand-rp a:focus-visible {
  outline-color: var(--rp-burgundy);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* Respected by the user's browser zoom rather than overriding it. */
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.7;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ── Skip link, for keyboard and screen-reader users ─────────────────── */

/* Hidden the same way as `.visually-hidden`, by clipping it to nothing in
 * place, rather than by parking it at left: -9999px. iOS Safari painted a
 * dark square in the top-left corner of afterteamedia.com, the only page
 * checked that carried this link (Ruby's home page has none); the off-screen
 * offset is the one thing here a phone could get wrong, so it is gone. */
.skip-link {
  position: absolute;
  left: 0;
  top: 0;
  background: var(--deep);
  color: var(--deep-ink);
  padding: 0.7rem 1.1rem;
  border-radius: 0 0 4px 0;
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  z-index: 40;
}

.skip-link:not(:focus) {
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Present for a screen reader, absent on screen: the "(opens in a new tab)"
 * on Ruby's buttons, and the headings that name her page's sections without
 * printing a label nobody needs to see. */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Layout ───────────────────────────────────────────────────────────
 *
 * Three primitives and nothing else. `.band` is a full-width horizontal
 * slice of the page and owns the vertical rhythm; `.wrap` centres content
 * inside it at the widest measure; `.measure` narrows to prose width.
 * Everything on both sites is some arrangement of these three.
 */

.band {
  padding: clamp(3.5rem, 9vw, 7rem) var(--gutter);
}

.band--tight {
  padding-top: clamp(2.5rem, 6vw, 4.5rem);
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
}

.band--ruled {
  border-top: 1px solid var(--rule);
}

.band--tint {
  background: var(--page-tint);
}

/* The one deep band. Inside it the whole colour system inverts, so the
 * components below need no deep-specific variants of their own: they read
 * these custom properties and get the app's ground for free. */
.band--deep {
  background: var(--deep);
  color: var(--deep-ink);
  --ink: var(--deep-ink);
  --ink-muted: var(--deep-ink-muted);
  --rule: var(--deep-rule);
  --rule-strong: var(--deep-boundary);
  --accent-ink: var(--deep-accent-ink);
  --accent-ink-strong: var(--deep-accent-ink-strong);
  --accent-mark: var(--deep-accent);
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
}

.measure {
  max-width: var(--measure);
}

.measure-wide {
  max-width: var(--measure-wide);
}

.centred {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* Centring a band centres what is inside it, including the two things that
 * carry their own width: a narrowed measure, and a row of store buttons. */
.centred .measure,
.centred .measure-wide {
  margin-left: auto;
  margin-right: auto;
}

.centred .stores {
  justify-content: center;
}

/* ── The masthead ─────────────────────────────────────────────────────
 *
 * Not sticky. A bar that follows you down a page about putting something
 * down is the wrong instinct, and there is nothing in it you need twice.
 */

/* The wrap plus its gutters, because the gutters are this box's own padding.
 * A band puts its gutters outside its `.wrap`, so a masthead capped at the bare
 * wrap came out one gutter narrower on each side than everything under it: the
 * logo stood 40px in from the hero's left edge and the nav stopped 40px short
 * of the right, which read as a lopsided header. `.links` and `.follow` add the
 * gutters for the same reason. */
.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin: 0 auto;
  padding: 1.75rem var(--gutter) 1.5rem;
}

/* The footer's rule, mirrored at the top, on afterteamedia.com and
 * warmestregards.app. With nothing joining the brand at the left and the nav
 * at the right, the nav read as stranded at the far edge rather than placed
 * there. A hairline running edge
 * to edge under both gives the space between them a reason, as the footer's
 * does for the mark at its right. Built the same way as the footer: the
 * gutters become margin, so the rule spans the wrap exactly and the logo and
 * the last nav link sit on its two ends. */
.masthead--ruled {
  width: calc(100% - var(--gutter) * 2);
  max-width: var(--wrap);
  padding-left: 0;
  padding-right: 0;
  border-bottom: 1px solid var(--rule);
}

.masthead__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.masthead__brand:hover {
  color: var(--accent-ink);
}

/* Sized by height rather than by both axes, so the slot takes either a square
 * mark or a wide wordmark without needing a second rule. The max-width is a
 * guard, not a target: a logo wider than this is being asked to do the job the
 * adjacent text already does. */
.masthead__brand img {
  height: 30px;
  width: auto;
  max-width: 11rem;
  display: block;
}

/* A masthead carrying a full lockup instead of a mark beside live text.
 *
 * There is no text in the link at all, and that is the point: the logo already
 * *is* the wordmark — "After Tea" set in Cormorant Garamond with the tracked
 * caps beneath it — so re-lettering the same words next to it in a fallback
 * stack would put the join on display. The accessible name comes from the
 * image's `alt`, which is why that one is not empty.
 *
 * `max-width: none` because the guard above assumes a mark; this lockup is
 * 4.63:1 and would be squashed by it. */
.masthead__brand--logo {
  gap: 0;
}

/* 40px, then 52px. Sized up from 36px after looking at it: the lockup sets
 * "MEDIA" small against "After Tea", so the tracked caps are the first thing to
 * fail, and below about 40px of overall height they close up. */
.masthead__brand--logo img {
  height: 2.5rem;
  max-width: none;
}

@media (min-width: 40em) {
  .masthead__brand--logo img {
    height: 3.25rem;
  }
}

.masthead__nav {
  display: flex;
  gap: 1.75rem;
  font-family: var(--font-ui);
  font-size: 0.875rem;
}

.masthead__nav a {
  color: var(--ink-muted);
  text-decoration: none;
}

.masthead__nav a:hover {
  color: var(--accent-ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* ── Type ─────────────────────────────────────────────────────────────
 *
 * The scale is deliberately wide: a very large serif display against a very
 * small tracked sans eyebrow, with little in between. That contrast is most
 * of what makes a page of two typefaces look composed.
 */

.eyebrow {
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 1.5rem;
}

/* An ember dot before the label. The app's one warm colour, at the smallest
 * size it can be useful — enough to place the brand, not enough to shout. */
.eyebrow--marked::before {
  content: "";
  display: inline-block;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--accent-mark);
  margin-right: 0.6rem;
  vertical-align: 0.06em;
}

h1,
.display {
  font-family: var(--font-display);
  font-size: clamp(2.375rem, 6.2vw, 4rem);
  line-height: 1.06;
  font-weight: 400;
  letter-spacing: -0.017em;
  margin: 0 0 1.25rem;
  text-wrap: balance;
}

h2 {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3.6vw, 2.5rem);
  line-height: 1.16;
  font-weight: 400;
  letter-spacing: -0.012em;
  margin: 0 0 1.125rem;
  text-wrap: balance;
}

/* Upright, and the functional face — not the display one, which every other
 * heading uses.
 *
 * This is where being faithful to the app stopped being right. "Warmest Serif"
 * puts Fraunces 72pt *Italic* in the roman slot, exactly as the app does, so
 * setting `h3` in it slanted every subheading on the page. One screen at a time
 * the app carries that beautifully. A page stacking a dozen serif elements does
 * not: with the h1, the h2s, the lede, the statements and the captions all
 * leaning, there was no upright thing left to measure them against, and a
 * 21px slanted subhead read as less authoritative than the body text under it.
 *
 * So the display face is kept for display sizes, where the slant is a gesture,
 * and the subheads anchor the page. After Tea Media keeps Cormorant here: its
 * roman is upright, so it never had this problem. */
h3 {
  font-family: var(--font-ui);
  font-size: 1.125rem;
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: 0.002em;
  margin: 0 0 0.5rem;
}

/* A run of subheadings needs air above each one, but only where one actually
 * follows prose. Left as a margin on `h3` itself this would also push the
 * first subheading in a column away from the heading above it, and open a gap
 * under the numeral in a step. */
p + h3,
ul + h3,
ol + h3 {
  margin-top: 2.25rem;
}

/* The lede. Serif italic, mirroring the app's own Subtitle role, which is
 * the voice the app uses for the line under a question. */
.lede {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.1875rem, 2.1vw, 1.4375rem);
  line-height: 1.55;
  color: var(--ink-muted);
  margin: 0 0 2rem;
  text-wrap: pretty;
}

p {
  margin: 0 0 1.25rem;
  text-wrap: pretty;
}

ul,
ol {
  margin: 0 0 1.25rem;
  padding-left: 1.25rem;
}

li {
  margin-bottom: 0.5rem;
}

strong {
  font-weight: 600;
  color: var(--ink);
}

/* The functional sans voice: notices, metadata, legal lines. Mirrors the
 * app's own split between its authored serif and its Notice role. */
.notice {
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink-muted);
}

.updated {
  font-family: var(--font-ui);
  font-size: 0.875rem;
  letter-spacing: 0.01em;
  color: var(--ink-muted);
  margin: 0;
}

/* A quiet full-width statement between two bands. Large, unhurried, and the
 * only place the serif is set in the muted ink. */
.statement {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.375rem, 3vw, 1.875rem);
  line-height: 1.4;
  letter-spacing: -0.008em;
  color: var(--ink);
  margin: 0;
  text-wrap: pretty;
}

/* The line that answers the statement. The change of voice — sans against the
 * statement's serif — is what makes the pair read as a turn rather than as two
 * paragraphs, and that part was right.
 *
 * The size was not. Set at `.notice` size it came out as the smallest text on
 * the page, directly beneath the second largest, so the strongest line in the
 * copy read as a caption for the one above it. Looking at the rendered page is
 * the only way that shows up. It is now near body size, in the full ink rather
 * than the muted, and set further down. */
.statement + p {
  margin: 1.75rem 0 0;
}

/* Serif roman, not sans. Two earlier attempts at this got it wrong in the same
 * way, and the second is instructive: setting it in the functional sans and then
 * nudging it from 15px to 17px changed nothing anyone could see. Size was never
 * the problem. A short line of small sans under a large italic serif *looks*
 * like a caption, because that is exactly what captions look like, and no
 * amount of scaling argues with that.
 *
 * So the turn is made in the same family instead: the claim in italic, the
 * answer in roman at a comparable size. Lyrical, then plain — which is the
 * rhetorical move the copy is already making. */
.statement-answer {
  font-family: var(--font-ui);
  font-style: normal;
  font-size: clamp(1.25rem, 2.2vw, 1.5rem);
  line-height: 1.5;
  letter-spacing: -0.004em;
  color: var(--ink);
  margin: 2.25rem 0 0;
  max-width: 36rem;
  text-wrap: pretty;
}

/* ── Links ────────────────────────────────────────────────────────────
 *
 * Underlined, in the ember taken down to a text-safe value. An underline
 * rather than colour alone: colour alone fails 1.4.1 for anyone who cannot
 * separate this hue from the body ink.
 */

a {
  color: var(--accent-ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  text-decoration-color: color-mix(in srgb, var(--accent-ink) 45%, transparent);
  transition: color 120ms ease, text-decoration-color 120ms ease;
}

a:hover {
  color: var(--accent-ink-strong);
  text-decoration-color: currentColor;
}

a:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ── Rules ────────────────────────────────────────────────────────────── */

hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 3rem 0;
}

/* A short rule that opens a section, rather than a full-width one that
 * closes it. Ember, because at 2px by 2.5rem it is a mark, not text. */
.mark-rule {
  width: 2.5rem;
  height: 2px;
  background: var(--accent-mark);
  border: 0;
  margin: 0 0 1.75rem;
}

.centred .mark-rule,
.mark-rule--centred {
  margin-left: auto;
  margin-right: auto;
}

/* ── The hero ─────────────────────────────────────────────────────────
 *
 * One column until there is room for two. The device is second in the DOM
 * so that a narrow screen and a screen reader both get the words first.
 */

.hero {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
  align-items: center;
  max-width: var(--wrap);
  margin: 0 auto;
}

@media (min-width: 60em) {
  .hero {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: 4.5rem;
  }
}

.hero__text {
  max-width: 34rem;
}

/* The tagline, as the hero's headline. Bigger than the default h1, because
 * three two-word beats leave room a sentence never did: at 5.25rem the widest
 * beat, "Let it go.", still clears the 34rem column, and at the 3rem floor it
 * fits a 320px screen. One beat to a line, so the break always falls on a full
 * stop and never wherever the column happens to run out.
 *
 * The middle beat is the one place the ember sets display text, at its
 * text-safe value: "Burn it.", beside the fire it names. */
.tagline {
  font-size: clamp(3rem, 8.4vw, 5.25rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  margin-bottom: 1.5rem;
}

.tagline__beat {
  display: block;
}

.tagline__beat--burn {
  color: var(--accent-ink);
}

/* The eyebrow, carried inside the h1 so the main heading names the category
 * as well as the tagline. `.eyebrow` already sets its own face, size, weight,
 * tracking and margin; all this restores is what the h1 would otherwise lend
 * it — a block of its own, and body leading rather than display leading. */
.tagline__kicker {
  display: block;
  line-height: 1.7;
  text-wrap: wrap;
}

/* The line the headline used to be, now the lede's opening. Set in the full
 * ink so it still reads first within it. */
.lede__lead {
  color: var(--ink);
}

.hero__meta {
  font-family: var(--font-ui);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-muted);
  margin: 1.5rem 0 0;
}

/* The device sits in a very soft warm halo — the one gradient on either
 * site. It stands in for the light the app's ember throws, and it is the
 * reason the phone does not look pasted onto the paper. */
.hero__stage {
  position: relative;
  display: flex;
  justify-content: center;
}

/* Inset to zero horizontally, not to a negative value. A pseudo-element that
 * reaches past its parent's left and right edges widens the document, and at a
 * narrow viewport that is three pixels of horizontal scroll on a page that has
 * no reason to scroll sideways at all. The gradient spreads instead. */
.hero__stage::before {
  content: "";
  position: absolute;
  inset: -14% 0;
  background: radial-gradient(
    72% 48% at 50% 44%,
    rgba(255, 122, 47, 0.14) 0%,
    rgba(255, 122, 47, 0.05) 44%,
    rgba(255, 122, 47, 0) 74%
  );
  pointer-events: none;
}

/* ── The device ───────────────────────────────────────────────────────
 *
 * A size and a shadow, for anything shaped like a phone; `.device--capture`,
 * below, adds the bezel a screenshot lacks. Two shadows rather than one: a wide
 * soft cast for the lift and a tight dark one at the contact edge, without
 * which the phone floats.
 */

.device {
  display: block;
  width: 100%;
  max-width: 17.5rem;
  height: auto;
  filter: drop-shadow(0 26px 44px rgba(28, 27, 24, 0.19))
    drop-shadow(0 3px 8px rgba(28, 27, 24, 0.1));
}

.hero__stage .device {
  max-width: 20rem;
}

/* A screenshot has no bezel, so this draws one: a #141210 body, a #3a352f
 * hairline one pixel in, and 4px of bezel. Those are the values and the
 * proportion, 5 of 390, of the drawn phone mockups the page used to show.
 *
 * Every radius is a percentage pair, horizontal / vertical, because a single
 * percentage on a box this tall draws an ellipse rather than a corner. The
 * screen's corner is 48/380 of its width, the same mockups' proportion, which
 * on the capture's own 110:239 (1320 × 2868) is 12.63% / 5.81%. The frame's is
 * that radius plus the bezel, at 20rem. */
.device--capture {
  position: relative;
  padding: 0.25rem;
  background: #141210;
  border-radius: 13.56% / 6.33%;
  box-shadow: inset 0 0 0 1px #141210, inset 0 0 0 2px #3a352f;
}

.device--capture img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12.63% / 5.81%;
}

/* The Dynamic Island, which no screenshot contains because it is hardware.
 * Sized and placed as on the 6.9-inch iPhone the capture comes from — 126 ×
 * 37.33pt, 11.33pt down a 440 × 956pt screen — so it sits on the status bar's
 * own centre line, between the clock and the icons. */
.device--capture::after {
  content: "";
  position: absolute;
  top: calc(0.25rem + 1.18%);
  left: 50%;
  width: 27.9%;
  aspect-ratio: 126 / 37.33;
  transform: translateX(-50%);
  border-radius: 999px;
  background: #0b0f0d;
}

/* ── Store badges ─────────────────────────────────────────────────────
 *
 * The official artwork, which is the only thing that belongs here. Both
 * stores require their own badge for a download call to action and forbid
 * rebuilding or imitating it:
 *
 *   Apple, Marketing Resources and Identity Guidelines — "Include App Store
 *   badges in all digital and printed marketing materials as a clear call to
 *   action to get your app", "Use only the badge artwork provided in these
 *   guidelines", "Never ... create your own localized badge."
 *
 *   Google, Partner Marketing Hub — "If you're driving customers to download
 *   content on Google Play, please use Google Play badges", "Don't remove or
 *   rearrange badge elements, or otherwise adjust the badge in any way."
 *
 * These buttons were text for a while, reading "Download on the / App Store"
 * over a kicker — the badge lockup rebuilt in type, which is the specific
 * thing both prohibit. The justification recorded here at the time was that
 * two badges side by side is a lot of other people's branding on a quiet
 * page. That was an aesthetic preference, and not mine to make.
 *
 * ── Why 48px, and why that is the whole specification ─────────────────
 *
 * Both files are trimmed tight to the artwork. Measured with getBBox:
 * Apple draws 119.66 x 40.00 in a viewBox of exactly that, Google 239.18 x
 * 70.87 in 238.96 x 70.87 — a 0.11 hairline overhang, and 100% of the
 * viewBox height in both. So a rendered height *is* a visible height here,
 * and matching the two is simply setting one number.
 *
 * That mattered because it very nearly was not true. Google's *PNG* carries
 * a third of its height in transparent padding, where Apple's grey border is
 * the edge of the artwork — match those two on height and Google's badge
 * comes out visibly a third shorter, which is the one outcome its rules
 * forbid. The SVG is trimmed and the trap does not apply. It was measured
 * rather than assumed.
 *
 * At a shared 48px:
 *
 *   Apple    143.6px wide, aspect 2.992:1. Clears its 40px onscreen floor.
 *            Preferred *black* badge, required whenever another platform's
 *            badge is in the layout. First in the lineup, as it asks.
 *   Google   161.8px wide, aspect 3.372:1. Clears its 28px floor, and is
 *            12.7% wider and larger in area than Apple's, satisfying "the
 *            same size or larger than the other badges" on every reading.
 *
 * So Apple is the narrower of the two. That is expected and fine: the rule
 * is about size and prominence, not width parity.
 *
 * The 16px gap exceeds the quarter-of-badge-height clear space both require
 * (12px at this size), and `.stores` carries no background or border, so
 * nothing intrudes into it.
 *
 * No border, fill, radius or shadow from us, and no hover transform —
 * modifying the artwork is prohibited. The only affordance is opacity.
 */

.stores {
  list-style: none;
  padding: 0;
  margin: 2rem 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.store-badge {
  display: block;
  text-decoration: none;
}

.store-badge img {
  display: block;
  height: 48px;
  width: auto;
}

.store-badge:hover {
  opacity: 0.84;
}

.store-badge:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 4px;
}

/* ── The step sequence ────────────────────────────────────────────────
 *
 * Three steps, each opened by a hairline and a tracked numeral rather than
 * a circled badge. The rule does the work a box would have done.
 */

.steps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 2.5rem;
}

@media (min-width: 48em) {
  .steps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 3rem;
  }
}

.steps > li {
  margin: 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule-strong);
}

.step__num {
  display: block;
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--accent-ink);
  margin-bottom: 0.875rem;
}

.steps h3 {
  margin-bottom: 0.625rem;
}

.steps p {
  margin: 0;
  font-size: 1rem;
  color: var(--ink-muted);
}

/* ── Fact list ────────────────────────────────────────────────────────
 *
 * For the privacy claims and the studio's principles. Hairline-separated
 * rows rather than bullets: five short absolute statements read as a
 * specification this way, and as a shopping list with bullets.
 */

.facts {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--rule);
}

.facts > li {
  margin: 0;
  padding: 1.0625rem 0;
  border-bottom: 1px solid var(--rule);
  display: flex;
  gap: 1rem;
  align-items: baseline;
}

.facts > li::before {
  content: "";
  flex: none;
  width: 0.3125rem;
  height: 0.3125rem;
  border-radius: 50%;
  background: var(--accent-mark);
  transform: translateY(-0.2em);
}

/* ── Two-column prose ─────────────────────────────────────────────────── */

.duo {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}

@media (min-width: 52em) {
  .duo {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: clamp(3rem, 7vw, 6rem);
  }
}

.duo__aside {
  position: sticky;
  top: 2.5rem;
}

.duo__aside h2 {
  margin-bottom: 0.75rem;
}

.duo > :last-child > :last-child {
  margin-bottom: 0;
}

/* ── The publisher mark ───────────────────────────────────────────────
 *
 * The brand sheet's dark panel, given a place on the page: one quiet emerald
 * strip carrying the reversed lockup and a single line beneath it. It divides
 * what the company makes from how it makes it, and it is the only emerald
 * ground on the site — a second one would make this one ordinary, and the
 * identity is paper and cream.
 *
 * The reversed artwork is not optional here. The emerald lockup on an emerald
 * ground leaves nothing but the terracotta tea.
 */
.publisher-mark {
  text-align: center;
}

/* Sized for the stacked lockup, which is near-square at 1.14:1 rather than the
 * horizontal's 4.63:1. The stacked one belongs here: this band is centred and
 * has vertical room, which is the one place the cup can sit above the words
 * instead of beside them. */
.publisher-mark img {
  display: block;
  width: min(12.5rem, 54vw);
  height: auto;
  margin: 0 auto 2rem;
}

.publisher-mark p {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.25rem, 2.4vw, 1.5rem);
  line-height: 1.45;
  color: var(--ink-muted);
  margin: 0;
  text-wrap: balance;
}

/* ── The product card, for the studio site ────────────────────────────
 *
 * A rule on three sides and an icon. The border is `--rule-strong` rather
 * than `--rule`: this box groups content and its edge is doing real work,
 * so it is held to 1.4.11's 3:1 non-text floor — 3.33:1 against the page
 * ground where the hairline would be 1.28:1.
 */

/* A catalogue is one or more cards in a column. Present even when there is a
 * single card, so adding the second one is a copy-paste rather than a layout
 * decision taken in a hurry. */
.products {
  display: grid;
  gap: 1.5rem;
}

.product {
  display: grid;
  gap: 1.75rem;
  padding: clamp(1.75rem, 4vw, 2.5rem);
  border: 1px solid var(--rule-strong);
  border-radius: 4px;
  background: var(--page);
}

@media (min-width: 40em) {
  .product {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 2rem;
    align-items: start;
  }
}

.product__icon {
  width: 72px;
  height: 72px;
  display: block;
  border-radius: 16px;
  filter: drop-shadow(0 6px 14px rgba(28, 27, 24, 0.16));
}

/* A book cover in the same slot an app icon occupies. Portrait, square corners
 * and a hairline, because a cover is artwork with an edge rather than an icon
 * with a mask — a rounded 1:1 crop makes a novel look like a utility. */
.product__cover {
  width: 104px;
  height: auto;
  display: block;
  border: 1px solid var(--rule-strong);
  border-radius: 1px;
  filter: drop-shadow(0 8px 18px rgba(28, 27, 24, 0.2));
}

/* The line under a title: format, or platforms. Sans, quiet, tight to the
 * heading it belongs to. */
.product__meta {
  font-family: var(--font-ui);
  font-size: 0.875rem;
  letter-spacing: 0.01em;
  color: var(--ink-muted);
  margin: 0 0 1rem;
}

.product h3 {
  font-size: 1.625rem;
  margin-bottom: 0.375rem;
}

.product__body > :last-child {
  margin-bottom: 0;
}

.product__links {
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 1.25rem 0 0;
}

/* A row of quiet links. Used on the error pages, where the only useful thing
 * to offer is the two or three places the person might have been going. */
.linkrow {
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  margin: 2rem 0 0;
}

.centred .linkrow {
  justify-content: center;
}

/* ── Callout ──────────────────────────────────────────────────────────
 *
 * The one inset block. Used for the privacy policy's short version and the
 * support page's email address — the two things a person might have come
 * for and should not have to read to find.
 */

.inset {
  background: var(--page-tint);
  border: 1px solid var(--rule-strong);
  border-radius: 4px;
  padding: 1.5rem 1.625rem;
  margin: 0 0 2rem;
}

.inset > :last-child {
  margin-bottom: 0;
}

.inset__lead {
  font-family: var(--font-display);
  font-size: 1.1875rem;
  line-height: 1.5;
  margin: 0 0 0.75rem;
}

/* Contact details block. Address needs its italic removed. */
address {
  font-style: normal;
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  line-height: 1.75;
  color: var(--ink-muted);
}

address strong {
  color: var(--ink);
}

/* ── Definition-style FAQ ─────────────────────────────────────────────── */

.faq {
  margin: 0;
  border-top: 1px solid var(--rule);
}

.faq dt {
  font-family: var(--font-display);
  font-size: 1.1875rem;
  line-height: 1.4;
  color: var(--ink);
  margin: 0;
  padding: 1.75rem 0 0.5rem;
}

.faq dd {
  margin: 0;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-muted);
}

.faq dd > :last-child {
  margin-bottom: 0;
}

/* ── Document pages ───────────────────────────────────────────────────
 *
 * The privacy policies and the support page. A long read gets a quiet
 * masthead-like header and nothing else.
 */

.doc {
  max-width: var(--measure);
  margin: 0 auto;
  padding: clamp(2.5rem, 6vw, 4rem) var(--gutter) clamp(3rem, 7vw, 5rem);
}

/* Every document page — the privacy policies and the support page — as wide as
 * its site: the page at the site's `--wrap`, with the full-width masthead and
 * footer its landing page has, and the reading column at `--measure-wide`, the
 * widest the landing page itself sets prose. It sits on the brand's left edge,
 * as that page's opening statement does. Any wider and a line runs past ninety
 * characters. On Ruby's site `--wrap` is 40rem, so her policy is exactly as
 * wide as her home page and quiz. */
/* Plus the gutters, which are this box's own padding, as on the masthead. */
.doc--wide {
  max-width: calc(var(--wrap) + var(--gutter) * 2);
}

.doc--wide main {
  max-width: var(--measure-wide);
}

.doc-head {
  margin-bottom: clamp(2.5rem, 5vw, 3.5rem);
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--rule);
}

.doc-head h1 {
  font-size: clamp(2rem, 4.6vw, 2.875rem);
  margin-bottom: 0.875rem;
}

/* Upright on a document page, where the display face is not wanted at this
 * size. A privacy policy is reference material: somebody is scanning it for the
 * one section they came for, and fifteen slanted section heads down a long page
 * are harder to pick out than fifteen upright ones. The h1 at the top keeps the
 * display face, so the page still opens in the brand's voice.
 *
 * After Tea Media's support page is the same shape and keeps Cormorant, whose
 * roman is upright and so reads perfectly well here. */
.doc h2 {
  font-family: var(--font-ui);
  font-size: 1.375rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.002em;
  margin: 3rem 0 0.875rem;
}

.brand-atm .doc h2,
.brand-atm.doc h2 {
  font-family: var(--font-display);
  font-size: 1.625rem;
  font-weight: 500;
  letter-spacing: -0.005em;
}

.doc h3 {
  font-family: var(--font-ui);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  margin: 2.25rem 0 0.5rem;
}

.doc code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    monospace;
  font-size: 0.875em;
  background: var(--page-tint);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 0.05em 0.35em;
}

/* ── The safety notice ────────────────────────────────────────────────
 *
 * Present on every page that describes the app, and deliberately not
 * styled as an alert: a red box would make the one paragraph about getting
 * help look like an error state. Quiet sans above the footer instead.
 */

/* The gutters are margin rather than padding, as on the footer below, so the
 * rule and the words both share the wrap's edges. */
.safety {
  width: calc(100% - var(--gutter) * 2);
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 2rem 0;
  border-top: 1px solid var(--rule);
}

.safety p {
  font-family: var(--font-ui);
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--ink-muted);
  max-width: 46rem;
  margin: 0;
}

/* ── Footer ───────────────────────────────────────────────────────────── */

/* The gutters are margin rather than padding: the rule is this box's top
 * border, so with padded gutters the rule ran to the wrap's edges while the
 * words stood a gutter inside them, out of line with every band above. */
footer {
  width: calc(100% - var(--gutter) * 2);
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 2.25rem 0 3.5rem;
  border-top: 1px solid var(--rule);
  font-family: var(--font-ui);
  font-size: 0.875rem;
  color: var(--ink-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  align-items: baseline;
  justify-content: space-between;
}

/* A landing page that is one column throughout, as Ruby's is: the footer takes
 * the column's width exactly, so its rule and its words share one edge with
 * everything above them. */
.footer--column {
  max-width: var(--wrap);
}

footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
}

footer nav a {
  white-space: nowrap;
}

footer p {
  margin: 0;
}

/* The company's registration details, in every footer on all three sites
 * except the 404s. UK trading-disclosure rules want a company's websites to
 * carry its name, where it is registered, its number and its registered
 * office, and a footer has them wherever someone lands rather than on one page
 * they would have to find.
 *
 * In a signed footer the line sits under the copyright and wraps inside its
 * column, so the mark keeps its place to the right wherever there is room for
 * both — on a phone there is not, and the mark drops beneath. In a footer
 * without the mark it takes a line of its own under the links and the
 * copyright, at the footer's full width. */
.footer__legal {
  max-width: 24rem;
}

footer > .footer__legal {
  flex-basis: 100%;
  max-width: none;
}
/* ── The signed footer ────────────────────────────────────────────────
 *
 * The app's pages end with the publisher's mark, and the footer is laid out
 * around it as two columns that share one bottom line: the small print on
 * the left — links above, copyright below — and the mark on the right. The
 * copyright's baseline and the foot of "After Tea Media" are the same line,
 * which is what ties the columns together rather than leaving each element
 * on an alignment of its own.
 *
 * In the footer rather than the masthead on purpose: each page has one
 * primary mark, and on warmestregards.app that is the app's. Here the company
 * reads as the maker, which is what it is, instead of as a co-brand.
 *
 * The mark is `brand/publisher-mark.svg`, copied byte for byte — check.py
 * fails if the two drift. That one rather than the full lockup because it sets
 * the whole name on one line; at footer size the lockup's tracked "MEDIA" is
 * about 4px tall. Its lettering is outlined, so it renders through `img`. */
.footer--signed {
  align-items: flex-end;
}
.footer__fine {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
/* A centred stack, because the mark itself is one: the label sits over the
 * cup's axis, so "Made by", the cup and the name read as a single sign-off.
 * The bottom margin lifts the name's foot onto the copyright's baseline —
 * the copyright's line box carries leading below its baseline, and the
 * image's box ends at the letters. */
.maker {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4375rem;
  color: var(--ink-muted);
  text-decoration: none;
}
.maker__label {
  font-size: 0.6875rem;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.maker img {
  display: block;
  height: 48px;
  width: auto;
}
/* `a.` because the mark is not always a link, and a label that underlined
 * itself under the pointer would promise a link that is not there. */
a.maker:hover .maker__label,
a.maker:focus-visible .maker__label {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* ── Ruby Pemberton: the link page ────────────────────────────────────
 *
 * rubypemberton.com is where every one of Ruby's bios points, so its home
 * page is a link page before it is anything else: a portrait, a name, a line,
 * and a stack of big buttons a thumb cannot miss. One centred column, built
 * for a phone and widening to 40rem on a larger screen.
 */

/* The column's three blocks of their own are as wide as a `.band > .wrap`, the
 * About band's: the column plus its gutters, so the content inside is exactly
 * `--wrap`. Left at `--wrap` with the gutters inside it, the buttons came out
 * one gutter narrower than the About text below them. */
.welcome,
.links,
.follow {
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin: 0 auto;
}

.welcome {
  padding: clamp(1.75rem, 6vw, 4rem) var(--gutter) 0;
  text-align: center;
}

/* Always a circle, as on her social profiles. No ring of ours: the logo is a
 * finished badge with its own cream border and terracotta ring, and a second
 * line round it would be a frame on a frame. 160px on a phone is what lets the
 * 480px file serve a 3x screen exactly; see the `sizes` on the image. */
.welcome__portrait {
  display: block;
  width: 10rem;
  height: 10rem;
  margin: 0 auto 1.75rem;
  border-radius: 50%;
}

.welcome__portrait img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

@media (min-width: 40em) {
  .welcome__portrait {
    width: 12rem;
    height: 12rem;
  }
}

/* The name is an outlined wordmark, so it sits on its own line with no line
 * box of its own to add air under it. The image is 38% descender — the tail of
 * the y — which is why the gap below looks smaller than the number says. */
.welcome__name {
  margin: 0 0 0.5rem;
  line-height: 0;
}

.welcome__name img {
  display: inline-block;
  height: 3.25rem;
  width: auto;
  max-width: 100%;
}

@media (min-width: 40em) {
  .welcome__name img {
    height: 3.75rem;
  }
}

/* The wordmark is the page's h1, so that the heading is her name. These undo
 * what `h1` and `.brand-atm h1` would lend it: the wordmark is an image with no
 * line box of its own, and the display size would only move its baseline. */
.brand-rp .welcome .welcome__name {
  font-size: 1rem;
  margin: 0 0 0.5rem;
}

/* "Not invisible. Unignorable." — a `.display` paragraph now rather than the
 * h1, set exactly as the h1 was. Held well under After Tea Media's display
 * size, which is tuned for a 56rem page: at 76px "Not invisible." no longer
 * fits this column on one line. */
.brand-rp .welcome__headline {
  font-size: clamp(2.5rem, 11vw, 3.375rem);
  margin: 0 0 1rem;
}

.welcome__line {
  max-width: 25rem;
  margin: 0 auto;
  color: var(--ink-muted);
  text-wrap: balance;
}

/* ── The buttons ──────────────────────────────────────────────────────
 *
 * Full width, stacked, and at least 72px tall, so every one is an easy target
 * for a thumb. The brief asks for the first two to be the boldest, so they are
 * filled in terracotta; the rest are paper with a boundary.
 *
 * A button whose link is not ready yet keeps its place and says "Coming soon".
 * That state is the absence of an `href` and nothing else: the label, the
 * dashed edge and the hiding of "(opens in a new tab)" all follow from it in
 * CSS. Going live is adding the `href` and the `target` and deleting the
 * `data-pending` note — one edit, and nothing to forget to undo.
 */

.links {
  padding: 2rem var(--gutter) clamp(3rem, 9vw, 4.5rem);
}

.links ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.875rem;
}

.links li {
  margin: 0;
}

.link-button {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  min-height: 4.5rem;
  padding: 0.875rem 1.25rem;
  border: 1px solid var(--rule-strong);
  border-radius: 12px;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-ui);
  text-align: center;
  text-decoration: none;
  text-wrap: balance;
  transition: background-color 120ms ease, border-color 120ms ease,
    color 120ms ease;
}

.link-button__title {
  font-size: 1.1875rem;
  font-weight: 500;
  line-height: 1.3;
}

.link-button__note {
  font-size: 1rem;
  line-height: 1.4;
  color: var(--ink-muted);
}

.link-button--primary {
  background: var(--accent-ink);
  border-color: var(--accent-ink);
  color: var(--page);
}

.link-button--primary .link-button__note {
  color: var(--page);
}

/* The global `a:hover` would turn the label burgundy; on a filled button that
 * is burgundy on terracotta. These hold the label where it is, and the fill is
 * what changes.
 *
 * Live buttons only, like the fills below. A "Coming soon" button has no fill,
 * so on the primary one this paper-coloured label would be paper on paper:
 * the title and "Coming soon" vanished on hover, and on a phone stayed gone
 * until something else was tapped, since touch keeps :hover after a tap. */
a.link-button[href]:hover {
  color: var(--ink);
}

a.link-button--primary[href]:hover {
  color: var(--page);
}

/* Pointer devices only. On a phone a tapped button would otherwise keep its
 * hover colour when you come back to the tab, which reads as "still pressed". */
@media (hover: hover) {
  a.link-button[href]:hover {
    background: var(--page-tint);
    border-color: var(--ink);
  }

  a.link-button--primary[href]:hover {
    background: var(--rp-burgundy);
    border-color: var(--rp-burgundy);
  }
}

a.link-button:focus-visible {
  outline-offset: 4px;
  border-radius: 12px;
}

.link-button:not([href]) {
  border-style: dashed;
  border-color: var(--rule-strong);
  background: transparent;
  color: var(--ink-muted);
  cursor: default;
}

.link-button:not([href]) .link-button__note {
  color: var(--ink-muted);
}

.link-button:not([href])::after {
  content: "Coming soon";
  margin-top: 0.5rem;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.link-button:not([href]) .link-button__newtab {
  display: none;
}

/* ── About, and the sign-off ──────────────────────────────────────────── */

.about p {
  margin-bottom: 1.5rem;
}

.signoff {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 500;
  margin: 0;
}

/* The signature sits on the same baseline as "With love,". The image runs
 * 38.6% of its height below the script's own baseline — the y's tail — and
 * vertical-align lowers the image's foot by exactly that: 0.3864 × 2.75em.
 * If the signature is regenerated, og/rubypemberton-art.py prints the new
 * share. */
.signature {
  height: 2.75em;
  width: auto;
  margin-left: 0.25em;
  vertical-align: -1.0626em;
}

/* ── Social icons ─────────────────────────────────────────────────────
 *
 * Single-colour glyphs in the page ink, in a row. Meta permits the Instagram
 * glyph in any solid colour when it sits in a line-up of social icons, which
 * this is. 48px targets, because these are the smallest things on the page
 * anyone will want to tap.
 *
 * An icon with no `href` yet is simply not shown: unlike a button, an icon
 * cannot explain that it is coming soon, and a dead one looks broken.
 */

.follow {
  padding: clamp(2rem, 6vw, 3rem) var(--gutter);
}

.socials {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 0.75rem;
}

.socials li {
  margin: 0;
}

.socials li:has(> a:not([href])) {
  display: none;
}

.socials a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  color: var(--ink);
}

.socials svg {
  display: block;
  width: 1.5rem;
  height: 1.5rem;
  fill: currentColor;
}

@media (hover: hover) {
  .socials a[href]:hover {
    color: var(--rp-burgundy);
    background: var(--page-tint);
  }
}

.socials a:focus-visible {
  outline-offset: 0;
  border-radius: 50%;
}

.brand-rp .footer__fine {
  flex: 1 1 15rem;
}

/* ── The footer on a phone ────────────────────────────────────────────
 *
 * Below 40em there is no room for the footer's two sides, so it stacks — and
 * stacked left-aligned, the links, the copyright, the small print and the mark
 * each sat on their own ragged edge with the mark stranded underneath. Centred
 * instead, on every site: one axis, top to bottom, with the mark closing it as
 * a sign-off. The small print is balanced so its lines come out even rather
 * than leaving one word on the last.
 *
 * Here, after every footer rule and `.brand-rp .footer__fine`, so that equal
 * specificity is settled by order. In a column, `flex-basis` would mean height,
 * which is why the row-layout bases are reset. */
@media (max-width: 39.99em) {
  /* The same 0.75rem between lines as inside `.footer__fine`, so a footer
   * whose lines are its own children (the company's) spaces them exactly as
   * one that groups them (the signed footers). */
  footer,
  footer.footer--signed {
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    text-align: center;
  }

  footer nav {
    justify-content: center;
    gap: 0.5rem 1.5rem;
  }

  .footer__fine,
  .brand-rp .footer__fine {
    flex: none;
    align-items: center;
  }

  .footer__legal,
  footer > .footer__legal {
    flex-basis: auto;
    max-width: 22rem;
    text-wrap: balance;
  }

  .maker {
    margin: 1rem 0 0;
  }
}

/* ── The 14 Years Later quiz ──────────────────────────────────────────
 *
 * rubypemberton.com/quiz/. Three screens in one page, the intro, a question
 * and the result, swapped with the `hidden` attribute. The intro and the head
 * of the result stand on the emerald, as Ruby's original did; the questions
 * and the rest of the result are on the paper, so the buttons are the home
 * page's own and every colour pair is one check.py already measures.
 */

/* Components below set `display`, which would otherwise beat the attribute. */
.quiz-page [hidden] {
  display: none !important;
}

.quiz-intro {
  padding-top: clamp(2.5rem, 8vw, 4rem);
}

/* The logo as a small badge, carrying the Pinterest card. Its own cream border
 * is what separates it from the emerald. */
.quiz-badge {
  display: block;
  width: 6.5rem;
  height: 6.5rem;
  margin: 0 0 1.75rem;
  border-radius: 50%;
}

.quiz-badge img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

/* The column is 40rem, so the headline is held under the company's display
 * size, as the home page's is. */
.brand-rp .quiz-intro h1 {
  font-size: clamp(2.375rem, 9.5vw, 3.125rem);
  line-height: 1.05;
  margin: 0 0 1.5rem;
}

/* Ruby's story, in the display face at a reading size: her voice, before the
 * functional sans takes over for the instructions. */
.quiz-story {
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 500;
  line-height: 1.45;
  margin: 0 0 1rem;
}

.quiz-meta,
.quiz-noscript {
  font-size: 1rem;
  color: var(--ink-muted);
  margin: 1.75rem 0 1.5rem;
}

/* The quiz's own buttons. The same shape and size as the home page's link
 * buttons, terracotta on the paper and cream on the emerald, because there
 * the terracotta's edge would vanish into the ground. */
.quiz-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 4rem;
  padding: 0.875rem 1.25rem;
  border: 1px solid var(--accent-ink);
  border-radius: 12px;
  background: var(--accent-ink);
  color: var(--page);
  font-family: var(--font-ui);
  font-size: 1.1875rem;
  font-weight: 500;
  line-height: 1.3;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease,
    color 120ms ease;
}

.quiz-button--quiet {
  background: var(--page);
  border-color: var(--rule-strong);
  color: var(--ink);
}

.band--deep .quiz-button {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--deep);
}

@media (hover: hover) {
  .quiz-button:hover {
    background: var(--rp-burgundy);
    border-color: var(--rp-burgundy);
  }

  .quiz-button--quiet:hover {
    background: var(--page-tint);
    border-color: var(--ink);
  }

  .band--deep .quiz-button:hover {
    background: var(--accent-ink-strong);
    border-color: var(--accent-ink-strong);
  }
}

.quiz-button:focus-visible,
.quiz-option:focus-visible,
.quiz-back:focus-visible,
.quiz-reclaim input:focus-visible {
  outline: 2px solid var(--rp-burgundy);
  outline-offset: 3px;
}

.band--deep .quiz-button:focus-visible {
  outline-color: var(--ink);
}

/* A heading takes focus when its screen appears, so that a screen reader
 * reads the new question. It is not a control, so it draws no ring. */
.quiz-page h2[tabindex]:focus {
  outline: none;
}

/* ── A question ── */

.quiz-question {
  padding-top: clamp(2rem, 6vw, 3rem);
}

/* Decoration: the same progress is given in words above the question. */
.quiz-progress {
  height: 4px;
  margin: 0 0 1.5rem;
  border-radius: 2px;
  background: var(--rule);
  overflow: hidden;
}

.quiz-progress span {
  display: block;
  width: 0;
  height: 100%;
  background: var(--accent-ink);
  transition: width 300ms ease;
}

.quiz-count {
  margin-bottom: 0.875rem;
}

.brand-rp .quiz-question h2 {
  font-size: clamp(1.875rem, 7.5vw, 2.375rem);
  line-height: 1.15;
  margin: 0 0 1.75rem;
}

.quiz-options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
}

.quiz-options li {
  margin: 0;
}

.quiz-option {
  display: block;
  width: 100%;
  min-height: 3.75rem;
  padding: 0.875rem 1.25rem;
  border: 1px solid var(--rule-strong);
  border-radius: 12px;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  line-height: 1.45;
  text-align: left;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease,
    box-shadow 120ms ease;
}

@media (hover: hover) {
  .quiz-option:hover {
    background: var(--page-tint);
    border-color: var(--ink);
  }
}

/* The chosen answer: a burgundy edge, doubled so it reads as a state and not
 * as hover. Shown for a beat before the next question, and again on the way
 * back. */
.quiz-option[aria-pressed="true"] {
  background: var(--page-tint);
  border-color: var(--rp-burgundy);
  box-shadow: inset 0 0 0 1px var(--rp-burgundy);
}

.quiz-back {
  min-height: 3rem;
  margin-top: 1.25rem;
  padding: 0.5rem 0;
  border: 0;
  background: none;
  color: var(--ink-muted);
  font-family: var(--font-ui);
  font-size: 1rem;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}

.quiz-back.is-hidden {
  visibility: hidden;
}

/* ── The result ── */

.quiz-result-top {
  padding-top: clamp(2.5rem, 8vw, 4rem);
  padding-bottom: clamp(2.5rem, 8vw, 3.5rem);
}

.brand-rp .quiz-result-name {
  font-size: clamp(2.375rem, 10vw, 3.25rem);
  line-height: 1.05;
  margin: 0 0 1.25rem;
}

.quiz-nowrap {
  white-space: nowrap;
}

.quiz-result-line {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.375rem;
  font-weight: 500;
  line-height: 1.45;
  margin: 0;
}

.quiz-result-body {
  padding-top: clamp(2.5rem, 7vw, 3.5rem);
}

.quiz-result-body h3 {
  margin: 2.5rem 0 0.75rem;
}

.quiz-also {
  color: var(--ink-muted);
}

.quiz-step {
  margin: 0;
  padding: 1.125rem 1.25rem;
  border-left: 3px solid var(--rp-burgundy);
  border-radius: 0 12px 12px 0;
  background: var(--page-tint);
}

.quiz-gp {
  margin-top: 1rem;
}

.quiz-reclaim label {
  display: block;
  margin: 1rem 0 0.375rem;
  font-size: 1rem;
  color: var(--ink-muted);
}

/* 17px, because iOS zooms the page into any field set smaller than 16px. */
.quiz-reclaim input {
  width: 100%;
  padding: 0.75rem 1rem;
  border: 1px solid var(--rule-strong);
  border-radius: 10px;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 1.0625rem;
}

.quiz-reclaim input::placeholder {
  color: var(--ink-muted);
  opacity: 1;
}

.quiz-reclaim .notice {
  margin-top: 1rem;
}

.quiz-links {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.875rem;
}

.quiz-links li {
  margin: 0;
}

.quiz-share-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
}

.quiz-again {
  margin-top: 2.5rem;
}

.quiz-signoff {
  margin-top: 2.5rem;
}

/* ── Placeholder marker ───────────────────────────────────────────────
 *
 * Wraps every value that is not yet known, so an un-substituted placeholder
 * is impossible to miss on a rendered page rather than shipping as
 * plausible fiction. web/README.md has the grep that finds them all.
 */

.todo {
  background: rgba(200, 106, 46, 0.12);
  color: var(--accent-ink);
  font-family: var(--font-ui);
  font-size: 0.8125rem;
  font-weight: 600;
  padding: 0.1em 0.45em;
  border-radius: 3px;
  border: 1px dashed var(--accent-mark);
}

/* ── Motion ───────────────────────────────────────────────────────────── */

/* ── The analytics notice ─────────────────────────────────────────────
 *
 * Built by analytics.js, shown once, and reopened from "Cookie settings" in
 * every footer. A small card at the foot of the screen in the site's own paper,
 * ink and hairline, so it reads as part of the page rather than as a vendor's
 * banner. It does not block the page: nothing on it has to be answered first.
 *
 * The two buttons are the same size and shape. Turning analytics off has to be
 * as easy as leaving it on, and a large "OK" beside a small text link would
 * argue otherwise. The fill marks the one that leaves things as they are.
 *
 * Bottom-left on a wide screen, so it sits away from the content's centre; on
 * a phone it spans the width above the home indicator.
 */
.consent {
  position: fixed;
  z-index: 50;
  left: var(--gutter);
  right: var(--gutter);
  bottom: max(1rem, env(safe-area-inset-bottom));
  max-width: 26rem;
  padding: 1.125rem 1.25rem 1.25rem;
  background: var(--page);
  color: var(--ink);
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  box-shadow: 0 10px 30px rgba(28, 27, 24, 0.12);
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  line-height: 1.55;
}

@media (max-width: 30em) {
  .consent {
    left: 0.75rem;
    right: 0.75rem;
    max-width: none;
  }
}

.consent__text {
  margin: 0 0 1rem;
  color: var(--ink-muted);
}

.consent__text a {
  white-space: nowrap;
}

.consent__actions {
  display: flex;
  gap: 0.625rem;
}

.consent__button {
  flex: 1 1 0;
  min-height: 2.75rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--ink);
  border-radius: 4px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
}

.consent__button--primary {
  background: var(--ink);
  color: var(--page);
}

@media (hover: hover) {
  .consent__button:hover {
    background: var(--page-tint);
  }

  .consent__button--primary:hover {
    background: var(--ink-muted);
    border-color: var(--ink-muted);
  }
}

.consent__button:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

@media print {
  .consent {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ── Print ────────────────────────────────────────────────────────────
 *
 * Only the privacy policy is ever likely to be printed, and it is the sort
 * of document people do print. Drop the chrome, keep the words, and put
 * link targets in the margin where a printed page cannot be clicked.
 */

@media print {
  .masthead,
  .skip-link,
  .hero__stage,
  .stores {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
    line-height: 1.5;
  }

  .doc,
  .doc--wide main,
  .wrap {
    max-width: none;
  }

  .band {
    padding: 0;
  }

  a {
    color: #000;
  }

  .doc a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    word-break: break-all;
  }

  h2,
  h3 {
    break-after: avoid;
  }
}
