/* ==========================================================================
   The Light After: shared structure.
   Everything here is layout, rhythm and behavior. Nothing here picks a
   color, a corner radius or an easing curve: those are tokens, and the
   theme in src/themes/ sets them. Keeping that split means a palette change
   is one file, and the theme can never break layout.
   ========================================================================== */

/* ---- token contract -----------------------------------------------------
   A theme MUST define every custom property in this block. Defaults here are
   the neutral fallback, so a half-finished theme still renders readably
   instead of collapsing to unstyled black-on-white.
   ------------------------------------------------------------------------ */
:root {
  /* color */
  --bg: #fbf9f6;
  --bg-alt: #f4f0ea;
  --surface: #ffffff;
  --ink: #23201c;
  --ink-soft: #5d574f;
  --ink-faint: #8b8379;
  --accent: #a8813f;
  --accent-ink: #ffffff;
  --accent-soft: #f0e6d5;
  --line: #e2dbd1;
  --danger: #b3261e;

  /* shape */
  --radius-btn: 6px;
  --radius-card: 10px;
  --radius-img: 8px;
  --border-w: 1px;
  --btn-pad: 0.95rem 1.9rem;

  /* type */
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-ui: var(--font-body);
  --display-weight: 400;
  --display-tracking: -0.01em;
  --eyebrow-tracking: 0.18em;
  /* Display faces differ enormously in apparent size at the same point size,
     so the theme tunes this to its face. Cormorant Garamond runs small. */
  --display-scale: 1;
  --display-leading: 1.08;

  /* motion */
  --dur: 640ms;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --reveal-from: translateY(22px);
  --reveal-blur: 0px;

  /* rhythm */
  --measure: 34rem;
  --gutter: clamp(1.25rem, 5vw, 4rem);
  --section-y: clamp(4.5rem, 11vw, 9rem);
  --wrap: 72rem;

  /* elevation */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 4px 12px rgba(0, 0, 0, 0.04);
  --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.13);
}

/* ---- reset ---- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }

/* Skip link: the site is one long page, so a keyboard user landing on the
   nav needs a way past it. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--bg);
  padding: 0.75rem 1.25rem; border-radius: var(--radius-btn);
}
.skip:focus { left: 1rem; top: 1rem; }

:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---- layout primitives ------------------------------------------------------
   Alignment, in one place (client question, 2026-10-06: "some sections justify
   left, some center. Which is it?"). It is left:
   1. One left edge. Every heading, paragraph, list, card grid, form,
      accordion and pull quote starts at the .wrap edge.
   2. A second edge only for reading text beside an image or a hanging
      section head: About the Book, Author and Buy share one column split
      (.split below), so their text starts at the same x. In a .two-col pair
      the right column starts at its own edge, top-aligned with the left.
   3. A width cap is a measure, not a column: reading text stops at
      --measure, forms at 52rem (.wrap--start). A cap ends the line on the
      right and never centers the block.
   4. Centered only for a standalone band whose whole content is one call to
      action, with no image beside it: the Join band (.signup) and the 404
      page (.notfound), one rule for both below: .wrap--narrow, text-align:
      center, balanced lines. A self-contained
      card such as the /team sign-in may sit centered with left text inside,
      like a dialog. Never a centered heading over left text.
   5. Side by side, a photo sits on its column's outer edge and a book cover
      is centered in its column (its drop shadow is part of the image, so an
      edge would look off). Stacked, every image is centered.
   6. Rhythm: eyebrow to heading 1rem, heading to lede 1.25rem, text to a
      button row 2rem, heading block to content the .section__head margin.
   ------------------------------------------------------------------------ */
.wrap { width: min(var(--wrap), 100% - var(--gutter) * 2); margin-inline: auto; }
/* The centered column, for the centered moments in rule 4 only. */
.wrap--narrow { width: min(52rem, 100% - var(--gutter) * 2); }
/* The full wrap, so the heading starts on the main edge, with the content
   held to 52rem: a form any wider reads as a spreadsheet. */
.wrap--start > * { max-width: 52rem; }
.section { padding-block: var(--section-y); position: relative; }
.section--alt { background: var(--bg-alt); }

