/* ==========================================================================
   MANX TALES — V0.1 design system
   --------------------------------------------------------------------------
   Order of the file:
     1.  Tokens
     2.  Reset & document
     3.  Typography
     4.  Layout primitives
     5.  Chrome: skip link, app bar, footer
     6.  Brand
     7.  Home
     8.  Explore
     9.  Story
     10. Ask
     11. Shared pieces: badges, evidence, cards, buttons, rails, skeletons
     12. Motion & responsive
   Designed for iPhone first. Notes throughout explain the mobile reasoning.
   ========================================================================== */

/* 1. TOKENS ============================================================== */

:root {
  /* Tells the browser to render form controls, scrollbars and the address bar
     in their dark variants. Matches <meta name="color-scheme"> in index.html. */
  color-scheme: dark;

  /* Ground: deep Irish-Sea slate. Warm, not a corporate blue. */
  --ink-900: #08141c;
  --ink-800: #0b1a24;
  --ink-700: #0f2230;
  --ink-600: #14293a;

  /* Text: warm parchment, so white never looks clinical on the dark ground. */
  --paper: #f5efe1;
  --paper-dim: #cfc7b5;
  --paper-faint: #9b9789;

  /* Accents. Gold is the heraldic register; the four category hues each hold a
     slightly different temperature so a reader learns them by colour alone. */
  --gold: #cba544;
  --gold-soft: #e3c477;
  --verdigris: #4fb3a5;
  --heather: #9a8ede;
  --slate-blue: #6fa8d6;
  --rose: #d4829a;

  --accent-history: var(--verdigris);
  --accent-place: var(--slate-blue);
  --accent-legend: var(--heather);
  --accent-culture: var(--rose);

  /* Type. System stacks only: this prototype must render instantly on a phone
     with no network round-trip for fonts. Display type is a true serif. */
  --font-display: ui-serif, "Iowan Old Style", "Palatino Linotype", Palatino,
    "Book Antiqua", Georgia, "Times New Roman", serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --tracking-eyebrow: 0.16em;

  /* Shape */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 22px;
  --r-xl: 28px;

  /* Space — generous by design; this is a browsing experience, not a dashboard. */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 22px;
  --s-6: 30px;
  --s-7: 40px;
  --s-8: 56px;

  /* Touch: Apple's 44pt minimum, with air around it. */
  --touch: 52px;

  --shell-max: 620px;

  /* Depth */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-2: 0 10px 30px -12px rgba(0, 0, 0, 0.6);
  --shadow-3: 0 22px 60px -24px rgba(0, 0, 0, 0.75);

  --hairline: rgba(245, 239, 225, 0.1);
  --hairline-strong: rgba(245, 239, 225, 0.18);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

/* 2. RESET & DOCUMENT ==================================================== */

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

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

body {
  margin: 0;
  min-height: 100svh;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  color: var(--paper);
  background-color: var(--ink-900);
  background-image:
    radial-gradient(120% 70% at 50% -8%, rgba(203, 165, 68, 0.13), transparent 62%),
    radial-gradient(90% 50% at 8% 12%, rgba(79, 179, 165, 0.08), transparent 70%),
    radial-gradient(110% 60% at 92% 30%, rgba(154, 142, 222, 0.07), transparent 72%),
    linear-gradient(180deg, var(--ink-800) 0%, var(--ink-900) 55%, #060f16 100%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

/* A faint woven texture, standing in for nothing and quietly preventing the
   flatness that makes dark UIs look cheap. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.5;
  background-image:
    repeating-linear-gradient(
      45deg,
      rgba(245, 239, 225, 0.014) 0 1px,
      transparent 1px 3px
    );
}

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

button {
  font: inherit;
  color: inherit;
}

a {
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: rgba(203, 165, 68, 0.18);
}

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

::selection {
  background: rgba(203, 165, 68, 0.32);
}

/* 3. TYPOGRAPHY ========================================================== */

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  margin: 0;
  letter-spacing: -0.012em;
}

p {
  margin: 0 0 var(--s-4);
}

p:last-child {
  margin-bottom: 0;
}

.mono {
  font-family: var(--font-mono);
  font-size: 0.82em;
  letter-spacing: 0.02em;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--s-3) var(--s-4);
  background: var(--gold);
  color: var(--ink-900);
  border-radius: 0 0 var(--r-sm) 0;
  font-weight: 600;
}

.skip-link:focus {
  left: 0;
}

/* 4. LAYOUT PRIMITIVES =================================================== */

.app-shell {
  position: relative;
  z-index: 1;
  max-width: var(--shell-max);
  margin: 0 auto;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
}

/* Wider canvas only once there is genuinely room — never on a phone. */
@media (min-width: 900px) {
  .app-shell {
    --shell-max: 720px;
  }
}

.app-outlet {
  flex: 1;
  outline: none;
}

.view {
  display: block;
  padding-bottom: var(--s-8);
}

.view--home {
  padding-bottom: var(--s-6);
}

.site-footer {
  margin-top: auto;
  padding: var(--s-6) var(--s-5) calc(var(--s-6) + var(--safe-bottom));
  border-top: 1px solid var(--hairline);
  text-align: center;
}

.site-footer__line {
  margin: 0 0 var(--s-1);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

.site-footer__fine {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--paper-faint);
  opacity: 0.75;
}

/* 5. CHROME ============================================================== */

.appbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 48px 1fr 48px;
  align-items: center;
  gap: var(--s-2);
  padding: calc(var(--safe-top) + 10px) var(--s-3) 10px;
  margin-bottom: var(--s-2);
  background: linear-gradient(
    180deg,
    rgba(8, 20, 28, 0.94) 0%,
    rgba(8, 20, 28, 0.82) 62%,
    rgba(8, 20, 28, 0) 100%
  );
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
}

.appbar__back,
.appbar__spacer {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
}

.appbar__back {
  color: var(--paper);
  background: rgba(245, 239, 225, 0.06);
  border: 1px solid var(--hairline);
  transition: background 160ms var(--ease), transform 160ms var(--ease);
}

.appbar__back:active {
  transform: scale(0.92);
  background: rgba(245, 239, 225, 0.12);
}

.appbar__back-icon {
  font-family: var(--font-display);
  font-size: 30px;
  line-height: 1;
  /* Optically centred: a lone guillemet sits high in its em box. */
  margin-top: -4px;
}

/* 6. BRAND =============================================================== */

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  justify-self: center;
  min-height: 44px;
}

.brand__mark {
  color: var(--gold);
  display: grid;
  place-items: center;
}

.triskelion {
  width: 22px;
  height: 22px;
}

