/* ===================================================================
   Calmffirmation site stylesheet
   One file, no framework, no build step. Design tokens come straight
   from the handoff brief. There are no shadows anywhere on this site:
   depth comes from a hairline border plus a gradient tint.
   =================================================================== */

/* ── Fonts, served from this site ─────────────────────────────────
   Google's stylesheet had to be fetched before the page could paint, and
   it described 29 files. Inter is one variable font covering every
   weight, so two files is the whole set. font-display:swap means text
   appears immediately in the fallback and swaps when the font lands.
   Hebrew is not in these files and falls back to the system font, which
   is what happened with Google's copy too. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter-var.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: 'Handlee';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/handlee-400.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;
}

/* ── Tokens ──────────────────────────────────────────────────────── */
/* ─────────────────────────────────────────────────────────────────
   Colour

   The site has two faces. Light is the default, because this is a
   website read in daylight, at a desk or on a phone. The app is the
   thing used in bed, and it stays dark.

   Dark is not a second palette. It is the SAME hues, mirrored: on a
   dark page the brand colours are used as they are, and on a light
   page a deeper step of the same hue is used, because every one of
   the original nine fails readability on white (salmon scored 2.4
   against a required 4.5). Every value below was measured, not
   guessed, and all of them pass 4.5:1.

   Names stay semantic. "--purple-light" means the version with more
   emphasis, which is lighter on a dark page and deeper on a light
   one. So nothing downstream has to know which mode it is in.
   ───────────────────────────────────────────────────────────────── */
:root {
  color-scheme: light dark;

  --bg: #fcfafd;
  --surface: #ffffff;
  --surface-deep: #f5f2f8;
  --border: #e6e1ef;
  --text: #211b2e;
  --text-muted: #575067;
  --text-faint: #6e6880;

  --purple: #7a50f7;
  --purple-light: #6435e4;
  --purple-deep: #5b21b6;
  --pink: #b6489a;
  --pink-light: #9a3680;
  --salmon: #bc4433;
  --salmon-light: #9e3324;

  /* Text sitting ON a solid accent button. */
  --on-accent: #ffffff;

  /* The sticky header, which shows the page faintly through itself. */
  --header-bg: rgba(252, 250, 253, 0.88);

  /* The logo's own gradient, salmon to lilac, pooled at the top of the
     page and gone by the time the reading starts. Anchored to the top
     of the document, not the viewport, so it does not follow a scroll. */
  --page-glow:
    radial-gradient(1100px 420px at 12% -6%, rgba(250, 128, 114, 0.16), transparent 62%),
    radial-gradient(1100px 440px at 88% -4%, rgba(167, 139, 250, 0.18), transparent 62%);

  --selection: rgba(122, 80, 247, 0.22);
  --ring: rgba(33, 27, 46, 0.25);

  /* How strongly a card is washed with its category colour. A tint that
     reads as a soft glow on a black page reads as a stain on a white
     one, so light gets a fraction of it. */
  --wash: 0.05;
  --wash-edge: 0.22;

  /* RGB triplets so the tint and border alphas can be built inline */
  --purple-rgb: 122, 80, 247;
  --pink-rgb: 182, 72, 154;
  --salmon-rgb: 188, 68, 51;

  --wordmark: linear-gradient(90deg, #d9452c, #7a50f7);

  --container: 1080px;
  --gutter: 32px;

  --font: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-accent: Handlee, cursive;

  --t: 150ms ease;
}

/* ── Dark ──────────────────────────────────────────────────────────
   The original palette, unchanged.

   It is written TWICE on purpose, and the two copies must always be
   edited together.

   The first copy answers the device. The second answers the button in
   the header. Both are needed: if dark lived only behind the button,
   then a visitor with scripting off would never get dark even with
   their phone set to it, and if it lived only behind the media query
   the button could not override the device.

   The :not() is what lets the button win. A visitor who has chosen
   light keeps light even on a device set to dark.
   ────────────────────────────────────────────────────────────────── */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0a0a0f;
    --surface: #141419;
    --surface-deep: #0d0d12;
    --border: #2a2833;
    --text: #eae8ed;
    --text-muted: #9a96a3;
    --text-faint: #8b8699;

    --purple: #a78bfa;
    --purple-light: #c4b5fd;
    --purple-deep: #8b5cf6;
    --pink: #cc7eb8;
    --pink-light: #dca4d0;
    --salmon: #fa8072;
    --salmon-light: #ffb4ab;

    --on-accent: #000000;
    --header-bg: rgba(10, 10, 15, 0.9);

    --page-glow:
      radial-gradient(1100px 420px at 12% -6%, rgba(250, 128, 114, 0.10), transparent 62%),
      radial-gradient(1100px 440px at 88% -4%, rgba(167, 139, 250, 0.13), transparent 62%);

    --selection: rgba(167, 139, 250, 0.35);
    --ring: rgba(234, 232, 237, 0.3);

    --wash: 0.22;
    --wash-edge: 0.3;

    --purple-rgb: 167, 139, 250;
    --pink-rgb: 204, 126, 184;
    --salmon-rgb: 250, 128, 114;

    --wordmark: linear-gradient(90deg, #fa8072, #a78bfa);
  }
}

