/* Reveal the Dream: shared styles
   Calm, premium, restrained. Mobile-first, light/dark aware.

   Built on top of assets/tokens/tokens.css (loaded first in every page's
   <head>). The custom properties below are a thin, page-local alias layer
   over the token names, kept only because the legal pages (privacy/terms/
   support) already use them; everything new should just reach for the
   --color-, --space-, --radius- and --shadow- tokens directly. Dark mode is
   NOT redefined here. tokens.css already flips every --color- value under
   prefers-color-scheme: dark, and these aliases inherit that automatically.
   (Careful editing this comment: a literal star-slash anywhere inside it,
   even mid-word, closes the comment early and silently drops every rule
   that follows until the next real one. That happened here once.) */

:root {
  --bg: var(--color-ground);
  --bg-warm: var(--color-ground-warm);
  --bg-elevated: var(--color-surface-raised);
  --surface: var(--color-surface);
  --text: var(--color-text-primary);
  --text-muted: var(--color-text-muted);
  --text-faint: var(--color-text-faint);
  --border: var(--color-border);
  --accent: var(--color-accent-active);
  --accent-strong: var(--color-accent-active);
  --accent-tint: var(--color-ground-warm);
  --shadow: var(--shadow-sm);
  --serif: var(--font-display);
  --sans: var(--font-sans);
}

* {
  box-sizing: border-box;
}

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

/* The builder's note walks the reader down the page by anchor link, so the
   jumps are animated rather than instant. Anyone who asks for less motion
   gets the plain jump back. */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* The header is sticky, so without this every #anchor target lands underneath it.
   Slightly more than the 71px header so the heading is not flush against its edge. */
html {
  scroll-padding-top: 88px;
}

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

img, svg {
  max-width: 100%;
  display: block;
}

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

a:hover {
  text-decoration: underline;
}

:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -48px;
  background: var(--color-surface-raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
  z-index: 100;
  transition: top var(--duration-fast) var(--ease-out);
}

.skip-link:focus {
  top: var(--space-4);
}

.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;
}

.container {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--space-6);
}

.container-lg {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--space-6);
}

/* ---------- Header ---------- */

/* Locked to the top of the viewport, so Download and Premium stay reachable from
   anywhere on the page. Opaque background is required: the header sits over content as
   it scrolls, and the default is transparent. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.site-header .container-lg {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: var(--space-5);
  padding-bottom: var(--space-5);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.brand:hover {
  text-decoration: none;
  opacity: 0.85;
}

.brand-mark {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  flex-shrink: 0;
  object-fit: cover;
}

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

.main-nav a {
  color: var(--text-muted);
  font-size: var(--font-size-small);
}

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

/* ---------- Footer ---------- */

/* No border and no top margin. Every page ends on a section that already provides the
   break, so this added a second divider and a large empty gap above it. The container's
   own padding-top is what gives the footer room. */
.site-footer {
  margin-top: 0;
}

.site-footer .container-lg {
  padding-top: var(--space-12);
  padding-bottom: var(--space-8);
}

/* One column on a phone, two on a small tablet, all five across from 900px.
   auto-fit rather than a fixed count so a sixth column can be added without
   touching the breakpoints. */
.footer-cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8) var(--space-6);
}

@media (min-width: 560px) {
  .footer-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 900px) {
  .footer-cols { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

.footer-col h2 {
  font-family: var(--sans);
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 var(--space-3);
}

.footer-col ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

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

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

.footer-base {
  margin-top: var(--space-10);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border);
}

.footer-copy {
  color: var(--text-faint);
  font-size: var(--font-size-caption);
}

/* ---------- Sections, general ---------- */

.section {
  padding: var(--space-20) 0;
}

.section-warm {
  background: var(--bg-warm);
}

.section-eyebrow {
  display: inline-block;
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-strong);
  margin: 0 0 var(--space-3);
}

.section-header {
  max-width: 640px;
  margin: 0 0 var(--space-10);
}

.section-header.centered {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.section h2 {
  font-family: var(--serif);
  font-size: var(--font-size-h2);
  font-weight: 500;
  margin: 0 0 var(--space-3);
  letter-spacing: -0.005em;
}

.section-intro {
  color: var(--text-muted);
  font-size: var(--font-size-body-lg);
  margin: 0;
}

.section-intro a {
  color: var(--accent-strong);
}

/* ---------- Hero ---------- */

.hero {
  /* Bottom padding is deliberately smaller than the top, so the section below starts
     peeking above the fold and there is a reason to keep scrolling. It used to stack with
     the old .idea section's own top padding to 176px, which parked most of a screen of
     nothing under the hero. That section is gone and the builder note follows directly. */
  padding: var(--space-16) 0 var(--space-10);
}

.hero-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-10);
  align-items: center;
}

/* The buttons are a sibling of the copy and the demo, not a child of the copy, so the
   single-column order can be headline, demo, buttons. Three black buttons directly under
   the subheading pushed the demo below the fold on a phone and read as clutter before
   anyone had seen what the app does. */
@media (min-width: 860px) {
  .hero-grid {
    grid-template-columns: 1.05fr 0.95fr;
    gap: var(--space-12);
    align-items: start;
  }
  .hero-visual { align-self: start; }
}

.hero-copy {
  text-align: center;
}

@media (min-width: 860px) {
  .hero-copy {
    text-align: left;
  }
}

.hero-eyebrow {
  /* block, not inline-block: as an inline-block it sat in a line box using the parent's
     larger line-height, and the half-leading above it pushed the eyebrow about 4px below
     the top of its own column, so the demo aligned to the column and looked misaligned
     against the text. No background or border here, so full width costs nothing, and
     text-align on .hero-copy still centres the words below 860px. */
  display: block;
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--space-4);
}

.hero h1 {
  font-family: var(--serif);
  font-size: var(--font-size-display);
  line-height: var(--line-height-tight);
  margin: 0 0 var(--space-5);
  font-weight: 500;
  letter-spacing: -0.01em;
}

.hero-hook {
  font-size: var(--font-size-body-lg);
  color: var(--text-muted);
  max-width: 480px;
  margin: 0 0 var(--space-8);
}

/* Below 860px .hero-copy is centre-aligned, so the 480px-capped paragraph needs auto
   margins to sit centred in a wider column. Above it the hero is left-aligned and it
   must not.
   The .hero-copy prefix is on purpose: the cancelling rule used to be a bare .hero-hook,
   which lost on specificity and never fired, leaving the paragraph centred inside a
   left-aligned column and indented 29px against the headline. */
.hero-copy .hero-hook {
  margin-left: auto;
  margin-right: auto;
}

@media (min-width: 860px) {
  .hero-copy .hero-hook {
    margin-left: 0;
    margin-right: 0;
  }
}

/* The two hero calls to action. Centred with the copy below 860px, flush left above. */
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-size: var(--font-size-body);
  justify-content: center;
  margin: 0;
}

@media (min-width: 860px) {
  .hero-actions { justify-content: flex-start; }
}

.hero-visual {
  width: 100%;
  max-width: 380px;
  margin: 0 auto;
}

@media (min-width: 860px) {
  .hero-visual {
    margin: 0 0 0 auto;
  }
}

/* In the demo the goal title sits ABOVE the photo, so the left column opens with text at
   the same y as the control panel opposite it. Margin flips to the underside; the hero's
   caption still sits below its photo and keeps the rule above. */
.demo-stage .reveal-caption {
  margin: 0 0 var(--space-3);
}

.reveal-caption {
  text-align: center;
  font-family: var(--serif);
  font-size: var(--font-size-body);
  color: var(--text);
  margin: var(--space-3) 0 0;
  /* Holds its line when the goal field is empty, which it is the moment somebody
     picks their own photo. Without this the whole demo jumps up as they choose. */
  min-height: 1.5em;
}

.reveal-slider {
  margin-top: var(--space-4);
}