.section__head { margin-bottom: clamp(2.25rem, 5vw, 3.5rem); }
.eyebrow {
  font-family: var(--font-ui);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--eyebrow-tracking);
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1rem;
}
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: var(--display-leading);
  text-wrap: balance;
}
h2 { font-size: calc(clamp(2rem, 1.3rem + 3vw, 3.2rem) * var(--display-scale)); }
h3 { font-size: calc(clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem) * var(--display-scale)); line-height: 1.25; }
p { text-wrap: pretty; }
.lede { font-size: clamp(1.1rem, 1rem + 0.5vw, 1.3rem); color: var(--ink-soft); max-width: var(--measure); }
.prose > p + p { margin-top: 1.35em; }
.prose { max-width: var(--measure); color: var(--ink-soft); }
.prose strong { color: var(--ink); font-weight: 600; }

/* ---- buttons -------------------------------------------------------------
   Shape lives entirely in tokens (--radius-btn, --border-w, --btn-pad) plus
   a per-theme override hook, because "button shape / border variation" is one
   of the five things each variation is supposed to change.
   -------------------------------------------------------------------------- */
.btn {
  --_bg: var(--accent);
  --_fg: var(--accent-ink);
  --_bd: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6em;
  padding: var(--btn-pad);
  font-family: var(--font-ui);
  font-size: 0.875rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  text-decoration: none; cursor: pointer;
  background: var(--_bg); color: var(--_fg);
  border: var(--border-w) solid var(--_bd);
  border-radius: var(--radius-btn);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform 220ms var(--ease),
              box-shadow 320ms var(--ease);
}
.btn--ghost { --_bg: transparent; --_fg: var(--ink); --_bd: var(--line); }
.btn--quiet {
  --_bg: transparent; --_fg: var(--accent); --_bd: transparent;
  padding-inline: 0; text-transform: none; letter-spacing: 0.02em;
  font-size: 0.95rem;
}
.btn-row { display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* ---- nav ---- */
.nav {
  position: sticky; top: 0; z-index: 90;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px) saturate(1.1);
  border-bottom: 1px solid transparent;
  transition: border-color 300ms var(--ease), background 300ms var(--ease);
}
.nav[data-stuck="true"] { border-bottom-color: var(--line); }
/* Where a sticky column rides: clear of this nav at its tallest (about 110px
   from 62rem to 67rem, where the CTA wraps to two lines) with room to
   breathe. Layout, not a theme token, so it lives here and not in the
   contract above. */
:root { --stick-top: 8rem; }
.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding-block: 0.9rem; }
.nav__brand {
  font-family: var(--font-display); font-size: 1.15rem; letter-spacing: 0.02em;
  text-decoration: none; white-space: nowrap;
}
.nav__links { display: none; gap: 1.75rem; list-style: none; padding: 0; }
.nav__links a {
  font-family: var(--font-ui); font-size: 0.8rem; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; text-decoration: none;
  color: var(--ink-soft); position: relative; padding-block: 0.35rem;
  transition: color 240ms var(--ease);
}
.nav__links a:hover, .nav__links a[aria-current="true"] { color: var(--ink); }
.nav__cta { display: none; }
@media (min-width: 62rem) {
  .nav__links { display: flex; }
  .nav__cta { display: inline-flex; }
}

/* Reading-progress rail. Width is written by site.js. */
.progress {
  position: absolute; left: 0; bottom: -1px; height: 2px; width: 0;
  background: var(--accent); transform-origin: left;
}

/* ---- hero ---- */
.hero { padding-block: clamp(3rem, 7vw, 6rem) clamp(4rem, 9vw, 7rem); position: relative; overflow: hidden; }
.hero__grid {
  display: grid; gap: clamp(2.5rem, 6vw, 4.5rem);
  grid-template-columns: 1fr; align-items: center;
}
@media (min-width: 60rem) { .hero__grid { grid-template-columns: 1.05fr 0.95fr; } }
.hero__kicker {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  color: var(--accent); margin-bottom: 1.1rem;
}
/* 0.25em, not a fixed rem: the gap to the subtitle has to grow with the
   title, or at desktop sizes the two lines touch. */