/* The same values again, for a visitor who chose dark by hand. */
:root[data-theme="dark"] {
    --bg: #0a0a0f;
    --surface: #141419;
    --surface-deep: #0d0d12;
    --border: #2a2833;
    --text: #eae8ed;
    --text-muted: #9a96a3;
    --text-faint: #8b8699;

    --purple: #a78bfa;
    --purple-light: #c4b5fd;
    --purple-deep: #8b5cf6;
    --pink: #cc7eb8;
    --pink-light: #dca4d0;
    --salmon: #fa8072;
    --salmon-light: #ffb4ab;

    --on-accent: #000000;
    --header-bg: rgba(10, 10, 15, 0.9);

    --page-glow:
      radial-gradient(1100px 420px at 12% -6%, rgba(250, 128, 114, 0.10), transparent 62%),
      radial-gradient(1100px 440px at 88% -4%, rgba(167, 139, 250, 0.13), transparent 62%);

    --selection: rgba(167, 139, 250, 0.35);
    --ring: rgba(234, 232, 237, 0.3);

    --wash: 0.22;
    --wash-edge: 0.3;

    --purple-rgb: 167, 139, 250;
    --pink-rgb: 204, 126, 184;
    --salmon-rgb: 250, 128, 114;

    --wordmark: linear-gradient(90deg, #fa8072, #a78bfa);
}

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

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  /* The glow sits at the top of the DOCUMENT, not the viewport, so it
     does not follow the reader down the page. no-repeat matters: without
     it the gradient tiles and reappears further down. */
  background: var(--page-glow) no-repeat top center, var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1 0 auto;
}

a {
  color: var(--purple);
  text-decoration: none;
  transition: color var(--t);
}

a:hover {
  color: var(--purple-light);
}

img {
  max-width: 100%;
}

/* Must win over any component that sets its own display value.
   .file-card is display:flex and .file-grid is display:grid, and either
   one silently beats the browser default of [hidden] { display: none },
   which would leave filtered-out cards on screen. */
[hidden] {
  display: none !important;
}

p {
  text-wrap: pretty;
}

::selection {
  background: var(--selection);
}

:focus-visible {
  outline: 2px solid var(--purple);
  outline-offset: 3px;
  border-radius: 4px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── Layout ──────────────────────────────────────────────────────── */
.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

.section {
  padding-top: 56px;
  padding-bottom: 56px;
}

.section--ruled {
  border-bottom: 1px solid var(--border);
}

.prose {
  max-width: 68ch;
}

/* ── Wordmark ────────────────────────────────────────────────────── */
.wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
}

.wordmark:hover {
  color: var(--text);
}

