/* ============================================================
   Worried About Henry · Arena MK · Sat 31 Oct 2026
   Pre-sale sign-up (teaser — key artwork lands separately).

   DESIGN NOTE — "bone relief, one raking light".
   There is no key artwork for this show yet: the brief is the WAH face
   logo, the date and the venue. So the page is composed, not photo-led,
   and the logo does the work.

   The signature is the logo used as a literal mask: .mark__sheen is
   mask-image'd to the same PNG and carries a slow highlight sweep, so the
   carved lines catch light like something cast rather than printed. A soft
   pool of light sits behind the mark and motivates that light direction —
   one consistent light story, which is why there is no second glow, no
   drop-shadow (gotcha 9) and no watermark anywhere else.

   STRICTLY BLACK AND WHITE (Adam, 2026-07-30). WAH's own brand is B/W and
   there is to be no chromatic accent at all. So every "accent" here is a
   VALUE move, not a hue move: bone at graded alpha for hairlines, pewter
   for captions, and the brightest element on the page is the primary CTA —
   a solid bone fill — because this page has exactly one job. Nothing may
   introduce a hue; if something needs emphasis, change its value.

   TYPE. Alte Haas Grotesk is the brand's own secondary face and is
   licence-clean to self-host (fsType 0, unrestricted embedding). Bulevar
   Poster is the brand display face and the face of the wordmark itself,
   but it is atipo commercial retail: it appears ONLY baked flat into
   images (_src/build-images.sh), never as a webfont. Hierarchy therefore
   reads brand-shouts / facts-speak — heavy condensed wordmark image above
   a letterspaced grotesque date line.
   ============================================================ */

/* ---------- Tokens ---------- */
:root {
  --ink:            #0A0A0C;   /* page base                                */
  --ink-deep:       #060608;
  --graphite:       #13141A;   /* panel base                               */
  --bone:           #EFEBE2;   /* brand marks + primary type (exact tint)  */
  --bone-dim:       rgba(239, 235, 226, 0.68);
  --bone-faint:     rgba(239, 235, 226, 0.44);
  --pewter:         #8A8D96;
  --rule:           rgba(239, 235, 226, 0.14);
  --rule-strong:    rgba(239, 235, 226, 0.30);
  --wash:           rgba(239, 235, 226, 0.08);  /* the only "fill" tint     */
  --danger:         #E8E2D6;   /* errors read by weight, not hue           */

  --sans: "Alte Haas Grotesk", -apple-system, BlinkMacSystemFont,
          "Helvetica Neue", Helvetica, Arial, sans-serif;

  --panel-w: 468px;
  --pad-x:   clamp(18px, 5vw, 56px);
}

/* ---------- Self-hosted brand face ---------- */
@font-face {
  font-family: "Alte Haas Grotesk";
  src: url("../fonts/altehaas-400.woff2?v=20260730-4") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Alte Haas Grotesk";
  src: url("../fonts/altehaas-700.woff2?v=20260730-4") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---------- Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* gotcha 16: html carries the base colour so body stays transparent over
   the fixed .bg layer. An opaque body paints over a z-index:-1 background. */
html {
  background: var(--ink);
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: transparent;
  color: var(--bone);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  min-height: 100svh;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--bone); }

.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;
}

/* ============================================================
   BACKGROUND — one pool of light, plus grain
   The grain is not decoration: a radial this large banded visibly on
   near-black, and the noise breaks the bands up. Neutral greys only.
   ============================================================ */
.bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(120% 90% at 50% -10%, #23242A 0%, rgba(35, 36, 42, 0) 62%),
    radial-gradient(80% 60% at 50% 108%, #15161A 0%, rgba(21, 22, 26, 0) 70%),
    var(--ink);
}
.bg::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Stage ---------- */
.stage {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}
.hero {
  flex: 1 1 auto;
  display: grid;
  gap: clamp(18px, 3vw, 26px);
  align-content: center;
  justify-items: center;          /* poster-centred on phones */
  text-align: center;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;                 /* gotcha 10: auto at EVERY breakpoint */
  padding: clamp(30px, 6vw, 60px) var(--pad-x) clamp(30px, 5vw, 52px);
  grid-template-areas:
    "lockup"
    "panel";
}

/* ============================================================
   THE LOCKUP — mark + wordmark + date, as one unit
   These are deliberately ONE grid item rather than three grid rows. As
   three rows opposite a row-spanning panel, each row stretched to a third
   of the panel's height and the items floated at the top of their rows,
   which read as three unrelated blocks. As a flex column the gap is
   literal, so the three read as a single lockup.
   ============================================================ */
/* Spacing is set as explicit child margins rather than one uniform `gap`,
   because the two joins are not equal: mark -> wordmark is the brand stack,
   wordmark -> date is brand-then-facts and wants slightly less. */
.lockup {
  grid-area: lockup;
  display: flex;
  flex-direction: column;
  align-items: center;            /* poster-centred on phones */
  gap: 0;
  width: 100%;
}
.lockup .word { margin-top: 22px; }
.lockup .meta { margin-top: 18px; }

/* ============================================================
   THE MARK — the signature
   ============================================================ */
.mark {
  position: relative;
  isolation: isolate;             /* required, or mix-blend-mode leaks to the page */
  width: min(46vw, 168px);
  aspect-ratio: 1 / 1;
}
.mark__face {
  width: 100%;
  height: 100%;
}
/* The logo re-used as a mask: only the carved strokes take the light. */
.mark__sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.55;
  mix-blend-mode: screen;         /* adds light, never darkens */
  background-image: linear-gradient(
    112deg,
    rgba(255, 255, 255, 0) 34%,
    rgba(255, 255, 255, 0.75) 46%,
    rgba(255, 255, 255, 0.95) 50%,
    rgba(255, 255, 255, 0.75) 54%,
    rgba(255, 255, 255, 0) 66%
  );
  background-repeat: no-repeat;
  background-size: 240% 100%;
  background-position: 190% 0;
  -webkit-mask-image: url("../images/mask-560.png?v=20260730-4");
          mask-image: url("../images/mask-560.png?v=20260730-4");
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: rake 9s ease-in-out 1.4s infinite;
}
/* Hide the sheen entirely where mask-image is unsupported, rather than
   letting a bare gradient rectangle sit over the logo. */
@supports not ((-webkit-mask-image: url("#")) or (mask-image: url("#"))) {
  .mark__sheen { display: none; }
}
@keyframes rake {
  0%,  14% { background-position: 190% 0; }
  62%, 100% { background-position: -90% 0; }
}

/* ---------- Wordmark ---------- */
.word { width: 100%; }
.word img {
  width: min(100%, 520px);
  margin: 0 auto;
}

/* ---------- Date / venue — the "facts speak" register ---------- */
.meta {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px clamp(12px, 3vw, 22px);
  margin: 0;
  font-size: clamp(0.8rem, 3.3vw, 1.02rem);
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--bone);
}
.meta__sep {
  width: 26px;
  height: 1px;
  background: var(--rule-strong);
  flex: none;
}
.meta__item { white-space: nowrap; }

/* ============================================================
   PANEL — the sign-up card
   gotcha 5: isolate the stacking context and never lay an absolute frame
   over the children, or the country dropdown becomes unclickable.
   ============================================================ */
.panel {
  grid-area: panel;
  isolation: isolate;
  width: 100%;
  max-width: var(--panel-w);
  margin: clamp(4px, 1.4vw, 14px) auto 0;
  padding: clamp(20px, 3.4vw, 30px);
  text-align: left;
  background: linear-gradient(180deg, rgba(31, 32, 38, 0.92) 0%, rgba(15, 16, 20, 0.94) 100%);
  border: 1px solid var(--rule);
  border-radius: 4px;             /* near-square: this is a document, not a bubble */
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(239, 235, 226, 0.06);
}

/* State machine: exactly one wrapper visible. Each wrapper carries its own
   eyebrow + title + lede, or the idle copy shows through underneath. */
.panel__idle, .panel__otp, .panel__success { display: none; }
.panel[data-form-state="idle"]    .panel__idle,
.panel[data-form-state="otp"]     .panel__otp,
.panel[data-form-state="success"] .panel__success { display: block; }

/* Eyebrow: a hairline rule + tracked caps. No pill — the panel's own square
   corners are the motif here. */
