/* ---------------------------------------------------------------------
   Blunt House Studio — coming soon page
   ------------------------------------------------------------------- */

:root {
  /* A "whiteprint" (diazo) palette — blue linework on warm white paper,
     the modern successor to the traditional blue-paper blueprint. */
  --bg: #f7f5f0;
  --bg-soft: #eeebe2;

  --line-rgb: 42, 84, 150;
  --line: rgba(var(--line-rgb), 0.68);
  --line-soft: rgba(var(--line-rgb), 0.32);
  --line-faint: rgba(var(--line-rgb), 0.14);
  --line-strong: #1c3d73;

  --ink: #1c1f26;
  --ink-muted: rgba(28, 31, 38, 0.64);
  --ink-faint: rgba(28, 31, 38, 0.42);

  /* Matches --line-strong: the primary CTA uses the same blue as the rest
     of the blueprint linework instead of an unrelated accent hue. */
  --accent-rgb: 28, 61, 115;
  --accent: #1c3d73;
  --accent-ink: #f7f5f0;

  --font-display: 'Archivo', 'Arial Black', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Inter', system-ui, sans-serif;

  --content-max: 40rem;

  /* Header bar height. .content reserves this much space at the top so the
     centered copy can never slide up underneath the logo/Contact row. */
  --topnav-h: 4.25rem;

  /* Fluid scale for the 3D blueprint scene. Stepped rather than a single
     vw-based value so it stays predictable, with a transition on the
     element that consumes it (.scene-stage) to smooth the steps out.
     --scene-scale grows with width; --scene-scale-max caps it by height so
     the sheet's bottom corner never runs off a short, wide window (a laptop
     browser is far wider than it is tall). The stage uses the smaller. */
  --scene-scale: 0.78;
  --scene-scale-max: 1.25;
}

@media (min-width: 400px) {
  :root { --scene-scale: 0.88; }
}
@media (min-width: 520px) {
  :root { --scene-scale: 1; }
}
@media (min-width: 640px) {
  :root {
    --scene-scale: 1.13;
    --topnav-h: 5.625rem;
  }
}
@media (min-width: 861px) {
  :root { --scene-scale: 1.25; }
}
@media (min-width: 1100px) {
  :root { --scene-scale: 1.56; }
}
@media (min-width: 1440px) {
  :root { --scene-scale: 1.74; }
}
@media (min-width: 1800px) {
  :root { --scene-scale: 2.16; }
}
@media (min-width: 2200px) {
  :root { --scene-scale: 2.44; }
}
@media (min-width: 2800px) {
  :root { --scene-scale: 2.81; }
}

/* Height caps, so the sheet's bottom corner stays clear of the bottom
   edge in windows that are short for their width (laptop browsers). */
