/* Palette from the Happenings style guide (paper, charcoal); petals sampled from the logo. */
:root {
  --paper: #FAFAF8;
  --char: #1F1E22;
  --ink-soft: #5A585E;
  --on-char: #F1F0EC;
  --m: clamp(24px, 4.4vw, 64px);
  --expo: cubic-bezier(0.16, 1, 0.3, 1);
  --glide: cubic-bezier(0.4, 0, 0.15, 1);
  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
html { background: var(--paper); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  color: var(--char);
  font-family: "Libre Franklin", "Helvetica Neue", Arial, sans-serif;
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
p, h1, h2 { margin: 0; font-weight: inherit; }

/* The rosette sits behind every pane. Without JS or with reduced motion it simply rests in place. */
.stage { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.night { position: absolute; inset: 0; background: var(--char); opacity: 0; }
.rig {
  --d: min(120vh, 86vw);
  position: absolute;
  left: 70%;
  top: 52%;
  width: var(--d);
  height: var(--d);
  margin: calc(var(--d) / -2) 0 0 calc(var(--d) / -2);
}
.spin, .petal, .bloom, .petal svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.petal svg { overflow: visible; }
.glow { position: absolute; inset: -20%; opacity: 0; }
.glow img { display: block; width: 100%; height: 100%; }
.ripple, .ring, .comet { position: absolute; inset: -2%; border-radius: 50%; opacity: 0; pointer-events: none; }
.current { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; fill: none; }
.run { stroke-dasharray: 0.13 1; stroke-dashoffset: 0.13; stroke-linecap: round; opacity: 0; }
.core { stroke: #FFFEFA; stroke-width: 2.5; }
.halo { stroke: #FFFEFA; stroke-width: 11; stroke-opacity: 0.2; }

main { position: relative; z-index: 1; }

.act { min-height: 100svh; padding: var(--m); }

/* Pane 1 */
.hero {
  display: grid;
  grid-template-rows: auto 1fr 1px;
  gap: 24px;
}
.mast { font-size: 1rem; font-weight: 400; letter-spacing: -0.005em; }
h1 {
  align-self: center;
  font-size: clamp(3.5rem, 10vw, 10.5rem);
  font-weight: 100;
  line-height: 0.98;
  letter-spacing: -0.045em;
}
.w { display: block; overflow: hidden; padding-bottom: 0.14em; margin-bottom: -0.14em; }
.w > span { display: block; }
.cue {
  display: none;
  width: 72px;
  height: 1px;
  background: currentColor;
  transform-origin: left;
}

/* Panes 2 and 3: the page goes dark and the type turns over */
.dark { background: var(--char); color: var(--on-char); }
.hold { display: flex; align-items: center; min-height: calc(100svh - 2 * var(--m)); }
h2 {
  max-width: 13ch;
  font-size: clamp(2.75rem, 7.4vw, 7.75rem);
  font-weight: 100;
  line-height: 1.02;
  letter-spacing: -0.04em;
}
.line h2 { font-size: clamp(2.75rem, 6.2vw, 6.5rem); }
h2 span { display: block; }
h2 .l2 { margin-top: 0.28em; font-weight: 300; }
.plat h2 { max-width: 15ch; font-size: clamp(2.5rem, 4.4vw, 5rem); }
.plat h2 span { text-wrap: balance; }
.plat h2 .l2 { margin-top: 0.22em; }

/* Pane 4 */
.closing {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  padding-bottom: 0;
  background: var(--paper);
  text-align: center;
}
.gold {
  max-width: 16ch;
  margin-bottom: auto;
  margin-top: 56vh;
  text-wrap: balance;
  font-size: clamp(2.5rem, 6.2vw, 6.5rem);
  font-weight: 100;
  line-height: 1.04;
  letter-spacing: -0.04em;
}

footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-self: stretch;
  gap: 4px 40px;
  padding: 16px 0 calc(16px + env(safe-area-inset-bottom));
  color: var(--ink-soft);
  font-size: 0.9375rem;
  font-weight: 400;
  text-align: left;
}
footer p { display: flex; align-items: center; gap: 0.3em; min-height: 44px; }
footer a { display: inline-flex; align-items: center; min-height: 44px; color: var(--char); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.25em; transition: text-underline-offset 200ms var(--expo); }
footer a:hover { text-underline-offset: 0.4em; }
a:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 2px; }

/* With motion: one scroll is one pane, and the moves below play on their own clock */
.js .act { height: 100svh; }
@media (pointer: coarse) {
  html.js { scroll-snap-type: y mandatory; }
  .js .act { scroll-snap-align: start; scroll-snap-stop: always; }
}
.js .dark, .js .closing { background: transparent; }
.js .rig { left: 0; top: 0; margin: 0; will-change: transform; }
.js .spin { will-change: transform; }
.js .petal, .js .glow, .js .night, .js .ring { will-change: opacity; }
.js .comet, .js .ripple { will-change: transform, opacity; }

.ready .rig { transition: transform 1400ms var(--glide); }
.ready .petal { transition: opacity 800ms ease-out; }
.ready .night { transition: opacity 1000ms ease-in-out; }
.ready .glow { transition: opacity 500ms ease-out; }

[data-pane="1"] .night, [data-pane="2"] .night { opacity: 1; }

/* Pane 2: the color drains away and the structure underneath draws itself */
[data-pane="1"] .petal { opacity: 0; }
.blueprint { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; opacity: 0; fill: none; }
.guides { stroke: var(--on-char); stroke-opacity: 0.2; stroke-width: 1; }
.lines { stroke-width: 1.5; }
.blueprint .d { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 0s linear 800ms; }
.ready .blueprint { transition: opacity 700ms ease-out; }
.ready[data-pane="1"] .blueprint { opacity: 1; transition: opacity 300ms ease-out; }
.ready[data-pane="1"] .blueprint .d { stroke-dashoffset: 0; transition: stroke-dashoffset 1900ms cubic-bezier(0.5, 0, 0.1, 1) var(--t); }

/* Pane 3, "the one": a single point of light runs through the six hearts in turn, filling each as it passes */
.ready[data-pane="2"] .blueprint { opacity: 1; }
.ready[data-pane="2"] .blueprint .d { stroke-dashoffset: 0; transition: stroke-dashoffset 500ms ease-out; }
.ready[data-pane="2"] .run { animation: run 780ms linear both; animation-delay: calc(var(--i) * 240ms + 300ms); }
@keyframes run {
  0% { stroke-dashoffset: 0.13; opacity: 0; }
  6% { opacity: 1; }
  94% { opacity: 1; }
  100% { stroke-dashoffset: -1; opacity: 0; }
}
.ready[data-pane="2"] .petal { transition: opacity 700ms ease-out calc(var(--i) * 240ms + 430ms); }
.lines path { transition: opacity 300ms ease-out; }
.ready[data-pane="2"] .blueprint .lines path { opacity: 0; transition: stroke-dashoffset 500ms ease-out, opacity 500ms ease-out calc(var(--i) * 240ms + 720ms); }
.guides { transition: opacity 300ms ease-out; }
[data-pane="2"] .guides { opacity: 0; transition: opacity 800ms ease-out 1900ms; }

/* "operating system": the rosette powers on, a ripple goes out, and a slow orbit keeps running */
[data-pane="2"] .glow { opacity: 0.74; }
.ready[data-pane="2"] .glow { transition: opacity 1000ms ease-out 2050ms; }
[data-pane="2"] .glow img { animation: breathe 7s ease-in-out 3400ms infinite alternate; }
@keyframes breathe {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0.55; transform: scale(1.035); }
}
.ripple { border: 1.5px solid var(--on-char); }
.ready[data-pane="2"] .ripple { animation: ripple 1900ms var(--expo) 2100ms both; }
.ready[data-pane="2"] .ripple.second { animation-delay: 2420ms; }
@keyframes ripple {
  0% { opacity: 0; transform: scale(0.62); }
  2% { opacity: 0.55; }
  100% { opacity: 0; transform: scale(1.5); }
}
.ring { border: 1px solid var(--on-char); }
[data-pane="2"] .ring { opacity: 0.13; }
.ready .ring, .ready .comet { transition: opacity 350ms ease-out; }
.ready[data-pane="2"] .ring { transition: opacity 1200ms ease-out 2600ms; }
.comet {
  background: conic-gradient(from 0deg, transparent 0 58%, #CCC3E6 70%, #BAE2E1 80%, #CDE298 86%, #FEE89A 91%, #FDAD88 96%, #F5ABB5 100%);
  -webkit-mask: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
  mask: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
}
[data-pane="2"] .comet { opacity: 1; }
.ready[data-pane="2"] .comet { transition: opacity 1200ms ease-out 2600ms; animation: orbit 11s linear infinite; }
@keyframes orbit { to { transform: rotate(360deg); } }

/* Words: quick to leave, and arriving on their own beats once a pane is current */
.js .fade { opacity: 0; transform: translate3d(0, 14px, 0); transition: opacity 350ms ease-out, transform 350ms ease-out; }
.js .on .fade {
  opacity: 1;
  transform: none;
  transition: opacity 1000ms ease-out var(--beat, 250ms), transform 1400ms var(--expo) var(--beat, 250ms);
}
.js .l2 { --beat: 800ms; }
.js .gold { --beat: 600ms; }
.js .plat .l1 { --beat: 200ms; }
.js .plat .l2 { --beat: 1250ms; }
.js .closing footer { opacity: 0; transition: opacity 350ms ease-out; }
.js .closing.on footer { opacity: 1; transition: opacity 1000ms ease-out 1100ms; }
.js .hero h1, .js .mast { transition: opacity 350ms ease-out; }
.js .hero:not(.on) h1, .js .hero:not(.on) .mast, .js .hero:not(.on) .cue { opacity: 0; }

/* The opening: six petals open in turn, then the words rise */
.js .bloom { animation: bloom 2000ms var(--expo) both; animation-delay: calc(var(--i) * 130ms + 120ms); }
@keyframes bloom {
  from { opacity: 0; transform: rotate(-46deg) scale(0.3); }
  to { opacity: 1; transform: none; }
}
.js .spin { animation: spin 360s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.js .w > span { animation: rise 1500ms var(--expo) both; animation-delay: calc(var(--i) * 140ms + 620ms); }
@keyframes rise {
  from { transform: translateY(108%); }
  to { transform: none; }
}
/* backwards only: a forwards fill would hold opacity against the pane rules above */
.js .mast { animation: arrive 1200ms ease-out 1300ms backwards; }
@keyframes arrive { from { opacity: 0; } to { opacity: 1; } }
.js .cue { display: block; align-self: end; animation: draw 2800ms var(--expo) 2000ms infinite; }
@keyframes draw {
  0% { transform: scaleX(0); opacity: 1; }
  70% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 0; }
}

@media (max-width: 760px) {
  h1 { align-self: end; font-size: clamp(3.25rem, 16.5vw, 6rem); }
  .hold { align-items: flex-end; }
  .gold { margin-top: 46vh; }
  footer { flex-direction: column; gap: 0; padding-top: 8px; }
  .rig { --d: 118vw; left: 60%; top: 36%; }
}