.panel__eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--bone);
  line-height: 1.2;
}
.panel__eyebrow::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, var(--rule-strong), rgba(239, 235, 226, 0));
}

.panel__title {
  margin: 0 0 11px;
  font-weight: 700;
  font-size: clamp(1.6rem, 4.4vw, 2.05rem);
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;             /* gotcha 8: never nowrap a display title */
  color: var(--bone);
}
.panel__title em {
  display: block;
  font-style: normal;
  font-weight: 400;
  color: var(--bone-dim);
}

.panel__lede {
  margin: 0 0 20px;
  font-size: 14.5px;
  line-height: 1.62;
  color: var(--bone-dim);
}
.panel__lede strong { color: var(--bone); font-weight: 700; }

/* gotcha 7: scope state paragraphs so they can't out-specify the eyebrow */
.panel__success p:not(.panel__eyebrow) {
  margin: 0 0 14px;
  font-size: 14.5px;
  line-height: 1.62;
  color: var(--bone-dim);
}
.panel__success-note {
  padding: 11px 14px;
  border-left: 2px solid var(--bone);
  background: var(--wash);
  color: var(--bone) !important;
  font-size: 14px;
}

/* ============================================================
   FORM
   ============================================================ */
/* gotcha 2: display:none ONLY. Off-screen positioning gets autofilled by
   Chrome/Edge, which silently blocks real signups. */
.form__honeypot { display: none !important; }

.form__row { position: relative; margin-bottom: 13px; }

/* Labels are sr-only, not display:none — placeholders carry the meaning
   visually, labels stay for screen readers. */
.form__label {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.form__input {
  width: 100%;
  padding: 13px 14px;
  font-family: var(--sans);
  font-size: 16px;               /* 16px min or iOS zooms the page on focus */
  line-height: 1.3;
  color: var(--bone);
  background: rgba(239, 235, 226, 0.045);
  border: 1px solid var(--rule);
  border-radius: 3px;
  transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
  -webkit-appearance: none;
  appearance: none;
}
.form__input::placeholder { color: var(--bone-faint); }
.form__input:hover { border-color: var(--rule-strong); }
.form__input:focus {
  outline: none;
  border-color: var(--bone);
  background: rgba(239, 235, 226, 0.08);
  box-shadow: 0 0 0 3px rgba(239, 235, 226, 0.14);
}
.form__input--otp {
  font-size: 1.55rem;
  font-weight: 700;
  letter-spacing: 0.42em;
  text-align: center;
  padding: 14px 10px 12px;
  text-indent: 0.42em;           /* recentre against the trailing tracking */
}

/* Errors carry by weight + a bone bar, since hue is not available. */
.form__error {
  margin: 7px 0 0;
  padding-left: 9px;
  border-left: 2px solid var(--bone);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--danger);
}
.form__error--global {
  margin-top: 12px;
  padding: 9px 12px;
  border-left-width: 2px;
  background: var(--wash);
}

/* Consent tick */
.form__row--check { margin: 16px 0 20px; }
.form__check {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 11px;
  align-items: start;
  cursor: pointer;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--bone-dim);
}
.form__check input[type="checkbox"] {
  width: 18px; height: 18px;
  margin: 1px 0 0;
  accent-color: var(--bone);
  cursor: pointer;
  flex: none;
}
/* No emphasis inside the consent line: "Louder events." reads at the same
   weight and colour as the rest of the sentence (Adam, 2026-07-30). */
.form__check a { color: var(--bone); text-underline-offset: 2px; }

/* ---------- Buttons ---------- */
/* The primary is a bone fill: the brightest element on the page, because
   the page has one job. Secondary actions are hairline outlines. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 14px 22px;
  font-family: var(--sans);
  font-weight: 700;
  /* gotcha 26: shrink type before an uppercase tracked label can wrap */
  white-space: nowrap;
  font-size: clamp(0.78rem, 3.4vw, 0.92rem);
  letter-spacing: clamp(0.04em, 0.4vw, 0.12em);
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease,
              box-shadow 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.btn--primary {
  color: var(--ink);
  background: var(--bone);
  box-shadow: 0 10px 30px rgba(239, 235, 226, 0.13);
}
.btn--primary:hover:not(:disabled) {
  background: #FFFDF7;
  transform: translateY(-1px);
  box-shadow: 0 14px 38px rgba(239, 235, 226, 0.2);
}
.btn:disabled { opacity: 0.6; cursor: progress; transform: none; }
.btn__arrow { font-size: 1.05em; line-height: 1; }