.brand__words {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
}

.brand__name {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.17em;
  color: var(--paper);
}

.brand__tagline {
  font-size: 9.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

/* 7. HOME ================================================================ */

.home-hero {
  position: relative;
  padding: var(--s-5) var(--s-5) var(--s-6);
  text-align: center;
}

.home-hero__crest {
  color: var(--gold);
  display: grid;
  place-items: center;
  margin: 0 auto var(--s-5);
  width: 76px;
  height: 76px;
  border-radius: 50%;
  border: 1px solid rgba(203, 165, 68, 0.32);
  background: radial-gradient(circle at 50% 35%, rgba(203, 165, 68, 0.2), transparent 70%);
  box-shadow: 0 0 40px -12px rgba(203, 165, 68, 0.45);
}

.home-hero__crest .triskelion {
  width: 42px;
  height: 42px;
}

.home-hero__title {
  font-size: clamp(38px, 13vw, 52px);
  letter-spacing: 0.06em;
  /* The wordmark is tracked display type, not body copy. */
  font-weight: 600;
  background: linear-gradient(180deg, #fffaf0 0%, var(--gold-soft) 78%, var(--gold) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.home-hero__tagline {
  margin: var(--s-2) 0 var(--s-5);
  font-family: var(--font-display);
  font-style: italic;
  font-size: 19px;
  color: var(--gold-soft);
}

.home-hero__intro {
  margin: 0 auto;
  max-width: 34ch;
  font-size: 16px;
  color: var(--paper-dim);
}

/* The card this browser holds, in the hero rather than at the foot of the page.
 *
 * It reads as a status, not an announcement: quiet, inline, and above the four
 * doors — so "is my card recognised?" is answered without scrolling, and answered
 * without the banner that exists to announce a tap. The dot is the only colour;
 * the detail is dimmer than the number, because the number is what a customer
 * looks for and the allowance is what they look at once. */
.home-hero .card-note {
  flex-wrap: wrap;
  margin: var(--s-4) auto 0;
  max-width: 34ch;
  padding: 0;
}

.home-hero .card-note__detail {
  color: var(--paper-faint);
  letter-spacing: 0.04em;
}

.menu {
  display: grid;
  gap: var(--s-3);
  padding: 0 var(--s-4);
}

.menu-card {
  position: relative;
  display: grid;
  grid-template-columns: 56px 1fr 24px;
  align-items: center;
  gap: var(--s-4);
  min-height: 92px;
  padding: var(--s-4) var(--s-5) var(--s-4) var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background:
    linear-gradient(135deg, rgba(245, 239, 225, 0.075) 0%, rgba(245, 239, 225, 0.02) 48%, rgba(0, 0, 0, 0.1) 100%);
  box-shadow: var(--shadow-2);
  overflow: hidden;
  transition: transform 220ms var(--ease-out), border-color 220ms var(--ease),
    box-shadow 220ms var(--ease);
}

/* A colour wash keyed to the card's category, so the four doors are
   distinguishable by feel as well as by label. */
.menu-card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background: radial-gradient(90% 130% at 0% 50%, var(--card-tint, transparent), transparent 62%);
}

.menu-card--history {
  --card-tint: rgba(79, 179, 165, 0.24);
  --card-accent: var(--accent-history);
}

.menu-card--place {
  --card-tint: rgba(111, 168, 214, 0.24);
  --card-accent: var(--accent-place);
}

.menu-card--legend {
  --card-tint: rgba(154, 142, 222, 0.26);
  --card-accent: var(--accent-legend);
}

.menu-card--culture {
  --card-tint: rgba(214, 138, 148, 0.22);
  --card-accent: var(--accent-culture);
}

.menu-card--ask {
  --card-tint: rgba(203, 165, 68, 0.22);
  --card-accent: var(--gold);
}

.menu-card:active {
  transform: scale(0.978);
  border-color: var(--hairline-strong);
}

.menu-card__icon {
  position: relative;
  z-index: 1;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: var(--r-md);
  color: var(--card-accent, var(--gold));
  background: rgba(8, 20, 28, 0.5);
  border: 1px solid var(--hairline);
}

.menu-card__icon .icon {
  width: 26px;
  height: 26px;
}

.menu-card__body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.menu-card__title {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 600;
  line-height: 1.2;
}

.menu-card__desc {
  font-size: 14px;
  line-height: 1.4;
  color: var(--paper-dim);
}

.menu-card--soon .menu-card__desc {
  color: var(--gold-soft);
  font-style: italic;
}

.menu-card__chevron {
  position: relative;
  z-index: 1;
  justify-self: end;
  font-family: var(--font-display);
  font-size: 26px;
  line-height: 1;
  color: var(--paper-faint);
}

.rail-slot {
  padding: 0 var(--s-4);
}

.rail-slot:empty {
  display: none;
}

/* --- Near you ---------------------------------------------------------- */

.nearby {
  margin: var(--s-6) 0 0;
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background:
    radial-gradient(120% 100% at 0% 0%, rgba(79, 179, 165, 0.1), transparent 60%),
    rgba(8, 20, 28, 0.4);
}

.nearby__title {
  font-size: 21px;
}

.nearby__intro {
  margin: var(--s-2) 0 var(--s-4);
  max-width: 40ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--paper-dim);
}

.nearby__button {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 48px;
  padding: 0 var(--s-5);
  border-radius: 999px;
  border: 1px solid rgba(79, 179, 165, 0.45);
  background: rgba(79, 179, 165, 0.14);
  color: var(--verdigris);
  font-size: 14.5px;
  font-weight: 600;
  transition: transform 170ms var(--ease), background 170ms var(--ease);
}

.nearby__button:active {
  transform: scale(0.97);
}

.nearby__button:disabled {
  opacity: 0.6;
}

.nearby__pin {
  width: 18px;
  height: 18px;
}

.nearby__status:empty {
  display: none;
}

.nearby__status {
  margin-top: var(--s-3);
}

.nearby__heading {
  margin: 0;
  font-family: var(--font-display);
  font-size: 17px;
  color: var(--verdigris);
}

.nearby__closest,
.nearby__error {
  margin: var(--s-2) 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--paper-dim);
}

.nearby__error {
  color: var(--gold-soft);
}

/* Why nothing opened automatically after a card tap. It states a distance, so
   it reads as an answer rather than an error. */
.nearby__arrival {
  margin: var(--s-3) 0 0;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid rgba(227, 196, 119, 0.3);
  background: rgba(227, 196, 119, 0.08);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--paper);
}

.nearby__arrival--standalone {
  margin: 0;
}