.hero__title { font-size: calc(clamp(2.9rem, 1.6rem + 5.4vw, 5.4rem) * var(--display-scale)); margin-bottom: 0.25em; }
.hero__sub {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(1.15rem, 1rem + 0.8vw, 1.6rem);
  color: var(--ink-soft); line-height: 1.35; margin-bottom: 1.6rem;
  max-width: 24ch;
}
.hero__name {
  font-family: var(--font-ui); font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.22em; text-transform: uppercase; color: var(--ink-faint);
  margin-bottom: 1.5rem;
}
.hero__tagline { font-size: clamp(1.05rem, 1rem + 0.4vw, 1.2rem); color: var(--ink-soft); max-width: 36ch; margin-bottom: 2rem; }
.hero__meta { margin-top: 1.75rem; font-size: 0.82rem; color: var(--ink-faint); letter-spacing: 0.04em; }

.hero__art { position: relative; display: grid; place-items: center; }
.hero__book { width: min(100%, 27rem); filter: drop-shadow(0 30px 45px rgba(0, 0, 0, 0.22)); }

/* ---- cards / grids ---- */
/* 20rem minimum caps the 72rem wrap at three columns, so the six-card sets
   (reader cards, speaking topics) land as 3+3 instead of 4+2. */
.grid { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); }
.grid--duo { grid-template-columns: repeat(auto-fit, minmax(min(26rem, 100%), 1fr)); }
.card {
  background: var(--surface);
  border: var(--border-w) solid var(--line);
  border-radius: var(--radius-card);
  padding: clamp(1.4rem, 3vw, 2rem);
  transition: transform 340ms var(--ease), box-shadow 340ms var(--ease),
              border-color 340ms var(--ease), background 340ms var(--ease);
}
.card h3 { margin-bottom: 0.55rem; }
.card p { color: var(--ink-soft); font-size: 0.95rem; }
.card__num {
  font-family: var(--font-display); font-size: 0.95rem; color: var(--accent);
  display: block; margin-bottom: 0.75rem; letter-spacing: 0.1em;
}

/* ---- pull quote ----
   Flush left on the text edge, one sentence to a line: build.py sets each
   sentence in a .pullquote__line, so the three "You are..." lines stack under
   one another at every width instead of wherever balance breaks them. */
.pullquote {
  font-family: var(--font-display); font-style: italic;
  font-size: calc(clamp(1.7rem, 1.1rem + 2.6vw, 3rem) * var(--display-scale));
  line-height: 1.22; text-wrap: balance;
  max-width: 24ch;
  padding-block: clamp(2.5rem, 6vw, 4rem);
  color: var(--ink);
}
.pullquote__line { display: block; }
.pullquote cite { display: block; font-style: normal; font-family: var(--font-ui);
  font-size: 0.75rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-faint); margin-top: 1.5rem; }

/* ---- the second edge: About the Book, Author, Buy ----
   One column split for every section that sets reading text beside an image
   or a hanging section head (rule 2 at the top), written once so the three
   text columns start at the same x and can never drift apart. */
.split, .author__grid, .buy__grid {
  display: grid; gap: clamp(2rem, 5vw, 4rem); grid-template-columns: 1fr; align-items: start;
}
/* Stacked, the section head's own margin is the space below it. */
.split { row-gap: 0; }
@media (min-width: 55rem) {
  .split, .author__grid, .buy__grid { grid-template-columns: 0.8fr 1.2fr; }
  .split > .section__head { margin-bottom: 0; }
}
/* 28rem is the photo's own 896px at 2x, so a retina screen draws it pixel for
   pixel. Any other size is a resample, and a slight shrink is the worst kind:
   the 0.8fr column came to 435.2px, 3% under, and the browser's filter for
   that smoothed the lashes, hair and skin to half their detail. So once the
   column can hold 28rem with a text column of about 34rem beside it (73rem,
   which takes in an iPad Air or Pro in landscape), it is exactly 28rem.
   Narrower two-column windows keep the fluid split. Stacked on a tablet the
   photo would otherwise stretch to the full wrap and be upscaled. */
@media (min-width: 73rem) { .split, .author__grid, .buy__grid { grid-template-columns: 28rem 1fr; } }

/* ---- author ---- */
.author__photo {
  width: min(100%, 28rem); aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 20%;
  border-radius: var(--radius-img);
}
/* Stacked (rule 5), centered like every other image on its own line. Below
   the sticky breakpoint, so the riding photo is untouched. */