.wordmark img {
  height: 26px;
  width: auto;
  display: block;
}

.wordmark span {
  font-family: var(--font-accent);
  font-size: 24px;
  line-height: 1;
  background: var(--wordmark);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Skip link: off screen until focused, then a normal looking button. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 18px;
  background: var(--purple);
  color: var(--on-accent);
  font-size: 14px;
  font-weight: 600;
  border-radius: 0 0 12px 0;
}

.skip-link:focus {
  left: 0;
  color: var(--on-accent);
}

/* ── Header ──────────────────────────────────────────────────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--header-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}

.site-header .wrap {
  padding-top: 16px;
  padding-bottom: 16px;
  display: flex;
  align-items: center;
  /* Three children now: wordmark, menu, actions. space-between would
     strand the menu in the middle, so the menu is pushed right instead
     and the actions sit after it. */
  gap: 18px;
}

.site-header .wrap > .nav {
  margin-left: auto;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 4px;
}

.nav {
  display: flex;
  align-items: center;
  gap: 26px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
}

.nav a {
  color: var(--text-muted);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color var(--t), border-color var(--t);
}

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

.nav a[aria-current="page"] {
  color: var(--text);
  border-bottom-color: var(--purple);
}

/* Items that are not built yet. Deliberately not links and not
   focusable, so keyboard users are not sent to a dead end. */
/* While the theme is being switched, every transition is turned off.

   Two reasons, and the first is a correctness bug rather than taste.
   A property that is being transitioned and whose value comes from a
   custom property does NOT re-resolve when that custom property changes:
   it keeps the old computed value. Pressing the toggle therefore left
   every button with the previous theme's background while its text had
   already changed, which put white text on a pale purple button. It
   corrected itself only on the next hover or reload.

   The second reason is that a whole page crossfading its colours looks
   like a fault. An instant switch reads as deliberate.

   The class is added, the theme changed, and the class removed on the
   next frame. See theme.js.
   ────────────────────────────────────────────────────────────────── */
.theme-switching *,
.theme-switching *::before,
.theme-switching *::after {
  transition: none !important;
}

/* ── Menu button (phones) ────────────────────── */
/* Never shown on a wide screen, and never shown without scripting,
   because then it could not open anything. The width rule lives in the
   phone block further down. */
.nav-toggle {
  display: none;
  background: none;
  border: 0;
  padding: 6px;
  margin: 0;
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--t);
}

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

.nav-toggle svg {
  display: block;
  width: 22px;
  height: 22px;
}

/* The X replaces the bars only while the menu is open. */
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded="true"] .icon-bars { display: none; }
.nav-toggle[aria-expanded="true"] .icon-close { display: block; }

/* ── Theme toggle ──────────────────────────────────────────────────
   Hidden until the inline script in <head> has run and marked the page
   as scripted. Without JavaScript the button could not do anything, and
   a control that does nothing is worse than no control.

   Both icons are in the markup and CSS shows one. Swapping an icon in
   JavaScript flickers; swapping which one is displayed does not.
   ────────────────────────────────────────────────────────────────── */
.theme-toggle {
  display: none;
}

.js .theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  padding: 2px;
  margin: 0;
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--t);
}

.theme-toggle:hover {
  color: var(--text);
}

.theme-toggle svg {
  display: block;
  width: 17px;
  height: 17px;
}

/* Light page: offer the moon. Dark page: offer the sun. The icon shows
   what the button will DO, not what the page currently is. */
.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
}

:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }

.nav-soon {
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 6px;
}

.soon-pill {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  border: 1px solid var(--text-faint);
  border-radius: 8px;
  padding: 2px 6px;
}

/* ── Site notice bar ─────────────────────────────────────────────── */
.notice {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--text-muted);
  text-align: center;
  padding: 10px var(--gutter);
}

.notice a {
  color: var(--purple);
}

/* ── Typography roles ────────────────────────────────────────────── */
.h-hero {
  margin: 0;
  font-size: 56px;
  line-height: 1.06;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--text);
  text-wrap: balance;
}

