/* Faith Minute — the landing page.
 *
 * Its own stylesheet rather than a section of `style.css`. The legal pages are
 * one column of prose on a padded body; this page is full-bleed bands with
 * their own grounds, and the two were fighting over `body`. `style.css` is now
 * the legal pages' file and this is the landing page's.
 *
 * Everything here is the app's design system, read off `src/theme/`:
 *
 *   colours   src/theme/colors.ts     — both palettes, token for token
 *   type      src/theme/typography.ts — Fraunces for display, Inter for UI
 *   radii     src/theme/layout.ts     — small 10, card 20, large 30, pill 50
 *   shadow    src/theme/shadows.ts    — the one card shadow, softened for a
 *                                       page seen at arm's length
 *
 * If the app's palette changes, change it here and in `style.css` too.
 *
 * The page alternates cream and near-black bands, and it does so whatever the
 * reader's phone is set to. That is the app's own rule rather than a new one:
 * the onboarding screens ask for a tone by name and alternate them screen by
 * screen, so "a reader in dark mode still sees the sequence as it was drawn"
 * (src/components/auth/AuthScreen.tsx). A page that followed the system would
 * paint every band near-black in dark mode and the rhythm would be gone.
 *
 * So there is no `prefers-color-scheme` block here — `style.css` keeps one,
 * because a privacy policy opened at night is prose to read rather than a
 * composition to look at. The near-black bands are the app's dark palette
 * quoted verbatim, slate accent and all, which is the ground the memorization
 * tab actually wears.
 */

/* ---- tokens ------------------------------------------------------------ */

:root {
  /* Light, always. The dark bands are painted by `.band-ink` rather than by
   * the reader's system, so the page must not be handed a dark form field or
   * scrollbar underneath a cream ground. */
  color-scheme: light;

  /* Light palette — src/theme/colors.ts, `lightColors`. */
  --background: #fbf8f3;
  --surface: #ffffff;
  --sand: #f3dec4;
  --border: #dcd6cc;
  --text: #221f1a;
  --text-secondary: #6e6c67;
  --text-muted: #9c948a;
  --accent: #d98c4a;
  /* `accentCounter` in src/theme/colors.ts: the accent the other palette
   * wears, for a mark that should not follow the ground it is printed on. */
  --accent-counter: #7c90b8;
  /* `onInverted` in src/theme/colors.ts: what goes on a shape filled with
   * `text`. It is the page's own ground read back, so unlike `--background`
   * it has to flip with the band — otherwise a cream fill on the ink band
   * gets a cream label and the button reads as empty. */
  --on-inverted: #fcf9f6;
  --track: #f2ede3;
  --callout: rgba(217, 140, 74, 0.1);
  --chip: rgba(217, 140, 74, 0.3);

  /* The four steps of the memorization grid, at increasing strength. */
  --activity-1: rgba(217, 140, 74, 0.3);
  --activity-2: rgba(217, 140, 74, 0.5);
  --activity-3: rgba(217, 140, 74, 0.72);
  --activity-4: #d98c4a;

  /* The dark band, which does not follow the theme: it is the app's dark
   * palette quoted on purpose, the same way the memorization tab wears it. */
  --ink: #1a1817;
  --ink-surface: #221f1a;
  --ink-border: #322d27;
  --ink-text: #fcf9f6;
  --ink-secondary: #9c948e;
  --ink-muted: #8a837d;
  --ink-accent: #7c90b8;
  --ink-accent-counter: #d98c4a;
  --ink-activity-1: rgba(124, 144, 184, 0.4);
  --ink-activity-2: rgba(124, 144, 184, 0.5);
  --ink-activity-3: rgba(124, 144, 184, 0.8);
  --ink-activity-4: #7c90b8;

  /* src/theme/layout.ts */
  --radius-small: 0.625rem;
  --radius-card: 1.25rem;
  --radius-large: 1.875rem;
  --radius-pill: 999px;

  --shadow-card: 0 1px 2px rgba(34, 31, 26, 0.04), 0 12px 32px rgba(34, 31, 26, 0.08);
  --shadow-device: 0 2px 6px rgba(34, 31, 26, 0.08), 0 30px 60px rgba(34, 31, 26, 0.18);

  --serif: Fraunces, Georgia, 'Times New Roman', serif;
  --sans: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --gutter: 1.5rem;
  --measure: 68rem;
  --band: clamp(4.5rem, 9vw, 7.5rem);
}

