/* =========================================================
   One Year Together — styles
   Mobile-first. Class names follow BEM (block__element--modifier).
   ---------------------------------------------------------
    1. Tokens                 9. Forever + hearts
    2. Base                  10. Lightbox + video
    3. Buttons               11. Back to top + mini player
    4. Navbar                12. Chowder & Panini peek + return button
    5. Hero + sections       13. Note card (dialog)
    6. Our Year + polaroids  14. Hidden letters
    7. Moments (photo booth) 15. Coco & Moose (hero play area)
    8. Music player          16. Cursor trail
                             17. Reduced motion
   ========================================================= */

/* ---------- 1. Tokens ---------- */
:root {
  /* Colour */
  --color-bg: #FFF8F3;
  --color-bg-blush: #FCE8EC;         /* Moments band, closing section, footer */
  --color-bg-sage: #EEF3EB;          /* Our Songs band */
  --color-bg-honey: #FFEBC8;         /* photo booth pop-up (under the sticker pattern) */
  --color-surface: #FFFFFF;
  --color-primary: #D98B9A;
  --color-primary-deep: #B5586B;
  --color-primary-deeper: #9A4558;   /* hover state for filled buttons */
  --color-accent: #F6D6DC;
  --color-sage: #A8BFA3;
  --color-text: #3A2E32;
  --color-muted: #7D6D71;            /* palette #8A7B7F nudged darker so small text passes WCAG AA on cream */

  /* Type */
  --font-heading: "Cormorant Garamond", Georgia, serif;
  --font-script: "Great Vibes", "Segoe Script", cursive;
  --font-body: "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Spacing */
  --space-xs: 0.5rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2.5rem;
  --space-xl: 4rem;
  --gutter: clamp(1rem, 5vw, 2.5rem);
  --section-pad: clamp(5rem, 12vw, 8.5rem);

  /* Shape */
  --radius-s: 10px;
  --radius-m: 18px;
  --radius-l: 28px;
  --radius-pill: 999px;
  --shadow-soft: 0 12px 32px -14px rgba(58, 46, 50, 0.28);
  --shadow-lift: 0 24px 48px -18px rgba(58, 46, 50, 0.4);

  --nav-h: 4rem;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Envelope drawings (SVG sprite in index.html) */
  --env-body: #F6D6DC;
  --env-flap: #EFBFCA;
  --env-line: #D98B9A;
  --env-seal: #B5586B;
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* Room for the scrollbar from the start, so the page doesn't shift sideways when it appears */
html { scrollbar-gutter: stable; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

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

/* Classes like .btn set their own display, which would otherwise beat the hidden attribute */
[hidden] { display: none !important; }

h1, h2, h3 {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 600;
  line-height: 1.15;
  color: var(--color-primary-deep);
}

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

button { font: inherit; color: inherit; }

a { color: var(--color-primary-deep); }

:focus-visible {
  outline: 3px solid var(--color-primary-deep);
  outline-offset: 3px;
  border-radius: 4px;
}
/* Sections receive focus from nav links; no ring needed there */
[tabindex="-1"]:focus { outline: none; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  border-radius: var(--radius-pill);
  background: var(--color-primary-deep);
  color: #fff;
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

svg { fill: currentColor; }

/* ---------- 3. Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.8rem 1.4rem;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-primary-deep);
  color: #fff;
  font-weight: 500;
  cursor: pointer;
  box-shadow: 0 10px 22px -12px rgba(181, 88, 107, 0.8);
  transition: transform 0.2s var(--ease-out), background-color 0.2s;
}
.btn:hover { background: var(--color-primary-deeper); transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn svg { width: 1.2rem; height: 1.2rem; }

/* Quieter outlined pill for secondary actions (photo booth: "See our prints again", "Download") */
.btn-soft {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 1rem 0.45rem 0.7rem;
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-primary-deeper);   /* 4.6:1 even on the pink hover */
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.2s;
}
.btn-soft:hover { background: var(--color-accent); }
.btn-soft svg { width: 1.3rem; height: 1.3rem; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  transition: transform 0.2s var(--ease-out), background-color 0.2s;
}
.icon-btn:hover { background: var(--color-accent); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { width: 1.4rem; height: 1.4rem; }

/* ---------- 4. Navbar ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  height: var(--nav-h);
}
/* Blurred background fades in once the page is scrolled (opacity only) */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(255, 248, 243, 0.8);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 1px 0 rgba(58, 46, 50, 0.06), 0 10px 30px -20px rgba(58, 46, 50, 0.35);
  opacity: 0;
  transition: opacity 0.35s;
}
.nav.is-scrolled::before,
.nav.is-open::before { opacity: 1; }
/* Touch screens: a near-solid bar instead of the blur, which is redone every frame while the page
   scrolls under it and is heavy work for older phones' GPUs */
@media (pointer: coarse) {
  .nav::before {
    background: rgba(255, 248, 243, 0.96);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  max-width: 72rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.nav__brand {
  font-family: var(--font-script);
  font-size: 1.9rem;
  line-height: 1;
  color: var(--color-primary-deep);
  text-decoration: none;
}

.nav__toggle {
  display: grid;
  gap: 5px;
  place-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}
.nav__toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-text);
  transition: transform 0.3s var(--ease-out), opacity 0.2s;
}
.nav.is-open .nav__toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav.is-open .nav__toggle-bar:nth-child(2) { opacity: 0; }
.nav.is-open .nav__toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Mobile: dropdown panel. visibility keeps hidden links out of the tab order. */
.nav__menu {
  position: absolute;
  top: calc(var(--nav-h) + 0.25rem);
  left: var(--gutter);
  right: var(--gutter);
  display: grid;
  gap: 0.25rem;
  margin: 0;
  padding: 0.75rem;
  list-style: none;
  background: var(--color-surface);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-lift);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.5rem);
  transition: opacity 0.25s, transform 0.25s var(--ease-out), visibility 0s 0.25s;
}
.nav.is-open .nav__menu {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

.nav__link {
  display: block;
  padding: 0.7rem 1rem;
  border-radius: var(--radius-pill);
  color: var(--color-text);
  font-size: 0.95rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 0.2s;
}
.nav__link:hover { background: rgba(246, 214, 220, 0.5); }
.nav__link.is-active { background: var(--color-accent); }

@media (min-width: 768px) {
  .nav__toggle { display: none; }
  .nav__menu {
    position: static;
    display: flex;
    padding: 0;
    background: none;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .nav__link { padding: 0.45rem 0.95rem; }
}

/* ---------- 5. Hero + shared section styles ---------- */
.hero {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  --play-h: clamp(170px, 30svh, 300px);   /* Coco & Moose's play area along the bottom (section 15) */
  min-height: 100svh;
  padding: calc(var(--nav-h) + 2rem) var(--gutter) calc(var(--play-h) + 6rem);   /* room for the scroll cue above the play area */
  overflow: hidden;
  text-align: center;
  --color-muted: #6B5C60;   /* darker grey here: the drifting glow can pass under the small text (keeps WCAG AA) */
}
/* Soft blush + sage glow behind the names. Like the music section it slowly drifts, blurred;
   larger than the hero so its edges never show. Only runs while on screen (.is-in-view, main.js). */
.hero::before {
  content: "";
  position: absolute;
  inset: -20svh -20vw auto;   /* sized by the screen, not the hero, so it stays put if the hero grows */
  height: 140svh;
  z-index: -1;
  background:
    radial-gradient(27% 23% at 34% 37%, rgba(246, 214, 220, 0.95), transparent 70%),
    radial-gradient(24% 21% at 69% 63%, rgba(168, 191, 163, 0.45), transparent 70%),
    radial-gradient(20% 19% at 66% 30%, rgba(217, 139, 154, 0.24), transparent 70%);
  filter: blur(30px);
  animation: color-drift 60s ease-in-out infinite alternate paused;
  will-change: transform;
}
.hero.is-in-view::before { animation-play-state: running; }

/* Shared by the hero and the music section */
@keyframes color-drift {
  from { transform: translate3d(-8%, -5%, 0) scale(1.15) rotate(-4deg); }
  to { transform: translate3d(8%, 5%, 0) scale(1) rotate(6deg); }
}

.hero__inner { max-width: 44rem; }
/* Kept out of the layout until main.js has put the names in and their fonts have loaded: taking up room
   in a stand-in font, it would make the hero taller, then shrink (moving everything) when the real one came.
   What hangs off the hero's edges waits too: on a screen too short for it all, the hero grows when the
   names come in, and they'd move. */
.hero:not(.is-ready) .hero__inner { display: none; }
.hero:not(.is-ready) :is(.scroll-cue, .hero__sparkle, .cats) { visibility: hidden; }
/* The opening: the names and lines fade up one after another, then the scroll cue drops in. CSS
   animations of opacity and transform, so they stay smooth while the page is still setting up.
   (.is-ready is added by main.js once the names are in.) */
.hero.is-ready .hero__inner > * { animation: rise-in 1.1s cubic-bezier(0.215, 0.61, 0.355, 1) 0.2s both; }
.hero.is-ready .hero__inner > :nth-child(2) { animation-delay: 0.35s; }
.hero.is-ready .hero__inner > :nth-child(3) { animation-delay: 0.5s; }
.hero.is-ready .hero__inner > :nth-child(4) { animation-delay: 0.65s; }
.hero.is-ready .scroll-cue { animation: drop-in 1s ease-out 1.1s both; }
@keyframes rise-in { from { opacity: 0; transform: translateY(30px); } }
@keyframes drop-in { from { opacity: 0; transform: translateY(-10px); } }
/* Sections marked data-reveal fade up as they come into view (main.js adds .is-revealed) */
.can-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(50px);
  transition: opacity 1s var(--ease-out), transform 1s var(--ease-out);
}
.can-reveal [data-reveal].is-revealed { opacity: 1; transform: none; }
/* Invisible markers main.js watches to tell how far the page has scrolled */
.hero__marker { position: absolute; left: 0; width: 1px; height: 1px; pointer-events: none; visibility: hidden; }

.hero__eyebrow,
.section__eyebrow {
  margin-bottom: 0.75rem;
  color: var(--color-muted);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
}

.hero__names {
  font-family: var(--font-script);
  font-size: clamp(3.6rem, 14vw, 8rem);
  font-weight: 400;
  line-height: 1.1;
}
.hero__amp { color: var(--color-primary); font-size: 0.75em; }

.hero__date {
  display: inline-flex;
  align-items: center;
  gap: 0.9rem;
  margin: 0.75rem 0 1.25rem;
  font-family: var(--font-heading);
  font-size: clamp(1.25rem, 3vw, 1.6rem);
  font-style: italic;
}
.hero__date::before,
.hero__date::after {
  content: "";
  width: 2.5rem;
  height: 1px;
  background: var(--color-primary);
}

.hero__line {
  max-width: 32ch;
  margin-inline: auto;
  color: var(--color-muted);
  font-size: 1.05rem;
}

.hero__sparkle {
  position: absolute;
  color: var(--color-primary);
  opacity: 0.6;
  animation: twinkle 3.5s ease-in-out infinite;
}
.hero__sparkle--1 { top: 22%; left: 14%; font-size: 1.1rem; }
.hero__sparkle--2 { top: 30%; right: 16%; font-size: 0.8rem; color: var(--color-sage); animation-delay: -1.2s; }
.hero__sparkle--3 { bottom: calc(var(--play-h) + 4rem); left: 22%; font-size: 0.9rem; animation-delay: -2.3s; }

@keyframes twinkle {
  0%, 100% { opacity: 0.25; transform: scale(0.85); }
  50% { opacity: 0.8; transform: scale(1.1); }
}
/* Paused once the hero is off screen (.is-in-view, main.js): off screen they can't run on the compositor,
   so they'd tick on the main thread every frame for the rest of the visit */
.hero:not(.is-in-view) :is(.hero__sparkle, .scroll-cue__dot) { animation-play-state: paused; }

.scroll-cue {
  position: absolute;
  bottom: calc(var(--play-h) + 1.25rem);   /* just above the cats' play area */
  inset-inline: 0;
  width: max-content;
  margin-inline: auto;
  display: grid;
  justify-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.5rem;
  color: var(--color-muted);
  font-size: 0.7rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  text-decoration: none;
}
.scroll-cue__mouse {
  display: block;
  width: 22px;
  height: 34px;
  border: 2px solid var(--color-primary);
  border-radius: 12px;
}
.scroll-cue__dot {
  display: block;
  width: 4px;
  height: 7px;
  margin: 6px auto 0;
  border-radius: 2px;
  background: var(--color-primary-deep);
  animation: scroll-dot 1.8s ease-in-out infinite;
}
@keyframes scroll-dot {
  0% { opacity: 0; transform: translateY(0); }
  30% { opacity: 1; }
  100% { opacity: 0; transform: translateY(12px); }
}

.section {
  position: relative;
  padding: var(--section-pad) var(--gutter);
}

.section__header {
  max-width: 38rem;
  margin: 0 auto var(--space-xl);
  text-align: center;
}
.section__title { font-size: clamp(2.6rem, 7vw, 4rem); }
/* Small heart ornament under every section title */
.section__title::after {
  content: "— ♥ —";
  display: block;
  margin-top: 0.6rem;
  color: var(--color-primary);
  font-family: var(--font-body);
  font-size: 0.75rem;
  letter-spacing: 0.5em;
}
.section__intro {
  margin-top: 1rem;
  color: var(--color-muted);
  font-size: 1.05rem;
}

/* ---------- 6. Our Year (journey) ----------
   js/journey.js pins the stage and moves the "world" (the line, its stations, the heart riding it) like a
   camera; each month's pin board opens over it full-screen. Board colours, frame and dot pitch come from
   JOURNEY_CONFIG as --board-1 … --board-12, --board-inset and --dot-pitch.
   .journey--still (reduced motion): a flat map that scrolls sideways, then the boards stacked. */
.journey { padding: 0; }
.journey__stage {
  position: relative;
  height: 100vh;
  height: 100lvh;   /* the tallest the screen gets, so no strip shows below a board when a phone's toolbar hides */
  overflow: clip;   /* clip, not hidden: focusing a photo mustn't scroll the stage */
}
.journey__header {
  position: absolute;
  inset: calc(var(--nav-h) + 3svh) 0 auto;
  z-index: 1;
  padding-inline: var(--gutter);
  pointer-events: none;
}

/* The world: line, stations, head */
.journey__map { position: absolute; inset: 0; }
.journey__world {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  will-change: transform;
}
.journey__path { position: absolute; overflow: visible; }
.journey__path--fill { will-change: transform; }   /* its own layer: drawing the line doesn't repaint the labels */
.journey__track,
.journey__fill {
  fill: none;
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.journey__track { stroke: var(--color-accent); }
.journey__fill { stroke: var(--color-primary-deep); }

/* Dark tone of the month's colour, for small text on it */
.journey__station,
.journey__month { --ink: color-mix(in oklab, var(--board), #000 62%); }
.journey__station { position: absolute; top: var(--y); left: var(--x); }
.journey__dot {
  position: absolute;
  top: -12px;
  left: -12px;
  width: 24px;
  height: 24px;
  border: 3px solid var(--color-primary-deep);
  border-radius: 50%;
  background: var(--color-surface);
  box-shadow: 0 0 0 5px var(--color-bg);
}
.journey__dot-core {
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--color-primary-deep);
  opacity: 0;
}
/* The month's card along the line, in its board colour */
.journey__label {
  position: absolute;
  bottom: 1.9rem;
  left: -1.75rem;
  width: 17rem;
  padding: 0.8rem 1.1rem 0.95rem;
  border: 1.5px solid color-mix(in oklab, var(--board), #000 14%);
  border-radius: var(--radius-s);
  background: var(--board);
  box-shadow: var(--shadow-soft);
}
.journey__meta {
  margin: 0 0 0.35rem;
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  line-height: 1.4;
  text-transform: uppercase;
}
.journey__teaser {
  margin: 0;
  color: var(--color-text);
  font-family: var(--font-heading);
  font-size: 1.2rem;
  font-style: italic;
  line-height: 1.25;
}

.journey__head {
  position: absolute;
  top: -14px;
  left: -16px;
  width: 32px;
  color: var(--color-primary-deep);
  will-change: transform;   /* moves every frame: a layer of its own, so nothing under it repaints */
  filter: drop-shadow(0 3px 4px rgba(58, 46, 50, 0.3));
}
.journey__head svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  stroke: #fff;
  stroke-width: 10;
  paint-order: stroke;
}
/* A hidden letter's envelope beside the line (main.js puts it in this spot), bobbing gently */
.journey__letter {
  position: absolute;
  top: var(--y);
  left: var(--x);
  visibility: visible;   /* stays reachable while an open board hides the rest of the map */
  animation: bob 3s ease-in-out infinite;
}
.journey__letter .stash {
  width: 3.2rem;
  height: 2.95rem;
  margin: -1.475rem 0 0 -1.6rem;
  filter: drop-shadow(0 6px 10px rgba(58, 46, 50, 0.25));
}

.journey__spark {
  position: absolute;
  top: -0.5em;
  left: -0.4em;
  color: var(--color-primary);
  font-size: 0.8rem;
  line-height: 1;
  opacity: 0;
  will-change: transform, opacity;   /* pooled: layers made once, not on every throw */
}
.journey__spark--dot {
  top: -3px;
  left: -3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-primary);
}

/* The parade: pixel effects along the line (journey.js → buildParade). Each one's strip of frames slides past
   a window one frame wide in steps(), a transform, so it plays on the compositor and costs the page nothing
   while scrolling. Only the stretches beside the camera (.is-live), and only while Our Year is on screen. */
.journey__parade { position: absolute; top: 0; left: 0; pointer-events: none; }
.journey__fx { position: absolute; display: none; overflow: hidden; }
.journey.is-in-view .is-live > .journey__fx { display: block; }
.journey__fx--flip { scale: -1 1; }
.journey__fx img {
  width: calc(var(--frames) * 100%);
  max-width: none;
  height: 100%;
  image-rendering: pixelated;
  will-change: transform;
  animation: journey-fx var(--time) steps(var(--frames)) var(--delay) infinite;
}
/* The frames play in the first 70%; then the strip has slid past and the window stays empty till the next */
@keyframes journey-fx { 70%, 100% { transform: translateX(-100%); } }

/* The boards: one per month, stacked in the stage. Each opens like an iris: a circle centred on the
   station's dot (--iris-x/y, radius --iris-r reaching the farthest corner) that journey.js grows with
   transform: scale() while counter-scaling the board inside, so it all runs on the compositor. */
.journey__months {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  pointer-events: none;   /* the envelope on the line stays clickable; only the circles take clicks */
}
.journey__month {
  position: absolute;
  inset: 0;
  overflow: hidden;
  overflow: clip;   /* clip where supported: never scrolled by focus */
  clip-path: circle(0);   /* closed: nothing inside is painted at all (but its photos can still take focus) */
}
.journey__month.is-open { clip-path: none; }
.journey__iris {
  position: absolute;
  left: calc(var(--iris-x) - var(--iris-r));
  top: calc(var(--iris-y) - var(--iris-r));
  width: calc(var(--iris-r) * 2);
  height: calc(var(--iris-r) * 2);
  overflow: hidden;
  overflow: clip;
  border-radius: 50%;
  pointer-events: auto;
  transform: scale(0);
}
.journey__month.is-open .journey__iris { will-change: transform; }   /* a layer only while it's in use */
.journey__month.is-full .journey__iris { overflow: visible; border-radius: 0; transform: none; }   /* no rounded clip to keep up */
.journey__board {
  position: absolute;
  left: calc(var(--iris-r) - var(--iris-x));   /* the board's top-left at the stage's */
  top: calc(var(--iris-r) - var(--iris-y));
  width: var(--stage-w);
  height: var(--board-h, 100%);
  transform-origin: var(--iris-x) var(--iris-y);   /* counter-scaled about the circle's centre */
  background: color-mix(in oklab, var(--board), #000 20%);   /* the frame */
}
.journey__month.is-open .journey__board { will-change: transform; }
/* Soft colour with a fine, perforated dot grid, inset from the frame */
.journey__face {
  position: absolute;
  inset: var(--board-inset, 12px);
  border-radius: 6px;
  background:
    radial-gradient(circle, color-mix(in oklab, var(--board), #000 14%) 1.2px, transparent 1.7px) 0 0 / var(--dot-pitch, 11px) var(--dot-pitch, 11px),
    var(--board);
  box-shadow: inset 0 2px 12px rgba(58, 46, 50, 0.18);
}
.journey__strings {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.journey__string {
  fill: none;
  stroke: color-mix(in oklab, var(--board), #000 40%);
  stroke-width: 1.2;
  stroke-dasharray: 1;   /* with pathLength="1": journey.js draws it by moving the offset from 1 to 0 */
  opacity: 0.6;
}

/* The note card: paper taped at both top corners, with the month's pin at the bottom left
   (the strings start there, and the card tilts around it) */
.journey__note {
  position: absolute;
  top: var(--y);
  left: var(--x);
  z-index: 1;
  width: var(--w);
  padding: 1.75rem 1.75rem 3rem;
  border-radius: 3px;
  background: #FFFDF9;
  box-shadow: 0 16px 30px -14px rgba(58, 46, 50, 0.45), 0 1px 2px rgba(58, 46, 50, 0.08);
  color: var(--color-text);
  transform-origin: 1.925rem calc(100% - 1.925rem);
}
.journey__note::before,
.journey__note::after {
  content: "";
  position: absolute;
  top: -0.45rem;
  width: 6rem;
  height: 1.55rem;
  background: repeating-linear-gradient(45deg, color-mix(in oklab, var(--board), #000 10%) 0 6px, rgba(255, 255, 255, 0.6) 6px 12px);
  box-shadow: 0 1px 2px rgba(58, 46, 50, 0.12);
  opacity: 0.92;
}
.journey__note::before { left: -1.7rem; rotate: -36deg; }
.journey__note::after { right: -1.7rem; rotate: 36deg; }
.journey__title {
  margin-bottom: 0.6rem;
  font-size: clamp(1.6rem, 2.3vw, 2.2rem);
}
.journey__text { margin: 0; font-size: 0.98rem; line-height: 1.6; }
.journey__pin {
  position: absolute;
  bottom: 1.35rem;
  left: 1.35rem;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background: var(--color-primary-deep);
  box-shadow: inset -0.12rem -0.12rem 0.3rem 0.02rem rgba(0, 0, 0, 0.45);
  filter: drop-shadow(0.25rem 0.15rem 0.2rem rgba(0, 0, 0, 0.4));
}

/* Pinned photos, after the swaying gallery: ghost-white card, coloured pin, caption underneath.
   A card hangs from its pin and fits its photo, at the photo's own shape, into the slot journey.js
   gave it (journey.js sets its position and size). */
.journey__photos { margin: 0; padding: 0; list-style: none; }
.journey__photo {
  --pin: crimson;
  --sway: 3deg;
  --sway-time: 1s;
  position: absolute;   /* left, top, width and margin are set by journey.js */
  z-index: 2;
  transform-origin: 50% 0.57rem;
}
/* Each card its own pin colour, sway time (7n) and swing (3n), like the swaying gallery */
.journey__photo:nth-child(7n + 1) { --pin: hotpink; --sway-time: 1.8s; }
.journey__photo:nth-child(7n + 2) { --pin: magenta; --sway-time: 1.3s; }
.journey__photo:nth-child(7n + 3) { --pin: orangered; --sway-time: 1.5s; }
.journey__photo:nth-child(7n + 4) { --pin: darkorchid; --sway-time: 1.1s; }
.journey__photo:nth-child(7n + 5) { --pin: deeppink; --sway-time: 1.6s; }
.journey__photo:nth-child(7n + 6) { --pin: mediumvioletred; --sway-time: 1.2s; }
.journey__photo:nth-child(3n + 1) { --sway: -3.3deg; }
.journey__photo:nth-child(3n + 2) { --sway: 2.4deg; }

.journey__card {
  position: relative;
  display: block;
  width: 100%;
  padding: 0.5rem 0.5rem 0;
  border: 0;
  border-radius: 5px;
  background: ghostwhite;
  box-shadow: 0 7px 8px rgba(0, 0, 0, 0.4);
  color: var(--color-text);
  text-align: center;
  cursor: zoom-in;
  transform-origin: 50% 0.57rem;   /* swings from its pin */
  /* The sway: a CSS animation of transform only, so the compositor runs it without the main thread.
     Paused except on the open board. */
  animation: journey-sway var(--sway-time) ease-in-out calc(var(--sway-time) * -0.5) infinite alternate paused;
}
.journey__photo:nth-child(even) .journey__card { animation-direction: alternate-reverse; }
.journey__month.is-open .journey__card { will-change: transform; animation-play-state: running; }
@keyframes journey-sway {
  from { transform: rotate(calc(var(--sway) * var(--sway-strength, 1) * -1)); }
  to { transform: rotate(calc(var(--sway) * var(--sway-strength, 1))); }
}
.journey__card:focus-visible { outline-offset: 5px; }
/* The pin: a domed head with a soft shadow */
.journey__card::after {
  content: "";
  position: absolute;
  top: 0.22rem;
  left: 50%;
  z-index: 1;
  width: 0.7rem;
  height: 0.7rem;
  margin-left: -0.35rem;
  border-radius: 50%;
  background: var(--pin);
  box-shadow: inset -0.1rem -0.1rem 0.3rem 0.02rem rgba(0, 0, 0, 0.5);
  filter: drop-shadow(0.3rem 0.15rem 0.2rem rgba(0, 0, 0, 0.5));
}
.journey__frame { position: relative; display: block; }
.journey__frame img {
  width: 100%;
  aspect-ratio: 1;   /* journey.js sets each photo's own shape once it has loaded */
  object-fit: cover;
  border-radius: 5px;
  background: color-mix(in oklab, var(--board), #fff 35%);   /* shows while the photo loads */
}
.journey__caption {
  display: block;
  padding: 0.4rem 0.2rem 0.5rem;
  color: #4A3B40;
  font-family: var(--font-heading);
  font-size: 1.05rem;
  font-style: italic;
  line-height: 1.2;
}

@media (max-width: 767.98px) {
  .journey__label { width: 13rem; }
  .journey__teaser { font-size: 1.05rem; }
  .journey__note { padding: 1.4rem 1.3rem 2.8rem; }
  .journey__text { font-size: 0.92rem; line-height: 1.55; }
  .journey__caption { font-size: 0.95rem; }
}

/* Reduced motion: no pin. The whole line on a map that scrolls sideways, then the boards stacked */
.journey--still .journey__stage { height: auto; overflow: visible; }
.journey--still .journey__header { position: static; padding: var(--section-pad) var(--gutter) 0; }
.journey--still .journey__map {
  position: relative;
  height: var(--map-h, 16rem);
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.journey--still .journey__world { will-change: auto; }
.journey--still .journey__label { top: 1.9rem; bottom: auto; }   /* below the line, clear of the hearts above it */
.journey--still .journey__head { display: none; }
.journey--still .journey__card { animation: none; }
.journey--still .journey__months,
.journey--still .journey__month { position: relative; inset: auto; pointer-events: auto; clip-path: none; }
.journey--still .journey__iris {
  position: static;
  width: auto;
  height: auto;
  overflow: visible;
  border-radius: 0;
  transform: none;
  will-change: auto;
}
.journey--still .journey__board { position: relative; left: auto; top: auto; width: auto; }

/* Polaroid frame (used in the photo letters and the closing section) */
.polaroid {
  --tilt: -2.5deg;
  position: relative;
  display: block;
  margin: 0;
  padding: 0.6rem 0.6rem 0;
  border: 1px solid rgba(58, 46, 50, 0.06);
  border-radius: 4px;
  background: #fff;
  box-shadow: var(--shadow-soft);
  text-align: center;
  cursor: zoom-in;
  rotate: var(--tilt);
  transition: rotate 0.5s var(--ease-out), scale 0.5s var(--ease-out);
}
.polaroid:nth-child(2n) { --tilt: 2deg; }
.polaroid:hover,
.polaroid:focus-visible { z-index: 2; rotate: 0deg; scale: 1.05; } /* z-index: lift above neighbours */

/* Washi tape (also on the photo booth strips) */
.polaroid::before,
.strip::before {
  content: "";
  position: absolute;
  top: -0.7rem;
  left: 50%;
  z-index: 1;
  width: 5.5rem;
  height: 1.4rem;
  margin-left: -2.75rem;
  background: repeating-linear-gradient(45deg, rgba(246, 214, 220, 0.9) 0 6px, rgba(255, 255, 255, 0.6) 6px 12px);
  box-shadow: 0 1px 2px rgba(58, 46, 50, 0.1);
  rotate: -3deg;
}
.polaroid:nth-child(2n)::before,
.strip:nth-child(2n)::before {
  background: repeating-linear-gradient(45deg, rgba(168, 191, 163, 0.7) 0 6px, rgba(255, 255, 255, 0.6) 6px 12px);
  rotate: 4deg;
}

.polaroid img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--color-accent);   /* shows while the photo loads */
}
.polaroid__caption {
  display: block;
  padding: 0.55rem 0.25rem 0.75rem;
  color: var(--color-muted);
  font-family: var(--font-heading);
  font-size: 1.1rem;
  font-style: italic;
  line-height: 1.3;
}

/* Video frames: the still image with a play button over it */
.polaroid--video { cursor: pointer; }
.polaroid__media { position: relative; display: block; }
.polaroid__play {
  position: absolute;
  inset: 0;
  width: clamp(2.25rem, 32%, 3.25rem);
  margin: auto;
  filter: drop-shadow(0 4px 10px rgba(58, 46, 50, 0.3));
  transition: scale 0.35s var(--ease-spring);
}
.polaroid__play circle { fill: rgba(255, 255, 255, 0.9); }
.polaroid__play path { fill: var(--color-primary-deep); }
.polaroid--video:hover .polaroid__play,
.polaroid--video:focus-visible .polaroid__play { scale: 1.12; }

/* ---------- 7. Moments (photo booth) ---------- */

/* Moments + Our Songs sit between the hero and the timeline as full-width tinted bands.
   The tints are darker than the cream page, so muted text gets a darker shade inside them
   to keep WCAG AA contrast (5.4:1 on blush, 5.6:1 on sage). */
.section--band { --color-muted: #6B5C60; }
.section--songs { background: var(--color-bg-sage); }
/* Pink band with a repeating sticker sheet (transparent PNG → WebP) on top */
.section--moments {
  background:
    url("../assets/images/photo-booth-pattern.webp") center / clamp(360px, 60vw, 600px) auto repeat,
    var(--color-bg-blush);
}

/* The booth on the page: striped awning, a sign, the camera window and the button */
.booth {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 1.25rem;
  width: min(21rem, 100%);
  margin-inline: auto;
  padding: 3rem 1.75rem 2rem;
  overflow: hidden;   /* clips the awning to the rounded corners */
  border-radius: var(--radius-l);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
}
.booth::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1.5rem;
  background: repeating-linear-gradient(90deg, var(--color-accent) 0 1.5rem, var(--color-surface) 1.5rem 3rem);
}
/* The section's heading, drawn as the booth's sign */
.booth__sign {
  margin: 0;
  color: var(--color-primary-deep);
  font-family: var(--font-script);
  font-weight: 400;   /* Great Vibes only has one weight; h2's 600 would fake-bold it */
  font-size: clamp(2.4rem, 7vw, 3rem);
}
.booth__window {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-m);
  background: var(--color-text);
  outline: 3px solid var(--color-primary);   /* rose outline with a white gap, like a camera's trim */
  outline-offset: 4px;
}
/* Flash bulb */
.booth__window::after {
  content: "";
  position: absolute;
  top: 0.9rem;
  right: 1rem;
  width: 0.75rem;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--color-accent);
}
.booth__lens {
  width: 42%;
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 34%, rgba(255, 255, 255, 0.5) 0 7%, transparent 8%),
    radial-gradient(circle, #1C1518 0 44%, #5A4A50 45% 58%, #2A2023 59%);
  outline: 2px solid var(--color-primary);   /* matches the camera's outline */
  outline-offset: 4px;
}
/* Appears once the booth has printed: opens the finished strips again */
.booth__film:not([hidden]) { animation: panel-in 0.5s var(--ease-out); }

/* The show (a .note dialog; .note.booth-show so it beats the .note rules later in this file):
   tall enough to scroll on phones, with room above for the washi tape */
.note.booth-show {
  width: min(40rem, calc(100% - 1rem));
  max-height: 100svh;
  padding: 1.25rem 0.5rem;
  overflow-y: auto;
}
.booth-show .note__paper {
  container-type: inline-size;
  rotate: -0.75deg;
  padding-inline: clamp(1.1rem, 5vw, 2rem);
  /* Light apricot card with a repeating sticker pattern (both the snapping and the printed stage) */
  background:
    url("../assets/images/photo-booth-card-pattern.webp") center / 340px repeat,
    var(--color-bg-honey);
}
/* Text on the stickers sits on little solid cream labels, so it stays readable (small text 4.7:1) */
.booth-show :is(.note__eyebrow, .booth-show__title, .booth-show__status:not(.visually-hidden), .booth-show__printed, .booth-show__skip) {
  width: fit-content;
  margin-inline: auto;
  padding: 0.2em 0.9em;
  border-radius: var(--radius-pill);
  background: #FFFBF3;
}
.booth-show .booth-show__status:empty { visibility: hidden; }   /* no empty label */
.booth-show .note__close { background: #FFFBF3; }
.booth-show .note__close:hover { background: var(--color-accent); }

.booth-show__viewfinder {
  position: relative;
  width: min(17rem, 100%);
  aspect-ratio: 1;   /* square, like the prints: fits landscape and portrait photos */
  margin: 1rem auto;
  overflow: hidden;
  border: 0.6rem solid var(--color-text);   /* the camera's frame */
  border-radius: var(--radius-m);
  background: var(--color-text);
}
.booth-show__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.booth-show__shot:not([src]) { visibility: hidden; }
.booth-show__count {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  color: #fff;
  font-family: var(--font-heading);
  font-size: 7rem;
  font-weight: 600;
}
.booth-show__flash {
  position: absolute;
  inset: 0;
  background: #fff;
  opacity: 0;
  pointer-events: none;
}
.booth-show__status,
.booth-show__printed {
  margin: 0 0 0.25rem;
  color: var(--color-muted);
  font-family: var(--font-heading);
  font-size: 1.1rem;
  font-style: italic;
}
.booth-show__status { min-height: 1.7em; }   /* no jump when the text changes */
.booth-show__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

/* The prints: two strips side by side on phones, stacked across on wider screens */
.booth-show__prints {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  margin: 1.5rem 0 1rem;
}
.booth-show__prints:not([hidden]) { animation: panel-in 0.5s var(--ease-out); }
.strip {
  position: relative;
  padding: 0.5rem 0.5rem 0.6rem;
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
  rotate: -1.5deg;
}
.strip:nth-child(2) { rotate: 1.25deg; }
.strip__frames {
  display: grid;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.strip__frames img {
  width: 100%;
  aspect-ratio: 1;   /* square photo-booth frames suit landscape and portrait photos */
  object-fit: cover;
  background: var(--color-accent);   /* shows while the photo loads */
}
.strip__caption {
  display: block;
  padding-top: 0.2rem;
  color: var(--color-muted);
  font-family: var(--font-heading);
  font-size: 0.95rem;
  font-style: italic;
}
.strip__stamp {
  margin: 0.4rem 0 0;
  color: var(--color-primary-deep);
  font-family: var(--font-script);
  font-size: 1.5rem;
}
.strip__date { margin: 0; color: var(--color-muted); font-size: 0.75rem; }

@container (min-width: 30rem) {
  .booth-show__prints { grid-template-columns: 1fr; gap: 1.75rem; }
  .strip { rotate: -0.75deg; }
  .strip:nth-child(2) { rotate: 0.75deg; }
  .strip__frames { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------- 8. Music player ---------- */

/* Behind the music: soft blush, rose, sage and honey clouds, blurred and slowly drifting.
   Only runs while the section is on screen (.is-in-view is set in main.js). */
.section--songs {
  isolation: isolate;
  overflow: hidden;   /* clips the drifting colours and the far-away covers */
}
.section--songs::before {
  content: "";
  position: absolute;
  inset: -20%;
  z-index: -1;
  background:
    radial-gradient(32% 38% at 22% 28%, rgba(246, 214, 220, 0.95), transparent 70%),
    radial-gradient(26% 30% at 78% 22%, rgba(217, 139, 154, 0.32), transparent 70%),
    radial-gradient(34% 40% at 70% 78%, rgba(168, 191, 163, 0.5), transparent 70%),
    radial-gradient(26% 30% at 20% 82%, rgba(242, 197, 124, 0.22), transparent 70%);
  filter: blur(40px);
  animation: color-drift 60s ease-in-out infinite alternate paused;   /* keyframes in section 5 */
  will-change: transform;
}
.section--songs.is-in-view::before { animation-play-state: running; }

.music {
  max-width: 62rem;
  margin-inline: auto;
  text-align: center;
}

/* Coverflow: every cover is stacked in the middle, then moved by its --offset from the current
   song (set in main.js): sideways, back into the distance, and turned towards the centre. */
.coverflow {
  --cover: min(13rem, 52vw);
  position: relative;
  touch-action: pan-y;   /* up/down scrolls the page; sideways swipes change the song */
  user-select: none;
  -webkit-user-select: none;
}
.covers {
  --step: 62%;   /* space between covers, as a share of a cover's width: neighbours peek in on phones */
  position: relative;
  height: calc(var(--cover) * 1.5);   /* the cover plus its reflection */
  margin: 0;
  padding: 0;
  list-style: none;
  perspective: 1000px;
}
@media (min-width: 700px) { .covers { --step: 105%; } }

/* One cover (Chowder's) holds a hidden-letter envelope instead of the play/pause button, shown while that
   cover is in the middle. As a side cover it's hidden and can't be clicked, so a click there plays the song. */
.covers__item > .stash {
  position: absolute;
  top: calc(var(--cover) / 2);
  left: 50%;
  z-index: 1;   /* above its cover */
  width: 3.5rem;
  height: 3.25rem;
  margin: -1.625rem 0 0 -1.75rem;
  filter: drop-shadow(0 4px 10px rgba(58, 46, 50, 0.35));
}
.covers__item.has-stash > .stash:hover { transform: scale(1.15) rotate(-6deg); }
.covers__item:not(:has(> .cover[aria-current="true"])) > .stash { visibility: hidden; }

.covers__item {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: calc(10 - var(--distance, 0));
  width: var(--cover);
  margin-left: calc(var(--cover) / -2);
  opacity: clamp(0, 4 - var(--distance, 0), 1);   /* four or more covers away: hidden */
  transform:
    translateX(calc(var(--offset, 0) * var(--step)))
    translateZ(calc(var(--distance, 0) * -110px))
    rotateY(calc(var(--offset, 0) * -25deg));
  transition: transform 0.6s var(--ease-out), opacity 0.4s;
}

.cover {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: var(--radius-m);
  background: var(--color-accent);   /* shows while the cover loads */
  cursor: pointer;
}
.cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  pointer-events: none;
  /* Mirror reflection underneath (Chrome, Edge, Safari; other browsers simply show no reflection) */
  -webkit-box-reflect: below 6px linear-gradient(transparent 55%, rgba(0, 0, 0, 0.3));
}
/* Play/pause on the middle cover when you hover or tab to it (not on the envelope's cover) */
.cover__overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: inherit;
  background: rgba(58, 46, 50, 0.45);
  color: #fff;
  opacity: 0;
  transition: opacity 0.3s;
}
.cover__overlay svg { width: 3.5rem; height: 3.5rem; }
.cover[aria-current="true"]:is(:hover, :focus-visible) .cover__overlay { opacity: 1; }
.has-stash .cover__overlay { display: none; }

/* Play/pause icons follow the player (.is-playing on .music) */
.cover__overlay .icon-pause,
.player__play .icon-pause,
.music.is-playing .icon-play { display: none; }
.music.is-playing .icon-pause { display: block; }

.player {
  width: min(24rem, 100%);
  margin-inline: auto;
}
/* Text sits right on the moving colours, so it uses the darkest shades:
   body text 7:1 or more everywhere, the large title and the seek bar 3.5:1 or more */
.player__title {
  margin: 0;
  color: var(--color-primary-deeper);
  font-family: var(--font-heading);
  font-size: clamp(1.7rem, 5vw, 2.1rem);
  font-weight: 600;
  line-height: 1.2;
}
.player__artist { margin: 0.25rem 0 1.5rem; color: var(--color-text); }

.player__progress {
  display: grid;
  grid-template-columns: 2.75rem 1fr 2.75rem;
  align-items: center;
  gap: 0.5rem;
  color: var(--color-text);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

.player__controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1.75rem;
  margin: 1.5rem 0 0.75rem;
}
/* Round frosted-glass buttons, like the original but in the site's colours */
.player__controls .icon-btn {
  width: 3.25rem;
  height: 3.25rem;
  border: 1px solid rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--color-primary-deeper);
}
.player__controls .icon-btn:hover { background: rgba(255, 255, 255, 0.85); transform: scale(0.96); }
.player__controls .player__play {
  width: 4.25rem;
  height: 4.25rem;
  border-color: transparent;
  background: var(--color-primary-deep);
  color: #fff;
  box-shadow: 0 12px 24px -10px rgba(181, 88, 107, 0.75);
}
.player__controls .player__play:hover { background: var(--color-primary-deeper); transform: scale(1.05); }
.player__play svg { width: 1.8rem; height: 1.8rem; }

.player__status {
  min-height: 1.4em;
  margin: 0;
  color: var(--color-text);
  font-size: 0.85rem;
}

/* Seek bar. --fill is set from JS for WebKit/Blink. The unfilled part is a see-through dark tint so it shows on the moving colours. */
.range {
  --fill: 0%;
  width: 100%;
  height: 1.25rem;
  margin: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.range::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 4px;
  background: linear-gradient(to right, var(--color-primary-deeper) var(--fill), rgba(58, 46, 50, 0.18) var(--fill));
}
.range::-webkit-slider-thumb {
  width: 14px;
  height: 14px;
  margin-top: -5px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--color-primary-deeper);
  box-shadow: 0 1px 4px rgba(58, 46, 50, 0.3);
  -webkit-appearance: none;
  appearance: none;
}
.range::-moz-range-track { height: 4px; border-radius: 4px; background: rgba(58, 46, 50, 0.18); }
.range::-moz-range-progress { height: 4px; border-radius: 4px; background: var(--color-primary-deeper); }
.range::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--color-primary-deeper);
  box-shadow: 0 1px 4px rgba(58, 46, 50, 0.3);
}


/* ---------- 9. Forever + footer ---------- */
.forever {
  isolation: isolate;
  overflow: hidden;
  text-align: center;
  background: linear-gradient(180deg, var(--color-bg), var(--color-bg-blush));
}
.forever__inner { position: relative; z-index: 1; max-width: 42rem; margin-inline: auto; }

.forever__photo {
  width: min(17rem, 72vw);
  margin: var(--space-l) auto;
}
.forever__photo .polaroid { --tilt: -3deg; width: 100%; }
/* A video is landscape: a wider frame that shows the whole picture */
.forever__photo:has(.polaroid--video) { width: min(30rem, 86vw); }
.forever__photo .polaroid--video img { aspect-ratio: 16 / 9; }

.forever__message p {
  font-family: var(--font-heading);
  font-size: clamp(1.25rem, 2.6vw, 1.5rem);
  line-height: 1.55;
}

.forever__signoff {
  margin-top: var(--space-l);
  color: var(--color-primary-deep);
  font-family: var(--font-script);
  font-size: clamp(2.4rem, 7vw, 3.25rem);
  line-height: 1.2;
}

/* Floating hearts (CSS only; only run while the section is on screen) */
.hearts {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.hearts span {
  position: absolute;
  bottom: -2rem;
  left: var(--x);
  color: var(--color-primary);
  font-size: var(--size);
  opacity: 0;
  animation: float-up var(--dur) linear var(--delay) infinite;
  animation-play-state: paused;
}
.forever.is-in-view .hearts span { animation-play-state: running; }
@keyframes float-up {
  0% { opacity: 0; transform: translate3d(0, 0, 0) rotate(0deg); }
  15%, 80% { opacity: var(--alpha); }
  100% { opacity: 0; transform: translate3d(var(--drift), -105vh, 0) rotate(var(--spin)); }
}

.footer {
  padding: 2rem var(--gutter) 2.5rem;
  background: var(--color-bg-blush);
  color: var(--color-muted);
  font-size: 0.85rem;
  text-align: center;
}

/* ---------- 10. Lightbox (native <dialog>) ---------- */
.lightbox {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 4rem 1rem 1.5rem;
  border: 0;
  background: transparent;
  color: #fff;
  overflow: hidden;
}
.lightbox[open] {
  display: grid;
  grid-template: "fig fig" 1fr "prev next" auto / 1fr 1fr;
  align-items: center;
  gap: 1rem;
  animation: fade-in 0.3s var(--ease-out);
}
.lightbox::backdrop { background: rgba(28, 20, 23, 0.92); } /* literal: older browsers do not pass variables into ::backdrop */

.lightbox__figure {
  grid-area: fig;
  display: grid;
  justify-items: center;
  gap: 0.9rem;
  justify-self: center;
  max-width: min(100%, 56rem);
  margin: 0;
  animation: zoom-in 0.35s var(--ease-out);
}
/* Timeline photos and videos keep their own shape (portrait or landscape) */
.lightbox__img,
.lightbox__clip {
  max-width: 100%;
  max-height: 72svh;
  border-radius: var(--radius-s);
  background: #2a2023;
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.6);
}
.lightbox__video {
  display: block;
  width: min(90vw, 56rem);
  max-height: 72svh;
  border-radius: var(--radius-s);
  background: #000;
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.6);
}
.lightbox__caption {
  font-family: var(--font-heading);
  font-size: 1.3rem;
  font-style: italic;
  text-align: center;
}
.lightbox__count {
  position: absolute;
  top: 1.35rem;
  left: 1.25rem;
  margin: 0;
  font-size: 0.85rem;
  opacity: 0.85;
}
.lightbox__close { position: absolute; top: 0.75rem; right: 0.75rem; }
.lightbox__nav--prev { grid-area: prev; justify-self: end; }
.lightbox__nav--next { grid-area: next; justify-self: start; }
.lightbox .icon-btn { background: rgba(255, 255, 255, 0.12); color: #fff; }
.lightbox .icon-btn:hover { background: rgba(255, 255, 255, 0.25); }
.lightbox :focus-visible { outline-color: #fff; }

@media (min-width: 700px) {
  .lightbox { padding: 3rem 1.5rem; }
  .lightbox[open] { grid-template: "prev fig next" 1fr / auto 1fr auto; gap: 1.5rem; }
  .lightbox__nav { justify-self: center; }
}

@keyframes fade-in { from { opacity: 0; } }
@keyframes zoom-in { from { opacity: 0; transform: scale(0.96); } }

/* ---------- 11. Back to top + mini music player ---------- */
.to-top {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 40;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--color-primary-deep);
  color: #fff;
  box-shadow: 0 12px 24px -10px rgba(181, 88, 107, 0.8);
  opacity: 0;
  visibility: hidden;
  transform: translateY(1rem) scale(0.9);
  transition: opacity 0.3s, transform 0.3s var(--ease-out), visibility 0s 0.3s;
}
.to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.to-top:hover { background: var(--color-primary-deeper); }
.to-top svg { width: 1.4rem; height: 1.4rem; }

/* Mini music player (same music as Our Songs). Phones: a spinning record above the envelope button
   (bottom stack: back-to-top, envelope, record), whose controls pop up above it.
   Wide screens: a bar at the bottom centre. Shown via .is-visible like the back-to-top button. */
.mini {
  position: fixed;
  right: 1.25rem;
  bottom: 8.75rem;   /* 1.25rem + two 3.75rem steps: above the lifted envelope button */
  z-index: 40;
  opacity: 0;
  visibility: hidden;
  transform: translateY(1rem) scale(0.9);
  transition: opacity 0.3s, transform 0.3s var(--ease-out), visibility 0s 0.3s;
}
.mini.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

/* The record: album cover with a hole in the middle, spinning while music plays */
.mini__disc {
  position: relative;
  display: block;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border: 3px solid var(--color-surface);
  border-radius: 50%;
  background: var(--color-text);
  box-shadow: var(--shadow-soft), 0 0 0 1px rgba(58, 46, 50, 0.06);
  cursor: pointer;
}
.mini__art {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
.mini__disc::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 0.6rem;
  height: 0.6rem;
  margin: auto;
  border-radius: 50%;
  background: var(--color-bg);
  box-shadow: 0 0 0 2px rgba(58, 46, 50, 0.25);
}
.mini.is-playing .mini__art { animation: spin 5s linear infinite; }
@keyframes spin { to { transform: rotate(1turn); } }
/* Little music-note badge, like the count on the envelope button */
.mini__badge {
  position: absolute;
  top: -0.45rem;
  left: -0.45rem;
  display: grid;
  place-items: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background: var(--color-primary-deep);
  color: #fff;
  font-size: 0.75rem;
}

/* Controls card: pops up above the record on phones */
.mini__panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.75rem);
  width: min(16rem, calc(100vw - 2.5rem));
  padding: 0.9rem 1rem 0.7rem;
  border-radius: var(--radius-m);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft), 0 0 0 1px rgba(58, 46, 50, 0.06);
  text-align: center;
}
.mini:not(.is-open) .mini__panel { display: none; }
.mini.is-open .mini__panel { animation: panel-in 0.3s var(--ease-out); }

.mini__title,
.mini__artist {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mini__title { color: var(--color-primary-deeper); font-weight: 500; }
.mini__artist { color: var(--color-muted); font-size: 0.8rem; }
.mini__progress {
  display: block;
  height: 3px;
  margin-top: 0.5rem;
  overflow: hidden;
  border-radius: 3px;
  background: rgba(58, 46, 50, 0.12);
}
.mini__bar {
  display: block;
  height: 100%;
  background: var(--color-primary-deep);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s linear;
}
.mini__controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.4rem;
}
.mini__controls .icon-btn { color: var(--color-primary-deeper); }
.mini__controls .mini__play {
  background: var(--color-primary-deep);
  color: #fff;
}
.mini__controls .mini__play:hover { background: var(--color-primary-deeper); }
.mini__play .icon-pause,
.mini.is-playing .mini__play .icon-play { display: none; }
.mini.is-playing .mini__play .icon-pause { display: block; }

/* Wide screens: one bar in the middle at the bottom: record · song · controls */
@media (min-width: 900px) {
  .mini {
    right: auto;
    bottom: 1.25rem;
    left: 50%;
    translate: -50% 0;   /* separate from transform, which the show/hide uses */
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.45rem;
    border-radius: var(--radius-pill);
    background: var(--color-surface);
    box-shadow: var(--shadow-soft), 0 0 0 1px rgba(58, 46, 50, 0.06);
  }
  .mini.is-open { padding-right: 0.75rem; }
  .mini__disc { width: 3.25rem; height: 3.25rem; box-shadow: none; }
  .mini__panel {
    position: static;
    display: flex;
    align-items: center;
    gap: 0.9rem;
    width: auto;
    padding: 0;
    background: none;
    box-shadow: none;
    text-align: left;
  }
  .mini__info { width: 11rem; }
  .mini__controls { margin: 0; gap: 0.4rem; }
}

/* ---------- 12. Chowder & Panini peek (bottom-left) ---------- */
.peek {
  position: fixed;
  left: 1rem;
  bottom: 0;
  z-index: 45;
  visibility: hidden;
  transform: translateY(120%);
  transition: transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), visibility 0s 0.8s;
}
.peek.is-visible {
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

.peek__open {
  display: grid;
  justify-items: start;
  gap: 0.6rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

/* Speech bubble */
.peek__bubble {
  position: relative;
  margin-left: 0.5rem;
  padding: 0.45rem 0.9rem;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
  color: var(--color-primary-deep);
  font-size: 0.85rem;
  font-weight: 500;
  white-space: nowrap;
  transform-origin: bottom left;
}
.peek__bubble::after {
  content: "";
  position: absolute;
  left: 1.25rem;
  bottom: -5px;
  width: 10px;
  height: 10px;
  background: var(--color-surface);
  rotate: 45deg;
}
.peek.is-visible .peek__bubble { animation: bubble-in 0.5s 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) both; }

.peek__art {
  display: flex;
  align-items: flex-end;
  transform-origin: bottom center;
}
.peek.is-visible .peek__art { animation: bob 3s ease-in-out infinite; }
.peek__open:hover .peek__art,
.peek__open:focus-visible .peek__art { animation: wiggle 0.6s ease-in-out; }

.peek__art img {
  width: auto;
  height: clamp(6.5rem, 13vw, 9.5rem);
  margin-bottom: 0.4rem;
  filter: drop-shadow(0 8px 12px rgba(58, 46, 50, 0.25));
}

/* Stand-in until you add your own image in data.js */
.peek__placeholder {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: 1rem;
  border: 3px solid #fff;
  border-radius: 50%;
  box-shadow: var(--shadow-soft);
  font-size: 1.7rem;
  line-height: 1;
}
.peek__placeholder--chowder { background: #CDB8EA; rotate: -6deg; }
.peek__placeholder--panini { margin-left: -0.9rem; background: #F9C6D3; rotate: 8deg; }

.peek__close {
  position: absolute;
  top: -0.8rem;
  right: -0.8rem;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--color-text);
  color: #fff;
  cursor: pointer;
}
.peek__close svg { width: 1rem; height: 1rem; }

/* Little round button that brings the peek back after it's closed */
.peek-return {
  position: fixed;
  left: 1rem;
  bottom: 1.25rem;
  z-index: 45;
  display: grid;
  place-items: center;
  width: 3.25rem;
  height: 3.25rem;
  padding: 0;
  overflow: hidden;
  border: 3px solid #fff;
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: var(--shadow-soft);
  font-size: 1.5rem;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(1rem) scale(0.8);
  transition: opacity 0.3s, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), visibility 0s 0.4s;
}
.peek-return.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.peek-return.is-visible:hover { transform: scale(1.08) rotate(-6deg); }
.peek-return img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;   /* frame their faces */
  scale: 1.35;
}

@keyframes bubble-in { from { opacity: 0; transform: translateY(6px) scale(0.6); } }
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
@keyframes wiggle {
  0%, 100% { transform: rotate(0deg); }
  25% { transform: rotate(-6deg); }
  75% { transform: rotate(6deg); }
}

/* ---------- 13. Note card (native <dialog>, used by the hidden letters) ---------- */
.note {
  width: min(26rem, calc(100% - 2.5rem));
  max-width: none;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
}
.note::backdrop {
  background: rgba(58, 46, 50, 0.45);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.note[open] .note__paper { animation: note-in 0.55s cubic-bezier(0.34, 1.56, 0.64, 1); }

.note__paper {
  position: relative;
  padding: 2.75rem 1.75rem 1.75rem;
  border: 1px solid rgba(58, 46, 50, 0.06);
  border-radius: 6px;
  background: #FFFDF9;
  box-shadow: var(--shadow-lift);
  color: var(--color-text);
  text-align: center;
  rotate: -1.5deg;
}
/* Washi tape, same as the photo frames */
.note__paper::before {
  content: "";
  position: absolute;
  top: -0.75rem;
  left: 50%;
  width: 6.5rem;
  height: 1.5rem;
  margin-left: -3.25rem;
  background: repeating-linear-gradient(45deg, rgba(246, 214, 220, 0.9) 0 6px, rgba(255, 255, 255, 0.6) 6px 12px);
  box-shadow: 0 1px 2px rgba(58, 46, 50, 0.1);
  rotate: 3deg;
}

.note__close { position: absolute; top: 0.5rem; right: 0.5rem; color: var(--color-muted); }
.note__close svg { width: 1.2rem; height: 1.2rem; }

.note__eyebrow {
  color: var(--color-muted);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.note__sign {
  margin: 0.75rem 0 1.5rem;
  color: var(--color-primary-deep);
  font-family: var(--font-script);
  font-size: 2rem;
  line-height: 1.2;
}

@keyframes note-in { from { opacity: 0; transform: translateY(30px) scale(0.9) rotate(-4deg); } }

/* ---------- 14. Hidden letters ---------- */

/* Envelope at the end of a line of text (or beside Our Year's line). Drawn open once found. */
.stash {
  display: inline-grid;
  place-items: center;
  vertical-align: -0.35em;
  width: 1.8rem;
  height: 1.65rem;
  margin-left: 0.35rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transition: transform 0.45s var(--ease-spring);
}
.stash svg { width: 100%; height: 100%; overflow: visible; }
.has-stash:hover .stash:not(.is-found) svg { animation: wiggle 0.9s ease-in-out infinite; }
.has-stash .stash:hover { transform: scale(1.2) rotate(-6deg); }

/* Floating envelope button: bottom-right, lifts above "back to top" when that appears */
.letters-fab {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 40;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--color-surface);
  box-shadow: var(--shadow-soft), 0 0 0 1px rgba(58, 46, 50, 0.06);
  cursor: pointer;
  transition: transform 0.35s var(--ease-out);
}
.to-top.is-visible ~ .letters-fab { transform: translateY(-3.75rem); }
.letters-fab svg { width: 1.75rem; height: auto; aspect-ratio: 48 / 44; }
.letters-fab:hover svg { animation: wiggle 0.6s ease-in-out; }
.letters-fab__count {
  position: absolute;
  top: -0.35rem;
  left: -0.45rem;
  min-width: 1.75rem;
  padding: 0.1rem 0.35rem;
  border-radius: var(--radius-pill);
  background: var(--color-primary-deep);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}

/* Letters dialog (reuses the .note paper card) */
.letters { width: min(31rem, calc(100% - 2rem)); }
.letters .note__paper { rotate: -0.75deg; padding-inline: clamp(1.1rem, 5vw, 2rem); }
.letters__panel:not([hidden]) { animation: panel-in 0.35s var(--ease-out); }

.letters__title,
.booth-show__title {
  margin: 0.25rem 0 1.25rem;
  font-size: clamp(1.8rem, 6vw, 2.2rem);
}

.letters__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.letters__tile {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 0.25rem;
  width: 100%;
  height: 100%;
  padding: 0.8rem 0.35rem 0.7rem;
  border: 1px dashed rgba(58, 46, 50, 0.18);
  border-radius: var(--radius-m);
  background: transparent;
  cursor: pointer;
  transition: transform 0.25s var(--ease-out), background-color 0.2s;
}
.letters__tile:hover { background: rgba(246, 214, 220, 0.3); transform: translateY(-2px); }
.letters__tile svg {
  width: 3rem;
  height: auto;
  aspect-ratio: 48 / 44;
  margin-bottom: 0.2rem;
  filter: grayscale(1);
  opacity: 0.45;
}
.letters__tile.is-found {
  border-style: solid;
  border-color: var(--color-accent);
  background: var(--color-surface);
}
.letters__tile.is-found svg { filter: none; opacity: 1; }
.letters__tile-num {
  color: var(--color-muted);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.letters__tile-title {
  color: var(--color-muted);
  font-family: var(--font-heading);
  font-size: 0.95rem;
  font-style: italic;
  line-height: 1.2;
}
.letters__tile.is-found .letters__tile-title { color: var(--color-text); }

.letters__hint {
  margin: 1.25rem 0 0;
  padding: 0.8rem 1rem;
  border-radius: var(--radius-s);
  background: rgba(168, 191, 163, 0.2);
  font-size: 0.88rem;
  line-height: 1.5;
  text-align: left;
}
.letters__hint::before { content: "✦ "; color: var(--color-primary-deep); }

.letters__reset,
.booth-show__skip {
  margin-top: 0.9rem;
  padding: 0.25rem;
  border: 0;
  background: none;
  color: var(--color-muted);
  font-size: 0.8rem;
  text-decoration: underline;
  cursor: pointer;
}

.letters__text {
  margin: 0;
  font-family: var(--font-heading);
  font-size: clamp(1.25rem, 4.2vw, 1.45rem);
  line-height: 1.5;
  text-align: left;
  white-space: pre-line;   /* blank lines in data.js become paragraphs */
}

/* A photo letter: its photos as two taped polaroids side by side (they open in the lightbox) */
.letters__photos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
  margin: 1.5rem 0.25rem 1.75rem;
}
/* Just one (e.g. a video letter): a single, slightly larger frame in the middle */
.letters__photos:has(> :only-child) { grid-template-columns: min(14rem, 100%); justify-content: center; }
/* An odd one out at the end (e.g. three photos): centred under the pair, the same size as the rest */
.letters__photos > :last-child:nth-child(odd):not(:only-child) { grid-column: 1 / -1; justify-self: center; width: calc(50% - 0.625rem); }

@keyframes panel-in { from { opacity: 0; transform: translateY(10px); } }

/* Confetti canvas: inside the letters dialog so it rains over the modal, not behind it */
.confetti {
  position: fixed;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ---------- 15. Coco & Moose (the hero's play area, js/cats.js) ----------
   A soft mat along the bottom of the first screen. The cats, bowl, bed and toys are buttons placed
   on it with transforms; sprites are frames of their sheets (background-position), drawn pixel-crisp.
   The cat menu is the pixel UI from the cat playground (assets/images/Cats/ui), scaled 2x. */
.cats {
  position: absolute;
  left: max(0.75rem, env(safe-area-inset-left));
  right: max(0.75rem, env(safe-area-inset-right));
  bottom: 0.75rem;
  height: var(--play-h);
  /* No floor drawn: they play right on the page, and only their shadows show where the ground is */
  text-align: left;
  font-family: "Pixelify Sans", var(--font-body);
  -webkit-tap-highlight-color: transparent;
  contain: layout style;
}
.cats.is-dragging, .cats.is-dragging * { cursor: grabbing !important; }

.cats__thing {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
  visibility: hidden;   /* until the art is in and everything is placed */
}
.hero.is-ready .cats.is-ready .cats__thing { visibility: visible; }
.cats__shadow {
  position: absolute;
  border-radius: 50%;
  background: rgba(58, 46, 50, 0.22);
  pointer-events: none;
}
.cats__body {
  position: absolute;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  cursor: grab;
  touch-action: none;   /* dragging a cat or toy doesn't scroll the page (the mat itself still does) */
}
.cats__thing--bowl .cats__body,
.cats__thing--bed .cats__body { cursor: pointer; touch-action: manipulation; }
.cats__body:focus-visible { outline: 3px solid var(--color-primary-deep); outline-offset: 2px; }
/* At the feet: the sprites hang off this point, and it turns (flips) and squashes them */
.cats__pose { position: absolute; width: 0; height: 0; pointer-events: none; }
.cats__sprite {
  position: absolute;
  background-repeat: no-repeat;
  image-rendering: pixelated;
  pointer-events: none;
}
/* A cat with a run strip shows it while it runs, instead of its sheet */
.cats__sprite--run,
.cats__thing.is-running .cats__sprite { display: none; }
.cats__thing.is-running .cats__sprite--run { display: block; }
.cats__thing--bowl.is-empty .cats__sprite { filter: grayscale(0.7) brightness(0.8); }   /* empty: click to refill */
.cats__tag {
  position: absolute;
  top: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  color: #F6E8D6;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  text-shadow: 0 2px 0 #403939, 0 -2px 0 #403939, 2px 0 0 #403939, -2px 0 0 #403939,
    2px 2px 0 #403939, -2px 2px 0 #403939, 2px -2px 0 #403939, -2px -2px 0 #403939;
  pointer-events: none;
}

/* Speech bubble: the bubble from the UI sheet, stretched round the words, tail at the bottom right */
.cats__bubble {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10001;
  border-style: solid;
  border-color: transparent;
  border-width: 6px 20px 12px 6px;
  border-image: url("../assets/images/Cats/ui/bubble.png") 3 10 6 3 fill / 6px 20px 12px 6px;
  padding: 1px 0 0 4px;
  color: #403939;
  font-size: 15px;
  font-weight: 600;
  line-height: 18px;
  white-space: nowrap;
  image-rendering: pixelated;
  pointer-events: none;
}

/* A pixel effect (hearts, music, alert): its strip of frames, played once */
.cats__fx {
  position: absolute;
  background-repeat: no-repeat;
  image-rendering: pixelated;
  pointer-events: none;
  animation: cats-fx calc(var(--frames) * 1s / 15) steps(var(--frames)) forwards;
}
@keyframes cats-fx { to { background-position-x: var(--end); } }

/* "Tap or drag us!" on a cat name plate, in the corner until the cats have been played with */
.cats__hint {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 10002;
  display: flex;
  align-items: center;
  min-height: 38px;
  margin: 0;
  border-style: solid;
  border-color: transparent;
  border-width: 6px 12px 6px 46px;
  border-image: url("../assets/images/Cats/ui/nameplate.png") 3 4 3 23 fill / 6px 8px 6px 46px;
  color: #403939;
  font-size: 14px;
  font-weight: 600;
  image-rendering: pixelated;
  pointer-events: none;
  transition: opacity 0.6s, transform 0.6s var(--ease-out);
}
.cats__hint.is-hidden { opacity: 0; transform: translateY(-6px); }
/* "You can't steal my cat.": the same name plate, popping up over a cat carried to the edge */
.cats__warning { opacity: 0; transition: opacity 0.3s; }
.cats__warning:empty { display: none; }
.cats__warning.is-shown { opacity: 1; animation: cats-pop 0.35s var(--ease-spring); }
@keyframes cats-pop { from { transform: scale(0.6); } }

/* The cat menu: the cream panel with cat ears, beside the cat */
.cat-menu {
  position: fixed;
  inset: auto;
  z-index: 80;
  width: 252px;
  margin: 0;
  padding: 0 6px 4px;
  overflow: visible;
  border-style: solid;
  border-color: transparent;
  border-width: 46px 14px 16px;
  border-image: url("../assets/images/Cats/ui/panel.png") 26 25 12 fill / 52px 50px 24px;
  background: none;
  color: #403939;
  font: 500 14px/1.3 "Pixelify Sans", var(--font-body);
  text-align: center;
  image-rendering: pixelated;
}
.cat-menu--fallback:not(.is-open) { display: none; }   /* browsers without popovers */
.cat-menu :focus-visible { outline: 3px solid #ff8a3d; outline-offset: 2px; border-radius: 4px; }
.cat-menu__name {
  display: flex;
  align-items: center;
  min-height: 38px;
  margin-bottom: 8px;
  border-style: solid;
  border-color: transparent;
  border-width: 6px 8px 6px 46px;
  border-image: url("../assets/images/Cats/ui/nameplate.png") 3 4 3 23 fill / 6px 8px 6px 46px;
}
.cat-menu__name:focus-within { outline: 3px solid #ff8a3d; outline-offset: 2px; }
.cat-menu__name input {
  width: 100%;
  min-width: 0;
  padding: 0 4px;
  border: 0;
  background: transparent;
  color: #403939;
  font: 600 17px/24px "Pixelify Sans", var(--font-body);
}
.cat-menu__name input:focus-visible { outline: none; }
.cat-menu__needs {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 3px 8px;
  margin: 0 2px 10px;
  font-size: 13px;
  text-align: left;
}
.cat-menu__meter {
  align-self: center;
  height: 12px;
  overflow: hidden;
  border: 2px solid #403939;
  border-radius: 3px;
  background: #D2C4B2;
}
.cat-menu__meter > span { display: block; height: 100%; background: var(--fill); transition: width 0.3s; }
.cat-menu__actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.cat-menu__moods { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
.cat-menu__moods-part { margin-top: 8px; padding-top: 6px; border-top: 2px dashed #D2C4B2; }
.cat-menu__title { margin: 0 0 4px; color: #403939; font: 600 14px/1.3 "Pixelify Sans", var(--font-body); }
/* Cream tile buttons, pressed in while held */
.cat-menu__button {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  height: 62px;
  padding: 0;
  border: 8px solid transparent;
  border-image: url("../assets/images/Cats/ui/tile.png") 4 fill / 8px;
  background: none;
  color: #403939;
  font: 600 13px/1.1 "Pixelify Sans", var(--font-body);
  image-rendering: pixelated;
  cursor: pointer;
}
.cat-menu__moods .cat-menu__button { height: 56px; font-size: 12px; }
.cat-menu__button:hover { filter: brightness(1.04); }
.cat-menu__button:active { border-image-source: url("../assets/images/Cats/ui/tile-down.png"); }
.cat-menu__button img { width: auto; height: 26px; image-rendering: pixelated; }
.cat-menu__frame {
  width: 32px;
  height: 32px;
  margin: -4px 0 -2px;
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
@media (max-height: 560px) {
  .cat-menu { max-height: calc(100dvh - 16px); overflow-y: auto; }   /* phones on their side: it scrolls */
}

/* ---------- 16. Cursor trail + click hearts (canvas drawn in main.js) ---------- */
.cursor-trail {
  position: fixed;
  inset: 0;
  z-index: 70;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ---------- 17. Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition: none !important; /* instant, so hidden→visible toggles take effect right away */
  }
  .hearts,
  .scroll-cue__dot { display: none; }
}
