/* ===== design/tokens/space.css ===== */
/* Spacing, radius, elevation, motion, and layering.
 * Each is a fixed ladder. An off-scale value is a defect — extend the ladder deliberately
 * instead of reaching for an arbitrary number.
 */

:root {
  /* Spacing — 4px base. Used for padding, margin, and gap. */
  --space-0:  0;
  --space-1:  0.25rem;  /*  4px */
  --space-2:  0.5rem;   /*  8px */
  --space-3:  0.75rem;  /* 12px */
  --space-4:  1rem;     /* 16px */
  --space-5:  1.5rem;   /* 24px */
  --space-6:  2rem;     /* 32px */
  --space-7:  3rem;     /* 48px */
  --space-8:  4rem;     /* 64px */

  /* Radius */
  --radius-sm:   0.25rem;
  --radius-md:   0.5rem;
  --radius-lg:   0.75rem;
  --radius-full: 9999px;

  /* Border widths. The accent bar that marks a thing as current or lead: down
   * the inline-start edge of a callout, a selected row, a group heading or a
   * summary card, and under the selected tab. Added when Tasks needed it and
   * the only width token in the system was the focus ring, which means
   * something else. Every component and prototype call site uses it; the
   * one-off `.note` rules in previews/ are page chrome, not components, and are
   * left alone deliberately. */
  --border-width-accent: 3px;

  /* Elevation. Kept shallow — depth is carried by surface tokens, not heavy shadow. */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.06);
  --shadow-md: 0 2px 8px rgb(0 0 0 / 0.10);
  --shadow-lg: 0 8px 24px rgb(0 0 0 / 0.14);

  /* Focus ring. One definition, used everywhere — never restyled per component. */
  --focus-ring-width:  2px;
  --focus-ring-offset: 2px;

  /* Minimum touch target (WCAG 2.5.5). Never shrink below this. */
  --target-min: 44px;

  /* Motion */
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* Layering. A z-index not from this ladder is a defect. */
  --z-base:     0;
  --z-dropdown: 100;
  --z-sticky:   200;
  --z-overlay:  300;
  --z-modal:    400;
  --z-toast:    500;
}

/* Users who ask for reduced motion get none. Honour this everywhere, always. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    --duration-base: 0ms;
  }
}

/* ===== apps/marketing/src/styles/fonts.css ===== */
/* Self-hosted webfonts — ADR-0020.
 *
 * These are served from our own container, not from Google Fonts, and that is a
 * privacy decision rather than a performance one. A `<link>` to
 * fonts.googleapis.com sends every visitor's IP address to a US processor before
 * they have agreed to anything, which would make Google a sub-processor of this
 * product for no purpose the product has. `docs/legal/` enumerates four
 * sub-processors deliberately; this page adds none.
 *
 * The consequence is that the page makes NO third-party request at all, which is
 * also what lets the CSP forbid every external origin outright.
 *
 * Both families are SIL Open Font License 1.1 — see `../fonts/README.md` for the
 * versions, the exact sources, and how to refresh them.
 *
 * latin-ext is carried as well as latin, not for completeness but because ADR-0014
 * commits to Turkish: `ğ ş İ ı` live in latin-ext, and a marketing page that
 * cannot spell the target market's language is a page that will be rebuilt.
 */