.nearby__results:empty {
  display: none;
}

.nearby__results {
  margin-top: var(--s-4);
  display: grid;
  gap: var(--s-2);
}

.nearby__row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: var(--s-3);
  min-height: 56px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: rgba(245, 239, 225, 0.04);
  transition: transform 180ms var(--ease-out), border-color 180ms var(--ease);
}

.nearby__row:active {
  transform: scale(0.985);
  border-color: var(--hairline-strong);
}

.nearby__art {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  color: var(--gold);
  background: linear-gradient(160deg, var(--ink-600), var(--ink-800));
  border: 1px solid var(--hairline);
}

.nearby__art .motif {
  width: 58%;
}

.nearby__body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.nearby__meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.nearby__place {
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

.nearby__name {
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.2;
}

/* Distance is the point of the list, so it gets tabular figures and emphasis. */
.nearby__distance {
  justify-self: end;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--verdigris);
  white-space: nowrap;
}

.nearby__note {
  margin: var(--s-1) 0 0;
  font-size: 11.5px;
  color: var(--paper-faint);
}

.nearby__picker {
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--hairline);
}

.nearby__picker-label {
  margin: 0 0 var(--s-2);
  font-size: 12.5px;
  color: var(--paper-faint);
}

.nearby__place-select {
  width: 100%;
  min-height: 46px;
  padding: 0 var(--s-3);
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline-strong);
  background: rgba(8, 20, 28, 0.6);
  color: var(--paper);
  /* 16px keeps iOS Safari from zooming when the picker opens. */
  font-size: 16px;
  font-family: var(--font-body);
}

/* Island-wide stories have no distance, so they read as a quieter footnote
   beneath the places you can actually walk to. */
.nearby__row--island .nearby__distance {
  color: var(--paper-faint);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* --- Arrival ----------------------------------------------------------- *
 *
 * Shown for the second or two between a card tap and knowing where the visitor
 * is. It replaces the whole menu rather than appearing above it, so the tap
 * never looks like it opened the wrong page.
 * ---------------------------------------------------------------------- */

.arrival {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  margin: var(--s-6) 0 0;
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: rgba(8, 20, 28, 0.4);
  font-size: 15px;
  color: var(--paper-dim);
}

.arrival__body {
  min-width: 0;
}

/* Says why the location prompt is about to appear. This is the one piece of
   onboarding the product has, so it is not fine print. */
.arrival__lead {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.45;
  color: var(--paper);
}

.arrival__status {
  margin: var(--s-2) 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--paper-faint);
}

.arrival__dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--verdigris);
  animation: listen-pulse 1.6s ease-in-out infinite;
}

/* --- Beside this place ------------------------------------------------- *
 *
 * The story a card opens says what else is within a short drive, using the
 * story's own coordinates rather than the visitor's. It reuses .nearby__row, so
 * this block only has to lay out the heading, the confirmation line and the
 * list — the rows themselves are identical to the "Near you" panel.
 * ---------------------------------------------------------------------- */

.here {
  margin: var(--s-6) 0 0;
}

.here:empty,
.here__slot:empty {
  display: none;
}

.here__lead {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid rgba(79, 179, 165, 0.35);
  background: rgba(79, 179, 165, 0.1);
  font-size: 14px;
  color: var(--paper);
}

/* A dot, not an icon: the same mark the "card detected" footnote uses, so the
   card's arrival reads as one idea in both places. */
.here__pin {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--verdigris);
}

.here__intro {
  margin: var(--s-2) 0 var(--s-3);
  max-width: 46ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--paper-dim);
}

.here__list {
  display: grid;
  gap: var(--s-2);
}

.card-note {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  margin: var(--s-5) 0 0;
  padding: var(--s-2) var(--s-4);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--paper-faint);
}

.card-note--inline {
  justify-content: flex-start;
  margin-top: var(--s-4);
  padding: 0;
}

.card-note__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--verdigris);
  box-shadow: 0 0 10px var(--verdigris);
}

/* 8. EXPLORE ============================================================= */

.explore-hero {
  position: relative;
  padding: var(--s-4) var(--s-5) var(--s-6);
  overflow: hidden;
}

.explore-hero__art {
  color: var(--gold);
  opacity: 0.22;
  position: absolute;
  right: -18px;
  top: -6px;
  width: 150px;
  height: 150px;
  pointer-events: none;
}

.explore-hero__eyebrow {
  display: block;
  font-size: 11.5px;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--gold-soft);
  margin-bottom: var(--s-2);
}

.explore-hero__title {
  font-size: clamp(34px, 11vw, 44px);
}

.explore-hero__blurb {
  margin: var(--s-3) 0 0;
  max-width: 32ch;
  font-size: 15.5px;
  color: var(--paper-dim);
}

.explore-list {
  display: grid;
  gap: var(--s-3);
  padding: 0 var(--s-4);
}

.explore-empty {
  padding: var(--s-6) var(--s-4);
  text-align: center;
  color: var(--paper-faint);
}

.explore-more {
  margin-top: var(--s-6);
  padding-top: var(--s-6);
  border-top: 1px solid var(--hairline);
  display: grid;
  gap: var(--s-3);
}

.explore-more__label {
  margin: 0 0 var(--s-2);
  font-size: 11.5px;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--paper-faint);
}

.explore-more__links {
  display: grid;
  gap: var(--s-2);
}

/* 9. STORY =============================================================== */

/* --- Listen ------------------------------------------------------------
   Deliberately small and inline: listening is an extra, not the main act. The
   button is still a full-size touch target even though it reads as a chip. */

.listen-wrap {
  margin: 0 var(--s-5) var(--s-5);
}

/* Listen and Voice sit side by side; the Voice control is secondary. */
.listen__row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}

.listen__voice-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 var(--s-4);
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--paper-dim);
  background: rgba(245, 239, 225, 0.05);
  border: 1px solid var(--hairline);
  transition: transform 170ms var(--ease), background 170ms var(--ease);
}

.listen__voice-toggle:active {
  transform: scale(0.97);
}

.listen__voice-toggle[aria-expanded='true'] {
  color: var(--gold-soft);
  border-color: rgba(203, 165, 68, 0.4);
  background: rgba(203, 165, 68, 0.1);
}

.listen__voice-icon {
  font-size: 13px;
  line-height: 1;
}

.listen__voice {
  margin-top: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: rgba(8, 20, 28, 0.45);
}

