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

:root {
  --mint: #d2f9e6;
  --ink: #0f4d3a;
  --moss: #17805f;
  --sheet-radius: 4.7rem;
  --landing-drift: 30vh;
  --ease-rise: linear(0, 0.003 2%, 0.014 6.1%, 0.026 10.2%, 0.041 14.3%, 0.059 18.4%, 0.08 22.4%,
    0.104 26.5%, 0.134 30.6%, 0.172 34.7%, 0.22 38.8%, 0.286 42.8%, 0.387 46.9%, 0.545 51%,
    0.693 55.1%, 0.781 59.2%, 0.838 63.2%, 0.878 67.3%, 0.909 71.4%, 0.932 75.5%, 0.951 79.5%,
    0.966 83.7%, 0.978 87.7%, 0.988 91.8%, 0.995 95.9%, 1);
}

html {
  scrollbar-width: none;
  background-color: var(--mint);
}

html::-webkit-scrollbar {
  width: 0;
  height: 0;
}

body {
  background-color: #000;
  min-height: 100dvh;
}

/* ---------- The two screens ---------- */

.cover {
  position: relative;
  /* Puts back the mint the drift takes from behind the sheet's lower corners; the z-index is what makes it show over the positioned footer. */
  z-index: 1;
  background: linear-gradient(var(--mint) 50%, rgb(from var(--mint) r g b / 0) 50%);
}

.landing {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 100dvh;
  display: grid;
  place-items: center;
  overflow: hidden;
  background-color: var(--mint);
  transform: translate3d(0, calc(var(--landing-drift) * var(--scroll-progress, 0) * -1), 0);
}

.sheet {
  position: relative;
  z-index: 3;
  /* Two radii of slack: enough that mid-scroll the sheet is a plain rectangle with no corner showing. */
  min-height: calc(100dvh + var(--sheet-radius) * 2);
  /* Nothing painted behind the lower pair, so the landing's mint shows through them. */
  border-radius: var(--sheet-radius);
  background-color: #fff;
  color: var(--ink);
  display: grid;
  place-items: center;
  padding: 1.5rem;
}

/* ---------- The contact card ---------- */

.contact {
  width: min(100%, 84rem);
  padding: clamp(1.75rem, 4.6vw, 4.75rem) clamp(1.75rem, 4vw, 3.75rem);
  border-radius: clamp(1.75rem, 4vw, 3rem);
  background-color: var(--mint);
  color: var(--ink);
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  gap: clamp(2.5rem, 4vw, 3rem);
  font-family: 'Aspekta', system-ui, sans-serif;
}

.contact__intro {
  display: flex;
  flex-direction: column;
  gap: clamp(1.75rem, 4vw, 3.75rem);
}

/* Two weights of the one face stand in for Worth's roman/italic pairing. */
.contact__title {
  /* The cap sits ~0.1em below the em box top; trimming it puts the T on the input's top edge. */
  margin-top: -0.1em;
  font-family: 'Bricolage Grotesque', 'Bricolage Metrics Fallback', system-ui, sans-serif;
  font-size: clamp(2.75rem, 6vw, 5rem);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.04em;
}

.contact__title em {
  font-style: normal;
  font-weight: 700;
}

.contact__lede {
  max-width: 28ch;
  font-size: clamp(1.0625rem, 1.6vw, 1.5rem);
  font-weight: 250;
  line-height: 1.3;
  letter-spacing: -0.02em;
}

/* align-items: end is what pins the foot row's button to the card's right edge. */
.contact__form {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2rem;
}