@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("./fonts/instrument-serif-latin.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("./fonts/instrument-serif-latin-ext.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Karla is a variable font: one file covers 400 through 700, so the page carries
 * three weights for the price of one request. */
@font-face {
  font-family: Karla;
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("./fonts/karla-latin.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: Karla;
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("./fonts/karla-latin-ext.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ===== apps/marketing/src/styles/brand.css ===== */
/* The marketing brand layer — ADR-0020, STORY-049.
 *
 * This is NOT the product's design system. `design/tokens/color.css` is teal on
 * neutral grey, chosen for contrast on application screens; this is warm paper,
 * a high-contrast serif and a terracotta accent, chosen as an identity for one
 * public page. Both are deliberate and they are different things.
 *
 * The reason it lives here rather than in `design/tokens/`:
 *   1. Somebody importing `design/tokens/index.css` must never get this palette.
 *   2. `check-tags.mjs` watches `design/` as an input to the WEB surface, so a
 *      marketing colour tweak filed there would demand a `web` tag for a change
 *      that does not touch the web client. A tag that overstates what shipped is
 *      worse than no tag — `git.md`.
 *
 * The SCALES are not re-typed. `design/tokens/space.css` is inlined ahead of this
 * file by `build.mjs`, so `--space-*` here is the product's own ladder, one copy,
 * and `check-spacing.mjs` covers this directory so it stays that way.
 *
 * ── the three theme states ──────────────────────────────────────────────────
 * `design.md` requires all three, and the reason is that a colour whose only
 * definition sits inside a media query breaks one of them:
 *   1. bare :root                                     -> light
 *   2. prefers-color-scheme: dark, guarded            -> dark
 *   3. :root[data-theme="dark"]                       -> dark, explicitly
 *
 * There is no theme toggle on this page (decided 2026-09-06 — dark follows the
 * system), so state 3 is never reached in production today. It is defined anyway:
 * the day a toggle is added, the tokens must already work in both directions, and
 * writing it later is how one of the three states quietly ends up missing.
 */

:root {
  /* ---- private palette. Components use the semantic tokens below, never these ---- */
  --brand-paper-0: #faf6ef; /* the ground */
  --brand-paper-1: #f3ece0; /* alternating band */
  --brand-paper-2: #fffdf8; /* raised: the event card */
  --brand-paper-3: #f7f1e6; /* inset: the card's footnote */
  --brand-ink-900: #24201b;
  --brand-ink-600: #5c554a;
  /* Darkened from #857a68, which measured 3.59:1 on the alternating band against
   * the 4.5:1 small text needs. It sets every label, unit and line of fine print
   * on the page, so it was four failures at once — and none of them were visible
   * by eye, which is the whole argument for check-contrast-marketing.mjs. */
  --brand-ink-400: #6e6555;
  --brand-line-200: #e7ddcd;
  --brand-line-300: #ddd3c3;
  --brand-clay-700: #6f2a17;
  --brand-clay-600: #9c3d24;
  /* Likewise: 2.58:1 on the band, against the 3:1 large text needs. It sets the
   * numerals beside the five failure modes. */
  --brand-clay-400: #a67254;

  --brand-night-0: #17130f;
  --brand-night-1: #1e1813;
  --brand-night-2: #221b16;
  --brand-night-3: #1a1510;
  --brand-night-4: #100d0a;
  --brand-cream-50: #f4ece1;
  --brand-cream-200: #c2b5a4;
  --brand-cream-400: #9d8f7d;
  --brand-umber-700: #2e251e;
  --brand-umber-600: #382d25;
  --brand-clay-300: #e89a73;
  --brand-clay-200: #f2b795;
  --brand-clay-800: #8a6a56;

  /* ---- semantic: light ---- */
  --color-paper: var(--brand-paper-0);
  --color-paper-alt: var(--brand-paper-1);
  --color-paper-raised: var(--brand-paper-2);
  --color-paper-inset: var(--brand-paper-3);

  --color-ink: var(--brand-ink-900);
  --color-ink-soft: var(--brand-ink-600);
  --color-ink-mute: var(--brand-ink-400);

  --color-rule: var(--brand-line-300);
  --color-rule-soft: var(--brand-line-200);

  --color-accent: var(--brand-clay-600);
  --color-accent-hover: var(--brand-clay-700);
  --color-accent-quiet: var(--brand-clay-400);
  --color-on-accent: var(--brand-paper-0);

  --color-footer: var(--brand-ink-900);
  --color-footer-ink: #ddd2c3;
  --color-footer-mute: #a39684;
  --color-footer-rule: #3b342c;

  --shadow-card: 0 12px 32px rgb(60 44 30 / 0.07);

  color-scheme: light;

  /* ---- type ----
   * Display sizes use clamp() rather than a step per breakpoint, so the widths
   * BETWEEN breakpoints are designed too rather than merely surviving. Each is a
   * named step; an off-ladder font-size in a component is still a defect. */
  --font-display: "Instrument Serif", Iowan Old Style, Palatino, Georgia, serif;
  --font-body: Karla, "Segoe UI", system-ui, -apple-system, sans-serif;

  --step-hero: clamp(2.5rem, 5.4vw, 4.125rem);
  --step-section: clamp(2rem, 3.6vw, 2.875rem);
  --step-close: clamp(2.25rem, 4.4vw, 3.625rem);
  --step-card: 1.375rem;
  --step-module: 1.5625rem;
  --step-price: 2.75rem;
  --step-lede: clamp(1.0625rem, 1.4vw, 1.25rem);
  --step-body: 1rem;
  --step-small: 0.9375rem;
  --step-micro: 0.8125rem;
  --step-tiny: 0.75rem;

  --leading-display: 1.04;
  --leading-heading: 1.1;
  --leading-body: 1.6;
  --leading-lede: 1.65;

  --tracking-display: -0.02em;
  --tracking-label: 0.14em;

  --weight-regular: 400;
  --weight-semibold: 600;

  --measure: 68ch;

  /* ---- rhythm ----
   * Every value is a step from the product ladder inlined above. The section
   * rhythm changes at two breakpoints rather than scaling continuously, because
   * `check-spacing.mjs` requires spacing to come from the ladder and a clamp()
   * of raw lengths is exactly the off-scale value that rule exists to catch. */
  /* The page stops growing at 1320px. Without this the hero grid's second column
   * keeps widening on a large monitor and the event card ends up half a metre
   * across — which is what it did, and it was only visible by opening the page on
   * a wide viewport rather than by reading the grid declaration. */
  --content-max: 82.5rem;

  --pad-inline: var(--space-8);
  --pad-block: var(--space-8);
  --gap-grid: var(--space-7);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-paper: var(--brand-night-0);
    --color-paper-alt: var(--brand-night-1);
    --color-paper-raised: var(--brand-night-2);
    --color-paper-inset: var(--brand-night-3);

    --color-ink: var(--brand-cream-50);
    --color-ink-soft: var(--brand-cream-200);
    --color-ink-mute: var(--brand-cream-400);

    --color-rule: var(--brand-umber-600);
    --color-rule-soft: var(--brand-umber-700);

    /* Terracotta cannot survive on this ground — #9c3d24 as text on #17130f is
     * under 3:1. The accent lifts to a paler clay and the filled button inverts
     * to dark text on it, which is why --color-on-accent is not simply "paper". */
    --color-accent: var(--brand-clay-300);
    --color-accent-hover: var(--brand-clay-200);
    --color-accent-quiet: var(--brand-clay-800);
    --color-on-accent: #1a120d;

    --color-footer: var(--brand-night-4);
    --color-footer-ink: #ddd2c3;
    --color-footer-mute: #8d8172;
    --color-footer-rule: #2c241d;

    --shadow-card: 0 12px 32px rgb(0 0 0 / 0.45);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --color-paper: var(--brand-night-0);
  --color-paper-alt: var(--brand-night-1);
  --color-paper-raised: var(--brand-night-2);
  --color-paper-inset: var(--brand-night-3);

  --color-ink: var(--brand-cream-50);
  --color-ink-soft: var(--brand-cream-200);
  --color-ink-mute: var(--brand-cream-400);

  --color-rule: var(--brand-umber-600);
  --color-rule-soft: var(--brand-umber-700);

  --color-accent: var(--brand-clay-300);
  --color-accent-hover: var(--brand-clay-200);
  --color-accent-quiet: var(--brand-clay-800);
  --color-on-accent: #1a120d;

  --color-footer: var(--brand-night-4);
  --color-footer-ink: #ddd2c3;
  --color-footer-mute: #8d8172;
  --color-footer-rule: #2c241d;

  --shadow-card: 0 12px 32px rgb(0 0 0 / 0.45);

  color-scheme: dark;
}

/* ===== apps/marketing/src/styles/page.css ===== */
/* The marketing page — STORY-049, direction "Kitchen Notebook".
 *
 * Every spacing value is a step from the product ladder (`--space-*`, inlined
 * ahead of this file by `build.mjs`) and every colour and size is a token from
 * `brand.css`. `check-spacing.mjs` covers this directory, so an off-scale
 * padding fails the build rather than surviving review.
 *
 * Layout is classes rather than inline styles for one reason worth stating: a
 * media query and a theme token cannot reach an inline style, so responsiveness
 * and dark mode are the things that decide this.
 *
 * Breakpoints, in `em` so they respect the reader's font size:
 *   64em / 1024px — hero drops to one column
 *   68em / 1088px — plans 4 up -> 2 up
 *   62em /  992px — modules 3 up -> 2 up
 *   56em /  896px — failure modes 2 up -> 1 up, footer 4 up -> 2 up
 *   48em /  768px — header links collapse to the menu control
 *   39em /  624px — plans 2 up -> 1 up
 *   36em /  576px — buttons full width, footer to one column
 */

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

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

/* No `scroll-behavior: smooth`, and this is a decision rather than an omission.
 *
 * With smooth set on the root, Chrome ANIMATES the initial scroll to a fragment,
 * and the webfont swapping in shifts the layout underneath that animation and
 * cancels it. Measured here: loading `/#pricing` cold left the page at the top,
 * 2322px short of the section, while the same jump with `auto` landed exactly.
 * Preloading the faces did not fix it.
 *
 * So somebody pasting a link to a section would have arrived at the wrong place —
 * on the one page whose job is to be linked to. An anchor that always lands beats
 * one that animates and sometimes does not, and the honest fix without JavaScript
 * is not to animate. `prefers-reduced-motion` is moot as a result: there is no
 * motion anywhere on this page. */

body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--step-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;

  /* A pasted URL or a long unbroken word wraps rather than widening its box and
   * pushing the page sideways. See design/tokens/index.css — same reasoning, and
   * `break-word` rather than `anywhere` for the same reason. */
  overflow-wrap: break-word;
}

p,
h1,
h2,
h3 {
  margin: 0;
}

h1,
h2,
h3 {
  font-weight: var(--weight-regular);
}

img,
svg {
  max-width: 100%;
  height: auto;
}

a {
  color: var(--color-accent);
  text-decoration: none;
}

a:hover {
  color: var(--color-accent-hover);
  text-decoration: underline;
}

/* One focus style, defined once. :focus-visible so a mouse click shows nothing
 * and a keyboard always does. */
:where(a, button):focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.serif {
  font-family: var(--font-display);
}

.eyebrow {
  font-size: var(--step-micro);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  font-weight: var(--weight-semibold);
  color: var(--color-ink-mute);
}

/* ── shared type ─────────────────────────────────────────────────────────── */

.h1 {
  font-size: var(--step-hero);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}

.h2 {
  font-size: var(--step-section);
  line-height: var(--leading-heading);
}

.h3 {
  font-size: 1.1875rem;
  font-weight: var(--weight-semibold);
}

.lede {
  font-size: var(--step-lede);
  line-height: var(--leading-lede);
  color: var(--color-ink-soft);
  max-width: var(--measure);
  text-wrap: pretty;
}

.body {
  color: var(--color-ink-soft);
}

.fine {
  font-size: var(--step-small);
  color: var(--color-ink-mute);
}

/* ── sections ────────────────────────────────────────────────────────────── */

.section {
  padding-block: var(--pad-block);
  padding-inline: max(var(--pad-inline), calc((100% - var(--content-max)) / 2));
}

.section--alt {
  background: var(--color-paper-alt);
  border-block: 1px solid var(--color-rule);
}

/* The heading should not sit flush against the top edge after an anchor jump. */
.section[id] {
  scroll-margin-block-start: var(--space-5);
}

.intro {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 45rem;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding-inline: var(--space-6);
  padding-block: var(--space-3);
  border-radius: var(--radius-sm);
  font-weight: var(--weight-semibold);
  font-size: 1.0625rem;
  text-align: center;
}

.btn:hover {
  text-decoration: none;
}

/* `a.btn` rather than `.btn`, and this is not cosmetic: `a { color: … }` is one
 * element plus nothing, and a bare `.btn` class loses to it. The first build of
 * this page rendered every "Start free" as a filled terracotta block with an
 * invisible terracotta label, and the markup gave no hint — it was found by
 * looking at the rendered page. */
a.btn--primary {
  background: var(--color-accent);
  color: var(--color-on-accent);
}

a.btn--primary:hover {
  background: var(--color-accent-hover);
  color: var(--color-on-accent);
}

/* The border is `--color-ink-mute`, not `--color-rule`. A hairline rule measures
 * about 1.3:1 on paper and 1.6:1 on the night ground, and `design.md` requires
 * 3:1 on a meaningful UI boundary — which the edge of a control certainly is.
 * Container hairlines stay delicate on purpose; they are not controls. */
a.btn--quiet {
  border: 1px solid var(--color-ink-mute);
  color: var(--color-accent);
}

a.btn--quiet:hover {
  border-color: var(--color-accent);
  color: var(--color-accent-hover);
}

.btn--small {
  font-size: var(--step-small);
  padding-inline: var(--space-5);
  padding-block: var(--space-2);
}

/* ── masthead ────────────────────────────────────────────────────────────── */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-4);
  padding-inline: max(var(--pad-inline), calc((100% - var(--content-max)) / 2));
  border-block-end: 1px solid var(--color-rule);
}

a.wordmark {
  font-family: var(--font-display);
  font-size: 1.625rem;
  letter-spacing: -0.01em;
  color: var(--color-ink);
}

a.wordmark:hover {
  color: var(--color-ink);
  text-decoration: none;
}

.masthead__nav {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  font-size: var(--step-small);
}

.masthead__nav a:not(.btn) {
  color: var(--color-ink-soft);
}

.masthead__nav a:not(.btn):hover {
  color: var(--color-accent);
}

/* Present at phone width, and it opens nothing yet — STORY-049 says so out loud.
 * The two links it would reveal are both reachable by scrolling. */
.masthead__menu {
  display: none;
  align-items: center;
  justify-content: center;
  inline-size: 44px;
  block-size: 44px;
  padding: var(--space-0);
  background: none;
  border: 1px solid var(--color-ink-mute);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  cursor: pointer;
}

@media (max-width: 47.999em) {
  .masthead__nav a:not(.btn) {
    display: none;
  }

  .masthead__menu {
    display: inline-flex;
  }
}

/* ── hero ────────────────────────────────────────────────────────────────── */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 620px) minmax(0, 1fr);
  gap: var(--gap-grid);
  align-items: center;
  padding-block: var(--pad-block);
  padding-inline: max(var(--pad-inline), calc((100% - var(--content-max)) / 2));
}