@media (max-width: 54.9375rem) { .author__photo { margin-inline: auto; } }
/* Two columns: the photo rides beside the text and stops where the text
   ends. The grid area is the sticky container, so the end of the row is the
   stop; align-self: start keeps the item photo-height, which is what leaves
   it room to travel. On a short window the photo narrows (4:5 of the height
   left below the offset) so all of it stays in view while it rides; svh,
   because a tablet's toolbars coming and going must not resize it. The full
   28rem needs 45rem (720px) of window height. */
@media (min-width: 55rem) {
  .author__media { position: sticky; top: var(--stick-top); align-self: start; }
  .author__photo {
    width: min(100%, (100vh - var(--stick-top) - 2rem) * 0.8);
    width: min(100%, (100svh - var(--stick-top) - 2rem) * 0.8);
  }
}
.author__sig {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(1.2rem, 1rem + 0.9vw, 1.55rem);
  color: var(--accent); margin-top: 2rem; line-height: 1.3;
}

/* ---- buy ---- */
/* Columns are the shared split above; the cover is centered against the text. */
.buy__grid { align-items: center; }
.buy__cover { width: min(100%, 26rem); margin-inline: auto; filter: drop-shadow(0 24px 40px rgba(0,0,0,0.2)); }
.retailer {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1.1rem 1.4rem; text-decoration: none;
  border: var(--border-w) solid var(--line); border-radius: var(--radius-card);
  background: var(--surface);
  transition: transform 300ms var(--ease), border-color 300ms var(--ease), box-shadow 300ms var(--ease);
}
.retailer__name { font-weight: 600; font-size: 1rem; }
.retailer__sub { font-size: 0.82rem; color: var(--ink-faint); }
.retailer__go { font-size: 1.1rem; color: var(--accent); transition: transform 300ms var(--ease); }
.retailer:hover .retailer__go { transform: translateX(4px); }

/* ---- media ---- */
/* The first label and its underline start on the text edge (rule 1), so the
   space between tabs is gap, not padding. On a phone the three split the row
   between them (see the phone block); wrap stays as the fallback for a zoomed
   or very narrow window. */
.media__tabs { display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; margin-bottom: 2rem; border-bottom: 1px solid var(--line); }
.tab {
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 0.7rem 0; cursor: pointer;
  font-family: var(--font-ui); font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-faint);
  transition: color 240ms var(--ease), border-color 240ms var(--ease);
}
.tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
.tab:hover { color: var(--ink); }
.tabpanel[hidden] { display: none; }

.appearance {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding-block: 1.1rem; border-bottom: 1px solid var(--line); text-decoration: none;
}
.appearance:hover .appearance__show { color: var(--accent); }
.appearance__show { font-size: 1.1rem; font-weight: 600; transition: color 240ms var(--ease); }
.appearance__host { font-size: 0.88rem; color: var(--ink-faint); }
.pill {
  font-family: var(--font-ui); font-size: 0.68rem; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  padding: 0.3rem 0.7rem; border-radius: 999px; white-space: nowrap;
  background: var(--accent-soft); color: var(--accent);
}

.qlist { list-style: none; padding: 0; display: grid; gap: 0.6rem; counter-reset: q; }
.qlist li {
  counter-increment: q; position: relative; padding-left: 2.6rem;
  color: var(--ink-soft); padding-block: 0.4rem;
}
.qlist li::before {
  content: counter(q, decimal-leading-zero);
  position: absolute; left: 0; top: 0.45rem;
  font-family: var(--font-display); font-size: 0.85rem; color: var(--accent);
  letter-spacing: 0.08em;
}

/* 18rem lands the tiles three across on a desktop, with the same 1.25rem gap
   as every other card grid. */
.kit {
  display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  container: kit / inline-size;
}
/* A last row that is not full would leave empty cells, so the first tile, the
   full kit, widens instead and the rest fill whole rows, whatever the count.
   37.25rem, 56.5rem and 75.75rem are where 18rem tiles with a 1.25rem gap go
   to two, three and four across. */
