:root {
  /* Interface type. The serif stays for editorial copy; controls,
     tables and dashboards read better in a grotesque. */
  --font-ui: "Poppins", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display-ui: "Montserrat", var(--font-ui);
}

/**
 * Port-specific additions.
 *
 * The 35 stylesheets carried over from the React build are untouched —
 * this file holds only what the PHP port needs on top of them, so the
 * originals stay a clean reference and anything added here is obvious.
 *
 * Loaded last, after every section stylesheet.
 */

/* ---------------------------------------------------------------
   [hidden] must actually hide.

   React rendered only the selected tab panel; the port renders all of
   them and toggles `hidden`, so the copy is in the HTML for search
   engines and no-JS visitors. But `[hidden]` and `.audience__panel`
   have identical specificity, and the section stylesheet loads later —
   so its `display: grid` won, and every panel showed at once.
   --------------------------------------------------------------- */
[hidden] {
  display: none !important;
}

/* ---------------------------------------------------------------
   Breathing room under the closing pair of buttons.
   --------------------------------------------------------------- */
.closing__actions {
  margin-bottom: clamp(5rem, 8vw, 7rem);
}

/* ---------------------------------------------------------------
   Stone cards are links to their own page, not just captions.
   --------------------------------------------------------------- */
.scat__btn {
  display: block;
  width: 100%;
  text-align: left;
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
  font: inherit;
}

.scat__card {
  transition: transform 0.5s var(--ease-out), opacity 0.4s var(--ease-out);
}

.scat__card:hover {
  transform: translateY(-4px);
}

.scat__open {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.6rem;
  font-family: var(--font-mono, "IBM Plex Mono", monospace);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold, #c9a227);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.scat__card:hover .scat__open,
.scat__card.is-active .scat__open {
  opacity: 1;
  transform: translateY(0);
}

/* ---------------------------------------------------------------
   Voice: the waveform is a real control, not a picture.

   Bars are buttons-in-spirit — the whole track is scrubbable with a
   pointer, and the played portion is lit gold.
   --------------------------------------------------------------- */
.voice__wave {
  position: relative;
  cursor: pointer;
  touch-action: none;
}

.voice__bar {
  transition: background-color 0.18s linear, opacity 0.18s linear;
}

.voice__bar.is-played {
  background-color: var(--gold, #c9a227);
  opacity: 1;
}

.voice__head {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--gold, #c9a227);
  pointer-events: none;
  transform: translateX(-0.5px);
}

.voice__player.is-playing .voice__head {
  box-shadow: 0 0 12px 1px rgba(201, 162, 39, 0.55);
}

/* ---------------------------------------------------------------
   Section illustrations added by the port (process steps, story
   divider). Kept here so the original section CSS stays untouched.
   --------------------------------------------------------------- */
.pstep__plate {
  position: relative;
  overflow: hidden;
  border-radius: 2px;
  aspect-ratio: 4 / 3;
  margin-bottom: 1.1rem;
  box-shadow: inset 0 0 0 1px var(--rule, rgba(237, 231, 219, 0.12));
}

.pstep__plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.72) brightness(0.78) contrast(1.06);
  transition: transform 1.2s var(--ease-out), filter 0.6s var(--ease-out);
}

.process__step.is-active .pstep__plate img {
  filter: saturate(1) brightness(0.94) contrast(1.02);
  transform: scale(1.04);
}

/* ---------------------------------------------------------------
   Voice play/pause button (the port makes it a real control).
   --------------------------------------------------------------- */
.voice__play {
  display: inline-grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  border: 0;
  cursor: pointer;
  color: var(--gold, #c9a227);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--rule-strong, rgba(237, 231, 219, 0.24));
  transition: background 0.35s var(--ease-out), box-shadow 0.35s var(--ease-out);
}

.voice__play:hover,
.voice__play:focus-visible {
  background: rgba(201, 162, 39, 0.1);
  box-shadow: inset 0 0 0 1px var(--gold, #c9a227);
}

.voice__wave:focus-visible {
  outline: 1px solid var(--gold, #c9a227);
  outline-offset: 6px;
}

/* ---------------------------------------------------------------
   Dust to Diamonds — a photograph rather than drawn facets.
   --------------------------------------------------------------- */
.diamonds__stage {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: 2px;
  aspect-ratio: 1 / 1;
  box-shadow: inset 0 0 0 1px var(--rule, rgba(237, 231, 219, 0.12));
}

.diamonds__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.6) brightness(0.82) contrast(1.1);
  transition: transform 1.6s var(--ease-out), filter 0.8s var(--ease-out);
}

.diamonds__stage:hover .diamonds__photo {
  transform: scale(1.05);
  filter: saturate(0.85) brightness(0.95) contrast(1.04);
}

.diamonds__stage .diamonds__glint {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    60% 50% at 30% 25%,
    rgba(233, 217, 163, 0.28),
    transparent 70%
  );
  mix-blend-mode: screen;
}

