@font-face {
  font-family: "Qinferly";
  src: url("../fonts/qinferly-personal-use/Qinferly.ttf") format("truetype");
  font-display: swap;
}

:root {
  /* Speed at which the hover popup opens/closes (fade + scale). Lower = snappier. */
  --popup-speed: 1s;
  /* Vertical gap between the cursor and the popup. Lower = more under the cursor. */
  --popup-offset-y: 30px;

  /* --- Poem reveal (POLA-style per-character left-to-right darkening) --- */
  /* How long a single character takes to go from faint to solid + slide home. */
  --poem-reveal-speed: 0.5s;
  /* Delay added per character across the line — THE reveal-speed knob. Smaller =
     the wavefront races across the line faster; larger = slower, lazier sweep. */
  --poem-sweep-step: 0.01s;
  /* How far each visual row slides in as it reveals. */
  --poem-reveal-shift: -0.35em;
  /* Resting opacity of not-yet-revealed characters — they sit faintly visible,
     then darken to full as the wavefront sweeps across. 0 = fully hidden. */
  --poem-rest-opacity: 0.14;
  /* Easing for each character's fade + slide. */
  --poem-reveal-ease: ease-out;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* Page background lives on <html> only. If it were on <body> (an in-flow box), its
   background would paint on top of the z-index:-1 petal canvas and hide it. */
html {
  background: #f6ece2;
}

#scene {
  position: fixed;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  z-index: 1;
}

/* ---------------------------------------------------------------------------
   Loading screen — sits above everything (z-index 100) until every asset
   (models, textures, fonts, audio) has downloaded, then fades away. JS adds
   .loaded to fade it out and .started to body (which releases the headline
   cascade, paused below until the experience actually begins).
   --------------------------------------------------------------------------- */
#loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f6ece2;
  transition: opacity 0.8s ease;
}

#loader.loaded {
  opacity: 0;
  pointer-events: none;
}

.loader-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
}

/* Soft pulsing bloom while assets stream in */
.loader-flower {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, #e7b79c 0%, #d0a48c 55%, transparent 72%);
  animation: loader-pulse 1.5s ease-in-out infinite;
}

@keyframes loader-pulse {
  0%, 100% { transform: scale(0.7); opacity: 0.55; }
  50%      { transform: scale(1);   opacity: 1; }
}

.loader-label {
  font-family: "Qinferly", "Caveat", cursive;
  font-size: 26px;
  color: #c08c72;
}

.loader-track {
  width: 180px;
  height: 3px;
  border-radius: 3px;
  background: rgba(208, 164, 140, 0.25);
  overflow: hidden;
}

#loader-bar {
  width: 0%;
  height: 100%;
  background: #c08c72;
  border-radius: 3px;
  transition: width 0.3s ease;
}

/* "Tap to begin" — hidden while downloading; the loader swaps into this state
   once every asset is ready (JS adds .ready). The tap that dismisses it also
   unlocks audio, so the music starts on the experience's first frame. */
.loader-hint {
  font-family: "Qinferly", "Caveat", cursive;
  font-size: 26px;
  color: #c08c72;
  opacity: 0;
  transition: opacity 0.4s ease;
}

#loader.ready {
  cursor: pointer;
}

#loader.ready .loader-label,
#loader.ready .loader-track {
  display: none;
}

#loader.ready .loader-hint {
  opacity: 1;
}

/* Hold the headline cascade until the loader is dismissed. A paused animation
   sits frozen before its delay, so it plays in full once .started is added. */
body:not(.started) #bg-text .char-inner {
  animation-play-state: paused;
}

/* Landing text — behind the transparent canvas so flowers can mask it */
#bg-text {
  position: fixed;
  top: 18%;
  left: 50%;
  transform: translateX(-50%);
  z-index: 0;
  margin: 0;
  font-family: "Qinferly", "Caveat", cursive;
  font-size: clamp(40px, 6vw, 120px);
  font-weight: 400;
  text-align: center;
  line-height: 1.3em;
  color: #d0a48c;
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
  transform: translateX(-50%) scale(1);
  filter: blur(0px);
  transition: opacity 0.8s ease, transform 0.8s ease, filter 0.8s ease;
}

/* Faded once a flower is chosen — blur + shrink while fading out */
#bg-text.faded {
  opacity: 0;
  transform: translateX(-50%) scale(0.92);
  filter: blur(8px);
}

/* Per-character wrappers. Outer .char carries the mouse-driven displacement
   (JS inline transform); inner .char-inner carries the cascade-in animation,
   so the two transforms never fight over the same element. */
#bg-text .char {
  display: inline-block;
  transform: translate(0, 0);
  will-change: transform;
}