/* A native select, so iOS shows its own picker wheel. */
.listen__voice-select {
  width: 100%;
  min-height: 44px;
  padding: 0 var(--s-3);
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline-strong);
  background: rgba(8, 20, 28, 0.6);
  color: var(--paper);
  /* 16px keeps iOS Safari from zooming the page when the picker opens. */
  font-size: 16px;
  font-family: var(--font-body);
}

.listen__voice-select:disabled {
  opacity: 0.6;
}

/* The open list is drawn by the browser. It does not always follow color-scheme,
   and the text inherits the light colour above — so on a browser that paints the
   list white, the voice names are white on white until the pointer highlights
   one. Explicit, opaque colours here; the same fix and the same reasoning as the
   admin panel's selects. tools/css-check.mjs asserts the contrast of this pair. */
.listen__voice-select option {
  background-color: #0e1c24;
  color: #f5efe1;
}

.listen__voice-note {
  margin: var(--s-3) 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--paper-faint);
}

.listen {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 44px;
  padding: 0 var(--s-4) 0 var(--s-3);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--gold-soft);
  background: rgba(203, 165, 68, 0.1);
  border: 1px solid rgba(203, 165, 68, 0.34);
  transition: transform 170ms var(--ease), background 170ms var(--ease),
    border-color 170ms var(--ease);
}

.listen:active {
  transform: scale(0.97);
}

.listen__icon {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  font-size: 11px;
  color: var(--ink-900);
  background: linear-gradient(160deg, var(--gold-soft), var(--gold));
}

.listen__status {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--paper-faint);
}

/* Speaking: make it obvious that something is running and can be stopped.
   The pulse is decoration only — the label already says "Stop". */
.listen-wrap[data-state='speaking'] .listen {
  color: var(--ink-900);
  background: linear-gradient(160deg, var(--gold-soft), var(--gold));
  border-color: transparent;
}

.listen-wrap[data-state='speaking'] .listen__icon {
  color: var(--gold-soft);
  background: var(--ink-800);
  animation: listen-pulse 1.6s ease-in-out infinite;
}

.listen-wrap[data-state='speaking'] .listen__status {
  color: rgba(8, 20, 28, 0.72);
}

.listen-wrap[data-state='paused'] .listen {
  border-color: var(--hairline-strong);
}

.listen__hint {
  margin: var(--s-3) 0 0;
  max-width: 40ch;
  font-size: 12px;
  line-height: 1.5;
  color: var(--paper-faint);
}

/* A refusal must be noticeable, not just present. */
.listen__hint[data-tone='alert'] {
  color: var(--gold-soft);
}

/* Shown on its own, when there is no control to sit under — a browser with no
   speech engine. It needs the same side margin the control has, so the
   explanation lines up with the masthead above it. */
.listen__hint--standalone {
  margin: 0 var(--s-5) var(--s-5);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: rgba(245, 239, 225, 0.03);
  font-size: 12.5px;
}

.listen-wrap[data-state='blocked'] .listen {
  border-color: var(--hairline-strong);
  color: var(--paper-dim);
  background: rgba(245, 239, 225, 0.06);
}

@keyframes listen-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}

.story {
  display: block;
}

.story__head {
  padding: var(--s-3) var(--s-5) var(--s-5);
}

.story__meta {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
  flex-wrap: wrap;
}

.story__minutes {
  font-size: 11.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

.story__title {
  font-size: clamp(32px, 10.5vw, 42px);
  line-height: 1.08;
}

.story__subtitle {
  margin: var(--s-3) 0 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 19px;
  line-height: 1.4;
  color: var(--gold-soft);
}

/* The image block: a photograph over the story's motif line art.
   The line art is always present as the base layer, so a photograph that is
   slow, blocked or simply missing degrades to on-brand artwork rather than an
   empty frame. Nothing here loads from a third party. */

.photo {
  position: relative;
  display: block;
  overflow: hidden;
  background: linear-gradient(160deg, var(--ink-600) 0%, var(--ink-700) 45%, var(--ink-800) 100%);
}

/* Fallback layer ------------------------------------------------------- */

.photo__fallback {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: grid;
  place-items: center;
  color: var(--gold);
}

.photo__motif {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
}

.photo__glow {
  position: absolute;
  width: 62%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(203, 165, 68, 0.22), transparent 68%);
  filter: blur(6px);
}

.photo__fallback .motif {
  width: 42%;
  opacity: 0.85;
  position: relative;
  z-index: 1;
}

.photo__fallback .motif--large {
  width: 54%;
  filter: drop-shadow(0 6px 24px rgba(203, 165, 68, 0.25));
}

/* Photograph ----------------------------------------------------------- */

/* z-index 1 puts the photograph above the fallback artwork at all times.
   The explicit value matters: without it, `.photo::after` below would paint
   over the image, because both are positioned and the pseudo-element is
   declared later in the stylesheet. */
.photo__img {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  /* Cover, not contain: these are landscape photographs of buildings and
     landscapes, and a letterboxed image would look broken. */
  object-fit: cover;
  object-position: center;
  /* Visible by default. Fading in is a progressive enhancement — if the
     script never runs, or the load event is missed, the photo must still
     show. Only an actual load failure hides it. */
  opacity: 1;
  transition: opacity 420ms var(--ease-out);
}

/* Contrast scrim. Sits above the photograph but below captions; z-index 2
   keeps it below `.tile__badge` (z-index 3). */
.photo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(6, 15, 22, 0.34) 0%, transparent 38%, rgba(6, 15, 22, 0.5) 100%);
}

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

.hero {
  margin: 0 0 var(--s-5);
}

/* The frame owns the aspect ratio and the rounded card treatment; the
   photograph simply fills it. Keeping the caption outside this element is what
   stops `object-fit: cover` from cropping into the text.

   16/10 on a phone rather than 4/3: at 4/3 the hero plus its caption and note
   filled the entire first screen on an iPhone, so the opening paragraph landed
   just below the fold and the page read as "a photo and no text". Starting the
   story on the first screen matters more than a taller picture. */
.hero__frame {
  display: block;
  position: relative;
  aspect-ratio: 16 / 10;
  margin: 0 var(--s-4);
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-3);
}

/* A taller crop on a phone, a cinematic one once there is width for it. */
@media (min-width: 700px) {
  .hero__frame {
    aspect-ratio: 16 / 9;
  }
}

.hero__photo {
  position: absolute;
  inset: 0;
}

.hero__caption {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5) 0;
  font-size: 11.5px;
  letter-spacing: 0.06em;
  line-height: 1.5;
  color: var(--paper-faint);
}

.hero__caption-dot {
  flex: none;
  width: 5px;
  height: 5px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--gold);
  opacity: 0.7;
}