/* ---- ground ------------------------------------------------------------ */

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

html {
  /* The nav anchors and the mark in the masthead all ride on this. */
  scroll-behavior: smooth;
  /* Clears the floating masthead when a nav link jumps down the page: the
   * bar's own height, the gap it sits in, and a little air under it. */
  scroll-padding-top: 8rem;
}

body {
  margin: 0;
  background: var(--background);
  color: var(--text);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* The app is printed on paper. A tiled photograph of it would be a third of a
 * megabyte, so the grain is generated instead — turbulence at a low enough
 * opacity to be felt rather than seen, which is all the texture does there. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)' opacity='0.055'/%3E%3C/svg%3E");
}

main,
header,
footer {
  position: relative;
  z-index: 1;
}

.wrap {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ---- type -------------------------------------------------------------- */

h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.12;
  margin: 0;
  text-wrap: balance;
}

h1 {
  font-size: clamp(2.4rem, 6.4vw, 4rem);
}

h2 {
  /* The floor raised with the h3 under it, for the same reason: 4.2vw does
   * not overtake it until an 800px viewport, so a phone and a tablet only
   * ever see the floor. The clamp stays here though — unlike the h3 it has
   * somewhere to go, and a desktop still reads these at 2.8rem. */
  font-size: clamp(2.1rem, 4.2vw, 2.8rem);
}

h3 {
  /* One size at every width. This was a clamp, but 2.6vw only reaches the
   * ceiling past a 1077px viewport — everything narrower than a desktop sat
   * on the floor, so the floor was the real setting and raising it to meet
   * the ceiling is what the rule already meant. A phone gets 28px against
   * 15px body copy; at the 1.35rem it started from, a heading and the
   * paragraph under it read as one block of text. */
  font-size: 1.75rem;
  letter-spacing: -0.015em;
}

p {
  margin: 0;
  /* A shade under the base size on a phone, the full 1rem from 600px up.
   * Body copy at 16px sits too close to the headings beside it on a narrow
   * screen, where they are pinned to their own floor and cannot grow away
   * from it. */
  font-size: clamp(0.9375rem, 0.8125rem + 0.5vw, 1rem);
  color: var(--text-secondary);
  text-wrap: pretty;
}

a {
  color: inherit;
}

/* The seven kinds of lesson, where the paragraph names them. Full strength as
 * well as heavier: on a near-black band the secondary grey they sit in is the
 * quiet part, and weight alone barely separates them from it. 600 rather than
 * 700 because that is the heaviest Inter the page loads — 700 would be a
 * shape the browser draws itself. */
strong {
  font-weight: 600;
  color: var(--text);
}

/* Went missing with the list this page used to have, and the pills that
 * replaced it inherited a browser's 1em margin and 40px indent — enough to
 * shift every absolute position on the section. */
ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.eyebrow {
  display: block;
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1rem;
}

.lede {
  font-size: clamp(1.0625rem, 1.8vw, 1.25rem);
  line-height: 1.65;
  max-width: 34rem;
}

/* ---- masthead ---------------------------------------------------------- */

/* A card rather than a bar across the top, so it belongs to the same family
 * as the bands and the footer. It floats in the gutter and the page runs
 * under it: cream at seven tenths, so what passes beneath is visible through
 * it, with the blur doing the work of keeping the type legible over whatever
 * that happens to be. It does take a little of the near-black bands' colour
 * as they go by, which is the cost of being see-through and the point of it. */
.masthead {
  position: sticky;
  top: var(--gutter);
  z-index: 20;
  margin: var(--gutter) var(--gutter) 0;
  backdrop-filter: saturate(1.5) blur(20px);
  -webkit-backdrop-filter: saturate(1.5) blur(20px);
  /* The flat colour first, for a browser that drops color-mix: it is better
   * for the bar to be opaque there than to have no ground at all. */
  background: var(--background);
  background: color-mix(in srgb, var(--background) 70%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  transition: box-shadow 0.3s ease;
}

/* Lifted off the page only once there is page under it to be lifted off. */
.masthead.is-scrolled {
  box-shadow: var(--shadow-card);
}

.masthead .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: 4rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--serif);
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
  color: var(--text);
}

.brand img {
  width: 2rem;
  height: 2rem;
  border-radius: 0.5rem;
}

