/* ==========================================================================
   The Long Road — site styles
   Mobile-first. The palette is the game's own (lib/theme/app_theme.dart):
   one ember accent, dimmed semantic hues, rarity as the only firework.
   ========================================================================== */

:root {
  /* ground */
  --bg: #1a1410;            /* AppColors.background */
  --surface: #2a2218;       /* AppColors.surface */
  --card: #352c22;          /* AppColors.card */
  --border: #4a4038;        /* AppColors.cardBorder */
  --plaque: #14100b;        /* AppColors.plaque — the one surface darker than bg */

  /* text */
  --text: #e8dcc8;          /* textPrimary */
  --text-2: #a09080;        /* textSecondary */
  /* textFaded, lightened from the game's #706050: on a phone in daylight the
     site's whispers are functional text (consent line, captions, footer), so
     the web token clears WCAG AA (≈4.7:1 on --bg) where the in-game one
     could stay atmospheric. */
  --text-3: #8f7f6b;

  /* the one accent + dimmed semantics */
  --ember: #c99a5b;
  --slate: #7b93ad;         /* rest, calm info — the storm's word colour */
  --brick: #a96665;         /* danger */
  --sage: #75937a;          /* success */

  /* storm ground — the band's own darkness */
  --storm-bg: #0e0b09;
  --storm-sky: #14161c;

  --wrap: 66rem;
  --radius: 8px;

  /* rhythm tokens — the two values a spacing pass retunes, single-point edits */
  --space-section: 4.5rem;
  /* the signature fade-to-east hairline; three sites share it so they can
     never drift apart */
  --hairline: linear-gradient(90deg, var(--border), transparent 85%);

  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
}

/* ── reset-ish ─────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.65;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
/* UA default figure margin (1em 40px) silently shrank every gallery card and
   mis-gapped the carousel — reset it globally so the trap stays disarmed */
figure { margin: 0; }
a { color: var(--ember); text-decoration: none; }
a:hover, a:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; border-radius: 2px; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 1.25rem; }
.pixel { image-rendering: pixelated; image-rendering: crisp-edges; }

/* ── type grammar (the game's own) ─────────────────────────────────────── */
/* faint label — small caps strip over a section */
.overline {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ember);
  margin: 0 0 0.75rem;
}
/* whisper — the quiet lowercase line; never a button, never tappable */
.whisper {
  color: var(--text-3);
  font-size: 0.875rem;
  letter-spacing: 0.02em;
}
h1, h2, h3 { line-height: 1.15; margin: 0; }
h2 {
  font-size: clamp(1.5rem, 5.2vw, 2.25rem);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.lede { color: var(--text-2); font-size: 1.0625rem; max-width: 42rem; }

/* ── header ────────────────────────────────────────────────────────────── */
.site-head {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 10;
  padding: 0.9rem 0;
}
.site-head .wrap {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.brand {
  display: inline-flex; align-items: center; gap: 0.55rem;
  color: var(--text);
  font-size: 0.8125rem; font-weight: 800;
  letter-spacing: 0.22em; text-transform: uppercase;
}
.brand:hover { text-decoration: none; }
.brand svg { width: 22px; height: 22px; flex: none; }
.site-nav { display: flex; gap: 1.1rem; }
.site-nav a {
  color: var(--text-2);
  font-size: 0.75rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  /* thumb-sized targets at every width; negative margins absorb the padding
     so the visual row doesn't move (same trick as the 560px stack below) */
  display: inline-block;
  padding: 0.75rem 0.25rem;
  margin: -0.75rem -0.25rem;
}
.site-nav a:hover { color: var(--ember); text-decoration: none; }
/* you-are-here, in the accent the header already reserves for hover */
.site-nav a[aria-current="page"] { color: var(--ember); }

/* Small phones: brand and navigation become two deliberately separate rows.
   A divider and three equal-width, 48px tap targets keep the small link
   labels comfortably apart. */
@media (max-width: 560px) {
  .site-head {
    padding: calc(1rem + env(safe-area-inset-top, 0px)) 0 1rem;
  }
  .site-head .wrap {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
  }
  .brand {
    min-height: 3rem;
    font-size: 0.8125rem;
    letter-spacing: 0.18em;
  }
  .brand svg { width: 20px; height: 20px; }
  .site-nav {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.5rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--border);
  }
  .site-nav a {
    min-height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0.5rem 0.25rem;
    font-size: 0.6875rem;
    line-height: 1.2;
    letter-spacing: 0.16em;
    color: var(--text-3);
    white-space: nowrap;
  }
}

/* subpages get a solid header instead of the floating one */
.site-head.solid {
  position: static;
  background: var(--bg);
  border-bottom: 1px solid;
  border-image: var(--hairline) 1;
}

/* ── hero ──────────────────────────────────────────────────────────────── */
.hero {
  position: relative;
  min-height: 96svh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 5.5rem 0 9.5rem; /* foot padding keeps copy clear of the road band */
  overflow: hidden;
}
.hero-road {
  position: absolute; inset: auto 0 0 0;
  /* capped at the copy's reserved foot padding so the pines can never rise
     behind the CTA row on a tall, narrow hero */
  height: min(38%, 10rem);
  width: 100%;
  pointer-events: none;
}
.hero-road canvas { width: 100%; height: 100%; display: block; }
.hero-copy { position: relative; z-index: 2; }
.hero h1 {
  font-size: clamp(2.4rem, 11vw, 5rem);
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text);
}
.hero .promise {
  margin: 1.1rem 0 0;
  font-size: clamp(1.05rem, 3.6vw, 1.35rem);
  color: var(--text-2);
  max-width: 34rem;
}
.hero .sub {
  margin: 0.9rem 0 0;
  max-width: 36rem;
}
.cta-row {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  margin-top: 2rem;
}
.platform-line { margin-top: 1.4rem; }