@media (min-height: 700px) {
  :root { --scene-scale-max: 1.4; }
}
@media (min-height: 760px) {
  :root { --scene-scale-max: 1.56; }
}
@media (min-height: 880px) {
  :root { --scene-scale-max: 1.725; }
}
@media (min-height: 960px) {
  :root { --scene-scale-max: 1.89; }
}
@media (min-height: 1060px) {
  :root { --scene-scale-max: 2.09; }
}
@media (min-height: 1200px) {
  :root { --scene-scale-max: 2.375; }
}
@media (min-height: 1350px) {
  :root { --scene-scale-max: 2.675; }
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

/* Everything outside the 3D scene is sized in rem, so the root size is the
   one dial that grows the whole page on large screens. Phones, tablets and
   laptops stay at the browser default; past ~1600px wide it ramps up with
   the viewport (18px at 1920, capped at 21px), and the vh term keeps a
   short, wide window from scaling the copy past what fits on screen. */
html {
  font-size: clamp(1rem, min(0.375rem + 0.625vw, 2.1vh), 1.3125rem);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------ page shell ---------------------------- */

.page {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
  /* The tint is sized to the first screen, not the page, so it stays put
     when the contact panel makes the page taller. */
  background:
    radial-gradient(ellipse 70% 60% at 50% 46%, rgba(var(--line-rgb), 0.07), transparent 62%)
      top center / 100% 100vh no-repeat,
    var(--bg);
  background-size: 100% 100svh;
}

/* The background layers are pinned to the first screen's height rather
   than stretching with .page: they're positioned in percentages, so when
   the contact panel grew the page they slid down (and the scene's
   perspective shifted) even though nothing above the panel had moved. */
.scene-wrap,
.scrim {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 100vh;
  height: 100svh;
}

/* Soft vignette centered behind the text column — keeps the centered copy
   legible while letting the blueprint scene show through at the edges. */
.scrim {
  z-index: 1;
  /* Broad, soft veil over the copy — lets the sheet show through as a faint
     watermark. The opaque patch behind the form lives on
     .notify-form__row::before so it tracks the form at every size. */
  background:
    radial-gradient(
      ellipse 26% 34% at 50% 46%,
      rgba(247, 245, 240, 0.82) 0%,
      rgba(247, 245, 240, 0.55) 42%,
      rgba(247, 245, 240, 0.24) 66%,
      rgba(247, 245, 240, 0.04) 85%,
      transparent 100%
    );
  pointer-events: none;
}

/* -------------------------------- 3D scene ----------------------------- */

.scene-wrap {
  z-index: 0;
  perspective: 1600px;
  perspective-origin: 50% 50%;
}

/* Positions + scales the composition. Pure CSS, never touched by JS, so it
   stays in charge of responsive sizing across phones through ultrawide
   monitors. */
.scene-stage {
  position: absolute;
  top: 53%;
  left: 50%;
  width: 1px;
  height: 1px;
  transform-style: preserve-3d;
  transform: scale(min(var(--scene-scale, 1), var(--scene-scale-max, 99)));
  transition: transform 0.4s ease;
}

/* Centered on desktop so the larger sheet sits behind the copy and has
   equal room above and below; phones keep it a little lower. */
@media (min-width: 1100px) {
  .scene-stage {
    top: 50%;
  }
}

/* Interactive tilt only — a SMALL rotateX/rotateY delta from the mouse,
   applied as the outermost rotation (i.e. in true screen space, unaffected
   by the static base tilt nested inside it). JS drives this element's
   transform every frame; it must never set position/scale, and must never
   carry the base isometric angle itself, or the delta stops corresponding
   to simple up/down/left/right from the viewer's perspective. */
.scene {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  transform-style: preserve-3d;
  transform: rotateX(0deg) rotateY(0deg);
  will-change: transform;
}

/* The static isometric-ish base pose. Nested INSIDE .scene (not the other
   way around) so the interactive delta above always reads as screen-space
   tilt, regardless of this base orientation. Never touched by JS. */
.scene-base {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  transform-style: preserve-3d;
  transform: rotateX(58deg) rotateZ(-38deg);
}

/* A single "blueprint sheet" — a bordered, gridded drafting sheet sitting
   behind the content. Flat and un-rotated, like a card in the scene's local
   space; the scene's own rotateX/rotateZ tilt is what makes it read as
   receding at an angle, the same way the old ground plane did. */
.sheet {
  position: absolute;
  top: -165px;
  left: -240px;
  width: 480px;
  height: 330px;
  transform: translateZ(-50px);
  border: 1px solid var(--line);
  background: rgba(var(--line-rgb), 0.02);
}

.sheet__grid {
  position: absolute;
  inset: 16px;
  border: 1px solid var(--line-soft);
  background-image:
    linear-gradient(var(--line-faint) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-faint) 1px, transparent 1px);
  background-size: 28px 28px;
}

.sheet__tick {
  position: absolute;
  width: 18px;
  height: 18px;
}
.sheet__tick--tl {
  top: -9px;
  left: -9px;
  border-top: 1px solid var(--line-strong);
  border-left: 1px solid var(--line-strong);
}
.sheet__tick--tr {
  top: -9px;
  right: -9px;
  border-top: 1px solid var(--line-strong);
  border-right: 1px solid var(--line-strong);
}
.sheet__tick--bl {
  bottom: -9px;
  left: -9px;
  border-bottom: 1px solid var(--line-strong);
  border-left: 1px solid var(--line-strong);
}
.sheet__tick--br {
  bottom: -9px;
  right: -9px;
  border-bottom: 1px solid var(--line-strong);
  border-right: 1px solid var(--line-strong);
}

/* A drafting sheet's title block: a ruled corner box, left empty. */
.sheet__titleblock {
  position: absolute;
  right: 16px;
  bottom: 16px;
  width: 120px;
  height: 42px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line-strong);
  /* Semi-opaque rather than solid var(--bg): at the sheet's current scale a
     fully opaque fill read as an unexplained blank gap in the grid instead
     of a ruled title-block detail. Letting the grid show through faintly
     keeps it legible as an overlay, not a hole. */
  background: rgba(247, 245, 240, 0.6);
}
.sheet__titleblock-row {
  flex: 1;
  border-top: 1px solid var(--line);
}
.sheet__titleblock-row:first-child {
  border-top: none;
}