.h-page {
  margin: 0 0 14px;
  font-size: 42px;
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: var(--text);
  text-wrap: balance;
}

.h-large {
  margin: 0 0 12px;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--text);
}

.h-card {
  margin: 14px 0 12px;
  font-size: 25px;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.2;
  color: var(--text);
}

.h-section {
  margin: 0;
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--text);
}

.h-prose {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}

.h-sub {
  margin: 0 0 10px;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}

.lead-hero {
  margin: 26px 0 0;
  max-width: 46ch;
  font-size: 18px;
  line-height: 1.6;
  color: var(--text-muted);
}

.lead-page {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  color: var(--text-muted);
}

.eyebrow {
  display: block;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
}

.accent-line {
  font-family: var(--font-accent);
  color: var(--purple-light);
}

.meta-note {
  font-size: 13px;
  line-height: 1.65;
  color: var(--text-faint);
}

/* ── Buttons ─────────────────────────────────────────────────────── */
.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 24px;
  border-radius: 14px;
  background: var(--purple);
  color: var(--on-accent);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
  transition: background var(--t);
}

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

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: none;
  color: var(--text);
  font-family: var(--font);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--t), border-color var(--t), background var(--t);
}

.btn-ghost:hover:not([aria-disabled="true"]) {
  border-color: var(--purple);
  color: var(--purple);
}

/* Anything waiting on content the owner has not uploaded yet. */
[aria-disabled="true"] {
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}

/* ── Play Store badge ────────────────────────────────────────────── */
.badge {
  display: block;
  width: 160px;
  height: 48px;
  margin-top: 28px;
}

.badge--footer {
  width: 140px;
  height: 42px;
  margin-top: 8px;
}

/* Placeholder holds the exact final size so the layout does not move
   when the real badge arrives. */
.badge-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-size: 11px;
  color: var(--text-faint);
  text-align: center;
}

/* ── Home: app status card ─────────────────────── */
/* Sits where the Google Play badge will go, so it is read by someone
   already looking for the download. Tinted rather than loud: it is news,
   not an alarm. */
.status-card {
  margin-top: 28px;
  max-width: 420px;
  padding: 18px 20px;
  border: 1px solid rgba(var(--purple-rgb), 0.3);
  border-radius: 14px;
  background: rgba(var(--purple-rgb), 0.07);
}

.status-title {
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--purple-light);
}

.status-body {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
}

.status-link {
  display: inline-block;
  margin-top: 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--purple-light);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.status-link:hover {
  color: var(--text);
}

/* ── Home: hero ──────────────────────────────────────────────────── */
.hero .wrap {
  padding-top: 88px;
  padding-bottom: 72px;
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 56px;
  align-items: center;
}

/* Equalizer. The staggered durations are the point: the bars visibly
   drift out of sync and slow down, which is what the app does. */
.eq {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  height: 40px;
  margin-bottom: 32px;
}

.eq span {
  display: block;
  width: 4px;
  height: 100%;
  border-radius: 2px;
  transform-origin: bottom;
  animation: calmBar var(--dur) ease-in-out infinite;
}

.eq span:nth-child(1) { background: var(--pink); --dur: 1s; }
.eq span:nth-child(2) { background: var(--pink-light); --dur: 1.35s; }
.eq span:nth-child(3) { background: var(--purple); --dur: 1.8s; }
.eq span:nth-child(4) { background: var(--purple); --dur: 2.4s; }
.eq span:nth-child(5) { background: var(--purple-light); --dur: 3.2s; }
.eq span:nth-child(6) { background: var(--purple-light); --dur: 4.2s; }