.masthead nav {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  font-size: 0.9375rem;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.nav-links a {
  color: var(--text-secondary);
  text-decoration: none;
  transition: color 0.2s ease;
}

.nav-links a:hover {
  color: var(--text);
}

/* ---- store buttons ------------------------------------------------------ */

.stores {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* The app's own primary button: the text colour as a fill, the page's
 * background read back as the label. Dark against a bar that is mostly
 * see-through, so the one thing on the page asking to be pressed is the one
 * thing up there with any weight. */
.store {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--background);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition:
    transform 0.2s ease,
    opacity 0.2s ease;
}

.store:hover {
  transform: translateY(-1px);
  opacity: 0.88;
}

.store svg {
  width: 0.95rem;
  height: 0.95rem;
}

/* The page's own links go first: they are a way of skipping down a page the
 * reader can also just scroll. The stores are the reason the page exists, so
 * they stay to the last, losing their labels rather than themselves. */
@media (max-width: 56rem) {
  .nav-links {
    display: none;
  }
}

@media (max-width: 30rem) {
  .store span {
    display: none;
  }

  .store {
    padding: 0.5rem;
  }

  .store svg {
    width: 1.05rem;
    height: 1.05rem;
  }
}

/* ---- hero -------------------------------------------------------------- */

.hero {
  padding: clamp(2.5rem, 6vw, 4.5rem) 0 0;
  text-align: center;
  position: relative;
  overflow: hidden;
}

/* A single warm bloom behind the headline, the accent at a tenth. The page is
 * flat paper everywhere else; this is the one place it catches light. */
.hero::before {
  content: '';
  position: absolute;
  top: -18rem;
  left: 50%;
  width: min(60rem, 130vw);
  aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle, rgba(217, 140, 74, 0.16) 0%, transparent 62%);
  pointer-events: none;
}

.hero .wrap {
  position: relative;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--chip);
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-pill);
  margin-bottom: 1.75rem;
}

.pill::before {
  content: '';
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--accent);
}

.hero h1 {
  max-width: 20ch;
  margin: 0 auto;
}

.hero .lede {
  margin: 1.5rem auto 0;
  max-width: 38rem;
}

.hero-note {
  margin-top: 2rem;
  font-size: 0.875rem;
  color: var(--text-muted);
}

.hero-note a {
  color: var(--accent);
  text-underline-offset: 3px;
}

/* The two phones, the second one dropped and turned slightly so they read as
 * one object rather than two pictures side by side. */
.hero-shots {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: clamp(1rem, 4vw, 3rem);
  margin-top: clamp(3rem, 6vw, 4.5rem);
  padding-bottom: clamp(3rem, 7vw, 5rem);
}

.hero-shots .device:first-child {
  transform: rotate(-2.5deg) translateY(1.5rem);
}

.hero-shots .device:last-child {
  transform: rotate(2.5deg);
}

/* Both phones survive a phone. They were sized for a desktop and one of them
 * had to go; sized to the space instead, the pair fits. `flex` divides
 * whatever the gutters leave between them, and the cap is the width they
 * already have above this breakpoint, so nothing steps as a screen widens
 * across it. */
@media (max-width: 40rem) {
  .hero-shots {
    /* Meets the gap above the breakpoint at 640px, so that does not step
     * either. */
    gap: clamp(1.25rem, 4vw, 3rem);
  }

  .hero-shots .device {
    /* 2.5rem of corner on a 146px handset is a quarter of its width, which
     * is not the shape of a phone any more. Meets 2.5rem exactly at the
     * breakpoint, as the width does. */
    --corner: clamp(1.5rem, 6.25vw, 2.5rem);
    flex: 1 1 0;
    width: auto;
    max-width: 13rem;
    border-radius: var(--corner);
  }

  .hero-shots .device .screen {
    border-radius: calc(var(--corner) - 0.45rem);
  }

  /* The stagger comes down with them. The full turn and drop, on something
   * this size, reads as one phone sliding off the other. */
  .hero-shots .device:first-child {
    transform: rotate(-2deg) translateY(0.75rem);
  }

  .hero-shots .device:last-child {
    transform: rotate(2deg);
  }
}

/* ---- device ------------------------------------------------------------ */