.hero__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.hero__actions {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
}

@media (max-width: 63.999em) {
  .hero {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 35.999em) {
  .hero__actions {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }

  .hero__actions .btn {
    inline-size: 100%;
  }
}

/* ── the event card ──────────────────────────────────────────────────────── */

.card {
  background: var(--color-paper-raised);
  border: 1px solid var(--color-rule);
  box-shadow: var(--shadow-card);
}

.card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-4);
  padding-inline: var(--space-5);
}

.card__title {
  font-family: var(--font-display);
  font-size: 1.3125rem;
}

.card__pill {
  font-size: var(--step-tiny);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: var(--weight-semibold);
  color: var(--color-accent);
  border: 1px solid var(--color-accent);
  padding-block: var(--space-1);
  padding-inline: var(--space-2);
  white-space: nowrap;
}

.card__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-3);
  padding-inline: var(--space-5);
  border-block-start: 1px solid var(--color-rule-soft);
}

.card__label {
  font-size: var(--step-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: var(--weight-semibold);
  color: var(--color-ink-mute);
}

.card__value {
  font-family: var(--font-display);
  font-size: var(--step-card);
  color: var(--color-ink);
  text-align: end;
}

.card__value span {
  font-size: var(--step-small);
  color: var(--color-ink-mute);
}

.card__note {
  padding-block: var(--space-3);
  padding-inline: var(--space-5);
  border-block-start: 1px solid var(--color-rule-soft);
  background: var(--color-paper-inset);
  font-size: var(--step-micro);
  line-height: 1.5;
  color: var(--color-ink-soft);
}

/* ── the five failure modes ──────────────────────────────────────────────── */

.fails {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-7) var(--space-8);
  padding-block-start: var(--space-7);
}