@keyframes calmBar {
  0%, 100% { transform: scaleY(0.22); opacity: 0.45; }
  50% { transform: scaleY(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .eq span {
    animation: none;
    transform: scaleY(0.6);
    opacity: 0.8;
  }
  html { scroll-behavior: auto; }
}

.hero-accent {
  margin: 30px 0 0;
  font-family: var(--font-accent);
  font-size: 21px;
  color: var(--pink-light);
}

/* Phone mockup */
.phone-col {
  display: flex;
  justify-content: center;
}

.phone {
  width: 230px;
  height: 470px;
  border-radius: 34px;
  border: 1px solid var(--border);
  /* Deliberately dark in both modes. This is a picture of the app, and
     the app is used in the dark. A white phone would misrepresent it. */
  background: #000;
  padding: 8px;
  overflow: hidden;
}

.phone-screen {
  width: 100%;
  height: 100%;
  border-radius: 27px;
  overflow: hidden;
  background: var(--bg);
}

.phone-screen video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.video-placeholder {
  width: 100%;
  height: 100%;
  background: linear-gradient(180deg, rgba(167, 139, 250, 0.22), rgba(10, 10, 15, 0.6) 60%), #0a0a0f;
  /* Inside the phone it is always night, so the text and the ring are
     set here rather than inherited from the page, which may be light. */
  --ring: rgba(234, 232, 237, 0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 20px;
}

.video-placeholder .play-ring {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid var(--ring);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #eae8ed;
  font-size: 18px;
}

.video-placeholder p {
  margin: 0;
  text-align: center;
  font-size: 12px;
  line-height: 1.5;
  color: #9a96a3;
  max-width: 20ch;
}

/* ── Cards ───────────────────────────────────────────────────────── */
/* A tinted card takes its colour from --accent-rgb, set by a modifier
   class. One rule serves every accent on the site. */
.card {
  border-radius: 16px;
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 28px 26px;
}

.card--tint {
  border-color: rgba(var(--accent-rgb), 0.3);
  background: linear-gradient(180deg, rgba(var(--accent-rgb), 0.22), rgba(0, 0, 0, 0) 60%), var(--surface);
  padding: 32px;
}

.accent-pink { --accent: var(--pink); --accent-light: var(--pink-light); --accent-rgb: var(--pink-rgb); }
.accent-salmon { --accent: var(--salmon); --accent-light: var(--salmon-light); --accent-rgb: var(--salmon-rgb); }
.accent-purple { --accent: var(--purple); --accent-light: var(--purple-light); --accent-rgb: var(--purple-rgb); }

.mode-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.mode-grid .eyebrow {
  color: var(--accent-light);
}

.mode-grid p {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-muted);
}

/* Numbered steps */
.steps-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.step-num {
  display: block;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--purple);
  margin-bottom: 16px;
  font-weight: 600;
}

.steps-grid p {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
}

.section-eyebrow {
  margin: 0 0 8px;
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 600;
}

/* ── Home: downloads call to action ──────────────────────────────── */
.cta-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 48px;
  flex-wrap: wrap;
}

.cta-row p {
  margin: 0;
  max-width: 44ch;
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-muted);
}

/* ── Downloads ───────────────────────────────────────────────────── */
.cat-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 6px;
}

.cat-bar {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 1px;
  background: var(--accent);
}

.cat-count {
  font-size: 12px;
  color: var(--text-faint);
  letter-spacing: 0.03em;
}

.cat-blurb {
  margin: 0 0 24px 32px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 56ch;
}

.filters {
  display: flex;
  gap: 12px;
  margin: 0 0 24px 32px;
  flex-wrap: wrap;
}

.filters select {
  padding: 9px 12px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font);
  font-size: 13px;
  cursor: pointer;
}

.no-match {
  margin: 0 0 24px 32px;
  font-size: 14px;
  color: var(--text-faint);
}

.file-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 16px;
}

.file-card {
  border-radius: 16px;
  border: 1px solid rgba(var(--accent-rgb), var(--wash-edge));
  background: linear-gradient(180deg, rgba(var(--accent-rgb), var(--wash)), rgba(0, 0, 0, 0) 60%), var(--surface);
  padding: 22px 22px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.file-card h3 {
  margin: 0 0 6px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--accent-light);
}