.device {
  position: relative;
  flex: 0 0 auto;
  width: clamp(13rem, 22vw, 16.5rem);
  padding: 0.5rem;
  border-radius: 2.5rem;
  background: linear-gradient(160deg, #3a352f, #17150f);
  box-shadow: var(--shadow-device);
}

/* The hairline highlight along the top edge of a real handset. */
.device::before {
  content: '';
  position: absolute;
  inset: 1px;
  border-radius: inherit;
  border: 1px solid rgba(255, 255, 255, 0.16);
  pointer-events: none;
}

.device .screen {
  position: relative;
  aspect-ratio: 9 / 19.5;
  border-radius: 2.05rem;
  overflow: hidden;
  background: var(--sand);
}

.device img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Until the real screenshots land. `site.js` adds `is-missing` when a file
 * 404s, so a half-built page says which file it is waiting for instead of
 * showing a broken-image glyph. */
.device.is-missing img {
  display: none;
}

.device.is-missing .screen {
  background:
    repeating-linear-gradient(
      -45deg,
      transparent,
      transparent 10px,
      rgba(34, 31, 26, 0.05) 10px,
      rgba(34, 31, 26, 0.05) 20px
    ),
    var(--track);
}

.device.is-missing .screen::after {
  content: attr(data-shot);
  position: absolute;
  inset: auto 0 50% 0;
  text-align: center;
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-muted);
}

/* ---- bands ------------------------------------------------------------- */

.band {
  padding: var(--band) 0;
}

.band-head {
  max-width: 40rem;
  margin: 0 auto clamp(3rem, 6vw, 4.5rem);
  text-align: center;
}

.band-head p {
  margin-top: 1.25rem;
  font-size: 1.0625rem;
}

.band-head .lede {
  margin-inline: auto;
}

/* The near-black band. Everything inside it swaps to the dark palette, which
 * is why the tokens are re-declared rather than the colours written twice. */
.band-ink {
  --surface: var(--ink-surface);
  --border: var(--ink-border);
  --text: var(--ink-text);
  --text-secondary: var(--ink-secondary);
  --text-muted: var(--ink-muted);
  --accent: var(--ink-accent);
  --accent-counter: var(--ink-accent-counter);
  --on-inverted: var(--ink);
  --chip: rgba(124, 144, 184, 0.3);
  --callout: rgba(124, 144, 184, 0.1);
  --track: #2f2b28;
  --activity-1: var(--ink-activity-1);
  --activity-2: var(--ink-activity-2);
  --activity-3: var(--ink-activity-3);
  --activity-4: var(--ink-activity-4);

  background: var(--ink);
  color: var(--ink-text);
  /* In dark mode the band's ground and the page's are the same near-black.
   * The hairline is what keeps it a band there; in light mode it is barely
   * visible against the near-black and costs nothing. */
  border: 1px solid var(--ink-border);
  /* Rounded off the page's corners so the band reads as a card the width of
   * the window rather than a stripe of a different colour. */
  border-radius: var(--radius-large);
  margin: 0 var(--gutter);
}

/* Inset, the band's own text sits a gutter further in than the cream bands'
 * — invisible while the page is wider than the measure, because both then
 * centre on it, and plain to see once it is not. So below that the band goes
 * edge to edge and the alternation carries on without the step. */
@media (max-width: 52rem) {
  .band-ink {
    margin-inline: 0;
    border-radius: 0;
    border-inline: 0;
  }
}

.band-ink h2,
.band-ink h3 {
  color: var(--ink-text);
}

/* ---- feature ----------------------------------------------------------- */

.feature {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: clamp(2.5rem, 7vw, 6rem);
}

/* Every other one turned around, so the eye crosses the page as it descends
 * instead of running down one gutter. */
.feature.flip .feature-art {
  order: -1;
}

.feature-art {
  display: flex;
  justify-content: center;
}

.feature-text h3 {
  margin-bottom: 1rem;
}

.feature-text p + p {
  margin-top: 1rem;
}