#bg-text .char.space {
  white-space: pre;
}

#bg-text .char-inner {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em) rotate(6deg);
  animation: char-cascade 0.6s cubic-bezier(0.2, 0.8, 0.25, 1) forwards;
  animation-delay: var(--char-delay, 0s);
}

@keyframes char-cascade {
  to {
    opacity: 1;
    transform: translateY(0) rotate(0deg);
  }
}

/* Hover popup — follows the mouse in phase 1 */
.popup {
  position: fixed;
  top: 0;
  left: 0;
  padding: 8px 14px;
  background: rgba(30, 28, 24, 0.92);
  color: #f6f3ec;
  font-family: "Caveat", cursive;
  font-size: 22px;
  border-radius: 10px;
  pointer-events: none;
  opacity: 0;
  transform-origin: top center;
  transform: translate(-50%, var(--popup-offset-y, 4px)) scale(0);
  transition: opacity var(--popup-speed) ease, transform var(--popup-speed) ease,
    background-color 0.35s ease, color 0.35s ease;
  white-space: nowrap;
  z-index: 10;
}

.popup.visible {
  opacity: 1;
  transform: translate(-50%, var(--popup-offset-y, 4px)) scale(1);
}

/* Per-flower popup colour themes (set in JS from the hovered flower's index). */
.popup.theme-left   { background: #b62b22; color: #fff7f2; }   /* left  — red bg,  white text */
.popup.theme-center { background: #fbf7ee; color: #8a6d0a; }   /* center— white bg, dark-yellow text */
.popup.theme-right  { background: #234fb0; color: #f2f5ff; }   /* right — blue bg, white text */

/* Falling-petal back layer — pinned behind every mesh and text (z-index -1, below
   #bg-text at 0). Drawn on a 2D canvas; see the petal system in main.js. */
#petals {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0; /* JS fades this to 1 on the first active frame (slow reveal) */
  transition: opacity 2.5s ease;
}

/* Poem panel — right half, scroll-reveal in phase 2 */
.poem {
  position: fixed;
  top: 0;
  right: 0;
  width: 50vw;
  height: 100%;
  overflow-y: auto;
  /* Top pad parks the first line at screen centre, so it reveals as the poem
     opens (the "very beginning"). Bottom pad lets the last line scroll up to
     centre too. Both keys off the -48% centre band in the IntersectionObserver. */
  padding: 50vh 6vw 50vh 4vw;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.8s ease;
  z-index: 5;
  user-select: none;
}

.poem.active {
  opacity: 1;
  pointer-events: auto;
}

.poem-inner {
  max-width: 34ch;
}

.poem .line {
  font-family: "Cormorant Garamond", serif;
  font-size: clamp(20px, 2.4vw, 34px);
  line-height: 1.5;
  color: #2a2620;
  margin-bottom: 0.9em;
}

.poem .signature {
  font-family: "Caveat", cursive;
  font-size: clamp(28px, 3.2vw, 46px);
  color: #6b4f3a;
  margin-top: 1.4em;
}

/* Each word is an atomic box: it lays out on the line as one unit and never
   breaks internally, so a word always stays whole (wraps only at the spaces). */
.poem .p-word {
  display: inline-block;
  white-space: nowrap;
}

/* Each VISUAL row (a wrapped line-break) slides in as its own unit. Its slide is
   timed off the SAME character sweep as the darkening: it starts when this row's
   first glyph begins darkening (first * sweep-step) and lasts exactly as long as
   the wavefront takes to cross the row plus one glyph's fade —
   (last - first) * sweep-step + reveal-speed — so slide and reveal finish together. */
.poem .p-row {
  display: block;
  transform: translateX(calc(-1 * var(--poem-reveal-shift)));
  transition:
    transform calc((var(--poem-row-last) - var(--poem-row-first)) * var(--poem-sweep-step) + var(--poem-reveal-speed)) var(--poem-reveal-ease) calc(var(--poem-row-first) * var(--poem-sweep-step));
}

.poem .line.revealed .p-row,
.poem .signature.revealed .p-row {
  transform: translateX(0);
}

/* Per-character fade — each glyph starts faint and darkens to solid on its own
   index * sweep-step delay, so the darkening sweeps left-to-right across the line.
   No transform here anymore; the slide is handled per-line above. */
.poem .p-char {
  display: inline-block;
  opacity: var(--poem-rest-opacity);
  transition: opacity var(--poem-reveal-speed) var(--poem-reveal-ease);
  transition-delay: calc(var(--poem-char-index, 0) * var(--poem-sweep-step));
}

.poem .line.revealed .p-char,
.poem .signature.revealed .p-char {
  opacity: 1;
}