.file-card .desc {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-muted);
}

.tags {
  display: flex;
  gap: 6px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.tag {
  font-size: 11px;
  padding: 3px 8px;
  border-radius: 8px;
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  color: var(--accent-light);
}

.file-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.file-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.file-actions-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

.btn-text {
  color: var(--accent-light);
}

.file-meta {
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}

.text-panel {
  margin: 0;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--surface-deep);
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-muted);
  font-style: italic;
}

.btn-download {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 12px;
  /* Solid, not an outline. This is the one thing the page exists for, and
     as a thin outline it was being read as a disabled control. */
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  transition: background var(--t), color var(--t), border-color var(--t);
}

.btn-download:hover:not([aria-disabled="true"]) {
  background: var(--accent-light);
  border-color: var(--accent-light);
  color: var(--on-accent);
}

/* ── How to Use ──────────────────────────────────────────────────── */
.howto-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 200px;
  gap: 40px;
  align-items: start;
  max-width: 68ch;
  margin-top: 44px;
}

.howto-block:first-of-type {
  margin-top: 0;
}

.howto-block img {
  width: 100%;
  /* The three screenshots are all different shapes, one of them landscape.
     height:auto keeps each one's own proportions instead of forcing a
     single shape onto all of them. */
  height: auto;
  border-radius: 16px;
  border: 1px solid rgba(var(--accent-rgb), 0.3);
  display: block;
}

.howto-block h3 {
  margin: 0 0 18px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--text);
}

.howto-block .eyebrow {
  margin: 0 0 6px;
  color: var(--accent-light);
}

.step-list {
  margin: 0;
  padding: 0 0 0 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.step-list li {
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-muted);
}

/* Bullet list with a coloured left rule, used for the Calm Mode
   controls and the privacy summary. */
.accent-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.accent-list li {
  padding-left: 18px;
  border-left: 2px solid var(--accent, var(--purple));
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-muted);
}

.accent-list strong {
  color: var(--text);
  font-weight: 600;
}

.accent-list li.is-pink { border-left-color: var(--pink); }
.accent-list li.is-salmon { border-left-color: var(--salmon); }
.accent-list li.is-purple { border-left-color: var(--purple); }

/* ── Prose pages (About, Privacy, blog posts) ────────────────────── */
.prose-body h2 {
  margin: 40px 0 8px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}

.prose-body h2:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* When a coloured summary list sits above the body (privacy policy), the
   first body heading keeps its rule, because it is not the first thing
   on the page. */
.prose-body.has-summary h2:first-child {
  margin-top: 0;
  padding-top: 28px;
  border-top: 1px solid var(--border);
}

.prose-body h3 {
  margin: 28px 0 8px;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}

.prose-body p {
  margin: 14px 0 0;
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-muted);
}

.prose-body strong {
  color: var(--text);
  font-weight: 600;
}

.prose-body ul,
.prose-body ol {
  margin: 14px 0 0;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.prose-body li {
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-muted);
}

.prose-body blockquote {
  margin: 24px 0;
  padding-left: 18px;
  border-left: 2px solid var(--purple);
  font-style: italic;
  color: var(--text);
}

.prose-body img {
  width: 100%;
  border-radius: 12px;
  border: 1px solid var(--border);
  display: block;
  margin: 24px 0;
}

.prose-body hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 36px 0;
}

.page-head {
  margin-bottom: 44px;
  padding-bottom: 36px;
  border-bottom: 1px solid var(--border);
}

.page-date {
  margin: 0 0 36px;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* ── Blog ────────────────────────────────────────────────────────── */
.post-list {
  display: flex;
  flex-direction: column;
}

.post-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  padding: 28px 0;
  border-bottom: 1px solid var(--border);
}

.post-row--cover {
  grid-template-columns: minmax(0, 1fr) 160px;
}

.post-row:first-child {
  padding-top: 0;
}