@media (max-width: 52rem) {
  .feature {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  .feature.flip .feature-art {
    order: 0;
  }
}

/* A quiet line under a feature, for the things that are true but should not
 * take a paragraph — "you can set a reminder". */
.note {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 1.5rem;
  padding: 0.55rem 1rem 0.55rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--callout);
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.note svg {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  color: var(--accent);
}

/* ---- the week, scattered ------------------------------------------------ */

/* The seven kinds of lesson are not a block of their own. They are laid over
 * the whole "daily lessons" band and sit in the gaps its layout already
 * leaves — beside the centred title, out past the phone, along the foot below
 * the column that ends first — so the week reads as something happening
 * around the section rather than a list appended to it.
 *
 * That is why the band is positioned and given more room top and bottom than
 * the others: the pills need somewhere to be that is not on top of a
 * sentence. */
.band-scatter {
  position: relative;
  /* A flat 2rem rather than a share of `--band`: this is the one band whose
   * head sits close to its own top edge, and the room the band scales is all
   * wanted at the foot, where three pills lie under the columns. The cream
   * section above keeps its own padding, so the two are not touching. */
  padding-top: 2rem;
  padding-bottom: calc(var(--band) + 4rem);
}

.cats {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  /* The content's box, not the window's. Anchored to the band, the pills
   * drifted further from the text the wider the window got — every percentage
   * was of a box that keeps growing while the column it is meant to sit
   * beside stops at the measure. Centred on the measure instead, each one
   * holds its distance from the paragraph or the phone it belongs to. */
  width: min(100%, var(--measure));
  margin-inline: auto;
  /* Over the text, never in front of selecting it. */
  pointer-events: none;
  z-index: 2;
}

/* Cream pills on the near-black band: `--background` is the one token
 * `.band-ink` does not restate, so it is still the page's own paper here, and
 * `--ink` is the ground they are lying on. */
.cat {
  position: absolute;
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.6rem 1.1rem;
  border-radius: var(--radius-pill);
  background: var(--background);
  color: var(--ink);
  white-space: nowrap;
  box-shadow: var(--shadow-card);

  /* The state `site.js` adds. Held small and low until its turn comes.
   *
   * `translate` and `scale` rather than one `transform`, because the pill has
   * two jobs for them: arriving, which is a transition, and then drifting,
   * which is an animation. As separate properties the drift can own
   * `translate` while `scale` stays where the arrival left it. */
  opacity: 0;
  scale: 0.86;
  translate: 0 10px;
  transition:
    opacity 0.45s ease,
    scale 0.55s cubic-bezier(0.22, 1.4, 0.4, 1),
    translate 0.55s cubic-bezier(0.22, 1.4, 0.4, 1);
}

.cat.is-in {
  opacity: 1;
  scale: 1;
  translate: 0 0;
}

/* And once it has landed it never settles. A 16px rise and fall over three
 * seconds or so — far enough and quick enough to be seen rather than only
 * felt — started late enough that the arrival is over before the drift takes
 * `translate` off it. */
@media (prefers-reduced-motion: no-preference) {
  .cat.is-in {
    animation: cat-drift 3s ease-in-out 0.7s infinite;
  }

  /* Out of step with each other, or seven pills breathe as one object. */
  .cat:nth-child(2).is-in {
    animation-duration: 3.6s;
    animation-delay: 1.1s;
  }

  .cat:nth-child(3).is-in {
    animation-duration: 2.8s;
    animation-delay: 0.9s;
  }

  .cat:nth-child(4).is-in {
    animation-duration: 3.9s;
    animation-delay: 1.4s;
  }

  .cat:nth-child(5).is-in {
    animation-duration: 3.2s;
    animation-delay: 0.8s;
  }

  .cat:nth-child(6).is-in {
    animation-duration: 4.1s;
    animation-delay: 1.3s;
  }

  .cat:nth-child(7).is-in {
    animation-duration: 3s;
    animation-delay: 1s;
  }
}

@keyframes cat-drift {
  0%,
  100% {
    translate: 0 0;
  }

  50% {
    translate: 0 -16px;
  }
}

.cat svg {
  align-self: center;
  /* Solid shapes, so they can be smaller than an outline would need to be
   * and still hold their silhouette beside the word. */
  width: 1rem;
  height: 1rem;
  color: #7c90b8;
}

.cat-kind {
  font-family: var(--serif);
  font-size: 1.05rem;
  font-weight: 600;
}

.cat-day {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #6e6c67;
}

/* Centred under the title rather than pinned to a side. `left`/`right` at 0
 * with an auto inline margin does it without a transform, which the pop-in
 * animation is already using. `--nudge` holds the right edge in from the
 * band, and the auto margins split what is left — so the pill shifts left by
 * half of whatever it is given. */
.cat-centre {
  left: 0;
  right: var(--nudge, 0px);
  width: fit-content;
  margin-inline: auto;
}

/* Two sizes, and a fade kept apart from them.
 *
 * They used to be one class: `far` meant smaller *and* dimmer, so only a small
 * pill could be a faded one. That is why the fade alternated for four pills
 * and then stopped — it was following the sizes, which follow nothing. The
 * fade is `--dim` now and falls on every other pill, all the way down. */
.cat-far {
  padding: 0.45rem 0.9rem;
}

.cat-dim.is-in {
  opacity: 0.82;
}

.cat-far .cat-kind {
  font-size: 0.9rem;
}

.cat-far .cat-day {
  font-size: 0.6875rem;
}

.cat-far svg {
  width: 0.9rem;
  height: 0.9rem;
}

/* Below this the week does not appear at all.
 *
 * The pills need margins to sit in and gaps between the columns to sit
 * between, and a window no wider than the measure has neither — they used to
 * fall back into the flow here, but a heap of them stacked under the section
 * heading is not the same idea, it is the list this replaced with worse
 * manners. Nothing is lost by dropping them: the paragraph in this very
 * section names all seven kinds, in bold, and that paragraph is what a phone
 * gets. */
@media (max-width: 84rem) {
  .band-scatter {
    /* No pills lying under the columns, so the band does not need the extra
     * room at its foot that they were given. */
    padding-bottom: var(--band);
  }

  .cats {
    display: none;
  }
}

/* Nothing to wait for if motion is not wanted: the whole week is simply
 * there, which is what the list it replaced did. And a jump to an anchor is a
 * jump rather than a journey up the page. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .cat,
  .cat-far,
  .cat-dim {
    opacity: 1;
    scale: 1;
    translate: 0 0;
    transition: none;
    animation: none;
  }
}

/* ---- the two techniques ------------------------------------------------ */

/* Lifted from the app's memorization onboarding
 * (src/components/onboarding/MethodTiles.tsx), down to the 10px label and the
 * 24px glyph. The pictures are drawn rather than the retention charts the app
 * shows elsewhere: those are meant to be read at half a page, and at this size
 * they would be a grey smudge. Widening gaps say spacing; a rising bar says
 * retrieval. */
.techniques {
  margin-top: 1.75rem;
}

.tiles {
  display: flex;
  gap: 0.5rem;
}

.tile {
  flex: 1;
  min-width: 0;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
}

.glyph {
  display: flex;
  align-items: center;
  height: 1.5rem;
  /* The width the glyph has on a phone. The tiles are wider here than in the
   * app, and three bars stretched across a wide tile stop reading as a chart
   * and start reading as blocks. */
  max-width: 8.75rem;
}

.glyph-bars {
  align-items: flex-end;
  gap: 3px;
}

/* Three returns after the first sitting, each further out than the last and
 * each a little fainter. The widening is the whole point, so the last gap is
 * a long way from the first rather than one step more. */
.node {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

.node-strong {
  background: var(--activity-4);
}

.node-2 {
  background: var(--activity-3);
}

.node-3 {
  background: var(--activity-2);
}

.node-4 {
  background: var(--activity-1);
}

.rule {
  flex: 0 0 auto;
  height: 1px;
  margin: 0 3px;
  background: var(--border);
}

.rule-1 {
  width: 4px;
}

.rule-2 {
  width: 10px;
}

.rule-3 {
  width: 24px;
}

.bar {
  flex: 1;
  border-radius: 2px;
  background: var(--chip);
}

.bar-1 {
  height: 35%;
}

.bar-2 {
  height: 60%;
}

/* The one the reader is meant to want. */
.bar-3 {
  height: 100%;
  background: var(--accent);
}

.tile-name {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-counter);
}

.tile-gloss {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.6875rem;
  line-height: 1.45;
  color: var(--text-secondary);
}

/* The pair stays a pair on a phone. Stacked, each tile ran the whole width
 * of the column and read as a paragraph with a picture on it, rather than
 * as one of two techniques set against each other — which is the only
 * reason to draw them at all. What gives at that width is the tracking and
 * the padding, not the arrangement. */
@media (max-width: 34rem) {
  .tile {
    padding: 0.5rem;
  }

  .tile-name {
    letter-spacing: 0.06em;
  }
}

/* ---- coming soon ------------------------------------------------------- */

.soon {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
}

.soon-card {
  position: relative;
  /* Wide enough that a fourth will not fit beside three, so the five sit
   * three and two rather than four and a stray. */
  flex: 1 1 18rem;
  max-width: 24rem;
  padding: 1.75rem 1.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  background: color-mix(in srgb, var(--surface) 60%, transparent);
  transition:
    transform 0.3s ease,
    border-color 0.3s ease;
}

.soon-card:hover {
  transform: translateY(-4px);
  border-color: var(--accent);
}

.soon-card h4 {
  margin: 0 0 0.5rem;
  font-family: var(--serif);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--text);
}