/* Keep this after the base hero rule: the mobile header is taller once its
   rows have real tap targets, so the floating header needs explicit room
   before the development label. */
@media (max-width: 560px) {
  .hero {
    justify-content: flex-start;
    padding-top: 12.25rem;
  }
}

/* ── buttons (theme grammar: ember primary, bordered secondary) ───────── */
.btn {
  display: inline-block;
  padding: 0.9rem 1.6rem;
  border-radius: var(--radius);
  font-size: 0.875rem; font-weight: 800;
  letter-spacing: 0.12em; text-transform: uppercase;
  border: 1px solid transparent;
  cursor: pointer;
  text-align: center; /* a wrapped label at 320px must not go ragged-left */
  transition: filter 120ms ease, border-color 120ms ease, color 120ms ease;
}
.btn:hover { text-decoration: none; }
.btn:focus-visible { text-decoration: none; }
.btn:disabled { filter: brightness(0.8); cursor: default; }
.btn-primary { background: var(--ember); color: var(--bg); }
.btn-primary:hover, .btn-primary:focus-visible { filter: brightness(1.08); }
.btn-ghost {
  background: transparent; color: var(--text-2);
  border-color: var(--border);
}
.btn-ghost:hover, .btn-ghost:focus-visible { color: var(--ember); border-color: var(--ember); }

/* ── sections ──────────────────────────────────────────────────────────── */
.section { padding: var(--space-section) 0; }
/* press page: the tighter rhythm as a named decision, not inline styles */
.section-tight { padding: 2.5rem 0; }

/* The road explains the loop; the Gathering below is its own interactive
   chapter. The asymmetric shared space keeps the two from reading as one
   long section without leaving a dead gulf before the habits that follow. */
#road { padding-bottom: 3rem; }
.parties-section {
  padding: 4.25rem 0 3.5rem;
  border-top: 1px solid;
  border-bottom: 1px solid;
  border-image: var(--hairline) 1;
  background: linear-gradient(180deg,
    rgba(20, 16, 11, 0.58), rgba(20, 16, 11, 0.12) 48%,
    rgba(20, 16, 11, 0.42));
}
.parties-head { text-align: center; }
.parties-head .lede { margin: 0.9rem auto 0; }
.section-tight .entry-body { margin-top: 1rem; }
.section-tight > .whisper { margin: 0.5rem 0 1.2rem; }
.section-head { margin-bottom: 2rem; }
.section-head .lede { margin: 0.9rem 0 0; }

/* bridge whisper between sections (…the wind turns.) */
.bridge {
  text-align: center;
  padding: 2.5rem 1.25rem;
  font-style: italic;
}

/* ── the four beats ────────────────────────────────────────────────────── */
/* Bare text, no cards: explanatory copy sits on the ground (the legacy
   section's own treatment). After this, every raised surface+border
   rectangle on the homepage is genuinely tappable — the material rule. */