.post-date {
  display: block;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 8px;
}

.post-row h2 {
  margin: 0 0 8px;
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.25;
}

.post-row h2 a {
  color: var(--text);
}

.post-row h2 a:hover {
  color: var(--purple-light);
}

.post-row p {
  margin: 0;
  max-width: 68ch;
  font-size: 15px;
  line-height: 1.6;
  color: var(--text-muted);
}

.post-row img {
  width: 160px;
  height: 100px;
  object-fit: cover;
  border-radius: 12px;
  border: 1px solid var(--border);
  display: block;
}

.empty-state {
  margin: 0;
  font-size: 14px;
  color: var(--text-faint);
}

.post-foot {
  margin-top: 48px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
  font-size: 14px;
}

.post-foot a {
  color: var(--text-muted);
}

.post-foot a:hover {
  color: var(--purple);
}

/* ── Contact form ─────────────────────────────────────────────── */
.field {
  margin-bottom: 20px;
}

.field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text);
  margin-bottom: 7px;
}

.field input,
.field textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  transition: border-color var(--t);
}

.field input:focus,
.field textarea:focus {
  border-color: var(--purple);
  outline: none;
}

.field textarea {
  resize: vertical;
  min-height: 140px;
}

.field-hint {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  color: var(--text-faint);
}

/* The bot trap. Off screen rather than display:none, because some bots
   skip hidden fields but fill in ones they can still find. */
.trap-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status {
  margin: 16px 0 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-muted);
  min-height: 1.6em;
}

.form-status.is-ok { color: var(--purple-light); }
.form-status.is-bad { color: var(--salmon-light); }

/* ── Mailing list signup ──────────────────────── */
.signup-section {
  padding-top: 56px;
  padding-bottom: 72px;
}

.signup {
  border: 1px solid rgba(var(--purple-rgb), var(--wash-edge));
  background:
    linear-gradient(180deg, rgba(var(--purple-rgb), var(--wash)), rgba(0, 0, 0, 0) 70%),
    var(--surface);
  border-radius: 18px;
  padding: 30px 32px 28px;
  display: grid;
  gap: 24px;
  align-items: center;
  grid-template-columns: 1fr 1fr;
}

.signup-words h2 {
  margin: 0 0 8px;
}

.signup-words p {
  margin: 0;
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1.6;
}

/* The field and the button sit on one line while there is room, and the
   button goes full width underneath when there is not. */
.signup-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.signup-row input {
  flex: 1 1 200px;
  min-width: 0;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  transition: border-color var(--t);
}

.signup-row input:focus {
  border-color: var(--purple);
  outline: none;
}

/* Left to the browser this is #757575 in both themes, which scored 4.29
   on dark and 4.44 on light, both under the 4.5 mark. Set explicitly so
   it follows the theme like everything else. */
.signup-row input::placeholder {
  color: var(--text-faint);
  opacity: 1;
}

.signup-row .btn-primary {
  flex: 0 0 auto;
  margin: 0;
}

.signup-fine {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-faint);
}

.signup .form-status {
  margin-top: 10px;
}

@media (max-width: 740px) {
  .signup {
    grid-template-columns: 1fr;
    padding: 24px 22px 22px;
  }

  .signup-row .btn-primary {
    flex: 1 1 100%;
    justify-content: center;
  }
}

/* ── Footer ──────────────────────────────────────────────────────── */
.site-footer {
  border-top: 1px solid var(--border);
  background: var(--bg);
}

.footer-grid {
  padding-top: 52px;
  padding-bottom: 36px;
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) 1fr 1fr;
  gap: 48px;
}

.footer-brand .wordmark {
  margin-bottom: 12px;
}

.footer-brand .wordmark img {
  height: 20px;
}

.footer-brand .wordmark span {
  font-size: 19px;
}

.footer-brand p {
  margin: 0;
  max-width: 32ch;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-faint);
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 13px;
}