.contact__fields {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.contact__row {
  display: flex;
  gap: 1.5rem;
}

.contact__row .field {
  flex: 1 1 0;
  min-width: 0;
}

/* The placeholder carries the label, so the real one is kept for assistive tech only. */
.field {
  display: block;
  position: relative;
}

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

.field__control {
  width: 100%;
  padding: 1.5rem;
  border: 1px solid transparent;
  border-radius: 1rem;
  background-color: #fff;
  color: var(--ink);
  font-family: 'Aspekta', system-ui, sans-serif;
  font-size: 1rem;
  font-weight: 250;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.field__control::placeholder {
  color: color-mix(in srgb, var(--ink) 50%, transparent);
}

.field__control:focus {
  outline: none;
  border-color: var(--moss);
}

/* The native arrow goes and a chevron is painted in its place, in ink. */
.field--select .field__control {
  appearance: none;
  padding-right: 3.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%230f4d3a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1.5rem center;
  background-size: 1rem 1rem;
  cursor: pointer;
  text-overflow: ellipsis;
}

/* Unselected, the select shows its disabled first option - which has to read as a placeholder. */
.field--select .field__control:invalid {
  color: color-mix(in srgb, var(--ink) 50%, transparent);
}

.field--select .field__control option {
  color: var(--ink);
}

.contact__foot {
  width: 100%;
  display: flex;
  justify-content: flex-end;
}

.contact__submit {
  flex: 0 0 auto;
  width: 10rem;
  padding: 1.5rem;
  /* Border and leading borrowed from .field__control, or the button stands 1.2px taller. */
  border: 1px solid transparent;
  border-radius: 1rem;
  background-color: var(--ink);
  color: var(--mint);
  font-family: 'Aspekta', system-ui, sans-serif;
  font-size: 1rem;
  font-weight: 250;
  line-height: 1.2;
  letter-spacing: -0.02em;
  text-align: center;
  cursor: pointer;
  transition: opacity 150ms ease;
}

.contact__submit:hover {
  opacity: 0.85;
}

/* One column: the card is the full width of the sheet's padding box. */
@media (max-width: 56rem) {
  .contact {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .contact__lede {
    max-width: none;
  }
}

@media (max-width: 34rem) {
  .contact__row {
    flex-direction: column;
  }

  .contact__submit {
    width: 100%;
  }
}

/* ---------- The footer, uncovered rather than animated ---------- */

.footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  background-color: #000;
  color: var(--mint);
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 4vh, 2.5rem);
  padding: clamp(2rem, 5vh, 3rem) clamp(1.5rem, 4vw, 3rem) clamp(1.5rem, 3vh, 2rem);
  font-family: 'Aspekta', system-ui, sans-serif;
}

.footer__wordmark {
  font-family: 'Bricolage Grotesque', 'Bricolage Metrics Fallback', system-ui, sans-serif;
  font-size: clamp(4rem, 16vw, 13rem);
  font-weight: 700;
  line-height: 0.82;
  letter-spacing: -0.03em;
}

.footer__copyright {
  font-size: 0.9375rem;
  font-weight: 250;
  letter-spacing: -0.01em;
  opacity: 0.65;
}

/* The footer is fixed, so this gives its height back to the document to scroll through. */
.footer-spacer {
  height: var(--footer-height, 0px);
}

/* ---------- The discovery call button ---------- */

.topbar {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  padding: clamp(1rem, 2.4vw, 1.75rem);

  /* Arrives with the lede, once the word has finished building. */
  animation: topbar-arrive 817ms var(--ease-rise) 4520ms both;
}

@keyframes topbar-arrive {
  from { opacity: 0.001; transform: translateY(-12px); }
  to   { opacity: 1; transform: translateY(0); }
}

.cta {
  position: relative;
  /* The clip is what sells the roll: both copies travel the button's full height, not the text's. */
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-width: 15rem;
  height: 2.75rem;
  padding: 0 0.75rem;
  border: 1px solid rgb(from var(--ink) r g b / 0.3);
  border-radius: 2px;
  font-family: 'Aspekta', system-ui, sans-serif;
  font-size: 0.875rem;
  font-weight: 250;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgb(from var(--ink) r g b / 0.8);
  transition: border-color 300ms ease, color 300ms ease;
}

.cta:hover,
.cta:focus-visible {
  border-color: var(--ink);
  color: var(--ink);
}

/* The resting pair gives the button its width; the incoming pair is stretched over it so its transform is the roll alone. */
.cta__label--next,
.cta__icon--next {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
}

.cta__label--next { left: 0.75rem; }
.cta__icon--next { right: 0.75rem; }

.cta__icon {
  display: flex;
  align-items: center;
}

.cta__arrow {
  width: 0.8125rem;
  height: 0.8125rem;
}

.cta__label,
.cta__icon {
  transition: transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Below the button, and the arrow additionally to the left, so it comes in on the diagonal. */
.cta__label--next { transform: translateY(2.35em); }
.cta__icon--next  { transform: translate(-1.8em, 2.35em); }

.cta:hover .cta__label,
.cta:focus-visible .cta__label { transform: translateY(-3.6em); }

.cta:hover .cta__icon,
.cta:focus-visible .cta__icon { transform: translate(1.8em, -3.6em); }

.cta:hover .cta__label--next,
.cta:focus-visible .cta__label--next,
.cta:hover .cta__icon--next,
.cta:focus-visible .cta__icon--next { transform: translate(0, 0); }

@media (max-width: 40rem) {
  .cta {
    min-width: 0;
    gap: 1rem;
    height: 2.375rem;
    font-size: 0.75rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .topbar {
    animation: letter-appear 300ms linear 4520ms both;
  }

  /* The swap still happens, it just does not travel: the second pair is simply not used. */
  .cta__label,
  .cta__icon {
    transition: none;
  }

  .cta__label--next,
  .cta__icon--next {
    display: none;
  }
}

/* ---------- The wordmark ---------- */

/* The build runs on delays against page load, 150ms to 4520ms, each set on its own rule. */

.wordmark {
  grid-area: 1 / 1;
  /* Block, not flex: flex blockifies each letter span, and glyphs shaped in isolation lose their kerning. */
  display: block;
  text-align: center;
  padding: 1.5rem;
  font-family: 'Bricolage Grotesque', 'Bricolage Metrics Fallback', system-ui, sans-serif;
  font-size: clamp(4.8rem, 29vw, 24rem);
  font-weight: 700;
  line-height: 1;
  color: var(--ink);

  /* The line the letters drop through: above it nothing is painted. */
  --reveal-line: calc(1.5rem + 0.071em);
  -webkit-mask-image: linear-gradient(to bottom, transparent var(--reveal-line), #000 var(--reveal-line));
  mask-image: linear-gradient(to bottom, transparent var(--reveal-line), #000 var(--reveal-line));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* Offset with top, not transform: a transform needs inline-block, which costs the kerning. */
.wordmark__letter {
  position: relative;
}

/* The real letter stays in the line, inked transparent, so it keeps its advance, its kerning and the word for assistive tech. */
.wordmark__letter--slot {
  color: transparent;
}

.wordmark__grow,
.wordmark__stem,
.wordmark__tittle,
.wordmark__slide,
.wordmark__point,
.wordmark__one,
.wordmark__rise {
  position: absolute;
  line-height: 1.1988;
  color: var(--ink);
}

/* ---------- The "a" ---------- */

.wordmark__mark {
  position: absolute;
  left: 50%;
  top: 0.667em;
  width: 0.54em;
  height: auto;
  transform: translate(-50%, -50%);
  animation: mark-spin-in 900ms cubic-bezier(0.16, 1, 0.3, 1) 650ms both,
             mark-wind-down 460ms cubic-bezier(0.5, 0, 0.8, 0.4) 3030ms forwards;
}

@keyframes mark-spin-in {
  from { transform: translate(-50%, -50%) rotate(-540deg) scale(0); }
  to   { transform: translate(-50%, -50%) rotate(0deg) scale(1); }
}

/* It keeps turning the way it came in rather than reversing. */
@keyframes mark-wind-down {
  from { transform: translate(-50%, -50%) rotate(0deg) scale(1); }
  to   { transform: translate(-50%, -50%) rotate(180deg) scale(0); }
}

/* The a grows out of the point the burst collapses to - the same centre, measured off the glyph. */
.wordmark__grow {
  left: 0;
  top: 0;
  transform-origin: 0.26em 0.6669em;
  animation: letter-grow 460ms cubic-bezier(0.2, 0.75, 0.3, 1) 3560ms both;
}

@keyframes letter-grow {
  from { transform: scale(0); }
  to   { transform: scale(1); }
}

/* ---------- The "i" ---------- */

.wordmark__stem {
  left: 0;
  top: 0;
  animation: stem-grow 640ms cubic-bezier(0.33, 0, 0.25, 1) 150ms both;
}

/* The clip travels up from the baseline, so the stem rises out of the line from nothing. */
@keyframes stem-grow {
  from { clip-path: inset(1.86em 0 0 0); }
  to   { clip-path: inset(0.379em 0 0 0); }
}

.wordmark__dot {
  position: absolute;
  left: 50%;
  top: 0.287em;
  width: 0.19em;
  height: auto;
  transform: translate(-50%, -50%);
  animation: dot-fall 460ms 650ms both,
             star-lift-off 460ms cubic-bezier(0.55, 0, 0.85, 0.4) 3030ms forwards;
}

/* Falls and lands: it stops dead on the line and spends the momentum deforming. */
@keyframes dot-fall {
  0% {
    top: -0.55em;
    transform: translate(-50%, -50%) scale(0.88, 1.18);
    animation-timing-function: cubic-bezier(0.75, 0, 0.9, 0.35);
  }
  45% {
    top: 0.287em;
    transform: translate(-50%, -50%) scale(1.24, 0.76);
    animation-timing-function: cubic-bezier(0.25, 0, 0.2, 1);
  }
  68% {
    transform: translate(-50%, -50%) scale(0.92, 1.08);
    animation-timing-function: ease-in-out;
  }
  85% {
    transform: translate(-50%, -50%) scale(1.04, 0.96);
    animation-timing-function: ease-in-out;
  }
  100% {
    top: 0.287em;
    transform: translate(-50%, -50%) scale(1, 1);
  }
}

/* It fell onto the stem, so it lifts off it - out through the same cut in the mask that the f fell through. */
@keyframes star-lift-off {
  from { transform: translate(-50%, -50%) translateY(0) scale(1, 1); }
  to   { transform: translate(-50%, -50%) translateY(-0.75em) scale(1, 1); }
}

/* A copy of the i cut down to its dot; the clip travels with the letter, so it is set once and never animated. */
.wordmark__tittle {
  left: 0;
  top: 0;
  clip-path: inset(0.18em 0 0.8188em 0);
  animation: tittle-drop 460ms cubic-bezier(0.3, 0.2, 0.35, 1) 3560ms both;
}

/* 0.30em, not the star's 0.75em: an arrival cannot spend most of its travel above the mask line. */
@keyframes tittle-drop {
  from { transform: translateY(-0.3em); }
  to   { transform: translateY(0); }
}

/* ---------- The "r" ---------- */

/* A static box that does the hiding; the copy inside it slides out. A clip-path on the moving letter mis-composites. */
.wordmark__hide {
  position: absolute;
  left: -0.026em;
  top: 0;
  width: 1em;
  height: 1.2em;
  overflow: hidden;
}

.wordmark__slide {
  left: 0.026em;
  top: 0;
  animation: r-step-out 520ms cubic-bezier(0.45, 0.05, 0.3, 1) 1550ms both;
}

@keyframes r-step-out {
  from { transform: translateX(-0.5em); }
  to   { transform: translateX(0); }
}

/* ---------- The "s" ---------- */

/* The ground. Its bottom edge sits just below the lowest resting ink; the top clears the wordmark's own mask. */
.wordmark__ground {
  position: absolute;
  left: 0;
  top: -1.2em;
  width: 0.5103em;
  height: 2.16em;
  overflow: hidden;
}

.wordmark__one,
.wordmark__rise {
  top: 1.2em;
}

/* Offset so the 1's ink centre lands on the s's, not its origin. */
.wordmark__one {
  left: 0.1202em;
  animation: one-rise 480ms cubic-bezier(0.15, 0.72, 0.35, 1) 1110ms both,
             column-lift-out 640ms cubic-bezier(0.4, 0, 0.25, 1) 1790ms forwards;
}

.wordmark__rise {
  left: 0;
  animation: column-lift-in 640ms cubic-bezier(0.4, 0, 0.25, 1) 1790ms both;
}

@keyframes one-rise {
  from { transform: translateY(0.95em); }
  to   { transform: translateY(0); }
}

/* 1.15em is the notch: it clears the ground at one end and the sky at the other. The two lifts must stay equal. */
@keyframes column-lift-in {
  from { transform: translateY(1.15em); }
  to   { transform: translateY(0); }
}

/* forwards, not both: with both it would fill backwards from load and there would be no rise to follow. */
@keyframes column-lift-out {
  from { transform: translateY(0); }
  to   { transform: translateY(-1.15em); }
}

/* ---------- The full stop ---------- */

/* One continuous 180deg sweep, hinged on the ink's left edge so the panel opens away from the s. */
.wordmark__stop {
  position: absolute;
  left: 50%;
  top: 0.8355em;
  width: 0.185em;
  height: auto;
  transform: translate(-50%, -50%);
  transform-origin: 0 50%;
  backface-visibility: hidden;
  animation: mark-hinge-in 460ms cubic-bezier(0.15, 0.6, 0.5, 1) 2070ms both,
             mark-hinge-out 460ms cubic-bezier(0.5, 0, 0.85, 0.4) 3030ms forwards;
}

@keyframes mark-hinge-in {
  from { transform: translate(-50%, -50%) perspective(1.6em) rotateY(90deg); }
  to   { transform: translate(-50%, -50%) perspective(1.6em) rotateY(0deg); }
}

@keyframes mark-hinge-out {
  from { transform: translate(-50%, -50%) perspective(1.6em) rotateY(0deg); }
  to   { transform: translate(-50%, -50%) perspective(1.6em) rotateY(-90deg); }
}

/* The stop hinges in behind the mark, on what is for all purposes the same line. */
.wordmark__point {
  left: 0;
  top: 0;
  transform-origin: 0.0175em 50%;
  backface-visibility: hidden;
  animation: stop-hinge-in 460ms cubic-bezier(0.15, 0.6, 0.5, 1) 3560ms both;
}

@keyframes stop-hinge-in {
  from { transform: perspective(1.6em) rotateY(-90deg); }
  to   { transform: perspective(1.6em) rotateY(0deg); }
}

/* ---------- The "f" ---------- */

.wordmark__letter--drop {
  animation: letter-drop 820ms 150ms both;
}

@keyframes letter-drop {
  0% {
    top: -0.95em;
    animation-timing-function: cubic-bezier(0.45, 0, 0.75, 0.35);
  }
  42% {
    top: 0.13em;
    animation-timing-function: cubic-bezier(0.25, 0.8, 0.4, 1);
  }
  68% {
    top: -0.045em;
    animation-timing-function: ease-in-out;
  }
  86% {
    top: 0.015em;
    animation-timing-function: ease-in-out;
  }
  100% {
    top: 0;
  }
}

/* ---------- Reduced motion: the same schedule, without the travel ---------- */

@keyframes letter-appear {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes icon-fade-out {
  to { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .landing {
    transform: none;
  }

  .wordmark__letter--drop,
  .wordmark__stem {
    animation: letter-appear 300ms linear 150ms both;
  }

  .wordmark__dot,
  .wordmark__mark {
    animation: letter-appear 300ms linear 650ms both,
               icon-fade-out 460ms linear 3030ms forwards;
  }

  .wordmark__slide {
    animation: letter-appear 300ms linear 1550ms both;
  }

  .wordmark__stop {
    animation: letter-appear 300ms linear 2070ms both,
               icon-fade-out 460ms linear 3030ms forwards;
  }

  .wordmark__grow,
  .wordmark__tittle,
  .wordmark__point {
    animation: letter-appear 300ms linear 3560ms both;
    transform: none;
  }

  /* The 1 is a joke told in movement, so it stays under the ground and the s fades up in the slot. */
  .wordmark__one {
    animation: none;
    transform: translateY(0.95em);
  }

  .wordmark__rise {
    animation: letter-appear 300ms linear 3270ms both;
    transform: none;
  }
}

/* ---------- The line under the word ---------- */

.lede {
  grid-area: 1 / 1;
  align-self: end;
  justify-self: center;
  z-index: 2;
  margin-bottom: 11vh;
  padding: 0 1.5rem;
  font-family: 'Aspekta', system-ui, sans-serif;
  font-size: clamp(1rem, 1.7vw, 1.375rem);
  font-weight: 250;
  line-height: 1.3;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--ink);

  /* Rises with the 3D mark, on the same delay. */
  animation-name: lede-rise;
  animation-duration: 817ms;
  animation-delay: 4520ms;
  animation-fill-mode: both;
  /* Its own longhand, so a browser without linear() falls back to ease here and keeps the rest. */
  animation-timing-function: var(--ease-rise);
}

/* Fade and travel on one curve: a flat start, a vertical middle, a long settle - hence the sampled easing. */
@keyframes lede-rise {
  from { opacity: 0.001; transform: translateY(120px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* After .lede's own rule rather than up with the rest, since the two have the same specificity. */
@media (prefers-reduced-motion: reduce) {
  .lede {
    animation-name: letter-appear;
    animation-duration: 300ms;
    animation-timing-function: linear;
  }
}

/* ---------- The 3D mark, layered over the wordmark ---------- */

.landing__mark {
  grid-area: 1 / 1;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

/* Camera framing is tied to height, so --stage-height sets how big the mark renders; width only buys backdrop. */
.logo3d {
  --stage-height: min(clamp(422px, 67vh, 809px), 92vw);
  position: relative;
  width: min(100%, calc(var(--stage-height) * 1.4));
  height: var(--stage-height);
  transform: translateY(-4%);
  touch-action: none;
}

/* Hidden until logo3d.js says the word is built: the plane behind the glass is a copy of the FINISHED wordmark. */
.logo3d__canvas {
  display: block;
  width: 100%;
  height: 100%;
  visibility: hidden;
}

.logo3d.is-live .logo3d__canvas {
  visibility: visible;
}

body.is-dragging {
  user-select: none;
}

/* ---------- Fonts ---------- */

@font-face {
  font-family: 'Aspekta';
  src: url('../fonts/aspekta/Aspekta-250.otf') format('opentype');
  font-weight: 250;
  font-style: normal;
  font-display: swap;
}

/* block, not swap: every offset in the wordmark is measured off this face's metrics. */
@font-face {
  font-family: 'Bricolage Grotesque';
  src: url('../fonts/BricolageGrotesque-VariableFont_opsz,wdth,wght.ttf') format('truetype-variations');
  font-weight: 200 800;
  font-style: normal;
  font-display: block;
}

/* If Bricolage never loads, these overrides keep the baseline where the measured offsets expect it. */
@font-face {
  font-family: 'Bricolage Metrics Fallback';
  src: local('Helvetica Neue'), local('Arial'), local('Liberation Sans');
  ascent-override: 92.94%;
  descent-override: 26.94%;
  line-gap-override: 0%;
}

/* ---------- The start gate ---------- */

/* Every entrance is filled, so pausing holds each on its first keyframe until boot.js says the page has loaded. */
html:not(.is-ready) *,
html:not(.is-ready) *::before,
html:not(.is-ready) *::after {
  animation-play-state: paused !important;
}

/* The sequence is staged against the top of the page, so nothing can be scrolled away mid-build. */
html.is-locked {
  overflow: hidden;
  touch-action: none;
}