/* ---------- Reveal frames (canvas + fallback photo) ---------- */

.reveal-frame {
  position: relative;
  width: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--color-border);
  box-shadow: var(--shadow-lg);
}

.reveal-frame.aspect-1-1 {
  aspect-ratio: 1 / 1;
}

.reveal-frame.aspect-4-5 {
  aspect-ratio: 4 / 5;
}

.reveal-frame img,
.reveal-frame canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.reveal-frame canvas {
  display: block;
}

/* ---------- Interactive demo ---------- */

.demo {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
  align-items: start;
}

@media (min-width: 760px) {
  /* Both tracks are bounded and the pair is centred, rather than the panel taking "1fr"
     and eating whatever is left of the 1120px container. At 340px the photograph was the
     smaller half of a section whose entire job is showing the photograph, while the panel
     ran to about 700px of mostly empty row. The frame is 4:5, so widening the column
     raises the photo's height with it: 340x425 becomes 420x525. */
  .demo {
    grid-template-columns: minmax(0, 420px) minmax(0, 560px);
    justify-content: center;
    /* Both columns take the height of the taller one, so the panel's card and the photo
       finish level instead of one hanging 13px below the other. It has to be stretch rather
       than a fixed height because WHICH ONE IS TALLER CHANGES: the photo column is 564 in
       the normal state, and the panel grows to 624 the moment Custom journey length opens
       its number field. Content stays top-aligned inside both, deliberately, so opening and
       closing Custom does not shunt the controls up and down. */
    align-items: stretch;
  }
}

.demo-stage {
  max-width: 420px;
  margin: 0 auto;
  width: 100%;
}

.demo-readout {
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  font-variant-numeric: tabular-nums;
  font-size: var(--font-size-small);
  color: var(--text-muted);
}

/* Sits under the photo picker. Empty in the normal case: the line that used to live here
   was removed, and the element is kept because note() writes photo errors into it. */
.demo-photo-help {
  font-size: var(--font-size-caption);
  color: var(--text-faint);
  margin: var(--space-2, 8px) 0 0;
  line-height: 1.5;
}

/* Errors only. Empty and invisible until something is actually wrong. */
.demo-photo-note {
  font-size: var(--font-size-caption);
  color: var(--danger, #9b2c2c);
  margin: var(--space-2, 8px) 0 0;
  line-height: 1.5;
}

.demo-photo-note:empty {
  display: none;
}

/* This panel used to disappear into the page. --surface is #fffdf9 against a --bg of
   #fbf9f4, which is four levels per channel: a difference you can measure and cannot see,
   so the card read as a faint outline rather than an object. It is surface-raised (pure
   white) on the deeper shadow now, which is the same pairing the rest of the site uses for
   things that sit above the page.
   The section itself stays untinted deliberately. Backgrounds alternate warm/plain down the
   whole page and #demo sits between #builder and #dreams, both warm, so tinting this one
   would put three warm bands in a row and break the rhythm rather than fix the card. */
.demo-controls {
  background: var(--color-surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.field label {
  display: block;
  font-size: var(--font-size-small);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-2);
}

.seg {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.seg button {
  font: inherit;
  font-size: var(--font-size-small);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  color: var(--text);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}

.seg button:hover {
  border-color: var(--color-accent);
}

.seg button[aria-pressed="true"] {
  background: var(--color-accent-active);
  color: var(--color-on-accent-active);
  border-color: var(--color-accent-active);
}

/* Sliders are the main control on this site and they are used on phones, so the
   thumb is sized for a thumb. 34px across with a 44px tall hit area, which is the
   minimum comfortable touch target. The browser default was about 12px and was
   genuinely hard to grab. accent-color alone cannot set thumb size, so both the
   WebKit and the Firefox pseudo-elements are styled explicitly. */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 44px;
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  accent-color: var(--color-accent-active);
}

input[type="range"]:focus {
  outline: none;
}

input[type="range"]:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 4px;
  border-radius: var(--radius-full);
}

/* Rail */
input[type="range"]::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: var(--radius-full);
  background: linear-gradient(
    to right,
    var(--color-accent-active) 0 var(--range-fill, 0%),
    var(--color-border) var(--range-fill, 0%) 100%
  );
}

input[type="range"]::-moz-range-track {
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--color-border);
}

input[type="range"]::-moz-range-progress {
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--color-accent-active);
}

/* Thumb */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 34px;
  height: 34px;
  margin-top: -13px; /* centres a 34px thumb on an 8px rail */
  border-radius: var(--radius-full);
  background: var(--color-surface-raised);
  border: 2px solid var(--color-accent-active);
  box-shadow: var(--shadow-md);
}

input[type="range"]::-moz-range-thumb {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-full);
  background: var(--color-surface-raised);
  border: 2px solid var(--color-accent-active);
  box-shadow: var(--shadow-md);
}

input[type="range"]:active::-webkit-slider-thumb {
  background: var(--color-accent-active);
  border-color: var(--color-accent-active);
}

input[type="range"]:active::-moz-range-thumb {
  background: var(--color-accent-active);
  border-color: var(--color-accent-active);
}

/* "Slide" sits centred under the rail as a plain affordance for touch. */
.range-hint {
  text-align: center;
  font-size: var(--font-size-caption);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: var(--space-1, 4px) 0 0;
}

.range-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.range-value {
  font-variant-numeric: tabular-nums;
  font-size: var(--font-size-small);
  color: var(--text-muted);
}

/* ---------- Four styles ---------- */

.styles-slider {
  max-width: 360px;
  margin: 0 auto var(--space-10);
}

.styles-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-6);
}

@media (min-width: 760px) {
  .styles-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

.style-card {
  text-align: center;
}

.style-card .reveal-frame {
  margin-bottom: var(--space-4);
}

.style-card h3 {
  font-size: var(--font-size-body);
  font-weight: 600;
  margin: 0 0 var(--space-1);
}

.style-tag {
  display: inline-block;
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  color: var(--text-muted);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
}

.style-tag.is-premium {
  color: var(--color-on-accent);
  background: var(--color-accent);
  border-color: var(--color-accent);
}

/* ---------- Home screen widget ---------- */

.widget-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-10);
  align-items: center;
}

@media (min-width: 760px) {
  .widget-grid {
    grid-template-columns: minmax(0, 260px) 1fr;
  }
}

.device-frame {
  width: 100%;
  max-width: 240px;
  margin: 0 auto;
  padding: 12px 12px 18px;
  background: #14110d;
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}

.device-frame .device-notch {
  width: 70px;
  height: 16px;
  margin: 0 auto 8px;
  background: #000;
  border-radius: var(--radius-full);
}

/* A plain home screen for the widget to sit on: a quiet wallpaper and a date, and
   nothing else. No fake app icons. Inventing a home screen full of apps the user
   does not have would be dressing up a screenshot. */
.device-frame .device-screen {
  /* Cropped rather than a whole phone: a real home screen with only this widget on it
     is mostly empty, and a full 9/17 frame gave a large dead area under the widget. */
  aspect-ratio: 9 / 12;
  border-radius: var(--radius-md);
  overflow: hidden;
  padding: var(--space-6) var(--space-3) 0;
  background:
    radial-gradient(120% 70% at 20% 0%, #3c4b52 0%, rgba(60,75,82,0) 60%),
    linear-gradient(170deg, #232a2c 0%, #14181a 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.device-frame .device-date {
  font-size: 11px;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.72);
}

.device-frame .device-widget {
  width: 88%;
  height: auto;
  border-radius: 0;   /* the asset carries its own rounded corners in alpha */
}

.widget-copy {
  text-align: center;
}

@media (min-width: 760px) {
  .widget-copy {
    text-align: left;
  }
}

.widget-copy p {
  color: var(--text-muted);
  font-size: var(--font-size-body-lg);
  max-width: 46ch;
  margin: 0 auto;
}

@media (min-width: 760px) {
  .widget-copy p {
    margin-left: 0;
  }
}

/* ---------- Free vs Premium ---------- */

/* The plans section's one call to action, above the cards rather than below them. The two cards
   explain the difference; a reader who has already decided should not have to scroll past the
   whole comparison to act on it. */
.plans-cta {
  display: flex;
  justify-content: center;
  margin: 0 0 var(--space-6);
}

/* Larger than the hero's buttons, deliberately. This is the one place on the page where somebody
   decides to pay, so it is the largest call to action on it. Base .btn is 13/14px, which reads as
   a secondary control next to two full plan cards. */
.plans-cta .btn {
  padding: 18px 44px;
  font-size: var(--font-size-body-lg);
}

.plans-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}