.fail {
  display: flex;
  gap: var(--space-5);
}

.fail__n {
  font-family: var(--font-display);
  font-size: 2.125rem;
  color: var(--color-accent-quiet);
  line-height: 1;
}

.fail__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.fails__pull {
  display: flex;
  align-items: center;
}

.pull {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.4375rem;
  line-height: 1.45;
  color: var(--color-ink);
  border-inline-start: 3px solid var(--color-accent);
  padding-inline-start: var(--space-5);
}

@media (max-width: 55.999em) {
  .fails {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }
}

/* ── the six modules ─────────────────────────────────────────────────────── */

.modules {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6) var(--space-7);
  padding-block-start: var(--space-7);
}

.module {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border-block-start: 1px solid var(--color-rule);
  padding-block-start: var(--space-5);
}

.module__name {
  font-family: var(--font-display);
  font-size: var(--step-module);
}

@media (max-width: 61.999em) {
  .modules {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 39.999em) {
  .modules {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }
}

/* ── plans ───────────────────────────────────────────────────────────────── */

.plans {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-5);
  padding-block-start: var(--space-7);
}

.plan {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  padding: var(--space-5);
}

/* The lead plan is marked by a border AND by its label taking the accent, never
 * by colour alone — `design.md`. */
.plan--lead {
  border-color: var(--color-accent);
}