.btn--ghost {
  color: var(--bone);
  background: transparent;
  border-color: var(--rule-strong);
  margin-top: 12px;
}
.btn--ghost:hover {
  border-color: var(--bone);
  background: var(--wash);
}
.btn--ghost svg { width: 17px; height: 17px; flex: none; }

.form__resend {
  margin: 14px 0 0;
  text-align: center;
  font-size: 12.5px;
  color: var(--bone-faint);
}
.form__resend-btn {
  padding: 4px 12px 3px;
  font: inherit;
  font-weight: 700;
  color: var(--bone);
  background: transparent;
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  cursor: pointer;
}
.form__resend-btn:hover:not(:disabled) { background: var(--wash); }
.form__resend-btn:disabled { opacity: 0.5; cursor: default; }

/* ---------- App download block ---------- */
.appcta {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
}
.appcta__hook {
  margin: 0 0 7px;
  font-weight: 700;
  font-size: 1.02rem;
  line-height: 1.28;
  letter-spacing: -0.01em;
  color: var(--bone);
}
.appcta__hook em { font-style: normal; font-weight: 400; color: var(--bone-dim); }
.appcta__copy {
  margin: 0 0 14px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--bone-dim);
}
.appcta__badges { display: flex; flex-wrap: wrap; gap: 10px; }
.appcta__badge { display: block; transition: opacity 0.2s ease, transform 0.2s ease; }
.appcta__badge img { height: 40px; width: auto; }
.appcta__badge:hover { opacity: 0.85; transform: translateY(-1px); }

/* ============================================================
   FOOTER — full-width bar (basslayerz pattern)
   Sibling of .hero inside the flex-column .stage, so it spans the
   viewport regardless of .hero's max-width.
   ============================================================ */
.foot {
  flex-shrink: 0;
  width: 100%;
  margin: 0;
  padding: 18px var(--pad-x) 26px;
  background: rgba(6, 6, 8, 0.62);
  border-top: 1px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.foot__left { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.foot__legal {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--pewter);
}
.foot__legal a { color: var(--pewter); text-decoration: none; }
.foot__legal a:hover { color: var(--bone); }
.site-built { margin: 0; }
.site-built a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--pewter);
  text-decoration: none;
  border: 1px solid var(--rule);
  border-radius: 999px;
}
.site-built a:hover { border-color: var(--rule-strong); color: var(--bone); }
.site-built img { display: block; opacity: 0.9; }

/* ============================================================
   INTL-TEL-INPUT v25 — dropdown + search box
   ============================================================ */
.iti { width: 100%; display: block; }
.iti__tel-input, .iti input[type="tel"] { width: 100%; }

/* gotcha 19: until the vendor stylesheet lands, the list paints open */
.iti__dropdown-content.iti__hide { display: none !important; }

.iti--separate-dial-code .iti__selected-country,
.iti__selected-country {
  background: transparent;
  border-radius: 3px 0 0 3px;
}
.iti__selected-country:hover,
.iti__selected-country-primary:hover { background: rgba(239, 235, 226, 0.05); }
.iti__selected-dial-code { color: var(--bone); font-size: 15px; }
.iti__arrow { border-top-color: var(--bone-faint); }
.iti__arrow--up { border-bottom-color: var(--bone-faint); }