@container kit (37.25rem <= width < 56.5rem) {
  .kit__item:first-child:nth-last-child(odd) { grid-column: 1 / -1; }
}
@container kit (56.5rem <= width < 75.75rem) {
  .kit__item:first-child:nth-last-child(3n + 1) { grid-column: 1 / -1; }
  .kit__item:first-child:nth-last-child(3n + 2) { grid-column: span 2; }
}
.kit__item {
  display: flex; align-items: center; gap: 0.9rem; text-decoration: none;
  padding: 0.95rem 1.1rem;
  border: var(--border-w) solid var(--line); border-radius: var(--radius-card);
  background: var(--surface);
  transition: border-color 280ms var(--ease), transform 280ms var(--ease), background 280ms var(--ease);
}
.kit__icon {
  width: 2.1rem; height: 2.1rem; flex: none; display: grid; place-items: center;
  border-radius: calc(var(--radius-card) * 0.6);
  background: var(--accent-soft); color: var(--accent);
  font-size: 0.6rem; font-weight: 700; letter-spacing: 0.04em;
}
.kit__label { font-weight: 600; font-size: 0.92rem; line-height: 1.3; }
.kit__sub { font-size: 0.76rem; color: var(--ink-faint); line-height: 1.45; }

/* ---- praise ---- */
/* Card gaps are 1.25rem everywhere (.grid, .grid--tight, .kit, here). */
.praise__grid { columns: 1; column-gap: 1.25rem; }
@media (min-width: 48rem) { .praise__grid { columns: 2; } }
@media (min-width: 72rem) { .praise__grid { columns: 3; } }
.review {
  break-inside: avoid; margin-bottom: 1.25rem;
  background: var(--surface);
  border: var(--border-w) solid var(--line); border-radius: var(--radius-card);
  padding: clamp(1.4rem, 3vw, 1.9rem);
  transition: transform 340ms var(--ease), box-shadow 340ms var(--ease), border-color 340ms var(--ease);
}
.review__quote { font-family: var(--font-display); font-size: 1.12rem; line-height: 1.5; color: var(--ink); }
.review__quote::before { content: "\201C"; color: var(--accent); }
.review__quote::after { content: "\201D"; color: var(--accent); }
.review__name { margin-top: 1.1rem; font-weight: 600; font-size: 0.92rem; }
.review__cred { font-size: 0.78rem; color: var(--ink-faint); line-height: 1.45; }

/* ---- email, and the 404: the centered moments ---- */
/* The two centered moments (rule 4), the Join band and the 404 page: centered
   all the way down, with balanced lines so no word or link is left alone on
   the last one. */
.signup, .notfound { text-align: center; }
.signup .lede, .signup .signup__nudge, .notfound .lede { text-wrap: balance; }
/* 2em is the size this heading has always rendered at: the inline clamp() it
   replaces had no spaces around "+", which makes it invalid, so the browser
   dropped it and used its default h1 size. Kept, so the page looks the same. */
.notfound h1 { font-size: 2em; margin-bottom: 1.25rem; }
.notfound .lede { margin: 0 auto 2rem; }
.notfound .btn-row { justify-content: center; }
.signup__form {
  display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center;
  max-width: 44rem; margin: 2rem auto 0;
}
.signup__name { flex: 1 1 10rem; }
.signup__input { flex: 2 1 16rem; }
.signup__promise { margin-top: 1.1rem; font-size: 0.78rem; color: var(--ink-faint); }
.signup__nudge { margin-top: 1.5rem; font-size: 0.92rem; color: var(--ink-soft); }
.signup__nudge a { color: var(--accent); text-underline-offset: 3px; }
/* "Already on the team?" under the Launch Team page's buttons. */
.hero__member { margin-top: 1.1rem; font-size: 0.92rem; color: var(--ink-soft); }
.hero__member a { color: var(--accent); text-underline-offset: 3px; }
/* Inside the flex form (so site.js can find it scoped to the form), so it
   needs a full row of its own rather than sitting beside the button. */
.signup__form .form__status { flex: 1 0 100%; margin-top: 0.4rem; }
/* The free journal: one line above the waitlist form, and its download under
   the thank-you once a sign-up has gone through (site.js removes [hidden]). */
.signup__offer { margin: 1rem auto 0; max-width: 38rem; color: var(--ink-soft); }
.form__gift { margin: 1.25rem 0 0; }
.signup__form .form__gift { flex: 1 0 100%; margin-top: 0.75rem; }

/* ---- next ---- */
.next__item {
  display: grid; gap: 0.6rem 1.5rem; padding-block: 1.6rem;
  border-top: 1px solid var(--line);
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) { .next__item { grid-template-columns: 14rem 1fr auto; align-items: baseline; } }
.next__label { font-family: var(--font-display); font-size: 1.4rem; line-height: 1.3; }
.next__label a { text-decoration: none; transition: color 240ms var(--ease); }
.next__label a:hover { color: var(--accent); }
.next__body { color: var(--ink-soft); font-size: 0.95rem; }