.plan--lead .eyebrow {
  color: var(--color-accent);
}

.plan__price {
  font-family: var(--font-display);
  font-size: var(--step-price);
  line-height: 1;
}

.plan__price span {
  font-family: var(--font-body);
  font-size: var(--step-small);
  color: var(--color-ink-mute);
}

.plan__limits {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--step-small);
  color: var(--color-ink-soft);
  line-height: 1.5;
}

/* Four plan cards in a tablet's width leave about 165px each, which wraps
 * "Unlimited events" onto two lines and makes the price fight the label. The
 * header comment above promised this stage before the CSS had it — found by
 * opening the built page at 834px rather than by reading the stylesheet. */
@media (max-width: 67.999em) {
  .plans {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 38.999em) {
  .plans {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
  }
}

/* ── closing ─────────────────────────────────────────────────────────────── */

.close {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  text-align: center;
  padding-block: var(--pad-block);
  padding-inline: max(var(--pad-inline), calc((100% - var(--content-max)) / 2));
}

.close .h2 {
  font-size: var(--step-close);
  line-height: 1.05;
  max-width: 45rem;
}

.close .lede {
  max-width: 36rem;
}

@media (max-width: 35.999em) {
  .close .btn {
    inline-size: 100%;
  }
}

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

.footer {
  background: var(--color-footer);
  color: var(--color-footer-ink);
  padding-block: var(--space-7) var(--space-6);
  padding-inline: max(var(--pad-inline), calc((100% - var(--content-max)) / 2));
}

.footer a:not(.btn) {
  color: var(--color-footer-ink);
  font-size: var(--step-small);
}

.footer a:not(.btn):hover {
  color: var(--color-on-accent);
}

.footer .eyebrow {
  color: var(--color-footer-mute);
}

.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
  gap: var(--space-7);
  padding-block-end: var(--space-7);
  border-block-end: 1px solid var(--color-footer-rule);
}

