/* ── palette ───────────────────────────────────────────────────────────── */
:root {
  --cream:  #F5F1E8;
  --cream-2:#E7DFCE;   /* placeholder tint — one step down from the ground */
  --ink:    #111111;
  --warm:   #8C8071;   /* HAIRLINES ONLY — 3.42:1 on cream, fails WCAG AA for text */
  --warm-text: #655B4E; /* the same warm, dark enough to read: 5.90:1 on cream */

  /* How much the photographs are pulled toward the page's own colour. The wash
     is a cream layer in soft-light over each image; the filter takes the edge
     off saturation so a neon fairground and a beach at dusk can sit in the same
     column without one shouting. Raise --wash to unify harder, drop it to 0 for
     untouched photographs. */
  --wash: 0.28;
  --photo-filter: saturate(0.86) contrast(1.04) brightness(1.01);

  --measure: 34rem;
  --gutter:  clamp(1.5rem, 5vw, 4rem);
  --spine-w: 1px;
}

/* ── reset ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
/* No scroll-behavior:smooth here. With ScrollTrigger running, the browser's
   native smooth scroll is cancelled on its first frame, so scrollIntoView and
   scrollTo silently did nothing and the hero button was dead. Scrolling is
   animated in motion.js instead. */
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 300;
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.15rem);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; }
ol { list-style: none; margin: 0; padding: 0; }
h1, h2 { margin: 0; font-weight: 400; }
::selection { background: var(--ink); color: var(--cream); }
:focus-visible { outline: 1px solid var(--ink); outline-offset: 6px; }

/* ── hero ──────────────────────────────────────────────────────────────── */
.hero__backdrop {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: grayscale(1) blur(var(--backdrop-blur, 26px));
  opacity: var(--backdrop-opacity, 0.16);
  transform: scale(1.08);   /* hides the blur's soft edge */
  pointer-events: none;
}
/* Keeps the hairlines of the script legible over any backdrop. */
.hero__backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 50% at 50% 45%,
    color-mix(in srgb, var(--cream) 92%, transparent) 0%,
    color-mix(in srgb, var(--cream) 20%, transparent) 100%);
}

.hero {
  position: relative;
  overflow: hidden;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 12vh var(--gutter) 8vh;
  text-align: center;
}

.hero__names {
  font-family: 'Pinyon Script', cursive;
  font-size: clamp(3.25rem, 11vw, 8.5rem);
  line-height: 1.05;
  letter-spacing: 0.01em;
  /* Pinyon sits high in its em box; pull it back to optical centre. */
  margin-block: 0 clamp(2.5rem, 6vw, 4rem);
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0 0.28em;
}
.hero__amp {
  font-family: 'Cormorant Garamond', serif;
  font-style: italic;
  font-weight: 300;
  font-size: 0.42em;
  color: var(--warm);
  transform: translateY(-0.25em);
}
.hero__subtitle {
  margin: -2rem 0 2.5rem;
  font-style: italic;
  color: var(--warm);
}

/* ── the one button style ──────────────────────────────────────────────── */
.button {
  display: inline-block;
  font-size: 0.88rem;
  letter-spacing: 0.2em;
  text-transform: lowercase;
  text-decoration: none;
  color: var(--ink);
  padding: 0.9em 0.2em 0.5em;
  border-bottom: 1px solid var(--ink);
  transition: color 220ms ease, border-color 220ms ease, background 220ms ease;
}
.button:hover { color: var(--warm); border-color: var(--warm); }

.button--solid {
  background: var(--ink);
  color: var(--cream);
  border: 1px solid var(--ink);
  padding: 1.1em 2.8em 0.95em;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.92rem;
  font-weight: 400;
}
.button--solid:hover { background: transparent; color: var(--ink); }

/* Reads as the second of two choices, not a footnote. It borrows the button's
   letterspaced lowercase so the pair looks deliberate, and stays subordinate
   through size and weight rather than by being nearly invisible — italic warm
   text at 0.68rem was a whisper nobody heard. */
/* `hidden` sets display:none in the UA stylesheet, which ANY author display
   rule silently overrides — so this link was visible to everyone, not just
   people arriving from the card. Author rule needed to win it back. */
.hero__skip[hidden] { display: none; }

.hero__skip {
  display: inline-block;
  margin-top: 2.1rem;
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  color: color-mix(in srgb, var(--ink) 84%, transparent);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 38%, transparent);
  padding-bottom: 0.45em;
  transition: color 220ms ease, border-color 220ms ease;
}
.hero__skip:hover { color: var(--ink); border-color: var(--ink); }