/* ---- footer ---- */
.footer { padding-block: clamp(3rem, 6vw, 4.5rem) 2.5rem; border-top: 1px solid var(--line); font-size: 0.85rem; }
.footer__grid { display: grid; gap: 2rem; grid-template-columns: 1fr; }
@media (min-width: 48rem) { .footer__grid { grid-template-columns: 1.4fr 1fr 1fr; } }
.footer h4 { font-family: var(--font-ui); font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 0.9rem; }
.footer ul { list-style: none; padding: 0; display: grid; gap: 0.5rem; }
.footer a { color: var(--ink-soft); text-decoration: none; transition: color 220ms var(--ease); }
.footer a:hover { color: var(--accent); }
/* The bottom row is laid on the footer's own columns: the copyright on the
   main edge, and the credit line (and a publisher, when there is one) from
   the Connect column, so no line ends up pushed to the right or a few pixels
   off a column. Stacked on the main edge below 48rem, like the grid above. */
.footer__bottom {
  margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--line);
  display: grid; gap: 1rem 2rem; grid-template-columns: 1fr;
  color: var(--ink-faint); font-size: 0.78rem; text-wrap: pretty;
}
@media (min-width: 48rem) {
  .footer__bottom { grid-template-columns: 1.4fr 1fr 1fr; }
  .footer__bottom > :not(:first-child) { grid-column: 2 / -1; }
}

/* ---- scroll reveal ------------------------------------------------------
   The class is added by site.js only when IntersectionObserver exists, so
   with JS off every section is visible rather than permanently transparent.
   -------------------------------------------------------------------------- */
[data-reveal] { opacity: 1; }
.js [data-reveal] {
  opacity: 0;
  transform: var(--reveal-from);
  filter: blur(var(--reveal-blur));
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), filter var(--dur) var(--ease);
}
.js [data-reveal].is-in { opacity: 1; transform: none; filter: none; }
.js [data-reveal-stagger] > * { transition-delay: calc(var(--i, 0) * 70ms); }

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; transition: none !important; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ---- accordion (native <details>, so it works with JS off) ---- */
.acc-group { border-top: 1px solid var(--line); }
.acc { border-bottom: 1px solid var(--line); }
.acc__summary {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding-block: 1.35rem; cursor: pointer; list-style: none;
  font-family: var(--font-display); font-size: calc(clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem) * var(--display-scale));
  line-height: 1.3; text-wrap: balance;
  transition: color 240ms var(--ease);
}
.acc__summary::-webkit-details-marker { display: none; }
.acc__mark { position: relative; width: 1rem; height: 1rem; flex: none; }
.acc__mark::before, .acc__mark::after {
  content: ""; position: absolute; inset: 50% 0 auto 0; height: 1px;
  background: var(--accent); transition: transform 320ms var(--ease);
}
.acc__mark::after { transform: rotate(90deg); }
.acc[open] .acc__mark::after { transform: rotate(0deg); }
.acc__body { padding-bottom: 2rem; }

/* <picture> must not become the layout box: the <img> inside it carries all
   the positioning classes. */
picture { display: contents; }

/* ---- mobile menu --------------------------------------------------------
   Below the breakpoint the inline links are gone, so without this the phone
   gets a header with a name in it and no way to reach anything.
   ------------------------------------------------------------------------ */
.nav__end { display: flex; align-items: center; gap: 0.6rem; }
.nav__toggle {
  display: grid; place-items: center;
  width: 2.75rem; height: 2.75rem; padding: 0;
  background: none; border: var(--border-w) solid var(--line);
  border-radius: var(--radius-btn); cursor: pointer;
  transition: border-color 240ms var(--ease), background 240ms var(--ease);
}
.nav__toggle:hover { border-color: var(--accent); }
.nav__bars { position: relative; }
.nav__bars, .nav__bars::before, .nav__bars::after {
  content: ""; display: block; width: 1.1rem; height: 1.5px;
  background: var(--ink); transition: transform 280ms var(--ease), opacity 200ms var(--ease);
}
.nav__bars::before { position: absolute; transform: translateY(-6px); }
.nav__bars::after  { position: absolute; transform: translateY(6px); }
.nav__toggle[aria-expanded="true"] .nav__bars { background: transparent; }
.nav__toggle[aria-expanded="true"] .nav__bars::before { transform: rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__bars::after  { transform: rotate(-45deg); }

.menu {
  border-top: 1px solid var(--line);
  background: var(--bg);
  padding: 1.25rem var(--gutter) 1.75rem;
}
.menu[hidden] { display: none; }
.menu__links { list-style: none; padding: 0; margin: 0 0 1.25rem; display: grid; }
.menu__links a {
  display: block; padding: 0.85rem 0; text-decoration: none;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-display); font-size: 1.3rem;
}
.menu__cta { width: 100%; margin-top: 0.6rem; }