/* Attribution. Required by every licence the photographs are used under, so it
   is rendered as real text rather than hidden away. */
.hero__credit {
  margin: 0;
  padding: var(--s-2) var(--s-5) 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--paper-faint);
  opacity: 0.8;
  position: relative;
  z-index: 2;
}

.hero__credit-link {
  color: var(--gold-soft);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.story__note {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  margin: 0 var(--s-5) var(--s-6);
  padding: var(--s-3) var(--s-4);
  border-left: 3px solid var(--note-accent, var(--gold));
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: rgba(245, 239, 225, 0.04);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--paper-dim);
}

.story__note--legend {
  --note-accent: var(--accent-legend);
}

.story__note--history {
  --note-accent: var(--accent-history);
}

.story__note--place {
  --note-accent: var(--accent-place);
}

.story__note--culture {
  --note-accent: var(--accent-culture);
}

.story__note-dot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--note-accent);
}

/* --- The prose column ------------------------------------------------
   Reading measure is capped in ch, and settled at ~19px with generous leading,
   which is the comfortable band for sustained reading on a phone. */

.prose {
  padding: 0 var(--s-5);
  font-size: 18px;
  line-height: 1.72;
}

@media (min-width: 480px) {
  .prose {
    font-size: 19px;
  }
}

.prose__para {
  margin: 0 0 var(--s-5);
  max-width: 34ch;
  color: var(--paper);
}

.prose__heading {
  margin: var(--s-7) 0 var(--s-4);
  font-size: 24px;
  max-width: 28ch;
}

.prose__heading::after {
  content: "";
  display: block;
  width: 40px;
  height: 2px;
  margin-top: var(--s-3);
  background: linear-gradient(90deg, var(--gold), transparent);
  border-radius: 2px;
}

.prose__block {
  margin: 0 0 var(--s-5);
}

.prose__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--s-3);
  max-width: 34ch;
}

.prose__list li {
  position: relative;
  padding-left: var(--s-5);
}

.prose__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 13px;
  width: 8px;
  height: 1.5px;
  background: var(--gold);
  border-radius: 2px;
}

.prose__quote {
  margin: var(--s-6) 0;
  padding: var(--s-4) 0 var(--s-4) var(--s-5);
  border-left: 2px solid rgba(203, 165, 68, 0.45);
  font-family: var(--font-display);
  font-style: italic;
  font-size: 20px;
  line-height: 1.5;
  color: var(--gold-soft);
}

.prose__quote p {
  margin: 0 0 var(--s-3);
}

/* --- Callouts & evidence labels -------------------------------------- */

.callout {
  margin: var(--s-6) 0;
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: rgba(245, 239, 225, 0.045);
  border-left-width: 3px;
  border-left-color: var(--callout-accent, var(--gold));
}

.callout--history {
  --callout-accent: var(--accent-history);
}

.callout--tradition {
  --callout-accent: var(--gold);
}

.callout--legend {
  --callout-accent: var(--accent-legend);
}

.callout__label {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 11px;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--callout-accent);
}

.callout__text {
  margin: 0;
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--paper-dim);
}

/* The epistemic tag: what kind of claim is this section making? */
.evidence {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-bottom: var(--s-3);
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  border: 1px solid currentColor;
  opacity: 0.9;
}

.evidence--history {
  color: var(--accent-history);
}

.evidence--tradition {
  color: var(--gold-soft);
}

.evidence--legend {
  color: var(--accent-legend);
}

/* --- Did you know? ---------------------------------------------------- */

.fact {
  position: relative;
  margin: var(--s-7) var(--s-4) 0;
  padding: var(--s-5);
  border-radius: var(--r-xl);
  border: 1px solid rgba(203, 165, 68, 0.28);
  background:
    radial-gradient(120% 100% at 0% 0%, rgba(203, 165, 68, 0.16), transparent 62%),
    linear-gradient(150deg, rgba(245, 239, 225, 0.05), rgba(0, 0, 0, 0.12));
  box-shadow: var(--shadow-2);
}

.fact__head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

.fact__spark {
  color: var(--gold);
  display: grid;
  place-items: center;
  flex: none;
}

.icon--sm {
  width: 18px;
  height: 18px;
}

.fact__question {
  font-size: 20px;
  color: var(--gold-soft);
}

.fact__text {
  margin: 0;
  font-size: 16.5px;
  line-height: 1.62;
  color: var(--paper);
}

/* --- Footer of a story ------------------------------------------------ */

.story-footer {
  margin-top: var(--s-7);
}

.story-footer__top {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: 0 var(--s-4);
  margin-bottom: var(--s-5);
}

.story-footer__rule {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--hairline-strong), transparent);
}

.story-footer__back {
  align-self: center;
  font-size: 12px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

.next-up {
  padding: 0 var(--s-4);
}

.next-up__label {
  margin: 0 0 var(--s-3);
  padding-left: var(--s-1);
  font-size: 11.5px;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--paper-faint);
}

.next-up__card {
  display: grid;
  grid-template-columns: 64px 1fr 22px;
  align-items: center;
  gap: var(--s-4);
  min-height: 96px;
  padding: var(--s-3) var(--s-4) var(--s-3) var(--s-3);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: linear-gradient(140deg, rgba(245, 239, 225, 0.07), rgba(0, 0, 0, 0.12));
  box-shadow: var(--shadow-2);
  transition: transform 200ms var(--ease-out), border-color 200ms var(--ease);
}

.next-up__card:active {
  transform: scale(0.98);
  border-color: var(--hairline-strong);
}

.next-up__art {
  width: 64px;
  height: 64px;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  /* The photo component supplies the position/overflow context. */
}

.next-up__art .photo__fallback .motif {
  width: 60%;
}

.next-up__body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.next-up__title {
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1.15;
}

.next-up__subtitle {
  font-size: 13.5px;
  line-height: 1.35;
  color: var(--paper-dim);
}

.next-up__chevron {
  justify-self: end;
  font-family: var(--font-display);
  font-size: 24px;
  color: var(--paper-faint);
}

.related {
  padding: 0 var(--s-4);
  margin-top: var(--s-6);
}

.related:empty {
  display: none;
}

.related-grid {
  display: grid;
  gap: var(--s-3);
}

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

.story-back {
  padding: var(--s-6) var(--s-4) 0;
  display: grid;
}

/* 10. ASK =============================================================== */

.ask__hero {
  position: relative;
  padding: var(--s-4) var(--s-5) var(--s-6);
}

.ask__art {
  color: var(--gold);
  opacity: 0.2;
  position: absolute;
  right: -10px;
  top: 0;
  width: 140px;
  height: 140px;
  pointer-events: none;
}