.footer__brand {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.footer__brand .wordmark {
  color: var(--color-footer-ink);
  font-family: var(--font-display);
  font-size: 1.625rem;
}

.footer__blurb {
  font-size: var(--step-small);
  color: var(--color-footer-mute);
  max-width: 18rem;
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.footer__legal {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  flex-wrap: wrap;
  padding-block-start: var(--space-5);
}

.footer__legal p {
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--color-footer-mute);
}

@media (max-width: 55.999em) {
  .footer__top {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
  }

  .footer__brand {
    grid-column: span 2;
  }
}

@media (max-width: 35.999em) {
  .footer__top {
    grid-template-columns: minmax(0, 1fr);
  }

  .footer__brand {
    grid-column: auto;
  }
}

/* Footer links are a stacked list of destinations, not prose, so the 44px touch
 * target in `design.md` applies to them — and at their natural line height they
 * were about 20px with a 12px gap. The row becomes the target and the gap goes to
 * zero, so the rhythm is unchanged while the thing a thumb has to hit is not. */
@media (max-width: 47.999em) {
  .footer__col {
    gap: var(--space-0);
  }

  .footer__col a {
    display: flex;
    align-items: center;
    min-block-size: 44px;
  }
}

/* ── rhythm at smaller viewports ─────────────────────────────────────────── */

@media (max-width: 55.999em) {
  :root {
    --pad-inline: var(--space-7);
    --pad-block: var(--space-7);
    --gap-grid: var(--space-6);
  }
}

@media (max-width: 35.999em) {
  :root {
    --pad-inline: var(--space-5);
    --pad-block: var(--space-7);
  }
}