/* ---------------------------------------------------------------
   Sierra: three verifiable facts beside the story, so the section
   reads as a record rather than a eulogy.
   --------------------------------------------------------------- */
.sierra__facts {
  list-style: none;
  margin: 1.6rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-500, #9c9385);
}

.sierra__facts li {
  display: flex;
  gap: 0.9rem;
  align-items: baseline;
  padding-top: 0.55rem;
  border-top: 1px solid var(--rule, rgba(237, 231, 219, 0.12));
}

.sierra__facts span {
  color: var(--gold, #c9a227);
  min-width: 8.5rem;
}

/* ---------------------------------------------------------------
   The spiral, given depth.

   Three passes of the same sine at different radii. Blur and opacity
   fall off with distance, which is what stops it reading as a flat
   squiggle behind the cards.
   --------------------------------------------------------------- */
.process__thread-back {
  filter: blur(1.6px);
}

.process__thread-mid {
  filter: blur(0.3px);
}

.process__thread-front {
  filter: none;
}

.process__stage {
  perspective: 1400px;
  perspective-origin: 50% 45%;
}

.process__drum {
  transform-style: preserve-3d;
}

.process__step {
  transform-style: preserve-3d;
  backface-visibility: hidden;
}

/* ---------------------------------------------------------------
   The fingerprint, made pickable.

   The slabs were decoration; now each is a control tied to its legend
   row, and the depth readout counts to whichever is selected.
   --------------------------------------------------------------- */
.core__slab {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  overflow: hidden;
  border-radius: 2px;
  transition: transform 0.55s var(--ease-out), box-shadow 0.55s var(--ease-out),
              filter 0.55s var(--ease-out);
  filter: saturate(0.5) brightness(0.62);
  box-shadow: inset 0 0 0 1px var(--rule, rgba(237, 231, 219, 0.12));
}

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

.core__slab.is-on {
  filter: saturate(1) brightness(1);
  transform: translateX(clamp(6px, 1.2vw, 18px)) scale(1.015);
  box-shadow: inset 0 0 0 1px var(--gold, #c9a227),
              0 18px 40px -24px rgba(0, 0, 0, 0.9);
}

.core__slab:focus-visible {
  outline: 1px solid var(--gold, #c9a227);
  outline-offset: 3px;
}

.core__slab-depth {
  position: absolute;
  right: 0.7rem;
  bottom: 0.5rem;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  color: var(--bone, #ede7db);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9);
}

.core__slab.is-on .core__slab-depth {
  opacity: 1;
  transform: translateY(0);
}

.core__legend li {
  cursor: pointer;
  opacity: 0.42;
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.core__legend li.is-on {
  opacity: 1;
  transform: translateX(4px);
}

.core__legend li.is-on .core__tag-d {
  color: var(--gold, #c9a227);
}

/* ---------------------------------------------------------------
   The join: stone + page.
   --------------------------------------------------------------- */
.story__join {
  position: relative;
  display: grid;
  place-items: center;
  align-self: center;
  perspective: 700px;
}

.story__plus {
  position: relative;
  display: block;
  width: clamp(66px, 8vw, 104px);
  aspect-ratio: 1;
  transform-style: preserve-3d;
}

.story__plus-svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.6));
}

@media (max-width: 900px) {
  .story__join {
    transform: rotate(90deg);
    margin-block: 0.5rem;
  }
}

/* ---------------------------------------------------------------
   Landing stones: the whole card opens that stone.

   A stretched link rather than wrapping the card in an <a>: the card
   holds a list and a heading, and burying those inside a link makes a
   mess of the accessibility tree.
   --------------------------------------------------------------- */
.stones__card { position: relative; }

.stones__link {
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
}

.stones__go {
  display: block;
  margin-top: 1rem;
  font-family: var(--font-mono, "IBM Plex Mono", monospace);
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold, #c9a227);
  opacity: 0;
  transform: translateY(5px);
  transition: opacity 0.45s var(--ease-out), transform 0.45s var(--ease-out);
}

.stones__card:hover .stones__go,
.stones__link:focus-visible + .stones__visual ~ .stones__body .stones__go {
  opacity: 1;
  transform: translateY(0);
}

.stones__link:focus-visible {
  outline: 1px solid var(--gold, #c9a227);
  outline-offset: 6px;
}

/* ---------------------------------------------------------------
   The running total follows you down the choices.
   --------------------------------------------------------------- */
@media (min-width: 901px) {
  .cfg__stage {
    position: sticky;
    top: clamp(5rem, 9vh, 7.5rem);
    align-self: start;
    max-height: calc(100vh - 8rem);
    overflow-y: auto;
    scrollbar-width: thin;
  }
}

/* ---------------------------------------------------------------
   Core-depth gauge: further left, and a longer rail.
   --------------------------------------------------------------- */
.core-gauge {
  left: clamp(0.9rem, 2vw, 2rem) !important;
  right: auto !important;
}

.core-gauge__track {
  min-height: clamp(180px, 34vh, 340px) !important;
}

/* ---------------------------------------------------------------
   Strata lines: a vertical wave as the page moves.

   Each line's width is driven from JS on scroll, with a per-line phase
   offset, so the stack ripples rather than pulsing as one.
   --------------------------------------------------------------- */
.strata-lines__line,
.strata-lines > span {
  transform-origin: right center;
  will-change: transform, opacity;
}

/* ---------------------------------------------------------------
   Process and how-it-works plates were reading as hero images.
   Half the size puts them back to illustration weight.
   --------------------------------------------------------------- */
.pstep__plate {
  max-width: 100%;
  aspect-ratio: 4 / 3;
  margin-bottom: 0.7rem;
}

/* A third of what they were. They are illustrations on a spiral, not
   hero images, and at full width they read as the whole section.

   Height is the constraint that actually matters here, not width: the
   card sits at the front of a drum that is itself inside a pinned,
   full-viewport section, so anything taller than the stage runs off the
   top and bottom of the screen with no way to scroll to it. The card is
   therefore capped against the viewport and its body is clamped to four
   lines — the copy that does not fit is on /how-it-works, which is one
   click away and has room for all of it. */
.process__step {
  max-width: clamp(180px, 17vw, 250px);
}

.process__step-in {
  padding: 0.75rem 0.85rem;
  max-height: min(56vh, 26rem);
  overflow: hidden;
}

.process__step-title { font-size: 0.9rem; line-height: 1.05; margin-block: 0.15rem; }
.process__step-lead  { font-size: 0.72rem; margin-block: 0.1rem; }
.process__step-n     { font-size: 0.66rem; }

.process__step-body {
  font-size: 0.7rem;
  line-height: 1.42;
  margin-block: 0.35rem 0;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Shorter than 4:3 as well. The plate is there to say which step this
   is, not to be looked at. */
.pstep__plate {
  aspect-ratio: 16 / 10;
  margin-bottom: 0.55rem;
}

/* On a short laptop the whole card gets tighter again rather than
   overflowing the pinned stage. */
@media (min-width: 901px) and (max-height: 820px) {
  .process__step-in { max-height: 52vh; padding: 0.6rem 0.75rem; }
  .process__step-body { -webkit-line-clamp: 3; font-size: 0.68rem; }
  .pstep__plate { aspect-ratio: 2 / 1; margin-bottom: 0.45rem; }
}

.hstep__plate {
  max-width: 50%;
}

.hstep__plate img {
  width: 100%;
  height: auto;
  display: block;
}

@media (max-width: 900px) {
  .pstep__plate,
  .hstep__plate {
    max-width: 100%;
  }
}

/* ---------------------------------------------------------------
   The plaque's code, generated live.
   --------------------------------------------------------------- */
.plaque__qr {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  width: 100%;
}

.plaque__qr-state {
  position: absolute;
  inset: auto 0 42% 0;
  text-align: center;
  font-size: 0.56rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--plaque-dk, #2a2317);
  opacity: 0.72;
  transition: opacity 0.45s ease;
}

.plaque__qr.is-working .plaque__qr-state { animation: qr-pulse 1.25s ease-in-out infinite; }
.plaque__qr.is-ready   .plaque__qr-state { opacity: 0; }

@keyframes qr-pulse { 0%,100% { opacity: 0.35; } 50% { opacity: 0.85; } }

.plaque__qr-out { display: block; width: 100%; height: 100%; }
.plaque__qr-out svg { width: 100%; height: 100%; display: block; }

/* The code is cast into the metal, so it takes the plaque's colours
   rather than arriving as black on white. */
.plaque__qr-out svg path { fill: var(--plaque-dk, #2a2317); }
.plaque__qr-out svg rect { fill: transparent; }

/* A button that cannot act yet still looks like a button, and says why
   when pressed. A grey rectangle with no explanation reads as broken. */
.is-blocked { opacity: 0.55; }
.is-blocked:hover { opacity: 0.75; }

/* ---------------------------------------------------------------
   Phones: less to read.

   Testers on mobile reported "text and text, so much text in one go".
   On a small screen each section keeps its headline, one line of
   lede and its picture; the supporting paragraphs, fact lists and
   footnotes are for the desktop, where they sit beside the picture
   instead of stacking into a wall.
   --------------------------------------------------------------- */
@media (max-width: 640px) {
  .hero__notes,
  .mf__entry-body,
  .process__step-body,
  .mason__body,
  .mason__track,
  .diamonds__note,
  .diamonds__colours,
  .voice__note,
  .stones__hint,
  .sierra__facts {
    display: none !important;
  }

  /* Ledes stay, but short: three lines, then an ellipsis. */
  .story__lede,
  .voice__lede,
  .diamonds__lede,
  .closing__sub,
  .stones__head .lede,
  .phead__lede {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .mason__quote-text {
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* A little more air between what remains. */
  .section {
    padding-block: clamp(3rem, 12vw, 4.5rem);
  }
}

/* ---------------------------------------------------------------
   The spiral on phones.

   The desktop helix cannot fit a phone, and the old fallback was a
   plain column of 250px cards stuck to the left edge. On phones the
   four steps now hang off a glowing gold thread, each card full width
   with a numbered bead on the thread, and they swing in from
   alternating sides as you scroll (motion.js) — the same turning idea,
   told vertically.
   --------------------------------------------------------------- */
@media (max-width: 900px) {
  .process__drum {
    position: relative;
    display: grid;
    gap: 1.25rem;
    padding: 0.5rem 0 0.5rem 2.6rem;
    perspective: 900px;
  }

  .process__drum::before {
    content: "";
    position: absolute;
    left: 0.95rem;
    top: 0;
    bottom: 0;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(180deg, transparent, var(--gold-300) 8%, #e59384 55%, var(--gold-300) 92%, transparent);
    box-shadow: 0 0 14px rgba(201, 162, 39, 0.45);
  }

  .process__step {
    position: relative;
    top: auto;
    left: auto;
    max-width: none;
    width: 100%;
  }

  .process__step-in {
    position: relative;
    max-height: none;
    overflow: visible;
    padding: 1rem;
    border-radius: 18px;
    border: 1px solid rgba(201, 162, 39, 0.28);
    background:
      radial-gradient(120% 80% at 0% 0%, rgba(201, 162, 39, 0.12), transparent 60%),
      linear-gradient(160deg, rgba(38, 33, 29, 0.96), rgba(16, 14, 12, 0.98));
    box-shadow: 0 24px 50px -30px rgba(0, 0, 0, 0.95);
    transform-origin: left center;
  }

  .process__step:nth-child(even) .process__step-in {
    transform-origin: right center;
    background:
      radial-gradient(120% 80% at 100% 0%, rgba(229, 147, 132, 0.12), transparent 60%),
      linear-gradient(200deg, rgba(38, 33, 29, 0.96), rgba(16, 14, 12, 0.98));
  }

  /* The bead on the thread. */
  .process__step-n {
    position: absolute;
    left: -2.55rem;
    top: 1.1rem;
    display: grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    color: #17140c;
    background: linear-gradient(145deg, #f6dfa0, #b08622);
    box-shadow: 0 0 0 4px var(--ink-000), 0 0 18px rgba(232, 200, 114, 0.6);
  }

  .pstep__plate {
    aspect-ratio: 16 / 9;
    border-radius: 12px;
    margin-bottom: 0.85rem;
  }

  .pstep__plate img {
    filter: none;
  }

  .process__step-title { font-size: var(--step-2); line-height: 1.05; }
  .process__step-lead  { font-size: var(--step-0); }
}