.iti__dropdown-content {
  background: #101116;
  border: 1px solid var(--rule-strong);
  border-radius: 4px;
  box-shadow: 0 24px 54px rgba(0, 0, 0, 0.68);
  overflow: hidden;
}
.iti__search-input {
  width: 100%;
  padding: 12px 14px;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--bone);
  background: rgba(239, 235, 226, 0.05);
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
}
.iti__search-input::placeholder { color: var(--bone-faint); }
.iti__search-input:focus {
  outline: none;
  background: rgba(239, 235, 226, 0.09);
  border-bottom-color: var(--bone);
}
.iti__country-list {
  max-height: 248px;
  background: transparent;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-strong) transparent;
}
.iti__country-list::-webkit-scrollbar { width: 8px; }
.iti__country-list::-webkit-scrollbar-thumb {
  background: var(--rule-strong);
  border-radius: 999px;
}
.iti__country {
  padding: 9px 14px;
  font-size: 14px;
  color: var(--bone-dim);
}
.iti__country.iti__highlight,
.iti__country:hover {
  background: rgba(239, 235, 226, 0.11);
  color: var(--bone);
}
.iti__country-name { color: inherit; }
.iti__dial-code { color: var(--bone-faint); }
.iti__divider { border-bottom-color: var(--rule); }

/* ============================================================
   LEGAL PAGE
   ============================================================ */
.legal-wrap { background: var(--ink); }
.legal {
  max-width: 820px;
  margin: 0 auto;
  padding: clamp(26px, 5vw, 56px) var(--pad-x) 72px;
}
.legal__back {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 26px;
  padding: 7px 16px 7px 12px;
  border: 1px solid var(--rule-strong);
  border-radius: 3px;
  color: var(--bone);
  text-decoration: none;
  font-size: 12.5px;
}
.legal__back:hover { background: var(--wash); border-color: var(--bone); }
.legal__back-arrow { display: flex; width: 15px; height: 15px; color: var(--bone); }
.legal__back-arrow svg { width: 100%; height: 100%; }
.legal__back-label { display: inline-flex; gap: 5px; }
.legal__back-text { color: var(--pewter); }
.legal__back-brand { font-weight: 700; letter-spacing: 0.02em; }
.legal h1 {
  margin: 0 0 26px;
  font-weight: 700;
  font-size: clamp(1.75rem, 5.4vw, 2.5rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--bone);
}
.legal h2 {
  margin: 30px 0 10px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pewter);
}
.legal p {
  margin: 0 0 12px;
  font-size: 14.5px;
  line-height: 1.68;
  color: var(--bone-dim);
}
.legal a { color: var(--bone); }
.legal strong { color: var(--bone); }
.legal__meta {
  margin-top: 34px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-size: 12.5px;
  color: var(--pewter);
}

/* ============================================================
   RESPONSIVE
   Adam's format is fixed: ARTWORK LEFT, SIGN-UP BOX RIGHT. That is this
   block. Below the threshold there is not enough width for two columns, so
   the same order stacks (artwork above, box below) — the only sane phone
   behaviour and what the rest of the WAH fleet does.

   gotcha 20: use an aspect-ratio threshold, not width alone, or squarish
   desktop windows fall into a gap where neither treatment applies.
   Two columns need brand(300) + gap(48) + panel(468) + padding(112) ≈ 928px
   of real width, so the threshold is 1000px.
   ============================================================ */
@media (min-width: 1000px) and (min-aspect-ratio: 7/10) {
  .hero {
    align-content: center;
    align-items: center;
    justify-items: start;         /* gotcha 17: only inside the 2-col block */
    text-align: left;
    column-gap: clamp(32px, 4.4vw, 64px);
    grid-template-columns: minmax(260px, 400px) minmax(0, var(--panel-w));
    grid-template-areas: "lockup  panel";
    justify-content: center;
  }
  /* Left-aligned against the panel, and vertically centred as one block. */
  .lockup { align-items: flex-start; width: auto; }
  .lockup .word { margin-top: 18px; }
  .lockup .meta { margin-top: 15px; }
  .mark  { width: min(20vw, 200px); }
  .word img  { width: min(100%, 400px); margin: 0; }
  .meta  { justify-content: flex-start; }
  .panel { align-self: center; margin: 0; }
}

@media (min-width: 1240px) and (min-aspect-ratio: 7/10) {
  .hero { column-gap: clamp(48px, 5.5vw, 88px); }
  .mark { width: min(20vw, 228px); }
  .word img { width: min(100%, 460px); }
}

/* Landscape phones (gotcha 27): desktop-ish aspect, almost no height.
   Placed AFTER the desktop blocks so it wins at equal specificity — media
   queries add no specificity of their own. */