.ask__eyebrow {
  display: inline-block;
  margin-bottom: var(--s-3);
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid rgba(203, 165, 68, 0.4);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--gold-soft);
}

.ask__title {
  font-size: clamp(32px, 10vw, 42px);
}

.ask__intro {
  margin: var(--s-3) 0 0;
  max-width: 33ch;
  font-size: 15.5px;
  color: var(--paper-dim);
}

.ask__panel {
  padding: 0 var(--s-4);
}

.ask__form {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--s-2);
  align-items: center;
  padding: 6px 6px 6px var(--s-4);
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: rgba(8, 20, 28, 0.6);
  box-shadow: var(--shadow-2);
}

.ask__form:focus-within {
  border-color: rgba(203, 165, 68, 0.55);
}

.ask__input {
  min-height: var(--touch);
  border: 0;
  background: transparent;
  color: var(--paper);
  font-size: 16px; /* >=16px prevents iOS Safari from zooming on focus. */
  font-family: var(--font-body);
  min-width: 0;
}

.ask__input::placeholder {
  color: var(--paper-faint);
}

.ask__input:focus {
  outline: none;
}

.ask__send {
  width: var(--touch);
  height: var(--touch);
  border-radius: 50%;
  border: 0;
  display: grid;
  place-items: center;
  font-size: 21px;
  font-weight: 600;
  color: var(--ink-900);
  background: linear-gradient(160deg, var(--gold-soft), var(--gold));
  box-shadow: 0 6px 18px -6px rgba(203, 165, 68, 0.7);
  transition: transform 150ms var(--ease);
}

.ask__send:active {
  transform: scale(0.9);
}

.ask__status:empty {
  display: none;
}

.ask__reply {
  margin-top: var(--s-4);
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: rgba(245, 239, 225, 0.045);
}

.ask__reply--soon {
  border-color: rgba(203, 165, 68, 0.32);
  background: radial-gradient(120% 100% at 0% 0%, rgba(203, 165, 68, 0.13), transparent 65%);
}

.ask__reply-badge {
  display: inline-block;
  margin-bottom: var(--s-3);
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(203, 165, 68, 0.18);
  color: var(--gold-soft);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ask__reply-text {
  margin: 0 0 var(--s-3);
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1.35;
  color: var(--paper);
}

.ask__reply-note {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--paper-faint);
}

/* --- The guide's answers -------------------------------------------- *
 * Where an answer came from, the answer, and what it cost.
 * -------------------------------------------------------------------- */

.ask__remaining {
  margin: var(--s-3) 0 0;
  font-size: 13.5px;
  color: var(--paper-faint);
}

.ask__remaining:empty,
.ask__reply-footer:empty {
  display: none;
}

/* Not from the card's own stories: the same tint as the "not built yet" panel. */
.ask__reply--outside {
  border-color: rgba(203, 165, 68, 0.32);
}

.ask__story {
  display: inline-block;
  margin: 0 0 var(--s-3);
  font-family: var(--font-display);
  font-size: 15px;
  color: var(--gold-soft);
  text-decoration: none;
  border-bottom: 1px solid rgba(203, 165, 68, 0.4);
}

.ask__story:hover,
.ask__story:focus-visible {
  color: var(--paper);
  border-bottom-color: var(--paper);
}

.ask__reply-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--hairline);
}

/* A chip is a button in three places now, so the reset is written once against
   the element rather than listed per page. */
button.chip {
  appearance: none;
  font: inherit;
  cursor: pointer;
}

button.chip:hover,
button.chip:focus-visible {
  border-color: var(--gold-soft);
  color: var(--paper);
}

/* The chip that is currently in force: the voice being listened to, and the sort
   Near You is using. Keyed off `aria-current`/the state class rather than a
   presentational class, so the highlight and what a screen reader announces cannot
   disagree about which one is on. */
.chip.is-listening,
.nearby__modes [aria-current='true'] {
  border-color: var(--gold-soft);
  color: var(--gold-soft);
}

/* The Recommended | Closest switch, above the two lists it sorts. */
.nearby__modes {
  display: flex;
  gap: var(--s-2);
  margin: var(--s-5) 0 0;
}

.ask__suggestions {
  padding: var(--s-6) var(--s-4) 0;
}

.ask__suggestions-label {
  margin: 0 0 var(--s-3);
  font-size: 11.5px;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--paper-faint);
}

.ask__chips {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.ask__note {
  margin: var(--s-6) var(--s-4) 0;
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: rgba(8, 20, 28, 0.42);
}

.ask__note-title {
  margin-bottom: var(--s-3);
  font-size: 20px;
}

.ask__note-text {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--paper-dim);
}

.ask__cta {
  padding: var(--s-6) var(--s-4) 0;
  display: grid;
}

/* The way out of a problem, on the home screen. Type comes from .ask__reply-note. */
.help-line {
  margin: var(--s-6) var(--s-4) var(--s-4);
}

/* 11. SHARED PIECES ==================================================== */

/* --- Category badges -------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--badge-accent);
  border: 1px solid color-mix(in srgb, var(--badge-accent) 45%, transparent);
  background: color-mix(in srgb, var(--badge-accent) 14%, transparent);
}

.badge--md {
  padding: 5px 12px;
  font-size: 11px;
  letter-spacing: 0.14em;
}

.badge--sm {
  padding: 3px 9px;
  font-size: 9.5px;
  letter-spacing: 0.12em;
}

.badge--history {
  --badge-accent: var(--accent-history);
}

.badge--place {
  --badge-accent: var(--accent-place);
}

.badge--legend {
  --badge-accent: var(--accent-legend);
}

.badge--culture {
  --badge-accent: var(--accent-culture);
}

/* Fallback for browsers without color-mix(): keep the text readable. */
@supports not (color: color-mix(in srgb, red 50%, transparent)) {
  .badge {
    background: rgba(245, 239, 225, 0.08);
    border-color: currentColor;
  }
}

/* --- Story rows ------------------------------------------------------- */

.story-row {
  position: relative;
  display: grid;
  grid-template-columns: 66px 1fr 22px;
  align-items: center;
  gap: var(--s-4);
  min-height: 96px;
  padding: var(--s-3) var(--s-4) var(--s-3) var(--s-3);
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: linear-gradient(140deg, rgba(245, 239, 225, 0.06), rgba(0, 0, 0, 0.12));
  box-shadow: var(--shadow-1);
  transition: transform 200ms var(--ease-out), border-color 200ms var(--ease),
    background 200ms var(--ease);
}