.dim-line {
  position: absolute;
  top: 0;
  left: 0;
  height: 1px;
  background: var(--line-soft);
  transform-style: preserve-3d;
}
.dim-line::before,
.dim-line::after {
  content: '';
  position: absolute;
  top: -4px;
  width: 1px;
  height: 9px;
  background: var(--line-soft);
}
.dim-line::before {
  left: 0;
}
.dim-line::after {
  right: 0;
}
.dim-line span {
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  white-space: nowrap;
}

/* Width dimension, run along the sheet's bottom edge */
.dim-line--1 {
  width: 480px;
  transform: translate3d(-240px, 180px, -50px) rotateX(90deg);
}
/* Height dimension, run along the sheet's right edge */
.dim-line--2 {
  width: 330px;
  transform: translate3d(255px, 0, -50px) rotateX(90deg) rotateZ(90deg);
}

/* -------------------------------- content ------------------------------ */

.content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Deliberately flex-start, not center. With centering, the intro/message/
     form group is positioned by redistributing the leftover space above and
     below it — so anything that changes the group's total height (like the
     contact panel opening) recalculates that redistribution and visibly
     shifts the headline and message too, even though nothing about them
     changed. Anchoring from a fixed top offset means growth below can only
     push the footer down; it has no way to move what's above it. */
  justify-content: flex-start;
  min-height: 100vh;
  min-height: 100dvh;
  max-width: var(--content-max);
  margin: 0 auto;
  /* Capped with clamp() rather than plain vw: vw padding keeps growing with
     viewport width even after max-width stops the box growing, which on
     ultrawide monitors was eating the entire content column. */
  padding: 5rem clamp(1.5rem, 6vw, 5rem) 5rem;
  /* 10rem is ~half the intro/message/form group's height, so this parks
     the group just above optical center without justify-content: center.
     The floor keeps it clear of the header on short screens. */
  padding-top: max(calc(var(--topnav-h) + 2.5rem), calc(48vh - 10rem));
  padding-top: max(calc(var(--topnav-h) + 2.5rem), calc(48svh - 10rem));
  gap: 1.75rem;
  text-align: center;
}

.intro,
.notify-form {
  width: 100%;
}

/* Keeps the copy above the form's backdrop patch where the two overlap. */
.intro,
.message {
  z-index: 1;
}

.message {
  margin: 0 auto;
  max-width: 36rem;
  font-size: clamp(1rem, 0.75rem + 0.8vw, 1.25rem);
  line-height: 1.6;
  color: var(--ink-muted);
  text-wrap: balance;
}

.reveal {
  opacity: 0;
  transform: translateY(14px);
  animation: reveal 0.9s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: var(--delay, 0ms);
}

@keyframes reveal {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Hero heading: the tagline as a small eyebrow over the headline. */
.intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}

.intro__tagline {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(0.8125rem, 0.6rem + 0.55vw, 1.0625rem);
  font-stretch: 75%;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--line-strong);
}

.intro__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 0.2rem + 5.1vw, 3.25rem);
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}

/* --------------------------------- nav ---------------------------------- */

/* Absolute, not fixed: a transparent fixed bar let the form scroll up
   underneath the logo once the contact panel made the page taller. */
.topnav {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  height: var(--topnav-h);
  padding: 0 clamp(1.5rem, 4vw, 2.5rem);
}

/* The logo lockup: house mark + BLUNTHOUSE over a ruled STUDIO. Everything
   is sized in em off this one font-size so it keeps its proportions. */
.logo {
  display: flex;
  align-items: center;
  gap: 0.7em;
  font-size: 0.8125rem;
  color: var(--ink);
  text-decoration: none;
}
.logo:focus-visible {
  outline: 2px solid var(--line-strong);
  outline-offset: 6px;
}

/* 2.34em = the wordmark's two lines (1em + 0.34em gap + 1em), so the mark
   stands exactly as tall as the text beside it. */
.logo__mark {
  display: block;
  flex-shrink: 0;
  height: 2.34em;
  width: auto;
  aspect-ratio: 460 / 499;
}

.logo__name {
  --track: 0.15em;
  display: flex;
  flex-direction: column;
  font-family: var(--font-display);
  font-weight: 900;
  line-height: 1;
  letter-spacing: var(--track);
  text-transform: uppercase;
  white-space: nowrap;
}