.footer-col h2 {
  margin: 0 0 4px;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 600;
}

.footer-col a {
  color: var(--text-muted);
}

.footer-col a:hover {
  color: var(--purple);
}

.footer-col .soon-text {
  color: var(--text-faint);
}

.btn-share {
  margin-top: 4px;
  align-self: flex-start;
  padding: 10px 14px;
  border-radius: 12px;
  background: none;
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--font);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--t), border-color var(--t);
}

.btn-share:hover {
  border-color: var(--purple);
  color: var(--purple);
}

.footer-bottom {
  padding-bottom: 36px;
}

.footer-bottom-inner {
  padding-top: 22px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--text-faint);
}

/* ===================================================================
   Responsive. The prototype was desktop only, these are additions.
   =================================================================== */

@media (max-width: 1080px) {
  .hero-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 40px;
    justify-items: start;
  }

  .phone-col {
    justify-content: flex-start;
  }

  .steps-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .footer-grid {
    grid-template-columns: 1fr 1fr;
    gap: 40px;
  }

  .footer-brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 740px) {
  :root {
    --gutter: 20px;
  }

  .section {
    padding-top: 48px;
    padding-bottom: 48px;
  }

  .hero .wrap {
    padding-top: 56px;
    padding-bottom: 48px;
  }

  .h-hero {
    font-size: 38px;
  }

  .h-page {
    font-size: 32px;
  }

  .h-large {
    font-size: 26px;
  }

  .h-card {
    font-size: 22px;
  }

  /* Without scripting the menu simply stays on the page and wraps, which
     is what it did before the button existed. Nobody is locked out. */
  .site-header .wrap {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }

  .nav {
    flex-wrap: wrap;
    gap: 16px 18px;
    width: 100%;
  }

  /* With scripting, the menu collapses behind the button. The header goes
     back to a single row: logo on the left, theme and menu on the right.
     That is the whole point. It was taking three rows. */
  .js .site-header .wrap {
    flex-direction: row;
    align-items: center;
    gap: 12px;
    position: relative;
  }

  .js .nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
  }

  /* Dropped below the header rather than covering the screen. The menu is
     five items; a full screen panel for five items is theatre.
     [hidden] is overridden elsewhere in this file with display:none
     !important, which is why the open state is an attribute instead. */
  .js .site-header .wrap > .nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 6px var(--gutter) 14px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.16);
  }

  .js .site-header .wrap > .nav[data-open="true"] {
    display: flex;
  }

  /* Full width rows, so the whole strip is tappable rather than just the
     few characters of the word. */
  .js .nav a,
  .js .nav-soon {
    padding: 13px 2px;
    border-bottom: 1px solid var(--border);
  }

  .js .nav a[aria-current="page"] {
    color: var(--text);
    border-bottom-color: var(--border);
    box-shadow: inset 3px 0 0 -1px var(--purple);
    padding-left: 10px;
  }

  .js .nav-soon {
    border-bottom: 0;
  }

  .mode-grid,
  .steps-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .file-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .howto-block {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  .howto-block img {
    width: 60%;
    margin: 0 auto;
  }

  .cat-blurb,
  .filters,
  .no-match {
    margin-left: 0;
  }

  .filters select {
    flex: 1 1 140px;
  }

  .footer-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 36px;
  }

  .post-row--cover {
    grid-template-columns: minmax(0, 1fr);
  }

  .post-row img {
    width: 100%;
    height: 160px;
  }
}

/* Tap targets on any finger-driven screen, not only narrow ones. A tablet
   is wider than the phone breakpoint but is still tapped, not clicked. */
@media (pointer: coarse) {
  .nav a,
  .nav-soon {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* The icon itself is 17px, which is nowhere near a thumb. */
  .js .theme-toggle {
    min-height: 44px;
    min-width: 44px;
  }

  .filters select,
  .btn-ghost,
  .btn-download,
  .btn-share,
  .btn-primary {
    min-height: 44px;
  }
}