@media (min-width: 640px) and (min-aspect-ratio: 7/10) and (max-height: 560px) {
  .hero {
    align-content: start;
    align-items: start;
    justify-items: start;
    text-align: left;
    min-height: 0;
    column-gap: clamp(18px, 3vw, 32px);
    padding-top: 14px;
    padding-bottom: 14px;
    grid-template-columns: minmax(140px, 210px) minmax(0, 380px);
    grid-template-areas: "lockup  panel";
    justify-content: center;
  }
  .lockup { align-items: flex-start; width: auto; }
  .lockup .word { margin-top: 10px; }
  .lockup .meta { margin-top: 9px; }
  /* Cap hard here: a rotated phone has ~390px of height in total. */
  .mark { width: min(22vw, 104px); }
  .word img { width: min(100%, 230px); margin: 0; }
  .meta {
    justify-content: flex-start;
    gap: 6px 12px;
    font-size: 0.7rem;
    letter-spacing: 0.16em;
  }
  .panel { align-self: start; margin: 0; padding: 14px 16px; }

  /* ~390px of height against a ~490px idle panel, so this block is about
     getting eyebrow -> title -> email -> phone -> consent -> button onto one
     screen. The idle lede goes: the wordmark and date line beside it already
     state the event, venue and date, so it is the one genuinely redundant
     block. It is kept in the OTP and success states, where it carries
     instructions rather than repetition. */
  .panel__eyebrow { margin-bottom: 8px; font-size: 9.5px; }
  .panel__title { font-size: 1.24rem; line-height: 1.1; margin-bottom: 9px; }
  .panel__idle .panel__lede { display: none; }
  .panel__otp .panel__lede,
  .panel__success p:not(.panel__eyebrow) { margin-bottom: 11px; font-size: 12.5px; }

  .form__row { margin-bottom: 9px; }
  .form__input { padding: 10px 12px; }
  .form__row--check { margin: 10px 0 11px; }
  .form__check { font-size: 11.5px; line-height: 1.45; }
  .btn { padding: 11px 18px; }

  .appcta { margin-top: 13px; padding-top: 12px; }
  .appcta__hook { font-size: 0.92rem; }
  .appcta__badge img { height: 32px; }
  .foot { padding-top: 11px; padding-bottom: 13px; }
}

/* Portrait phones */
@media (max-width: 560px) {
  .hero { gap: clamp(14px, 3.2vw, 20px); }
  .mark { width: min(42vw, 138px); }
  .word img { width: min(100%, 400px); }
  .meta { letter-spacing: 0.16em; }
  .appcta__badge img { height: 36px; }
  .foot { justify-content: center; text-align: center; }
  .foot__left { justify-content: center; }
}

/* ============================================================
   ENTRY SEQUENCE
   One short orchestrated reveal, top-down, so the mark reads as the
   subject and the panel as the response. Screenshot caveat (gotcha 23):
   these use `both`, so a plain headless capture that races them shows an
   empty page — capture with --virtual-time-budget.
   ============================================================ */
@keyframes rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes bloom {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: none; }
}
.mark  { animation: bloom 0.72s cubic-bezier(0.22, 0.9, 0.3, 1) both; }
.word  { animation: rise 0.62s cubic-bezier(0.22, 0.9, 0.3, 1) 0.1s both; }
.meta  { animation: rise 0.62s cubic-bezier(0.22, 0.9, 0.3, 1) 0.18s both; }
.panel { animation: rise 0.68s cubic-bezier(0.22, 0.9, 0.3, 1) 0.26s both; }

/* ============================================================
   ACCESSIBILITY
   ============================================================ */
a:focus-visible,
button:focus-visible,
input:focus-visible,
.iti__selected-country:focus-visible {
  outline: 2px solid var(--bone);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  html { scroll-behavior: auto; }
  /* The blanket rule above would freeze the sheen on its final keyframe,
     i.e. swept off-canvas and invisible. Park it as a fixed highlight so
     the mark still reads as cast rather than flat. */
  .mark__sheen {
    animation: none !important;
    background-position: 44% 0;
    opacity: 0.3;
  }
}