@media (min-width: 640px) {
  .plans-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.plan-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  box-shadow: var(--shadow-sm);
}

.plan-card h3 {
  font-family: var(--serif);
  font-size: var(--font-size-h3);
  font-weight: 500;
  margin: 0 0 var(--space-4);
}

.plan-premium {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-md);
}

.plan-premium h3 {
  color: var(--accent-strong);
}

.plan-card ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}

.plan-card li {
  display: flex;
  gap: var(--space-3);
  color: var(--text-muted);
  font-size: var(--font-size-body);
}

.plan-card li::before {
  content: "";
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin-top: 8px;
  border-radius: var(--radius-full);
  background: var(--color-cover-2);
}

.plan-premium li::before {
  background: var(--color-accent);
}

/* ---------- Download ---------- */

.download-section {
  text-align: center;
}

.download-section p {
  color: var(--text-muted);
  font-size: var(--font-size-body-lg);
  max-width: 46ch;
  margin: 0 auto var(--space-2);
}

/* ---------- Feature list (legacy, still referenced) ---------- */

.lede {
  font-size: var(--font-size-body-lg);
  color: var(--text);
  text-align: center;
  max-width: 560px;
  margin: 0 auto var(--space-2);
}

.feature-list {
  list-style: none;
  padding: 0;
  margin: var(--space-8) 0 0;
  display: grid;
  gap: var(--space-5);
}

.feature-list li {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.feature-num {
  font-family: var(--serif);
  font-size: var(--font-size-small);
  color: var(--accent-strong);
  border: 1px solid var(--border);
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.feature-body h3 {
  margin: 2px 0 var(--space-1);
  font-size: var(--font-size-body);
  font-weight: 600;
}

.feature-body p {
  margin: 0;
  font-size: var(--font-size-small);
  color: var(--text-muted);
}

/* ---------- Buttons / badges ---------- */

.cta-row {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.hero-copy .cta-row {
  justify-content: center;
}

@media (min-width: 860px) {
  .hero-copy .cta-row {
    justify-content: flex-start;
  }
}

/* Both stores carry equal weight: the app ships on iPhone and Android alike. */
.store-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  background: #111;
  color: #fff;
  padding: 11px 20px;
  border-radius: 12px;
  font-size: var(--font-size-small);
  border: 1px solid rgba(255, 255, 255, 0.08);
  transition: opacity var(--duration-fast) var(--ease-out);
}

.store-badge:hover {
  text-decoration: none;
  opacity: 0.9;
}

.store-badge .glyph {
  width: 20px;
  height: 22px;
  flex-shrink: 0;
}

.store-badge .label {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  text-align: left;
}

.store-badge .label small {
  font-size: 11px;
  color: #cfcfcf;
}

.store-badge .label strong {
  font-size: 16px;
  font-weight: 600;
}

.placeholder-flag {
  display: block;
  text-align: center;
  font-size: var(--font-size-caption);
  color: var(--text-faint);
  margin-top: var(--space-3);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 22px;
  border-radius: var(--radius-sm);
  background: var(--color-accent-active);
  color: var(--color-on-accent-active);
  font-size: var(--font-size-small);
  font-weight: 600;
  border: none;
  cursor: pointer;
}

/* The outlined companion to .btn, for the second of a pair where only one should be the
   primary action. */
.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
}

/* The hero's two calls to action carry more weight than a general button. */
.hero-actions .btn {
  padding: 15px 30px;
  font-size: var(--font-size-body);
}

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

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

/* The contact form's inline result line. Errors are the same size and weight as the
   success case; only the colour differs, so a failure reads as information rather
   than alarm. */
.form-note.is-error {
  color: var(--accent-strong);
}

/* Currency picker on the download page. Hidden until the catalog loads, so it never
   renders as a select that cannot change anything. */
.currency-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-5);
}

.currency-row label {
  font-size: var(--font-size-small);
  font-weight: 600;
  color: var(--text-muted);
}

.currency-row select {
  font: inherit;
  font-size: var(--font-size-small);
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
}

/* Real Apple Watch screenshots, replacing the CSS watch mock that stood in before
   they existed. Two across on a phone, four across once there is room, so the
   complication is never orphaned on its own row. */

.watch-shots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6);
  max-width: 880px;
}

@media (min-width: 760px) {
  .watch-shots { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.watch-shot {
  margin: 0;
  text-align: center;
}

/* The screenshots are square-cornered captures of a round-cornered display, so the
   radius is added back here rather than baked into the asset. */
.watch-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14%;
  background: #000;
  box-shadow: var(--shadow-md, var(--shadow-sm));
}

.watch-shot figcaption {
  margin-top: var(--space-3);
  font-size: var(--font-size-caption);
  color: var(--text-muted);
  line-height: var(--line-height-body);
}

/* ---------- Platform buttons ----------
   Three stacked, full width. The two side-by-side store badges they replace sat in a
   narrow row that did not line up with the headline or the paragraph above them, and
   only named two of the six platforms the app runs on. */

/* Stacked on a phone, three across from 760px. They are one choice made three ways,
   so a row reads as a choice while a stack reads as a list of steps. */
.platform-buttons {
  display: grid;
  gap: var(--space-3);
  width: 100%;
  max-width: 480px;
}

@media (min-width: 760px) {
  .platform-buttons {
    grid-template-columns: repeat(3, max-content);
    justify-content: center;
    max-width: none;
    align-items: start;
  }
}

.platform-btn {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: 12px var(--space-4);
  border-radius: var(--radius-md);
  background: #1b1a17;
  color: #fff;
  font-size: var(--font-size-body);
  line-height: 1.2;
}

.platform-btn:hover {
  text-decoration: none;
  opacity: 0.92;
}

.platform-btn strong { display: block; font-weight: 600; line-height: 1.25; }

.platform-btn .glyph {
  width: 20px;
  height: 20px;
  flex: none;
}

/* The download section is centre-aligned, so the stack needs a width to centre within.
   Above 760px the row needs the full container instead: capped at 26rem the three
   buttons were 131px each and every label wrapped to three lines. */
/* Sized to the short label rather than to the container. A full-width button for the
   word "Apple" reads as a banner; these read as three things to pick between. */
.download-section .platform-buttons {
  max-width: 17rem;
  margin-inline: auto;
}

@media (min-width: 760px) {
  .download-section .platform-buttons {
    max-width: 620px;
    margin-inline: auto;
  }
}

/* The section uses the wide container for the button row, so its own copy needs a cap
   or the paragraph runs to 1120px and reads as a banner. */
.download-section p {
  max-width: 46rem;
  margin-inline: auto;
}

/* The full label is SHOWN, on its own line above the platform name. It used to be visually
   hidden on the reasoning that the heading above already said "Get Reveal the Dream", but the
   heading is not what somebody sees when the button is screenshotted, shared, or read on its
   own, and the product name doing the work is worth more than the line it costs.

   Owner's call 2026-08-12, matching how The Long View's buttons read. */
.btn-prefix {
  display: block;
  font-size: var(--font-size-caption);
  font-weight: 400;
  line-height: 1.25;
  white-space: nowrap;
  opacity: 0.82;
}

/* Below 760px the download section is centre-aligned, so the icon and label centre in
   the button rather than sitting hard left. The chevron stays pinned right, and an equal
   spacer opposite it keeps the pair on the true centre rather than the centre of what is
   left over. */
@media (max-width: 759px) {
  .pm-button { justify-content: center; }

  .pm-button > span { margin-right: 0; }

  .pm-button::before {
    content: "";
    width: 12px;
    margin-right: var(--space-2);
    flex: none;
    order: -1;
  }

  .pm-chevron { margin-left: auto; }

  .pm-button .glyph { margin-left: auto; }
}

/* The download-starting note.
   On the homepage it goes in a fixed slot below the three platform buttons. It used to be
   injected next to whatever was clicked, which dropped it inside the button grid: it took
   one narrow column and wrapped into four ragged lines beside the open menu. */
.dl-feedback {
  margin: var(--space-3) 0 0;
  font-size: var(--font-size-caption);
  line-height: var(--line-height-body);
  color: var(--text-muted);
}

/* A one-cell grid holding two stacked copies of the note. The hidden ghost carries the
   longest message and sets the height; the live one sits on top of it. Reserving the space
   this way is exact at every width, where a min-height guess was not: the string wraps to
   two lines at 1440px and three at 390px, so a fixed value shifted the matrix by 16px and
   42px respectively. */
.dl-feedback-slot {
  display: grid;
  justify-items: center;
  margin-top: var(--space-6);
  padding: 0 var(--space-4);
}

.dl-feedback-slot > .dl-feedback {
  grid-area: 1 / 1;
  margin: 0;
  max-width: 32rem;
  text-align: center;
  /* Opacity rather than [hidden], which would collapse the box and defeat the reservation. */
  opacity: 0;
  transition: opacity 160ms ease;
}

/* visibility, not display or opacity: it must keep occupying space while staying out of
   the accessibility tree and off the screen. */
.dl-feedback-ghost { visibility: hidden; }

.dl-feedback-slot .dl-feedback.is-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .dl-feedback-slot .dl-feedback { transition: none; }
}

