:root {
  --ground: #f5cbb7;
  --ink: #4a2334;
  --ink-soft: #8a5063;
  --stage-height: 100vh;
  --stage-height: 100svh;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: Georgia, "Times New Roman", serif;
  -webkit-font-smoothing: antialiased;
}

/* ---------- gate ---------- */
#gate {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--ground);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  /* `visibility` is delayed until the fade finishes, then flips to hidden.
     `pointer-events: none` alone blocks taps but NOT Tab — without this a
     keyboard user lands on an invisible "tap to begin" button after the gate
     has closed. */
  transition: opacity 0.9s ease, visibility 0s linear 0.9s;
  visibility: visible;
}
#gate.dismissed {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}
#gate-rose { width: 140px; height: 170px; }
.gate-for { margin: 0; font-style: italic; font-size: 21px; color: var(--ink); }
#enter {
  font: inherit;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid rgba(74, 35, 52, 0.3);
  border-radius: 999px;
  /* The type is deliberately small and quiet, but the tap target is not:
     min-height keeps it at the 44px minimum for a one-handed phone tap. */
  padding: 13px 26px;
  min-height: 44px;
  cursor: pointer;
}
#enter:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------- pinned stage ---------- */
#track {
  height: 640vh;
  height: 640svh;
  position: relative;
}
#stage {
  position: sticky;
  top: 0;
  height: var(--stage-height);
  overflow: hidden;
  background: var(--ground);
}
#scene { position: absolute; inset: 0; width: 100%; height: 100%; }

/* `fixed`, not `absolute`: over 6.4 screens of scroll, iOS Safari retracts its
   toolbar and the visual viewport grows past 100svh. An absolutely positioned
   layer scoped to #stage would leave a bare, unpainted strip at the bottom;
   fixed positioning covers the visual viewport regardless of chrome.
   TODO: confirm on a real iOS device — untested here, no browser available. */
.brush {
  position: fixed;
  inset: 0;
  pointer-events: none;
  opacity: 0.6;
  background:
    radial-gradient(60% 40% at 20% 16%, rgba(252, 226, 210, 0.75), transparent 70%),
    radial-gradient(52% 36% at 82% 60%, rgba(228, 176, 152, 0.5), transparent 72%),
    radial-gradient(70% 50% at 45% 94%, rgba(240, 200, 178, 0.55), transparent 70%);
}
.texture {
  position: fixed;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: 0.34;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.7' numOctaves='4'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.4'/></svg>");
}

/* ---------- letter: phone is a pinned lower band ----------
   Height is sized to the LONGEST block, not the average. At 16.5px/1.66 in a
   330px measure that is ~40 characters per line; the longest paragraph runs
   ~276 characters, so 7 lines ≈ 192px. 260px leaves headroom for wider glyph
   rendering on other devices. A band sized to the average silently clips. */
#letter {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 36px;
  height: 260px;
  z-index: 6;
  /* No padding here: .block is absolutely positioned, so its own left/right
     insets set the margin. Padding on this element would be inert. */
}
.block {
  position: absolute;
  left: 30px;
  right: 30px;
  top: 0;
  margin: 0;
  font-size: 16.5px;
  line-height: 1.66;
  color: var(--ink);
}
.block.closing { font-style: italic; }

/* ---------- desktop: real side columns ---------- */
@media (min-width: 900px) {
  #letter {
    inset: 0;
    height: auto;
    padding: 0;
  }
  /* Vertical centring uses margin-top, NOT transform: the render loop owns
     the transform property on .block and would overwrite it. */
  .block {
    position: absolute;
    top: 50%;
    margin-top: -3em;
    left: auto;
    right: auto;
    width: 300px;
    font-size: 17px;
  }
  .block:nth-child(odd)  { left: 6vw; }
  .block:nth-child(even) { right: 6vw; text-align: right; }
}

/* ---------- chrome ---------- */
#progress {
  position: fixed;
  left: 0;
  top: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--ink-soft);
  z-index: 40;
}
#mute {
  position: fixed;
  top: calc(14px + env(safe-area-inset-top));
  right: 14px;
  z-index: 40;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(74, 35, 52, 0.28);
  background: rgba(255, 244, 236, 0.55);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-size: 14px;
  cursor: pointer;
}
#mute:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---------- no-JS and reduced motion ---------- */
.no-js #track { height: auto; }
.no-js #stage { position: static; height: auto; padding: 40px 0; }
.no-js #letter { position: static; height: auto; }
.no-js .block { position: static; margin: 0 0 24px; opacity: 1; }
.no-js #gate { display: none; }
.no-js #scene,
.no-js .brush,
.no-js .texture { display: none; }

@media (prefers-reduced-motion: reduce) {
  #gate { transition: none; }
}