.story-row:active {
  transform: scale(0.98);
  border-color: var(--hairline-strong);
}

.story-row__thumb {
  width: 66px;
  height: 66px;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
}

.story-row__thumb .photo__fallback .motif {
  width: 58%;
}

.story-row__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  min-width: 0;
}

.story-row__title {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 600;
  line-height: 1.15;
}

.story-row__subtitle {
  font-size: 13.5px;
  line-height: 1.35;
  color: var(--paper-dim);
}

.story-row__chevron {
  justify-self: end;
  font-family: var(--font-display);
  font-size: 24px;
  color: var(--paper-faint);
}

/* --- Rails (horizontal scrollers) ------------------------------------- */

.section {
  margin-top: var(--s-6);
}

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-3);
  padding: 0 var(--s-1);
}

.section__title {
  font-size: 21px;
}

.section__link {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold-soft);
}

.rail {
  margin: 0 calc(-1 * var(--s-4));
}

.rail__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 68%;
  gap: var(--s-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: var(--s-1) var(--s-4) var(--s-4);
  /* Momentum scrolling on iOS, no visible scrollbar. */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.rail__track::-webkit-scrollbar {
  display: none;
}

@media (min-width: 520px) {
  .rail__track {
    grid-auto-columns: 46%;
  }
}

.rail__item {
  scroll-snap-align: start;
  min-width: 0;
}

.tile {
  display: grid;
  gap: var(--s-3);
}

.tile:active .tile__art {
  transform: scale(0.98);
}

.tile__art {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-2);
  transition: transform 220ms var(--ease-out);
}

/* The photograph fills the tile. z-index 0 keeps it under the scrim. */
.tile__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.tile__photo .photo__fallback .motif {
  width: 46%;
  opacity: 0.9;
}

/* Must sit above the photograph so the badge below stays readable. */
.tile__scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(180deg, transparent 45%, rgba(6, 15, 22, 0.75) 100%);
  pointer-events: none;
}

.tile__badge {
  position: absolute;
  z-index: 3;
  top: var(--s-3);
  left: var(--s-3);
}

.tile__title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.2;
}

.tile__subtitle {
  font-size: 13px;
  line-height: 1.4;
  color: var(--paper-dim);
  /* Two lines maximum keeps the rail tidy regardless of copy length. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* --- Chips ------------------------------------------------------------ */

.chip {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0 var(--s-3);
  border-radius: 999px;
  font-size: 12px;
  letter-spacing: 0.06em;
  border: 1px solid var(--hairline);
  background: rgba(245, 239, 225, 0.05);
  color: var(--paper-dim);
}

/* The four category-tinted chips went with `categoryChip()`, which nothing called:
   a chip's colour is the only thing those rules did, and no page asked for one. */

.chip--ghost {
  color: var(--paper-faint);
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch);
  padding: 0 var(--s-5);
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.03em;
  border: 1px solid transparent;
  transition: transform 170ms var(--ease), background 170ms var(--ease),
    border-color 170ms var(--ease);
}

.btn:active {
  transform: scale(0.97);
}

.btn--primary {
  color: var(--ink-900);
  background: linear-gradient(160deg, var(--gold-soft), var(--gold));
  box-shadow: 0 10px 26px -12px rgba(203, 165, 68, 0.8);
}

.btn--ghost {
  color: var(--paper);
  border-color: var(--hairline-strong);
  background: rgba(245, 239, 225, 0.05);
}

/* --- Messages & skeletons -------------------------------------------- */

.view--message {
  padding: var(--s-8) var(--s-5);
  text-align: center;
  display: grid;
  gap: var(--s-4);
  justify-items: center;
}

.message__title {
  font-size: 30px;
}

.message__text {
  margin: 0;
  max-width: 32ch;
  color: var(--paper-dim);
}

.skeleton {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-2) 0;
}

.skeleton__line {
  height: 16px;
  border-radius: 8px;
  background: linear-gradient(
    90deg,
    rgba(245, 239, 225, 0.06) 0%,
    rgba(245, 239, 225, 0.13) 50%,
    rgba(245, 239, 225, 0.06) 100%
  );
  background-size: 220% 100%;
  animation: shimmer 1.5s var(--ease) infinite;
}

.skeleton__line--1 {
  width: 72%;
}

.skeleton__line--2 {
  width: 92%;
}

.skeleton__line--3 {
  width: 58%;
}

.story-load {
  padding: var(--s-4) var(--s-5);
}

/* 12. MOTION & RESPONSIVE ============================================== */

/* Motion is decoration, never a precondition for visibility.

   There are deliberately NO enter animations declared in this stylesheet.

   Two attempts at a CSS enter animation both broke the page:
     1. keyframes fading from `opacity: 0` with `both` fill — if the animation
        did not run, the whole page stayed invisible;
     2. the same idea via the Web Animations API — an animation is a
        higher-priority source in the CSS cascade than this stylesheet, so a
        live animation overrode `opacity: 1` and hid the content again.

   Transitions are now applied from JavaScript (see `public/js/motion.js`),
   which only ever animates elements that are already composited and already
   visible. Nothing in this file can hide content, so a skipped animation
   degrades to "no animation" rather than "no page". */

@keyframes shimmer {
  from {
    background-position: 120% 0;
  }
  to {
    background-position: -120% 0;
  }
}

/* The only place opacity is reduced: a photograph whose file genuinely failed
   to load, so the line-art fallback underneath is what remains. This is set
   from JS on an `error` event, never as a default state. */
.photo.is-failed .photo__img {
  display: none;
}

.photo.is-failed .photo__fallback {
  opacity: 1;
}

/* Respect the system setting. Nothing here depends on animation to work. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Landscape phones: keep the sticky bar from eating the viewport. */
@media (max-height: 480px) and (orientation: landscape) {
  .appbar {
    position: static;
  }
  .home-hero__crest {
    display: none;
  }
}

/* --- The welcome a card holder arrives at ----------------------------- *
 *
 * Three screens share this block: the welcome itself, "which town are you in?",
 * and "your trip is over". They are the first thing a card holder sees, so the
 * rules from section 13 apply here too — no animation that content depends on, and
 * nothing hidden until something runs.
 *
 * The nearest story is a card-sized target rather than a row: the whole point of
 * the screen is to make reading it one easy tap.
 * ---------------------------------------------------------------------- */

.welcome {
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--s-6) var(--s-5) var(--s-8);
}