/* ---------- Message Me form, inside the builder note ----------
   Collapsed until the button is pressed. Reuses .contact-form and .field from the support
   page, so there is one set of form styles rather than two that drift. */

.builder-contact {
  margin-top: var(--space-6);
  padding: var(--space-6);
  max-width: 34rem;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.builder-contact .contact-form { margin-top: 0; }

.builder-contact .form-note { margin: 0 0 var(--space-4); }


/* Sub-line under a comparison row label. Without this it renders identically to the label and
   reads as a second feature rather than as a qualifier on the first one. */
.matrix-subnote {
  display: block;
  margin-top: 2px;
  font-size: var(--font-size-caption);
  font-weight: 400;
  color: var(--text-faint);
  line-height: 1.35;
}


/* Tier section header inside the matrix. Replaces a badge repeated on every row: the rows are
   grouped by tier, so the group only needs saying once, and dropping 18 badges also drops the
   height each one added to its row. */
/* The plan label runs vertically down the left edge of the grid instead of sitting in a
   full-width band across it. Two full-width bands cost two whole rows of height and pushed the
   table longer; the same information now rides alongside the rows it applies to.

   THE ROTATION IS ON THE INNER SPAN, NOT THE CELL. Transforms on a table-cell box are unreliable
   across engines, since the cell participates in table layout rather than being a normal block.
   Rotating a plain inline-block inside it is well defined everywhere.

   `vertical-rl` alone runs the text top to bottom with the letter bottoms facing left, away from
   the grid. The 180 degree turn makes it read bottom to top with the letter bottoms facing right,
   into the grid, which is what was asked for and is also the conventional direction for a
   left-edge label. */
:root { --matrix-tier-w: 2.75rem; }

.matrix-tier {
  width: var(--matrix-tier-w);
  min-width: var(--matrix-tier-w);
  padding: var(--space-2) var(--space-1);
  vertical-align: middle;
  text-align: center;
  border-bottom: 2px solid var(--border);
  border-right: 1px solid var(--border);
}

.matrix-tier > span {
  display: inline-block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  font-family: var(--sans);
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
}

.matrix-tier-note {
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-faint);
}

/* ---------- Customer reviews ----------
   Written by tools/build-reviews.py, never by hand. Renders nothing at all until there is
   at least one real, consented review in site/data/reviews.json, which is why these rules
   currently match no element on any page. */

.reviews {
  margin: var(--space-8) 0 var(--space-10);
}

.reviews-heading {
  font-family: var(--sans);
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 var(--space-5);
}

.review-card {
  margin: 0 0 var(--space-4);
  padding: var(--space-5) var(--space-6);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  text-align: left;
}

/* The stars are decorative; the accessible name lives on the aria-label of the paragraph,
   so a screen reader hears "4 out of 5" rather than four unpronounceable glyphs. */
.review-stars {
  margin: 0 0 var(--space-2);
  font-size: var(--font-size-body);
  letter-spacing: 0.1em;
  color: var(--accent-strong);
}

.review-card blockquote {
  margin: 0;
  font-size: var(--font-size-body-lg);
  line-height: var(--line-height-body);
  color: var(--text);
}

.review-card figcaption {
  margin-top: var(--space-3);
  font-size: var(--font-size-caption);
  color: var(--text-muted);
}

.review-platform { color: var(--text-faint); }

/* Two abreast once there is room. One column on a phone, where a side-by-side pair would
   make both unreadably narrow. */
@media (min-width: 760px) {
  .reviews {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 var(--space-5);
  }

  .reviews-heading { grid-column: 1 / -1; }
}

/* ---------- Platform and plan matrix ----------
   Seven platform columns will not fit a phone, so the wrapper scrolls sideways and the
   feature column is pinned. Pinning needs an opaque background on those cells: they sit
   over the scrolling ones, and a transparent default lets the numbers show through. */

/* contain: paint is load-bearing, not a tidy-up. Without it the table's 720px min-width
   escapes this wrapper and widens the DOCUMENT to 752px against a 390px viewport, so the
   whole page slid sideways on a real iPhone and left a blank band down the right of every
   section. overflow-x: auto alone does not stop it, and neither does max-width, an
   overflow clip on the section, or dropping the sticky first column. Reproduced in
   Simulator Safari and confirmed fixed there. */
.matrix-wrap {
  margin-top: var(--space-10);
  overflow-x: auto;
  contain: paint;
}

.matrix {
  width: 100%;
  min-width: 720px;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--font-size-small);
  text-align: left;
}

.matrix caption {
  caption-side: top;
  text-align: left;
  margin-bottom: var(--space-4);
  font-size: var(--font-size-caption);
  color: var(--text-muted);
}

.matrix th,
.matrix td {
  padding: 12px var(--space-4);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.matrix thead th {
  font-size: var(--font-size-caption);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
  border-bottom-width: 2px;
  white-space: nowrap;
}

.matrix td {
  text-align: center;
  color: var(--text);
}

.matrix .is-no { color: var(--text-faint); }

/* The pinned column. left:0 plus a background is the whole trick; without the background
   the scrolling cells slide visibly underneath it. */
/* SELECT THE FEATURE COLUMN BY NAME, NOT BY POSITION. This was `thead th:first-child`, which
   was the Feature header until the vertical plan column was added in front of it. The plan
   column then silently inherited a 15rem width meant for feature names, blew the table past the
   viewport and pushed Wear OS off the right edge. A positional selector is a rule that changes
   meaning when the markup moves. */
.matrix th[scope="row"],
.matrix thead th.matrix-feature-head {
  position: sticky;
  left: var(--matrix-tier-w);
  z-index: 1;
  background: var(--bg);
  font-weight: 500;
  color: var(--text);
  /* 15rem here ate most of a phone screen. Narrower, and the longer feature names are
     allowed to wrap rather than forcing the column wide. */
  width: 9rem;
  min-width: 9rem;
}

@media (min-width: 760px) {
  .matrix th[scope="row"],
  .matrix thead th.matrix-feature-head { width: 15rem; min-width: 15rem; }
}

/* The plan column sits to the left of the feature column and both stay put while the platforms
   scroll, so the reader never loses which row or which tier they are looking at. */
.matrix thead th.matrix-tier-head,
.matrix .matrix-tier {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--bg);
}