.soon-card p {
  margin: 0;
  font-size: 0.9375rem;
}

.chip {
  display: inline-block;
  margin-bottom: 1rem;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-pill);
  background: var(--chip);
  color: var(--accent);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
}

/* The app breathes these chips rather than blinking them: slow, and never all
 * the way down, because the label marks something that has not arrived. */
@media (prefers-reduced-motion: no-preference) {
  .soon-card .chip {
    animation: breath 3.2s ease-in-out infinite;
  }

  .soon-card:nth-child(2) .chip {
    animation-delay: 0.32s;
  }

  .soon-card:nth-child(3) .chip {
    animation-delay: 0.64s;
  }

  .soon-card:nth-child(4) .chip {
    animation-delay: 0.96s;
  }

  .soon-card:nth-child(5) .chip {
    animation-delay: 1.28s;
  }
}

@keyframes breath {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

/* ---- feedback board ---------------------------------------------------- */

/* The way through to /feedback. The app's primary button: the text colour as
 * a fill, and the ground the page is printed on read back as the label. */
.board-button {
  display: inline-flex;
  align-items: center;
  margin-top: 1.75rem;
  padding: 0.7rem 1.4rem;
  border-radius: var(--radius-pill);
  background: var(--text);
  color: var(--on-inverted);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  transition:
    transform 0.2s ease,
    opacity 0.2s ease;
}

.board-button:hover {
  transform: translateY(-2px);
  opacity: 0.9;
}

/* ---- footer ------------------------------------------------------------ */

.site-footer {
  padding: var(--band) 0 3rem;
}

/* The page's closing card: bordered and rounded like the bands above it, and
 * set off the bottom of the page as well as its sides, so the site ends on a
 * shape rather than on the ground running out.
 *
 * The gap above it matters now that the band before it is dark too — without
 * it the two cards meet and read as one block with a line through it. */
.site-footer.band-ink {
  margin-top: var(--gutter);
  margin-bottom: var(--gutter);
}

/* It keeps its edges at every width, where the bands above lose theirs. The
 * inset costs them the alignment of their text against the cream sections;
 * the footer has nothing below it to line up with, and being a card is the
 * whole of what it is doing here. */
@media (max-width: 52rem) {
  .site-footer.band-ink {
    margin-inline: var(--gutter);
    border-inline: 1px solid var(--ink-border);
    border-radius: var(--radius-large);
  }
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2.5rem;
  margin-bottom: 3.5rem;
}

/* The bare mark, so no tile to round off — and a size up on the masthead's,
 * which is the app icon and fills its square. This one does not, so at the
 * same width it would read smaller. */
.site-footer .brand img {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0;
}

.footer-top p {
  max-width: 22rem;
  margin-top: 0.9rem;
  font-size: 0.9375rem;
}

.socials {
  display: flex;
  gap: 0.6rem;
}

.socials a {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--text-secondary);
  transition:
    color 0.2s ease,
    border-color 0.2s ease,
    transform 0.2s ease;
}

.socials a:hover {
  color: var(--accent);
  border-color: var(--accent);
  transform: translateY(-2px);
}

.socials svg {
  width: 1.15rem;
  height: 1.15rem;
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--border);
  font-size: 0.875rem;
  color: var(--text-muted);
}

.footer-bottom nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.footer-bottom a {
  color: var(--text-secondary);
  text-decoration: none;
  transition: color 0.2s ease;
}

.footer-bottom a:hover {
  color: var(--accent);
}

/* A placeholder that must not survive to production. Loud on purpose — the
 * same class, and the same reason, as the one in `style.css`. Nothing on the
 * page wears it at the moment: the social links did, and the ring came off by
 * request. Kept for the next placeholder. */
.todo {
  outline: 2px solid #ffe08a;
  outline-offset: 2px;
}

/* ---- reveal ------------------------------------------------------------ */

/* Applied by `site.js` only when it runs, so a page without JavaScript is a
 * page with everything already visible rather than a blank one. */
@media (prefers-reduced-motion: no-preference) {
  .js .reveal {
    opacity: 0;
    transform: translateY(16px);
    transition:
      opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  }

  .js .reveal.is-in {
    opacity: 1;
    transform: none;
  }
}