/* letter-spacing also trails the last letter; pulling it back keeps the
   visible letters flush with the rules under them. */
.logo__name-main {
  margin-right: calc(-1 * var(--track));
}

.logo__name-sub {
  display: flex;
  align-items: center;
  gap: 0.25em;
  margin-top: 0.34em;
}
.logo__name-sub::before,
.logo__name-sub::after {
  content: '';
  flex: 1;
  height: max(1.5px, 0.1em);
  border-radius: 1em;
  background: currentColor;
}
.logo__name-sub::after {
  margin-left: calc(-1 * var(--track));
}

.topnav__contact {
  flex-shrink: 0;
  padding: 0.5rem 0.125rem 0.375rem;
  background: none;
  border: none;
  border-bottom: 1px solid transparent;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.topnav__contact:hover {
  color: var(--line-strong);
  border-bottom-color: var(--line-soft);
}
.topnav__contact:focus-visible {
  outline: 2px solid var(--line-strong);
  outline-offset: 3px;
}
.topnav__contact[aria-expanded='true'] {
  color: var(--line-strong);
  border-bottom-color: var(--line-strong);
}

@media (min-width: 640px) {
  .logo {
    font-size: 1rem;
  }
}

/* --------------------------------- form -------------------------------- */

.notify-form__row {
  position: relative;
  display: flex;
  gap: 0.6rem;
  max-width: 28.75rem;
  margin: 0 auto;
}

.notify-form__row::before {
  content: '';
  position: absolute;
  inset: -3rem -5rem;
  z-index: -1;
  background: radial-gradient(
    closest-side,
    var(--bg) 72%,
    rgba(247, 245, 240, 0.85) 86%,
    transparent 100%
  );
  pointer-events: none;
}

/* 1rem minimum on all inputs: iOS Safari zooms the page on focus below 16px. */
.notify-form__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 3rem;
  padding: 0 1rem;
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(var(--line-rgb), 0.26);
  border-radius: 2px;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.notify-form__input::placeholder {
  color: var(--ink-faint);
}

.notify-form__input:focus {
  outline: none;
  border-color: var(--line-strong);
  box-shadow: 0 0 0 3px rgba(var(--line-rgb), 0.14);
}

.notify-form__submit {
  flex-shrink: 0;
  height: 3rem;
  padding: 0 1.5rem;
  background: var(--accent);
  color: var(--accent-ink);
  border: 1px solid var(--accent);
  border-radius: 2px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
}

.notify-form__submit:hover:not(:disabled) {
  background: var(--ink);
  border-color: var(--ink);
}

.notify-form__submit:focus-visible {
  outline: 2px solid var(--line-strong);
  outline-offset: 2px;
}

.notify-form__submit:disabled {
  cursor: default;
  opacity: 0.75;
}

.notify-form__submit.is-loading .notify-form__submit-label {
  opacity: 0.6;
}

.notify-form__hp {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

.notify-form__status {
  min-height: 1.4em;
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
  color: var(--ink-muted);
}

.notify-form__status--error {
  color: #b3402c;
}

.notify-form__status--success {
  color: #1f7a4d;
}

/* ----------------------------- contact panel ----------------------------- */

.contact-panel {
  width: 100%;
  max-height: 0;
  margin-top: -1rem;
  overflow: hidden;
  opacity: 0;
  /* Scopes layout recalculation to this element instead of the whole
     document, so expanding it doesn't force the browser to also recompute
     layout for unrelated parts of the page on every frame of the
     transition. */
  contain: layout;
  transition: max-height 0.4s ease, opacity 0.3s ease;
}
.contact-panel.is-open {
  opacity: 1;
}

.contact-panel__intro {
  margin: 0 auto 1.1rem;
  max-width: 30rem;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-muted);
  text-wrap: balance;
}
.contact-panel__intro a {
  color: var(--line-strong);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: 28.75rem;
  margin: 0 auto;
}

.contact-form__row {
  display: flex;
  gap: 0.6rem;
}

.contact-form__field {
  flex: 1;
  min-width: 0;
}

.contact-form__input {
  width: 100%;
  padding: 0.75rem 1rem;
  background: rgba(255, 255, 255, 0.85);
  border: 1px solid rgba(var(--line-rgb), 0.26);
  border-radius: 2px;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.contact-form__input::placeholder {
  color: var(--ink-faint);
}
.contact-form__input:focus {
  outline: none;
  border-color: var(--line-strong);
  box-shadow: 0 0 0 3px rgba(var(--line-rgb), 0.14);
}
.contact-form__textarea {
  resize: vertical;
  min-height: 7rem;
  font-family: var(--font-body);
  line-height: 1.5;
}

.contact-form__submit {
  align-self: center;
  margin-top: 0.4rem;
  height: 2.75rem;
  padding: 0 1.5rem;
  background: rgba(255, 255, 255, 0.6);
  color: var(--line-strong);
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}
.contact-form__submit:hover:not(:disabled) {
  background: var(--line-strong);
  color: var(--accent-ink);
}
.contact-form__submit:focus-visible {
  outline: 2px solid var(--line-strong);
  outline-offset: 2px;
}
.contact-form__submit:disabled {
  cursor: default;
  opacity: 0.6;
}
.contact-form__submit.is-loading .contact-form__submit-label {
  opacity: 0.6;
}

.contact-form__status {
  min-height: 1.3em;
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-muted);
}
.contact-form__status--error {
  color: #b3402c;
}
.contact-form__status--success {
  color: #1f7a4d;
}

/* -------------------------------- footer -------------------------------- */

.footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: 1.25rem clamp(1.5rem, 6vw, 5rem) 1.75rem;
  text-align: center;
}