.welcome__title {
  margin: 0 0 var(--s-3);
  font-family: var(--font-display);
  font-size: clamp(26px, 8vw, 36px);
  line-height: 1.15;
  font-weight: 600;
  background: linear-gradient(180deg, #fffaf0 0%, var(--gold-soft) 78%, var(--gold) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.welcome__intro {
  margin: 0 0 var(--s-5);
  font-size: 16px;
  line-height: 1.55;
  color: var(--paper-dim);
}

.welcome__pick {
  display: block;
  padding: var(--s-4);
  margin-bottom: var(--s-5);
  border-radius: var(--r-md);
  border: 1px solid rgba(203, 165, 68, 0.45);
  background: rgba(203, 165, 68, 0.1);
  text-decoration: none;
  color: var(--paper);
}

.welcome__pick:active {
  border-color: rgba(203, 165, 68, 0.8);
  background: rgba(203, 165, 68, 0.16);
}

.welcome__pick-label {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--gold-soft);
}

.welcome__pick-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}

.welcome__pick-distance {
  font-size: 13px;
  color: var(--paper-faint);
}

.welcome__pick-title {
  display: block;
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.2;
  margin-bottom: var(--s-2);
}

.welcome__pick-subtitle {
  display: block;
  font-size: 15px;
  line-height: 1.5;
  color: var(--paper-dim);
}

.welcome__others-title {
  margin: 0 0 var(--s-3);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--paper-faint);
  font-weight: 500;
}

.welcome__row {
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  padding: var(--s-3) 0;
  border-top: 1px solid var(--hairline);
  text-decoration: none;
  color: var(--paper);
}

.welcome__row-art {
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  color: var(--paper-faint);
}

.welcome__row-body {
  display: block;
  min-width: 0;
}

.welcome__row-meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: 4px;
}

.welcome__row-distance {
  font-size: 12px;
  color: var(--paper-faint);
}

.welcome__row-title {
  display: block;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: 2px;
}

.welcome__row-subtitle {
  display: block;
  font-size: 14px;
  line-height: 1.45;
  color: var(--paper-dim);
}

.welcome__towns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
}

.welcome__town {
  font: inherit;
  font-size: 15px;
  min-height: 48px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline-strong);
  background: rgba(245, 239, 225, 0.04);
  color: var(--paper);
  cursor: pointer;
}

.welcome__town:active {
  border-color: rgba(203, 165, 68, 0.6);
  color: var(--gold-soft);
}

.welcome__actions {
  margin: var(--s-5) 0 0;
}

.welcome__browse {
  font: inherit;
  font-weight: 600;
  width: 100%;
  min-height: 48px;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline-strong);
  background: transparent;
  color: var(--gold-soft);
  cursor: pointer;
}

.welcome .card-note {
  justify-content: flex-start;
  margin: 0 0 var(--s-5);
  padding: 0;
}

/* --- A story behind the content switch -------------------------------- *
 *
 * A story whose text a card buys, seen by a visitor who has no card. The story's
 * own header stays — category, title, subtitle and reading time all stay public
 * on purpose — and the `.locked` block, which section 13 styles, sits under it and
 * says what opens the story. Only spacing is set here: the story header was
 * written for a left-aligned page, and `.locked` centres its own content.
 * ---------------------------------------------------------------------- */

.view--locked .badge {
  margin-bottom: var(--s-4);
}

.view--locked .story__title {
  margin-bottom: var(--s-2);
}

.view--locked .story__subtitle {
  margin-bottom: var(--s-3);
}

.view--locked .story__meta {
  margin-bottom: var(--s-7);
}

/* 13. CARD OUTCOMES ===================================================== */
/*                                                                         *
 * Server-rendered pages rather than part of the single-page app: the answer  *
 * to a card tap arrives as HTML, because it has to work before any           *
 * JavaScript runs and because the outcome may be a refusal.                  *
 *                                                                           *
 * The same block serves a card that cannot be activated and, in the next     *
 * stage, a visitor without a card who reaches protected content. One page,   *
 * one voice.                                                                 *
 *                                                                           *
 * Deliberately no animation of any kind. This is what someone sees when      *
 * something has gone wrong, and a fade that fails would leave them with a    *
 * blank screen instead of an explanation.                                    *
 * ---------------------------------------------------------------------- */

.locked {
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--s-8) var(--s-5) var(--s-7);
  text-align: center;
}

.locked__title {
  margin: 0 0 var(--s-6);
  font-family: var(--font-display);
  font-size: clamp(28px, 9vw, 40px);
  font-weight: 600;
  letter-spacing: 0.06em;
  background: linear-gradient(180deg, #fffaf0 0%, var(--gold-soft) 78%, var(--gold) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.locked__heading {
  margin: 0 0 var(--s-4);
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.25;
  color: var(--paper);
}

.locked__text {
  margin: 0 auto var(--s-5);
  max-width: 30ch;
  font-size: 16px;
  line-height: 1.55;
  color: var(--paper-dim);
}

.locked__card {
  margin: 0 0 var(--s-6);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--paper-faint);
}

.locked__actions {
  margin: 0;
}

.locked__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 var(--s-5);
  border-radius: var(--r-md);
  border: 1px solid rgba(203, 165, 68, 0.4);
  background: rgba(203, 165, 68, 0.12);
  color: var(--gold-soft);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
}

.locked__link:active {
  border-color: rgba(203, 165, 68, 0.7);
  background: rgba(203, 165, 68, 0.2);
}

/* The confirmation after a card is activated: it sits between the hero and the
   four doors, so it has to hold that gap on its own rather than rely on a
   neighbour's margin. */
.home-unlocked {
  padding: 0 var(--s-4) var(--s-4);
}

.home-unlocked .callout {
  margin: 0;
}

/* 14. CARD ACTIVE NOTICE =============================================== */
/*                                                                        *
 * The one moment a visitor is told their card worked. It sits above the   *
 * story, dismisses itself after a few seconds, and is present and readable  *
 * the instant it is rendered — it never fades in. The fade out is applied   *
 * from JavaScript, because this design system keeps motion out of the       *
 * stylesheet: a keyframe once outranked every other rule and hid the page.  *
 * --------------------------------------------------------------------- */

.card-active {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin: 0 var(--s-4) var(--s-4);
  padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid rgba(203, 165, 68, 0.35);
  background: rgba(203, 165, 68, 0.1);
}

.card-active__body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1 1 auto;
}

.card-active__label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
}

.card-active__detail {
  font-size: 13px;
  line-height: 1.35;
  color: var(--paper-dim);
}

.card-active__close {
  flex: none;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--paper-faint);
  font-size: 18px;
  line-height: 1;
}

.card-active__close:active {
  background: rgba(245, 239, 225, 0.08);
  color: var(--paper);
}