/* ── scroll cue ────────────────────────────────────────────────────────── */
.scroll-cue {
  margin-top: clamp(4rem, 12vh, 8rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.scroll-cue__rule {
  width: 1px;
  height: clamp(48px, 8vh, 76px);
  background: var(--warm);
  /* phase 2 scales this from 0; declared here so the seam already exists */
  transform-origin: top center;
}
.scroll-cue__word {
  font-size: 0.7rem;
  letter-spacing: 0.26em;
  text-transform: lowercase;
  color: var(--warm-text);
}

/* ── story / spine ─────────────────────────────────────────────────────── */
.story {
  position: relative;
  padding: clamp(4rem, 10vh, 7rem) var(--gutter) clamp(5rem, 12vh, 9rem);
}
.spine {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: var(--spine-w);
  height: 100%;
}
/* A scaled element rather than an SVG stroke-dash. The old spine lived in a
   viewBox squashed non-uniformly (1 unit wide, 1000 tall), so the dash pattern
   was measured in one coordinate system and drawn in another — which is why it
   drew at the wrong rate. scaleY has no such ambiguity and runs on the GPU. */
.spine__line {
  display: block;
  width: 100%;
  height: 100%;
  background: color-mix(in srgb, var(--warm) 55%, transparent);
  transform-origin: top center;
}

/* ── entries ───────────────────────────────────────────────────────────── */
.entries {
  --col-gap: clamp(2rem, 6vw, 5.5rem);
  display: grid;
  grid-template-columns: 1fr;
  row-gap: clamp(3rem, 9vh, 7rem);
  max-width: 74rem;
  margin-inline: auto;
}

/* Year markers break the spine rather than sit beside it. */
.year {
  grid-column: 1 / -1;
  justify-self: center;
  background: var(--cream);
  padding: 0.6rem 1.4rem;
  font-family: 'Bodoni Moda', Didot, serif;
  font-weight: 400;
  font-size: clamp(2.25rem, 5.5vw, 4rem);
  line-height: 1;
  letter-spacing: 0.02em;
}
.year + .entry { margin-top: 0; }

/* One entry per row, so the column descends instead of pairing up. The inner
   block is capped and pushed toward the spine — that closeness is what makes it
   read as a timeline rather than a two-column gallery. */
.entry {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--col-gap);
}
.entry__inner {
  grid-column: 1;
  justify-self: end;
  width: min(var(--w, 20rem), 100%);
  text-align: right;
}
/* The photographs are all the same shape, so width — not aspect ratio — is what
   keeps the column from falling into a rhythm. */
/* Uniform: one width for every frame. Heights still vary with each photo's own
   proportions, so the column breathes without the width implying a hierarchy
   that isn't there. */
.entries[data-frames='uniform'] .entry__inner { width: min(var(--uniform-w), 100%); }

.entry[data-size='lg'] { --w: 25rem; }
.entry[data-size='md'] { --w: 19.5rem; }
.entry[data-size='sm'] { --w: 14.5rem; }
.entry--right .entry__inner {
  grid-column: 2;
  justify-self: start;
  text-align: left;
}

.entry__month {
  display: block;
  margin-bottom: 1.1rem;
  font-size: 0.74rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--warm-text);
}
.entry__place {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  color: var(--warm-text);
}

.entry__caption {
  margin: 1.1rem 0 0;
  font-style: italic;
  font-size: 1rem;
  color: color-mix(in srgb, var(--ink) 82%, transparent);
}
.entry__caption:empty { display: none; }

/* Placeholder photo slots. Real <img> drops in with the same aspect-ratio box. */
.frame {
  position: relative;
  overflow: hidden;
  background: var(--cream-2);
}
.frame picture { display: block; width: 100%; height: 100%; }
.frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--photo-filter);
}
.frame::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--cream);
  mix-blend-mode: soft-light;
  opacity: var(--wash);
  pointer-events: none;
}
.placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 0.4rem;
  text-align: center;
}
.placeholder::after {
  content: '';
  position: absolute;
  inset: 12px;
  border: 1px solid color-mix(in srgb, var(--warm) 30%, transparent);
}
.placeholder__label {
  font-size: 0.6rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--warm);
}

/* ── fund ──────────────────────────────────────────────────────────────── */
.fund {
  position: relative;
  text-align: center;
  padding: clamp(6rem, 16vh, 12rem) var(--gutter) clamp(7rem, 18vh, 13rem);
}
.fund__terminus {
  position: absolute;
  top: 0;
  left: 50%;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--warm);
  transform: translate(-50%, -50%);
}
.fund__heading {
  font-family: 'Pinyon Script', cursive;
  font-size: clamp(2.5rem, 7vw, 4.75rem);
  line-height: 1.15;
  margin-bottom: 1.75rem;
}
.fund__body {
  max-width: var(--measure);
  margin: 0 auto clamp(2.5rem, 6vh, 4rem);
  color: color-mix(in srgb, var(--ink) 78%, transparent);
}

.fund__note {
  margin: 1.5rem auto 0;
  font-size: 0.8rem;
  font-style: italic;
  color: var(--warm-text);
}

.qr { margin: clamp(4rem, 10vh, 7rem) auto 0; width: max-content; }
/* The QR renders its own quiet zone, so it needs no padding or frame of its
   own — anything drawn around it eats into the margin scanners rely on. */
.qr__slot {
  display: block;
  /* 41 modules. At 132px that was ~3.2 CSS px per module — fine on a retina
     screen, marginal on a 1x one. 168px buys the margin back. */
  width: 168px;
  height: 168px;
}
.qr__caption {
  margin-top: 1rem;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: lowercase;
  color: var(--warm-text);
}

/* ── narrow ────────────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  :root { --gutter: 1.5rem; }

  .hero__names { flex-direction: column; gap: 0.05em; }
  .hero__amp { transform: none; }

  .spine { left: 1.5rem; transform: none; }

  .entries { padding-left: 3.5rem; row-gap: clamp(3rem, 8vh, 5rem); }
  .entry { grid-template-columns: 1fr; }
  .entry__inner,
  .entry--right .entry__inner { grid-column: 1; justify-self: start; text-align: left; width: 100%; }
  .year { justify-self: start; margin-left: -3.5rem; padding-left: 0.9rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