.matrix-feature { display: block; }

.matrix-plan {
  display: inline-block;
  margin-top: 3px;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.plan-free {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
}

.plan-paid {
  background: var(--color-accent-active);
  color: var(--color-on-accent-active);
}

.matrix tbody tr:last-child th,
.matrix tbody tr:last-child td { border-bottom: none; }

/* Only shown where the table actually scrolls. aria-hidden because the caption already
   tells a screen reader the same thing in a sentence, and this is a visual affordance. */
.matrix-swipe { display: none; }

@media (max-width: 759px) {
  .matrix-swipe {
    display: inline-block;
    margin-left: var(--space-2);
    font-size: 10px;
    letter-spacing: 0.12em;
    color: var(--text-faint);
  }
}

/* ---------- Platform button menus ----------
   Layered onto the plain links by platform-menu.js. Without JavaScript the buttons stay
   links to /download#<section>, so this is enhancement, never the only route. */

.pm {
  width: 100%;
}

.pm-button {
  border: none;
  cursor: pointer;
  font: inherit;
  justify-content: space-between;
}

/* The label and icon keep their own gap; the chevron is pushed to the far edge by
   space-between above, so the row reads icon, label, then the affordance. */
.pm-button > span { margin-right: auto; }

.pm-chevron {
  width: 12px;
  height: 8px;
  flex: none;
  margin-left: var(--space-2);
  transition: transform 160ms ease;
}

.pm.is-open .pm-chevron { transform: rotate(180deg); }

/* In flow, not absolute. MyLinedChart's buttons sit in a row so an overlay panel drops
   into empty space; these are stacked, so an overlay covered the two platforms below the
   one you opened. Pushing the stack open keeps all three visible. */
.pm-panel {
  margin-top: var(--space-2);
  padding: var(--space-4) var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, var(--shadow-sm));
  text-align: left;
}

.pm-panel ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
}

.pm-panel a {
  display: block;
  font-weight: 600;
  color: var(--text);
}

.pm-panel a:hover { color: var(--accent-strong); }

.pm-note {
  display: block;
  margin-top: 2px;
  font-size: var(--font-size-caption);
  color: var(--text-muted);
  font-weight: 400;
}

@media (prefers-reduced-motion: reduce) {
  .pm-chevron { transition: none; }
}

/* The pitch line inside the Premium card's h3. It has to stop inheriting the heading's
   serif face, size and weight, or it reads as part of the title rather than a line about
   it. Placed here, away from the .plan-* block, because the last version of this rule sat
   next to .plan-price and was swallowed when that dead rule was regex-deleted. */
.plan-pitch {
  /* inline, not block: as a block the em dash started its own line and read as a stray
     dash. It is meant to join "Premium" to the pitch, so it has to sit on that baseline. */
  display: inline;
  font-family: var(--sans);
  font-size: var(--font-size-small);
  font-weight: 400;
  line-height: var(--line-height-body);
  color: var(--text-muted);
}

.plan-pitch a { color: var(--accent-strong); }

/* Underlined and accented, for a link that has to read as the action in a sentence
   that is otherwise plain text. */
.link-accent {
  color: var(--accent-strong);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---------- Email capture ----------
   Used on the blog and at the foot of the homepage, so it lives here rather than in
   blog.css, which the homepage does not load. */

.signup {
  max-width: 42rem;
  margin: var(--space-14, 3.5rem) 0 0;
  padding: var(--space-7, 1.75rem) var(--space-6);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, var(--shadow-sm));
}

.signup h2 {
  font-family: var(--serif);
  font-size: var(--font-size-body-lg);
  font-weight: 500;
  margin: 0 0 var(--space-2);
  color: var(--text);
}

.signup p {
  margin: 0 0 var(--space-5);
  color: var(--text-muted);
  font-size: var(--font-size-small);
  line-height: var(--line-height-body);
}

.signup-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* The field takes the space and the button keeps its own, so they sit on one row until
   the row genuinely cannot hold them. */
.signup-form input[type="email"] {
  flex: 1 1 14rem;
  min-width: 0;
  font: inherit;
  font-size: var(--font-size-body);
  padding: 12px var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
}

.signup-form input[type="email"]:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 1px;
}

.signup-form .btn { flex: none; }

.signup-status {
  margin: var(--space-4) 0 0 !important;
  font-size: var(--font-size-small) !important;
}

.signup-status.is-error { color: var(--accent-strong); }

/* ---------- Builder's note ----------
   Photo sits first in the DOM so it leads on mobile; on desktop the grid moves
   it to the right column and the note reads text-left, face-right. */

.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong, var(--border));
}

.builder-note {
  display: grid;
  row-gap: var(--space-6);
  max-width: 1040px;
  margin: 0 auto;
}

/* Its own grid item, not part of .builder-body, so the heading can lead on
   mobile while the photo still sits beside the text on desktop. */
.builder-heading {
  font-family: var(--serif);
  font-size: var(--font-size-h2);
  margin: 0;
}

.builder-photo {
  margin: 0;
  max-width: 320px;
}

.builder-photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, var(--shadow-sm));
}

.builder-body p {
  color: var(--text-muted);
  font-size: var(--font-size-body-lg);
  line-height: var(--line-height-body);
  margin: 0 0 var(--space-4);
}

.builder-body p a {
  color: var(--accent-strong);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.builder-signoff {
  font-weight: 600;
  color: var(--text) !important;
}

/* The other-apps line sits between the signoff and the Message Me button. Quieter than the
   signoff above it, because it is an aside rather than the close of the note. The footer's
   "Other Apps I've Built" block still lists these separately; this one is inside the personal
   note, where a reader who just finished it is most likely to be curious who wrote it. */
.builder-other-apps {
  margin-top: var(--space-3);
  font-size: var(--font-size-small);
  color: var(--text-muted);
}

.builder-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

@media (min-width: 900px) {
  .builder-note {
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    grid-template-areas:
      "head photo"
      "body photo";
    column-gap: var(--space-12);
    row-gap: var(--space-5);
    align-items: start;
  }
  .builder-heading { grid-area: head; }
  .builder-body    { grid-area: body; }
  .builder-photo {
    grid-area: photo;
    max-width: none;
    position: sticky;
    top: var(--space-8);
  }
}

/* ---------- Legal pages ---------- */
/* NOTE: .legal-header / .legal-body / .container / bare h1/h2/h3 rules below are
   also what press.html (untouched, per project rules) is built on. Everything
   in this section that needs to look different on privacy/terms/support lives
   under NEW class names (.legal-hero, .legal-content, etc.) or under selectors
   made MORE specific by nesting inside those new classes (e.g.
   ".legal-body .legal-content h2"), so none of it can change press.html or
   leak into index.html, which uses neither .legal-header nor .legal-body. */

.legal-header {
  padding: var(--space-14, 3.5rem) 0 var(--space-2);
}

.legal-header h1 {
  font-family: var(--serif);
  font-size: var(--font-size-h1);
  margin: 0 0 var(--space-3);
  font-weight: 500;
}

.legal-meta {
  color: var(--text-faint);
  font-size: var(--font-size-small);
  margin: 0 0 var(--space-2);
}

.legal-body {
  padding: var(--space-6) 0 var(--space-16);
}

.legal-body h2 {
  font-family: var(--serif);
  font-size: var(--font-size-h3);
  font-weight: 500;
  margin: var(--space-10) 0 var(--space-3);
}

.legal-body h2:first-child {
  margin-top: 0;
}

.legal-body h3 {
  font-size: var(--font-size-body);
  font-weight: 600;
  margin: var(--space-5) 0 var(--space-2);
}

.legal-body p, .legal-body li {
  color: var(--text-muted);
  margin: 0 0 var(--space-4);
}

.legal-body ul {
  padding-left: var(--space-6);
  margin: 0 0 var(--space-4);
}

.legal-body strong {
  color: var(--text);
}

.callout {
  position: relative;
  background: var(--bg-warm);
  border: 1px solid var(--border);
  border-left: 4px solid var(--color-accent-active);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  margin: 0 0 var(--space-10);
}

.callout p {
  margin: 0;
  font-size: var(--font-size-body);
  color: var(--text);
}

/* Turns "The short version:" into its own visual line, styled as the block's
   label, without touching the underlying markup or wording: strong and its
   sibling text stay inside the same <p>, this only changes how it lays out. */
.callout strong {
  display: block;
  font-family: var(--serif);
  font-size: var(--font-size-body-lg);
  font-weight: 500;
  color: var(--accent-strong);
  margin-bottom: var(--space-2);
}

/* ---------- FAQ ---------- */

.faq-item {
  border-bottom: 1px solid var(--border);
  padding: var(--space-6) 0;
}

.faq-item:first-child {
  border-top: 1px solid var(--border);
}

.faq-item h3 {
  font-size: var(--font-size-body);
  font-weight: 600;
  margin: 0 0 var(--space-2);
}

.faq-item p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--font-size-small);
}