.beats { display: grid; gap: 1.75rem; }
.beat {
  background: none;
  border: 0;
  padding: 0;
}
.beat h3 {
  font-size: 0.8125rem; font-weight: 800;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ember);
  margin-bottom: 0.6rem;
}
.beat p { margin: 0; color: var(--text-2); font-size: 0.9375rem; }

/* ── the twelve (heroes, one signature skill each, three seats) ────────── */
.twelve { margin-top: 2.5rem; }
.twelve-headline {
  margin: 0;
  padding: 0.9rem 0;
  font-size: clamp(0.78rem, 2.7vw, 1rem);
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  color: var(--text-2);
}
.twelve-headline .dot { color: var(--ember); padding: 0 0.32em; }
/* the carousel: touch/swipe first; without JS it is simply a scrollable
   strip — the static fallback costs nothing */
.heroes {
  list-style: none;
  margin: 2rem 0 0; padding: 0 0 0.75rem;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 41%;
  gap: 0.7rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.hero-card {
  scroll-snap-align: start;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  padding: 0.95rem 0.6rem 0.9rem;
  text-align: center;
}
.js .hero-card { cursor: pointer; }
.js .hero-card:hover { border-color: var(--text-3); }
/* selected state is ember — the item grammar's one licensed selection hue */
.hero-card.seated,
.js .hero-card.seated:hover { border-color: var(--ember); }
.class-disc {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  margin-bottom: 0.55rem;
}
.class-disc svg { width: 18px; height: 18px; display: block; fill: currentColor; }
/* class hues — AppColors, verbatim */
.c-warrior { color: #a0a8b8; background: rgba(160, 168, 184, 0.12); }
.c-mage    { color: #8490b3; background: rgba(132, 144, 179, 0.12); }
.c-priest  { color: #85a985; background: rgba(133, 169, 133, 0.12); }
.c-rogue   { color: #c09b62; background: rgba(192, 155, 98, 0.12); }
.c-hunter  { color: #7ba19e; background: rgba(123, 161, 158, 0.12); }
.hero-name {
  display: block;
  font-weight: 800; font-size: 0.875rem;
  letter-spacing: 0.04em;
  color: var(--text);
}
.hero-skill {
  display: block; margin-top: 0.15rem;
  font-style: italic; font-size: 0.8125rem;
  color: var(--text-3);
}
/* the party plan — JS only; empty seats wear the Gathering's faint ember
   ring, a filled seat holds the hero's class disc */
.party-plan { display: none; }
.js .party-plan {
  display: block;
  max-width: 34rem;
  margin: 1.4rem auto 0;
  text-align: center;
}
.party-hint { margin: 0 0 0.6rem; }
.seats { display: flex; justify-content: center; gap: 0.9rem; }
.seat {
  width: 52px; height: 52px;
  padding: 0;
  border-radius: 50%;
  border: 1px dashed rgba(201, 154, 91, 0.32);
  background: none;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: default;
}
.seat.filled {
  border-style: solid;
  border-color: var(--border);
  background: var(--card);
  cursor: pointer;
}
.seat .class-disc { width: 42px; height: 42px; margin: 0; }
.party-line { margin: 0.8rem 0 0; min-height: 1.45rem; }
.party-submit { margin-top: 0.85rem; }
.party-submit:disabled { opacity: 0.48; }
.party-status { min-height: 1.45rem; margin: 0.65rem 0 0; }
.party-status.err { color: var(--brick); }

/* ── the gathering's party pool ──────────────────────────────────────── */
.party-pool {
  margin-top: 2rem;
}
.party-pool[hidden], .party-picker[hidden] { display: none; }
.party-pool-head { text-align: center; }
.party-pool-head .overline { margin-bottom: 0; }
.party-pool-head .whisper { margin: 0.7rem 0 0; }
.party-bubbles {
  position: relative;
  height: clamp(20rem, 45vw, 27rem);
  margin-top: 1.6rem;
  overflow: hidden;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background:
    radial-gradient(circle, rgba(201, 154, 91, 0.10) 0 1px,
      transparent 1.5px) 0 0 / 28px 28px;
  isolation: isolate;
}
.party-bubbles::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 8%; right: 8%; top: 50%;
  height: 1px;
  background: var(--hairline);
  opacity: 0.55;
}
.party-bubble {
  --bubble-size: 72px;
  position: absolute;
  left: 50%; top: 50%;
  width: var(--bubble-size);
  height: var(--bubble-size);
  padding: 0.4rem;
  transform: translate(-50%, -50%);
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-2);
  font: inherit;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease,
              color 140ms ease, filter 140ms ease;
}
.party-bubble:hover,
.party-bubble:focus-visible {
  border-color: var(--text-3);
  background: var(--card);
  color: var(--text);
}
.party-bubble.active {
  border-color: var(--ember);
  background: var(--card);
  color: var(--ember);
}
.party-bubble-glyphs { display: flex; align-items: center; gap: 0.14rem; }
.party-bubble .class-disc {
  width: 18px; height: 18px;
  margin: 0;
}
.party-bubble .class-disc svg { width: 9px; height: 9px; }
.party-bubble-count {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
}
.party-inspector {
  min-height: 8.5rem;
  padding-top: 1.5rem;
  text-align: center;
}
.party-inspector .overline { margin-bottom: 0.8rem; }
.party-inspector-team {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: clamp(0.8rem, 4vw, 2.2rem);
}
.party-inspector-member {
  width: min(28%, 9rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.3;
}
.party-inspector-member .class-disc { margin: 0; }
.party-rechoose { display: block; margin: 1.4rem auto 0; }
.party-rechoose-note { margin: 0.7rem 0 0; text-align: center; }

@media (max-width: 560px) {
  #road { padding-bottom: 2.5rem; }
  .parties-section { padding: 3.6rem 0 3rem; }
  .twelve { margin-top: 2.1rem; }
  .heroes { margin-top: 1.6rem; }
  .party-submit { width: 100%; }
  .party-pool { margin-top: 1.6rem; }
  .party-bubbles { height: 20rem; }
  .party-inspector-member { width: 30%; font-size: 0.75rem; }
}

/* ── the road's habits (three features; the lines survive as captions) ── */
.habits { padding: 3.4rem 0 3rem; }
.habits .overline { margin-bottom: 1.8rem; }
.habit-features { display: grid; gap: 2.6rem; }
.habit-feature { display: grid; gap: 1.1rem; align-items: center; }
.habit-visual {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--plaque);
  max-width: 240px;
}
/* portrait sources shown as a 4/5 window — the fire band is the middle of
   every frame, so a center-weighted crop keeps the subject */
.habit-visual img {
  width: 100%; height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center 42%;
}
.habit-copy h3 {
  font-size: 1rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
}
.habit-line {
  margin: 0.55rem 0 0;
  color: var(--text-2);
  font-size: 1.0625rem;
  font-style: italic;
  letter-spacing: 0.01em;
}
.habit-why {
  margin: 0.55rem 0 0;
  color: var(--text-3);
  font-size: 0.9375rem;
  max-width: 34rem;
}
.habits .habit-close { display: block; margin-top: 2.8rem; }

/* The stacked mobile version reads as one centered sequence: label, scene,
   caption, explanation. Desktop keeps the alternating editorial layout. */
@media (max-width: 767px) {
  .habits .overline,
  .habit-copy,
  .habits .habit-close {
    text-align: center;
  }
  .habit-visual {
    width: 100%;
    margin-inline: auto;
  }
  .habit-why {
    margin-right: auto;
    margin-left: auto;
  }
}

/* the shop feature's interim visual: the shop card's own grammar */
.shop-shelf {
  display: flex; align-items: center; justify-content: center;
  padding: 1.6rem 1.2rem;
  aspect-ratio: 4 / 5;
}
.stock-card {
  width: 100%;
  max-width: 170px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  padding: 0.85rem 0.9rem 0.9rem;
}
.stock-card p { margin: 0; }
.stock-tag {
  font-size: 0.625rem; font-weight: 800;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ember);
}
/* rarity is the licensed firework: the azure lives on the NAME only */
.stock-name { margin-top: 0.45rem; font-weight: 800; color: #3fa9e8; }
.stock-kind { margin-top: 0.1rem; font-size: 0.75rem; color: var(--text-3); }
.stock-cut { margin-top: 0.55rem; font-weight: 800; font-size: 1.125rem; color: var(--sage); }
.stock-note { margin-top: 0.55rem; font-size: 0.75rem; color: var(--text-3); }

/* ── places gallery ────────────────────────────────────────────────────── */
.places {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 72%;
  gap: 0.9rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 0.75rem;
  -webkit-overflow-scrolling: touch;
}
.place {
  scroll-snap-align: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--plaque);
}
/* height: auto releases the HTML height attribute (a presentational hint
   that would otherwise pin every tile to a fixed pixel height and defeat
   the aspect-ratio); the attributes stay in the HTML for pre-layout sizing.
   All gallery sources are 400×700, so 4/7 shows the whole scene, uncropped. */
.place img { width: 100%; height: auto; aspect-ratio: 4 / 7; object-fit: cover; }
.place figcaption {
  padding: 0.6rem 0.8rem;
  font-size: 0.8125rem;
  color: var(--text-3);
}

/* ── the storm band — the hard break ───────────────────────────────────── */
.storm {
  position: relative;
  min-height: 100svh;
  /* flex shrink-to-fit centers the copy block off the page rail — kept on
     purpose: the hard break reads as its own stage */
  display: flex; align-items: center;
  background:
    linear-gradient(180deg, var(--storm-sky) 0%, var(--storm-bg) 22%, var(--storm-bg) 100%);
  overflow: hidden;
}
.storm-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.storm-copy {
  position: relative; z-index: 2;
  padding: 6rem 0;
  max-width: 36rem;
}
/* The storm copy fades in when the band is entered — but the hidden state
   only exists under .js (set by an inline head script), so a no-JS visitor
   reads everything. */
.storm-copy h2 {
  font-size: clamp(2rem, 9vw, 3.6rem);
  letter-spacing: 0.14em;
  color: #ccd2da; /* the storm's cold read of textPrimary */
  transition: opacity 1200ms ease, transform 1200ms ease;
}
.js .storm:not(.on) .storm-copy h2 { opacity: 0; transform: translateY(10px); }
.storm-copy p {
  color: #8d94a0;
  font-size: 1rem;
  margin: 1.2rem 0 0;
  transition: opacity 1400ms ease 500ms;
}
.js .storm:not(.on) .storm-copy p { opacity: 0; }
.word-pin {
  display: inline-block;
  margin-top: 1.6rem;
  font-size: 0.6875rem; font-weight: 800;
  letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--slate);
  transition: opacity 1400ms ease 1200ms;
}
.js .storm:not(.on) .word-pin { opacity: 0; }
.storm-exit {
  position: absolute; z-index: 2;
  left: 0; right: 0; bottom: 1.6rem;
  text-align: center;
  font-style: italic;
  color: var(--text-3);
}

/* ── legacy section ────────────────────────────────────────────────────── */
.legacy p { max-width: 42rem; color: var(--text-2); }
.northstar {
  margin-top: 2rem;
  font-size: 1.125rem;
  color: var(--text);
  font-weight: 600;
}
.northstar .whisper { display: block; font-weight: 400; margin-top: 0.35rem; }

/* ── devlog strip + devlog pages ───────────────────────────────────────── */
.devlog-list { display: grid; gap: 0.9rem; margin: 0; padding: 0; list-style: none; }
.devlog-item {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.devlog-item a {
  display: block;
  position: relative;
  padding: 1.1rem 2.6rem 1.1rem 1.2rem;
  color: inherit;
}
/* the open-marker: a static affordance that exists before any pointer state
   (hover cannot be the only signal on touch); extends the entry pages' own
   arrow dialect */
.devlog-item a::after {
  content: "\2192";
  position: absolute;
  right: 1.2rem; top: 1.05rem;
  color: var(--text-3);
}
.devlog-item a:hover { text-decoration: none; border-radius: var(--radius); background: var(--card); }
.devlog-item a:active,
.devlog-item a:focus-visible { background: var(--card); border-radius: var(--radius); }
.devlog-item a:hover::after,
.devlog-item a:active::after,
.devlog-item a:focus-visible::after { color: var(--ember); }
/* the outline is the focus marker; a two-line underline on a block card is noise */
.devlog-item a:focus-visible { text-decoration: none; }
.devlog-item time {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--text-3);
  letter-spacing: 0.08em;
}
.devlog-item .verdict {
  display: block;
  margin-top: 0.3rem;
  color: var(--text);
  font-size: 0.9875rem;
}
.devlog-more { margin-top: 1.4rem; }

/* devlog entry page */
/* longhand on purpose: the shorthand's middle 0 was zeroing .wrap's side
   padding on the same element (equal specificity, later in the file) —
   every subpage rendered flush against the screen edge on mobile */
.entry { padding-top: 3rem; padding-bottom: 4rem; }
.entry .devlog-list { margin-top: 2rem; }
.entry-head time {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--text-3);
  letter-spacing: 0.08em;
}
.entry-head h1 {
  font-size: clamp(1.4rem, 5vw, 2rem);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-top: 0.4rem;
}
.entry-head .verdict {
  margin: 1rem 0 0;
  font-size: 1.0625rem;
  color: var(--text-2);
  font-style: italic;
}
.entry-body { margin-top: 2rem; max-width: 44rem; }
.entry-body ul { padding-left: 1.1rem; margin: 0; display: grid; gap: 0.9rem; }
.entry-body li { color: var(--text-2); font-size: 0.9375rem; }
.entry-body li::marker { color: var(--ember); }
.entry-body li ul {
  margin-top: 0.5rem;
  padding-left: 1rem;
  display: grid;
  gap: 0.4rem;
  font-size: 0.875rem;
}
.entry-body li ul li::marker { color: var(--text-3); }
.entry-body strong { color: var(--text); }
.entry-body p { color: var(--text-2); }
.entry-nav {
  margin-top: 3rem;
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: 0.8125rem;
}
.entry-nav a {
  display: inline-block;
  padding: 0.7rem 0.4rem;
  margin: -0.7rem -0.4rem; /* absorb: ~44px targets, zero layout shift */
}

/* ── the fire (email form) ─────────────────────────────────────────────── */
.fire {
  border-top: 1px solid;
  border-image: var(--hairline) 1;
}
/* prose links carry a quiet persistent underline: hue alone cannot mark a
   link here (ember is also the dead-label color), and an underlined ember
   phrase visibly stops being whisper text — a link the whisper is hosting */
.consent a, .entry-body a, .facts a, .site-foot .whisper a,
.entry-head .whisper a {
  text-decoration: underline;
  text-decoration-color: rgba(201, 154, 91, 0.45);
  text-underline-offset: 3px;
}
.fire-form { margin-top: 1.6rem; max-width: 30rem; }
.fire-form label {
  display: block;
  font-size: 0.6875rem; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 0.5rem;
}
.field-row { display: grid; gap: 0.75rem; }
.fire-form input[type="email"] {
  width: 100%;
  padding: 0.9rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 1rem;
  font-family: inherit;
}
.fire-form input[type="email"]::placeholder { color: var(--text-3); }
.fire-form input[type="email"]:focus { border-color: var(--ember); }
.fire-form input[type="email"]:focus-visible {
  outline: 2px solid var(--ember);
  outline-offset: 2px;
}
/* the ideas form reuses the fire form's field grammar; only the textarea
   is new */
.fire-form textarea {
  width: 100%;
  min-height: 9rem;
  padding: 0.9rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font: inherit;
  font-size: 1rem;
  line-height: 1.55;
  resize: vertical;
}
.fire-form textarea::placeholder { color: var(--text-3); }
.fire-form textarea:focus { border-color: var(--ember); }
.fire-form textarea:focus-visible {
  outline: 2px solid var(--ember);
  outline-offset: 2px;
}
/* honeypot — off-screen for humans, present for bots */
.hp-field {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}
.consent { margin-top: 0.9rem; font-size: 0.8125rem; }
.form-note { margin-top: 0.9rem; font-size: 0.9375rem; }
.form-note.ok { color: var(--sage); }
.form-note.err { color: var(--brick); }
.joined { display: none; }
.joined strong { color: var(--ember); }
/* no-JS server redirects land on these anchors — :target shows the state
   without a line of script */
.joined:target { display: block; }
#fire-oops { display: none; }
#fire-oops:target { display: block; }
/* server failure is NOT the visitor's address — its own anchor, its own line */
#fire-down { display: none; }
#fire-down:target { display: block; }
/* the ideas page's no-JS outcome states, same :target pattern */
#idea-left { display: none; }
#idea-left:target { display: block; }
#idea-oops { display: none; }
#idea-oops:target { display: block; }
#idea-down { display: none; }
#idea-down:target { display: block; }

/* ── answered ideas (injected by build_answers.dart) ───────────────────── */
.answers { margin-top: 4.5rem; }
.answers h2 { font-size: 1.05rem; letter-spacing: 0.14em; }
.answers > .whisper { margin: 0.6rem 0 0; }
.pair { margin-top: 2.8rem; }
.pair time {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--text-3);
  letter-spacing: 0.08em;
}
/* the idea: quoted, the player's own register; the reply: plain first-person
   body text. Quote-vs-body carries who is speaking — no labels. */