.footer__copyright {
  margin: 0;
  font-size: 0.875rem;
  color: var(--ink-muted);
  letter-spacing: 0.04em;
}

/* ------------------------------ responsive ------------------------------ */

@media (max-width: 860px) {
  .content {
    max-width: 100%;
  }
  .scrim {
    background:
      radial-gradient(
        ellipse 46% 27% at 50% 46%,
        rgba(247, 245, 240, 0.85) 0%,
        rgba(247, 245, 240, 0.55) 42%,
        rgba(247, 245, 240, 0.22) 68%,
        rgba(247, 245, 240, 0.04) 86%,
        transparent 100%
      );
  }
}

@media (max-width: 520px) {
  .notify-form__row {
    flex-direction: column;
  }
  /* Stacked over a full-width button, left-aligned text read as off-center
     against the centered copy. The near-opaque fill stands in for the form
     patch that's dropped on phones (below). */
  .notify-form__input {
    text-align: center;
    background: rgba(255, 255, 255, 0.9);
  }
  .notify-form__submit {
    width: 100%;
    font-size: 0.875rem;
  }
  .contact-form__row {
    flex-direction: column;
  }

  /* Phone type steps down ~12%. Inputs stay at 1rem: iOS Safari zooms the
     page on focus below 16px. */
  .contact-panel__intro {
    font-size: 0.8125rem;
  }
  .contact-form__submit {
    font-size: 0.875rem;
  }
  .notify-form__status,
  .contact-form__status {
    font-size: 0.75rem;
  }
  .footer__copyright {
    font-size: 0.75rem;
  }

  /* On a phone the sheet sits directly behind the copy and form, so the
     desktop veil and form patch hid nearly all of it. Keep only a light
     wash behind the headline/message; the inputs carry their own fill. */
  .scrim {
    background:
      radial-gradient(
        ellipse 55% 20% at 50% 40%,
        rgba(247, 245, 240, 0.5) 0%,
        rgba(247, 245, 240, 0.25) 55%,
        transparent 100%
      );
  }
  .notify-form__row::before {
    display: none;
  }
}

/* Short viewports (landscape phones, a browser window resized short) — the
   composition is already centered/scaled responsively, this just tightens
   vertical rhythm so everything fits without scrolling. */
@media (max-height: 560px) {
  :root {
    --topnav-h: 4rem;
  }
  .content {
    padding-top: calc(var(--topnav-h) + clamp(0.5rem, 3vh, 1.5rem));
    padding-bottom: clamp(1.25rem, 5vh, 2.5rem);
    gap: 1.1rem;
  }
  .intro {
    gap: 0.6rem;
  }
  .intro__title {
    font-size: clamp(1.5rem, 7vh, 2.25rem);
  }
  .message {
    display: none;
  }
  .footer {
    position: static;
    padding-top: 0.75rem;
  }
}

/* ---------------------------- reduced motion ----------------------------- */

@media (prefers-reduced-motion: reduce) {
  .reveal {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .scene-stage {
    transition: none;
  }
  .contact-panel {
    transition: none;
  }
}