/* ---------- Legal & support redesign ----------
   New markup, new classes: .legal-hero, .legal-back, .legal-layout, .legal-toc,
   .legal-content, .subscription-compare, .faq-list, .contact-card. Used only
   by privacy.html / terms.html / support.html. */

.legal-hero {
  padding: var(--space-16) 0 var(--space-10);
  background: var(--bg-warm);
  border-bottom: 1px solid var(--border);
}

.legal-hero h1 {
  font-family: var(--serif);
  font-size: var(--font-size-h1);
  font-weight: 500;
  letter-spacing: -0.01em;
  margin: var(--space-3) 0 var(--space-3);
}

.legal-hero .legal-meta {
  margin: 0;
}

.legal-back {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: var(--font-size-small);
  font-weight: 600;
  margin-bottom: var(--space-6);
}

.legal-back:hover {
  color: var(--text);
  text-decoration: none;
}

.legal-back .arrow {
  display: inline-block;
  transition: transform var(--duration-fast) var(--ease-out);
}

.legal-back:hover .arrow {
  transform: translateX(-3px);
}

/* ---- Layout: reading column, plus an optional "on this page" sidebar ---- */

.legal-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
  padding: var(--space-10) 0 var(--space-16);
}

@media (min-width: 900px) {
  .legal-layout {
    grid-template-columns: 200px minmax(0, 1fr);
    gap: var(--space-12);
  }
}

.legal-toc {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: var(--space-5);
}

@media (min-width: 900px) {
  .legal-toc {
    position: sticky;
    top: var(--space-6);
    max-height: calc(100vh - var(--space-12));
    overflow-y: auto;
  }
}

.legal-toc-title {
  display: block;
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 var(--space-3);
}

.legal-toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

.legal-toc ul {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0 0 0 var(--space-4);
  display: grid;
  gap: var(--space-2);
}

.legal-toc a {
  display: block;
  color: var(--text-muted);
  font-size: var(--font-size-small);
  line-height: var(--line-height-heading);
}

.legal-toc ul a {
  color: var(--text-faint);
}

.legal-toc a:hover {
  color: var(--accent-strong);
  text-decoration: none;
}

.legal-content {
  max-width: 42rem;
}

.legal-body .legal-content h2 {
  font-family: var(--serif);
  font-size: var(--font-size-h2);
  font-weight: 500;
  letter-spacing: -0.005em;
  margin: var(--space-12) 0 var(--space-4);
  scroll-margin-top: var(--space-8);
}

.legal-body .legal-content > h2:first-child,
.legal-body .legal-content > .callout:first-child + h2 {
  margin-top: 0;
}

.legal-body .legal-content h3 {
  font-family: var(--serif);
  font-size: var(--font-size-body-lg);
  font-weight: 600;
  color: var(--text);
  margin: 0 0 var(--space-3);
  scroll-margin-top: var(--space-8);
}

.legal-body .legal-content p,
.legal-body .legal-content li {
  color: var(--text-muted);
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
  margin: 0 0 var(--space-5);
}

.legal-body .legal-content ul {
  padding-left: var(--space-6);
  margin: 0 0 var(--space-5);
}

.legal-body .legal-content strong {
  color: var(--text);
}

.legal-body .legal-content .legal-lead {
  font-size: var(--font-size-body-lg);
  color: var(--text);
}

/* ---- Subscription comparison (Terms) ---- */

.subscription-compare {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  margin: var(--space-6) 0 var(--space-8);
}

@media (min-width: 640px) {
  .subscription-compare {
    grid-template-columns: 1fr 1fr;
  }
}

.subscription-block {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-6);
}

.subscription-block h3 {
  margin-top: 0;
}

.subscription-block ul {
  margin-bottom: 0;
}

.subscription-block li:last-child {
  margin-bottom: 0;
}

/* ---- FAQ list (Support) ---- */

.faq-list {
  display: grid;
  gap: var(--space-4);
  margin: 0 0 var(--space-12);
}

.faq-list .faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
}

.faq-list .faq-item:first-child {
  border-top: 1px solid var(--border);
}

.faq-list .faq-item h3 {
  font-family: var(--serif);
  font-size: var(--font-size-body-lg);
  font-weight: 500;
  color: var(--text);
  margin: 0 0 var(--space-2);
}

.faq-list .faq-item p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
}

/* Answers were single paragraphs until Premium needed two, so margin:0 above ran
   them together. Scoped to p + p, which leaves every one-paragraph answer alone. */
.faq-list .faq-item p + p {
  margin-top: var(--space-3);
}

/* ---- Home page FAQ (index.html only). New names, does not touch
   .faq-list / .faq-item above, which support.html already relies on. ---- */

.home-faq-list {
  display: grid;
  gap: var(--space-4);
  max-width: 760px;
  margin: 0 auto;
}

/* Two across from tablet up. align-items: start lets each card size to its own
   answer; stretching them to match a long neighbour leaves a visible hole of
   empty card under the short one. Reading order stays left to right, which is
   also the DOM order a screen reader follows. */
@media (min-width: 860px) {
  .home-faq-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    max-width: 1040px;
  }
}

.home-faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
}

.home-faq-item h3 {
  font-family: var(--serif);
  font-size: var(--font-size-body-lg);
  font-weight: 500;
  color: var(--text);
  margin: 0 0 var(--space-2);
}

.home-faq-item p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
}

.home-faq-item p a {
  color: var(--accent-strong);
}

/* ---- Contact card (Support) ---- */

.contact-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  box-shadow: var(--shadow-sm);
}

.contact-card > p:first-child {
  color: var(--text-muted);
  margin: 0 0 var(--space-5);
}

.contact-card .contact-form {
  margin-top: 0;
}

.contact-card .form-note {
  margin-top: var(--space-2);
}

@media (prefers-reduced-motion: reduce) {
  .legal-back .arrow { transition: none; }
  .legal-back:hover .arrow { transform: none; }
}

/* ---------- Press kit ---------- */

.press-download {
  margin: var(--space-5) 0 0;
}

.fact-list {
  list-style: none;
  margin: 0 0 var(--space-10);
  padding: 0;
  display: grid;
  gap: 0;
}

.fact-item {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border);
}

.fact-item:first-child {
  border-top: 1px solid var(--border);
}