@media (min-width: 62rem) {
  .nav__toggle { display: none; }
  .menu { display: none !important; }
}

/* On a phone the hero is the whole first screen; give the cover a chance to
   appear without three swipes. */
@media (max-width: 47.9375rem) {
  .hero { padding-block: 2.25rem 3rem; }
  .hero__title { font-size: clamp(2.6rem, 1.4rem + 7vw, 3.6rem); }
  .hero__tagline { margin-bottom: 1.5rem; }
  .hero__grid { gap: 2rem; }
  .btn { width: 100%; }
  .btn-row { gap: 0.6rem; }
  /* The media tabs share the row in thirds, so they stay one row and the
     underline runs edge to edge. */
  .media__tabs { gap: 0; }
  .tab { flex: 1 1 0; padding-inline: 0.5rem; }
  .nav__brand { font-size: 1rem; }
}

/* ---- utility ---- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- inner-page hero (launch team, speaking) ----
   Same grid as the home hero, with a smaller title: these headings are
   sentences, and at the home page's book-title size they wrap to five lines. */
.hero__title--page { font-size: calc(clamp(2.4rem, 1.5rem + 3.6vw, 4.1rem) * var(--display-scale)); margin-bottom: 1.25rem; }
/* Rule 5: side by side the photo sits on the wrap's right edge, under the
   nav button; stacked it is centered, like every other image on its own line. */
.page-hero__photo {
  width: min(100%, 24rem); aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 20%;
  border-radius: var(--radius-img); justify-self: center; box-shadow: var(--shadow-lg);
}
@media (min-width: 60rem) { .page-hero__photo { justify-self: end; } }

.two-col { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 60rem) { .two-col { grid-template-columns: 1.15fr 0.85fr; } }
.grid--tight { gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); }

/* A row of pills: the launch team hero facts, the speaking formats. 0.5rem
   both ways, so a wrapped row sits as close as the pills beside it. */
.pills { display: flex; flex-wrap: wrap; gap: 0.5rem; list-style: none; padding: 0; margin-top: 1.5rem; }
.formats { margin-bottom: 2rem; }

/* Numbered "how you can help" list. */
.steps { list-style: none; padding: 0; counter-reset: step; }
.steps li {
  counter-increment: step; display: grid; grid-template-columns: 2.75rem 1fr; gap: 0.5rem;
  padding-block: 1.1rem; border-top: 1px solid var(--line); color: var(--ink-soft);
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--font-display); font-size: 1.05rem; color: var(--accent); letter-spacing: 0.08em;
}

.ticks { list-style: none; padding: 0; display: grid; gap: 0.2rem; }
.ticks li {
  display: flex; gap: 0.85rem; align-items: baseline;
  padding-block: 0.8rem; border-top: 1px solid var(--line); color: var(--ink-soft);
}
.ticks li::before {
  content: ""; flex: none; width: 0.45rem; height: 0.45rem; border-radius: 50%;
  background: var(--accent); transform: translateY(-0.1rem);
}

/* "A gift, not a trade": the review-policy promise, set apart on purpose so
   nobody reads the launch team page as asking for reviews in exchange. */
.callout {
  background: var(--surface);
  border: var(--border-w) solid var(--line); border-left: 2px solid var(--accent);
  border-radius: var(--radius-card); padding: clamp(1.5rem, 3vw, 2.1rem);
}
.callout h3 { margin-bottom: 0.75rem; }
.callout p { color: var(--ink-soft); }
/* Its top on the "How you can help" eyebrow beside it, and it rides where the
   author photo rides, clear of the nav. */