.pair-note {
  margin: 0.7rem 0 1rem;
  padding: 0.2rem 0 0.2rem 1rem;
  border-left: 2px solid var(--border);
}
.pair-note p { margin: 0; color: var(--text); font-style: italic; }
.pair-note .whisper { font-style: normal; margin-top: 0.4rem; }
.pair-reply p { color: var(--text-2); margin: 0.6rem 0; max-width: 44rem; }
.pair-shipped { margin-top: 0.6rem; }

/* ── footer ────────────────────────────────────────────────────────────── */
.site-foot {
  margin-top: 3rem;
  padding: 2.2rem 0 2.6rem;
  border-top: 1px solid;
  border-image: var(--hairline) 1;
}
.foot-links {
  /* row-gap 0: the links' own padding carries the wrapped-row spacing */
  display: flex; flex-wrap: wrap; gap: 0 1.4rem;
  font-size: 0.75rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
}
.foot-links a {
  color: var(--text-3);
  display: inline-block;
  padding: 0.75rem 0; /* ~44px targets; CONTACT is a mailto — mis-taps hurt */
}
.foot-links a:hover { color: var(--ember); text-decoration: none; }
.site-foot .whisper { margin-top: 1rem; display: block; }

/* ── press page bits ───────────────────────────────────────────────────── */
.facts { display: grid; gap: 0.35rem 1.5rem; grid-template-columns: max-content 1fr; font-size: 0.9375rem; }
.facts dt { color: var(--text-3); }
.facts dd { margin: 0; color: var(--text-2); }
.swatches { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.swatch { width: 72px; }
.swatch i {
  display: block; height: 44px;
  border-radius: 6px; border: 1px solid var(--border);
}
.swatch span {
  display: block; margin-top: 0.3rem;
  font-family: var(--mono); font-size: 0.625rem; color: var(--text-3);
}
.dl-grid { display: grid; gap: 1rem; grid-template-columns: repeat(2, 1fr); align-items: start; }
.dl-grid .place img { aspect-ratio: auto; height: auto; }
.dl-grid .place a:hover img,
.dl-grid .place a:focus-visible img { opacity: 0.88; }

/* ── reveal on scroll (calm: small, slow, off under reduced motion) ─────
   The hidden state is gated on .js so a no-JS visitor sees the whole page —
   including the email form. */
.reveal { transition: opacity 900ms ease, transform 900ms ease; }
.js .reveal:not(.on) { opacity: 0; transform: translateY(14px); }

@media (prefers-reduced-motion: reduce) {
  .reveal, .storm-copy h2, .storm-copy p, .word-pin,
  .js .reveal:not(.on),
  .js .storm:not(.on) .storm-copy h2,
  .js .storm:not(.on) .storm-copy p,
  .js .storm:not(.on) .word-pin {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
}

/* ── desktop enhancement layer ─────────────────────────────────────────── */
@media (min-width: 640px) {
  .field-row { grid-template-columns: 1fr auto; }
  .dl-grid { grid-template-columns: repeat(3, 1fr); }
}

/* tablet: the four beats become a balanced 2×2 and the places carousel
   becomes a grid here, not at 640. Four columns would be too narrow at this
   width; they open into one row with the full desktop measure below. */
@media (min-width: 768px) {
  .parties-head { text-align: left; }
  .parties-head .lede {
    max-width: 52rem;
    margin-left: 0;
    margin-right: 0;
  }
  .beats { grid-template-columns: repeat(2, 1fr); gap: 2rem; }
  .places {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-columns: unset;
    overflow-x: visible;
  }
  /* the twelve stay a strip at every width — twelve cards never fit a row,
     and the swipe IS the browse; wider cards, more of them in view */
  .heroes { grid-auto-columns: 11.5rem; gap: 0.9rem; }
  /* habit features go image-beside-text, the image side alternating */
  .habit-feature { grid-template-columns: 240px 1fr; gap: 2.2rem; }
  .habit-feature:nth-child(even) { grid-template-columns: 1fr 240px; }
  .habit-feature:nth-child(even) .habit-visual { order: 2; }
  .habit-features { gap: 3.2rem; }
}

@media (min-width: 960px) {
  :root { --space-section: 6.5rem; }
  body { font-size: 17px; }
  .beats { grid-template-columns: repeat(4, 1fr); }
  .hero { padding-bottom: 12rem; }
  .hero-road { height: min(34%, 13rem); }
  .storm-copy { padding: 8rem 0; }
}