.fact-item dt {
  margin: 0;
  font-size: var(--font-size-small);
  font-weight: 600;
  color: var(--text);
}

.fact-item dd {
  margin: 0;
  color: var(--text-muted);
}

@media (max-width: 560px) {
  .fact-item {
    grid-template-columns: 1fr;
    gap: var(--space-1);
  }
}

.copy-blocks {
  display: grid;
  gap: var(--space-5);
  margin: 0 0 var(--space-10);
}

.copy-block {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}

.copy-block h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.copy-block p {
  margin: 0;
  color: var(--text);
}

.icon-showcase {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8);
  margin: 0 0 var(--space-10);
}

.icon-preview {
  width: 140px;
  height: 140px;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  flex-shrink: 0;
}

.icon-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

.icon-links li {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.icon-links span {
  color: var(--text-faint);
  font-size: var(--font-size-caption);
}

.press-shots {
  list-style: none;
  margin: 0 0 var(--space-10);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-6);
}

@media (min-width: 640px) {
  .press-shots {
    grid-template-columns: repeat(3, 1fr);
  }
}

.shot-card a {
  display: block;
}

.shot-card img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}

.shot-caption {
  margin: var(--space-2) 0 0;
  font-size: var(--font-size-caption);
  color: var(--text-muted);
}

/* ---------- Contact form ---------- */

.contact-form {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-2);
}

/* Without this, `form.hidden = true` does nothing: a class selector setting display beats
   the browser's own [hidden] { display: none }, so the element stays on screen while the
   DOM property reads true. Caught by screenshotting the success state, not by the test,
   which was happily asserting the property. */
.contact-form[hidden] { display: none; }

.field {
  display: grid;
  gap: var(--space-2);
}

/* Text inputs only. A range input inside a .field was picking up the boxed
   text-field look and rendering inside a white pill. */
.field input:not([type="range"]),
.field textarea {
  font: inherit;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-elevated);
  color: var(--text);
}

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

.form-note {
  font-size: var(--font-size-caption);
  color: var(--text-faint);
  margin-top: -4px;
}

/* ---------- Motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Responsive ---------- */

@media (max-width: 560px) {
  .site-header .container-lg {
    padding-top: var(--space-4);
    padding-bottom: var(--space-4);
    gap: var(--space-3);
  }

  /* At 375px the wordmark and the three nav links together exceed the viewport and
     "Reveal the Dream" wrapped onto two lines. Shrink both so it stays a single row. */
  .brand {
    font-size: 17px;
    gap: var(--space-2);
  }

  .brand-mark {
    width: 24px;
    height: 24px;
  }

  .main-nav {
    gap: var(--space-3);
  }

  .main-nav a {
    font-size: var(--font-size-caption);
  }

  .hero {
    padding: var(--space-10) 0 var(--space-10);
  }

  .section {
    padding: var(--space-14, 3.5rem) 0;
  }
}

/* Below ~400px the brand and the three nav links genuinely cannot share one row.
   Measured at 320px (iPhone SE, and anyone zoomed in) the nav ran to 361px against a
   320px viewport. `overflow-x: hidden` on body was hiding that rather than fixing it,
   so the header wraps here instead: brand on top, nav centred underneath. */
/* Download beside the hamburger on a phone, so the one action that matters is not
   buried behind a menu. Hidden on desktop, where the nav already carries it. */
.header-cta {
  display: none;
  /* auto on the left, nothing on the right: this pushes it off the wordmark and up
     against the hamburger, rather than parking it mid-row under space-between. */
  margin-left: auto;
  margin-right: 0;
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  background: var(--color-accent-active);
  color: var(--color-on-accent-active);
  font-size: var(--font-size-small);
  font-weight: 600;
  white-space: nowrap;
}

.header-cta:hover { text-decoration: none; opacity: 0.92; }

@media (max-width: 720px) {
  .header-cta { display: inline-flex; }
}

/* Above 720px the Download button used to be hidden and the nav carried a plain "Download" text
   link instead, so the same action looked like a button on a phone and like a link on a desktop.
   One element now, the button, at every width.

   ORDER MATTERS. The header is `justify-content: space-between` over [brand, cta, toggle, nav],
   so simply un-hiding the button parks it midway across the row between the wordmark and the nav.
   Pushing the nav right with an auto margin and giving the button `order: 3` puts it last, which
   is where a call to action belongs and where the phone already has it. */
@media (min-width: 721px) {
  .header-cta {
    display: inline-flex;
    order: 3;
    margin-left: var(--space-5);
  }

  .main-nav { margin-left: auto; }
}

/* At 320px the wordmark, the button and the hamburger together overflowed by 35px.
   Trimming the button and the container's side padding buys back 41px, which is enough
   without shrinking the wordmark. */
@media (max-width: 400px) {
  .header-cta {
    padding: 7px 12px;
    font-size: var(--font-size-caption);
    margin-right: var(--space-2);
  }

  .site-header .container-lg {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}

/* Below 340px the wordmark alone is 146px, and the row still overflowed after trimming
   the button and the padding. The mark is enough to identify the site at that size, so
   the text is hidden rather than shrunk to something unreadable. The link keeps an
   accessible name through the visually-hidden copy. */
@media (max-width: 340px) {
  .brand-text {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* ---------- Header nav: hamburger below 720px ----------
   Four links plus the wordmark do not fit a phone. The previous fix wrapped the nav
   onto a second row, but only below 400px, so a 402pt iPhone got neither the wrap nor
   enough room: the wordmark overlapped "Download" and "Terms" ran off the screen.
   A real collapse, at a width where the row genuinely stops fitting. */

.nav-toggle {
  display: none;
  width: 44px;                 /* 44px is the minimum comfortable touch target */
  height: 44px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--text);
}

/* Three bars drawn from one element: the middle is the box, the outer two are
   pseudo-elements, so there is no extra markup to keep in sync across seven pages. */
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: "";
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 160ms ease, opacity 160ms ease;
}

.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before { position: absolute; top: -6px; }
.nav-toggle-bars::after { position: absolute; top: 6px; }

/* Becomes an X while open, so the control says what it will do next. */
.nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after { top: 0; transform: rotate(-45deg); }

@media (max-width: 720px) {
  .nav-toggle { display: inline-flex; }

  /* Full-width panel under the header rather than an overlay: it cannot cover the page
     it is navigating, and it needs no scroll locking. */
  .main-nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 30;
    flex-direction: column;
    gap: 0;
    padding: var(--space-2) 0 var(--space-4);
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-md, var(--shadow-sm));
  }

  .main-nav.is-open { display: flex; }

  .main-nav a {
    padding: 14px var(--space-6);
    font-size: var(--font-size-body);
  }

  .site-header .container-lg { position: relative; }
}

@media (prefers-reduced-motion: reduce) {
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after { transition: none; }
}

/* ---------- Cover lab (Premium section) ---------- */

.cover-lab {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
  align-items: center;
  margin: 0 0 var(--space-12);
}

@media (min-width: 820px) {
  .cover-lab {
    grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
    gap: var(--space-12);
  }
}

.cover-lab .reveal-frame {
  max-width: 340px;
  margin: 0 auto;
}

.cover-controls h3 {
  font-family: var(--serif);
  font-size: var(--font-size-h3);
  font-weight: 500;
  margin: 0 0 var(--space-3);
}

.cover-controls > p {
  color: var(--text-muted);
  margin: 0 0 var(--space-6);
}

.cover-controls .field {
  margin-bottom: var(--space-6);
}

.cover-controls .field-label {
  display: block;
  font-size: var(--font-size-small);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-3);
}

.field-note {
  font-size: var(--font-size-small);
  color: var(--text-faint);
  margin: var(--space-3) 0 0;
}

.tint-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* The swatch shows the tint's own mid tone, so the row is a real preview of the
   seven cover colours rather than a set of abstract chips. */