@media (min-width: 60rem) { .callout { position: sticky; top: var(--stick-top); } }

.timeline__item { grid-template-columns: 1fr; }
@media (min-width: 48rem) { .timeline__item { grid-template-columns: 14rem 1fr; } }

.acc__body p { color: var(--ink-soft); max-width: var(--measure); }

/* ---- forms --------------------------------------------------------------
   One look for the waitlist row and the two long forms. Status colors come
   from tokens; the error red is --danger so a theme can soften it.
   ------------------------------------------------------------------------ */
.panel {
  background: var(--surface);
  border: var(--border-w) solid var(--line); border-radius: var(--radius-card);
  padding: clamp(1.4rem, 4vw, 2.6rem); box-shadow: var(--shadow-sm);
}
.form__note { font-size: 0.8rem; color: var(--ink-faint); margin-bottom: 1.25rem; }
.form__grid { display: grid; gap: 1.2rem 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 40rem) {
  .form__grid { grid-template-columns: 1fr 1fr; }
  .form__grid > * { grid-column: 1 / -1; }
  .form__grid > .field--half { grid-column: auto; }
}
.field { display: grid; gap: 0.4rem; align-content: start; min-width: 0; border: 0; padding: 0; margin: 0; }
.field__label { font-family: var(--font-ui); font-size: 0.86rem; font-weight: 600; color: var(--ink); padding: 0; }
.field__hint { font-size: 0.8rem; color: var(--ink-faint); margin-top: -0.25rem; }
/* On the public forms a note about what to type sits under its box, so the
   boxes in a pair of half-width fields line up whether or not one has a note.
   The instruction for a choice group stays above it, read before choosing.
   form[data-form] keeps /admin's fields as they are. */
form[data-form] .field:has(> .input) > .field__hint { order: 1; margin-top: 0; }
.req { color: var(--accent); }

.input {
  width: 100%; padding: 0.85rem 1.05rem;
  background: var(--surface); color: var(--ink);
  border: var(--border-w) solid var(--line); border-radius: var(--radius-btn);
  transition: border-color 240ms var(--ease), box-shadow 240ms var(--ease);
}
.input::placeholder { color: var(--ink-faint); }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.input:user-invalid { border-color: var(--danger); }
textarea.input { resize: vertical; min-height: 7.5rem; line-height: 1.55; }
/* A chevron drawn from two gradients so it takes the theme's ink, which an
   SVG data URI cannot. */
select.input {
  appearance: none; padding-right: 2.6rem; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
                    linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: calc(100% - 1.25rem) 52%, calc(100% - 0.9rem) 52%;
  background-size: 0.36rem 0.36rem; background-repeat: no-repeat;
}
.signup__form .input { width: auto; min-width: 0; }

.choices { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.choice {
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.55rem 0.95rem; cursor: pointer; font-size: 0.92rem;
  background: var(--surface);
  border: var(--border-w) solid var(--line); border-radius: var(--radius-btn);
  transition: border-color 220ms var(--ease), background 220ms var(--ease);
}
.choice:hover { border-color: var(--accent); }
.choice:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.choice input { accent-color: var(--accent); margin: 0; width: 1rem; height: 1rem; flex: none; }
.choice--ack {
  display: flex; align-items: flex-start; padding: 0; border: 0;
  background: none; color: var(--ink-soft); line-height: 1.5;
}
.choice--ack:has(input:checked) { background: none; }
.choice--ack input { margin-top: 0.22rem; }

.form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-top: 1.75rem; }
.form__status { font-size: 0.95rem; min-height: 1.4em; margin-top: 0.75rem; color: var(--ink-soft); }
.form__status:empty { margin-top: 0; }
.form__status:focus { outline: none; }
.form__status[data-state="ok"] { color: var(--accent); }
.form__status[data-state="error"] { color: var(--danger); }
/* Sent: the fields step aside and the thank-you takes their place. */
.js form.is-sent > :not([data-form-status]):not([data-form-gift]) { display: none; }
.js form.is-sent .form__status {
  font-family: var(--font-display); color: var(--ink); line-height: 1.35; margin: 0;
  font-size: calc(clamp(1.3rem, 1.1rem + 0.8vw, 1.7rem) * var(--display-scale));
}

/* Honeypot: off-screen rather than display:none, which some bots skip. */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