.tint-swatch {
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: var(--radius-full);
  border: 1px solid var(--border);
  background: var(--swatch, var(--color-cover-2));
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

.tint-swatch:hover {
  transform: scale(1.08);
}

.tint-swatch[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--bg-warm), 0 0 0 4px var(--color-accent-active);
}

.tint-swatch:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .tint-swatch { transition: none; }
  .tint-swatch:hover { transform: none; }
}

/* ---------- On your wrist ---------- */

/* Mirrors .widget-grid but with the copy first, so the two sections alternate
   rather than stacking two identical layouts. */
.watch-grid {
  align-items: center;
}

/* Single column, unlike the widget section above it. That two-up layout was built for
   one mock watch in a 320px rail; four real screenshots in the same rail render about
   65px wide each, which is too small to read the day count that is the whole point.
   Copy on top, shots full width beneath. */
.watch-grid {
  grid-template-columns: 1fr;
}

.watch-copy {
  max-width: 46rem;
}

.watch-copy {
  text-align: center;
  order: 2;
}

.watch-stage {
  order: 1;
}

@media (min-width: 760px) {
  .watch-copy { text-align: left; order: 1; }
  .watch-stage { order: 2; }
}

.watch-copy p {
  color: var(--text-muted);
  margin: 0 0 var(--space-4);
}

.watch-copy p:last-child { margin-bottom: 0; }

.watch-frame {
  width: 100%;
  max-width: 232px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* A watch read as a drawing, not a photograph: the strap tapers away so the
   case is what the eye lands on. */
.watch-band {
  width: 58%;
  height: 34px;
  background: linear-gradient(180deg, #3b3a38 0%, #2a2927 100%);
}

.watch-band-top {
  border-radius: var(--radius-md) var(--radius-md) 4px 4px;
}

.watch-band-bottom {
  border-radius: 4px 4px var(--radius-md) var(--radius-md);
  background: linear-gradient(0deg, #3b3a38 0%, #2a2927 100%);
}

.watch-body {
  width: 100%;
  padding: 12px 12px 10px;
  background: #14110d;
  border-radius: 34px;
  box-shadow: var(--shadow-lg);
  position: relative;
  z-index: 1;
}

.watch-body .reveal-frame {
  border-radius: 24px;
  box-shadow: none;
}

.watch-caption {
  margin: var(--space-2) 0 0;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.74);
}

/* ---------- Common dreams ---------- */

.dreams-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

@media (min-width: 620px) {
  .dreams-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .dreams-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4) var(--space-6); }
}

.dream-card {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "kind   length"
    "goal   goal";
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-5) var(--space-6);
  background: var(--color-surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.dream-kind {
  grid-area: kind;
  font-size: var(--font-size-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-cover-3);
}

/* The length is the commitment, so it reads as a fact rather than a label. */
.dream-length {
  grid-area: length;
  font-size: var(--font-size-caption);
  font-weight: 600;
  color: var(--accent-strong);
  white-space: nowrap;
}

.dream-goal {
  grid-area: goal;
  margin: 0;
  font-family: var(--serif);
  font-size: var(--font-size-h3);
  line-height: 1.25;
  color: var(--text);
}

/* ---------- Missing a day ---------- */

.missed-grid { align-items: center; }

@media (min-width: 760px) {
  .missed-grid { grid-template-columns: minmax(0, 340px) minmax(0, 1fr); }
}

.missed-stage .reveal-frame {
  max-width: 340px;
  margin: 0 auto;
}

.missed-copy { text-align: center; }
.missed-copy p { color: var(--text-muted); margin: 0 0 var(--space-4); }
.missed-copy p:last-child { margin-bottom: 0; }

@media (min-width: 760px) {
  .missed-copy { text-align: left; }
}

.missed-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3) var(--space-5);
  margin: var(--space-4) 0 0;
  font-size: var(--font-size-caption);
  color: var(--text-muted);
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.legend-swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  border: 1px solid var(--border);
  flex-shrink: 0;
}

/* Earned means the photo shows, so the swatch is the photo rather than an
   arbitrary colour that would not match anything on the canvas beside it. */
.legend-swatch.is-revealed {
  background-image: url("assets/demo/australia-1-1.jpg");
  background-size: cover;
  background-position: 60% 55%;
}
/* Swatches mirror the canvas: still to come is the cover at the app's 0.40
   default, missed is the same colour at 0.55, so a missed day reads as heavier
   than a pending one rather than lighter. */
.legend-swatch.is-covered {
  background: color-mix(in srgb, var(--color-cover-2) 40%, transparent);
  border-color: var(--color-cover-2);
}
.legend-swatch.is-missed {
  background: color-mix(in srgb, var(--color-cover-2) 55%, transparent);
  border-color: var(--color-cover-2);
}

/* ---------- Real screens ---------- */

.screens-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6) var(--space-4);
}

@media (min-width: 700px) {
  .screens-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1040px) {
  .screens-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-4); }
}

.screen-card img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}

.screen-goal {
  margin: var(--space-3) 0 var(--space-1, 4px);
  font-size: var(--font-size-small);
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
}

.screen-note {
  margin: 0;
  font-size: var(--font-size-caption);
  color: var(--text-faint);
  line-height: 1.35;
}

/* The demo's custom journey length. Shown only when "Custom" is the selected length, so the
   common 7/30 case keeps a two-button control and nobody has to read a number field to use it. */
.demo-custom-days {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.demo-custom-days[hidden] {
  display: none;
}

.demo-custom-days input {
  width: 6rem;
}

.demo-custom-days-unit {
  font-size: var(--font-size-small);
  color: var(--text-muted);
}

/* Footnote for the marker on the Custom journey length. margin-top:auto pins it to the
   bottom of the panel, which is exactly where the extra height goes now that the two
   columns stretch to match, so the spare space becomes the footnote's gutter instead of
   dead air. */
.demo-premium-note {
  /* Sits closer to the slider than to the card's bottom edge: it is a footnote to the two
     markers above it, not a separate block, so the gap under it stays larger than the gap
     over it. */
  margin: auto 0 calc(var(--space-2) * -1);
  text-align: right;
  font-size: calc(var(--font-size-caption) * 0.9);
  color: var(--text-faint);
}

/* The Premium marker. Default <sup> is too big and sits too far out from the word; this
   pulls it down and in so it reads as a footnote mark rather than a caret someone typed.
   line-height: 0 keeps it from adding to the button's height. */
.seg button sup,
.field label sup {
  font-size: 0.58em;
  line-height: 0;
  margin-left: 0.5px;
  vertical-align: 0.42em;
}

/* Shown only when the chosen reveal type has no custom-length geometry on the web. */
.demo-style-note {
  margin: var(--space-2) 0 0;
  font-size: var(--font-size-caption);
  color: var(--text-faint);
  line-height: 1.5;
}

.demo-style-note:empty {
  display: none;
}

/* The platform buttons repeated inside the Try it section sit between the intro and the
   demo grid, so the offer is in front of the reader before they start playing with it. */
#demo .platform-buttons {
  margin: 0 0 var(--space-10);
}

/* Store links in the download section. These exist for crawlers as much as for readers:
   platform-menu.js builds the App Store and Microsoft Store links at runtime, so before
   this the homepage's own HTML linked to neither and search engines saw no path to them. */
.dl-stores {
  margin: var(--space-4) 0 0;
  text-align: center;
  font-size: var(--font-size-small);
  color: var(--text-muted);
  line-height: 1.6;
}

/* A per-row qualifier in the matrix, for a feature that is not true of every platform in
   that row. It exists because the backup row ticked Windows, which has neither iCloud nor
   Google, so a free Windows user was being promised a backup they do not have. */
.matrix-feature-note {
  display: block;
  margin-top: var(--space-1, 4px);
  font-size: var(--font-size-caption);
  color: var(--text-faint);
  font-weight: 400;
  line-height: 1.45;
}
