/* ============================================================
   Simply Red - Summer Funk '27
   Gunnersbury Park, London - Friday 13 August 2027
   Presale signup. Client: Louder Entertainment.

   DIRECTION
   The client supplied one flat 4:5 poster, and its ground is a
   near-white sheet rather than the black every other build in this
   fleet sits on. So the page does not put the poster in a card on a
   contrasting ground - it adopts the poster's own paper as the page
   ground, and the sheet is shown with no frame, no shadow and no
   radius. Poster and page read as one printed object.

   The artwork's device is six vertical duotone strips of UNEQUAL
   width with STAGGERED tops and bottoms. That rhythm - not a generic
   rainbow - is what the background plates rebuild, at the poster's
   own measured proportions, crowding the outer edges and leaving the
   middle clear for content. The same six colours then do the one
   piece of functional work on the page: the step rule.

   COLOUR - every value below is a literal pixel off the supplied
   poster, not an interpretation:
     #F1F1F0  the sheet                      (poster ground)
     #17171A  the script black               ("Summer Funk '27")
     #D63034  Simply Red red                 ("FRI 13 AUG")
     #10141D  stage navy                     (Hucknall's shirt)
     #FF7739 #3D8AA4 #4CBA49
     #DC4749 #FFB641 #BB5597                 (the six strips)
   The red carries white at 4.85:1, so it is the primary button. On
   the sheet it measures 4.29:1, which clears large text but NOT body
   copy - secondary copy uses #5A5A5E (6.07:1) instead. Ink on sheet
   is 15.38:1.

   TYPE - two families, deliberately far apart in proportion.
   Jost (geometric, light, wide-tracked caps) answers the poster's
   thin letterspaced SIMPLY RED wordmark and carries every heading and
   button. Alte Haas Grotesk (warm humanist grotesque, tall x-height)
   carries all reading copy and every form field - this audience skews
   older and the fields have to stay effortless. The poster's own
   condensed date face is deliberately NOT repeated: it is already on
   the page as an image, and a second condensed gothic would compete
   with it rather than pair.

   SIGNATURE - the step rule. This token runs all three verifications
   (form -> SMS code -> email confirm) and OTP drop-off is worst when
   people cannot see how much is left. Three segments in the first
   three poster colours, driven by the same data-form-state the form
   logic already flips. It is the only decorated element on the page;
   everything else is quiet on purpose.
   ============================================================ */

@font-face {
  font-family: "Jost";
  src: url("/assets/fonts/Jost-var.woff2?v=20260908-4") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Alte Haas";
  src: url("/assets/fonts/altehaas-400.woff2?v=20260908-4") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Alte Haas";
  src: url("/assets/fonts/altehaas-700.woff2?v=20260908-4") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --sheet:     #F1F1F0;   /* poster ground - the page ground */
  --sheet-hi:  #FFFFFF;   /* form fields - OPAQUE, see the autofill rule */
  --ink:       #17171A;   /* script black (15.38:1 on the sheet) */
  --ink-soft:  #5A5A5E;   /* secondary copy (6.07:1) */
  --ink-faint: #8A8A8E;   /* placeholders, disabled */
  --line:      #D9D9D6;   /* hairlines and field borders */
  --red:       #D63034;   /* Simply Red red - primary button (white 4.85:1) */
  --red-deep:  #B02226;   /* hover / pressed */
  --navy:      #10141D;   /* stage navy */

  --s1: #FF7739;  --s2: #3D8AA4;  --s3: #4CBA49;   /* the six strips, */
  --s4: #DC4749;  --s5: #FFB641;  --s6: #BB5597;   /* in poster order */

  --danger:   #B02226;
  --whatsapp: #25D366;

  --display: "Jost", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --body:    "Alte Haas", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --maxw: 1080px;   /* leaves ~100px of margin at 1280 for the strip frame to sit in */
}

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

/* The `hidden` attribute is only display:none in the UA stylesheet, the weakest
   layer of the cascade, so ANY author rule that sets display beats it and the
   element stays on screen with no error anywhere. Keep this rule ABOVE
   everything that sets display, and never remove it. */
[hidden] { display: none !important; }

/* Ground colour lives on html, NOT body: an opaque body background paints over
   the z-index:-2 .bg layer and the artwork disappears. */
html {
  -webkit-text-size-adjust: 100%;
  background: var(--sheet);
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  font-family: var(--body);
  color: var(--ink-soft);
  background: transparent;
  display: flex;
  flex-direction: column;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ---------- the artwork's strip rhythm, rebuilt as the page ground ----------
   The plate is a FRAME, not a wallpaper: the strips are meant to sit in the
   page's outer margin. So it is only painted where there IS a margin for them
   to sit in. Below 1280px, and on any short viewport, the stage runs close to
   edge-to-edge and the strips passed straight behind the form - on a rotated
   phone the amber band ran through the consent copy. Clean sheet there
   instead; the poster already carries the strips at full strength, so nothing
   about the brand is lost.

   Two plates, both gated on the same conditions the preloads in the head use,
   so nothing is ever fetched for a viewport that will not paint it. */
.bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  background-color: var(--sheet);
  background-image: none;
  background-position: center;
  background-size: cover;
}
@media (min-width: 1280px) and (min-aspect-ratio: 7/10) and (min-height: 560px) {
  .bg { background-image: url("/assets/images/bg-desktop-sm.webp?v=20260908-4"); }
}
@media (min-width: 1501px) and (min-aspect-ratio: 7/10) and (min-height: 560px) {
  .bg { background-image: url("/assets/images/bg-desktop.webp?v=20260908-4"); }
}

/* Scrim, in the sheet's own colour rather than a tint, and horizontal because
   the strips are only ever at the left and right edges - a radial would fade
   them vertically for no reason. Fully opaque across the middle so the poster
   and the form always sit on clean paper. */
.bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    rgba(241,241,240,0) 0%,
    rgba(241,241,240,.30) 6%,
    rgba(241,241,240,.98) 17%,
    rgba(241,241,240,.98) 83%,
    rgba(241,241,240,.30) 94%,
    rgba(241,241,240,0) 100%);
}

/* Dither. Functional rather than decorative: the sheet is a large flat field
   and WebP bands visibly across it without a little tooth on top. */
.grain {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .035;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================================
   STAGE
   ============================================================ */
.stage {
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;                 /* auto at EVERY breakpoint - never plain 0 */
  padding: clamp(24px, 4vw, 56px) clamp(18px, 4vw, 44px);
  display: flex;
  align-items: center;
}
.stage__inner {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 58px);
  align-items: center;
}

/* ---------- the bill: the poster, shown as a sheet, not as a card ----------
   No border, no radius, no shadow, no background. The page ground IS this
   image's ground, so any frame would only announce the seam we are hiding. */
.bill {
  justify-self: center;
  width: 100%;
  max-width: 520px;
}
.bill__h1 { margin: 0; }
.bill__poster {
  display: block;
  width: 100%;
  height: auto;
  animation: riseIn .9s cubic-bezier(.16,.84,.36,1) both;
}
@keyframes riseIn {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   SIGNUP PANEL
   No card. The form sits on the sheet and the fields are the only
   filled shapes, which is what keeps the poster the loudest object
   on the page.
   ============================================================ */
.signup { justify-self: center; width: 100%; max-width: 470px; }
.panel {
  width: 100%;
  position: relative;
  isolation: isolate;             /* keeps the country dropdown above everything */
  animation: riseIn .9s .14s cubic-bezier(.16,.84,.36,1) both;
}
.panel__inner { position: relative; z-index: 1; }

/* --- state machine (app.js flips data-form-state on .panel) --- */
.panel__state { display: none; }
.panel[data-form-state="idle"]    .panel__idle    { display: block; }
.panel[data-form-state="otp"]     .panel__otp     { display: block; }
.panel[data-form-state="success"] .panel__success { display: block; }

/* ============================================================
   STEP RULE - the signature element
   Three segments in the first three poster colours, driven by the
   same data-form-state the form logic already sets. Sits OUTSIDE
   the state wrappers because it is panel chrome, not state content.
   ============================================================ */
.spine {
  display: flex;
  list-style: none;
  margin: 0 0 26px;
  padding: 0;
  gap: 6px;
}
.spine__step {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-family: var(--display);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color .3s ease;
}
/* the rule itself */
.spine__step::before {
  content: "";
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--line);
  transition: background-color .3s ease;
}
.spine__t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spine__n { display: none; }   /* the rule carries the sequence; a digit too is one signal more than the step needs */

/* reached (current or completed) - the poster colours, in poster order */
.panel[data-form-state="idle"]    .spine__step:nth-child(1)::before,
.panel[data-form-state="otp"]     .spine__step:nth-child(-n+2)::before,
.panel[data-form-state="success"] .spine__step::before { background: var(--s1); }
.panel[data-form-state="otp"]     .spine__step:nth-child(2)::before,
.panel[data-form-state="success"] .spine__step:nth-child(2)::before { background: var(--s2); }
.panel[data-form-state="success"] .spine__step:nth-child(3)::before { background: var(--s3); }

/* the step you are on - the only one with ink-weight type */
.panel[data-form-state="idle"]    .spine__step:nth-child(1),
.panel[data-form-state="otp"]     .spine__step:nth-child(2),
.panel[data-form-state="success"] .spine__step:nth-child(3) { color: var(--ink); }
/* steps already done stay legible but step back */
.panel[data-form-state="otp"]     .spine__step:nth-child(1),
.panel[data-form-state="success"] .spine__step:nth-child(1),
.panel[data-form-state="success"] .spine__step:nth-child(2) { color: var(--ink-soft); }

@media (max-width: 400px) {
  .spine__step { font-size: 9px; letter-spacing: .06em; }
}

/* ============================================================
   PANEL COPY
   ============================================================ */
.panel__title {
  margin: 0 0 16px;
  font-family: var(--display);
  /* 500, not the 300 this started on. Jost Light echoes the poster wordmark
     beautifully at poster scale, but at 38px on a near-white ground it went
     spindly and lost all authority next to the artwork (client-flagged,
     2026-09-08). 500 keeps the geometric character and the wide tracking while
     giving the line enough weight to hold the column. */
  font-weight: 500;
  font-size: clamp(1.75rem, 4.4vw, 2.35rem);
  line-height: 1.12;
  letter-spacing: .075em;
  text-transform: uppercase;
  color: var(--ink);
  text-wrap: balance;
}
/* House pattern across the fleet: the second line of the title carries the
   accent. <em> is used for the hook rather than a span so the emphasis is in
   the markup, not only the paint - reset from italic because this face is set
   as caps and a true italic would fight the poster's own script. */
.panel__title em { font-style: normal; color: var(--red); }

.panel__lede {
  margin: 0 0 12px;
  font-size: 15.5px;
  color: var(--ink-soft);
  /* 50ch (~444px), not the 44ch this started on. The venue is the fact people
     scan for, and at 44ch (~391px) the measure - not the 470px column - was
     what pushed "Gunnersbury Park" onto line two: the run up to and including
     it is 416px. 50ch clears that and still sits well inside the column and
     well under a 80-character line. */
  max-width: 50ch;
}
.panel__lede--last { margin-bottom: 24px; }
.panel__lede strong { color: var(--ink); font-weight: 700; }
.panel__success-note { margin: 0 0 14px; color: var(--red); font-size: 14.5px; }

/* ============================================================
   FORM
   ============================================================ */
.form__row { margin: 0 0 14px; }
/* labels stay for screen readers; placeholders carry the meaning visually */
.form__label {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.form__input {
  width: 100%;
  padding: 14px 15px;
  font-family: var(--body);
  font-size: 16px;                /* 16px minimum or iOS zooms the page on focus */
  color: var(--ink);
  background: var(--sheet-hi);    /* OPAQUE - see the autofill rule below */
  border: 1px solid var(--line);
  border-radius: 2px;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.form__input::placeholder { color: var(--ink-faint); }
.form__input:focus {
  outline: none;
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(214,48,52,.14);
}
.form__input--otp {
  font-family: var(--display);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: .42em;
  text-align: center;
  text-indent: .42em;             /* re-centres text that tracking pushes left */
}

/* Chrome paints autofilled inputs pale lavender and IGNORES background /
   background-color on :-webkit-autofill - a huge inset box-shadow is the only
   reliable override. A box-shadow cannot be semi-transparent, so the colour
   must be the FLATTENED OPAQUE equivalent of the field's rendered stack. The
   fields were made opaque white on purpose, so that value is simply
   --sheet-hi; keep them opaque, or this has to be recomputed by compositing
   field over sheet over the background plate. */
.form__input:-webkit-autofill,
.form__input:-webkit-autofill:hover,
.form__input:-webkit-autofill:focus,
.form__input:-webkit-autofill:active {
  -webkit-box-shadow: 0 0 0 1000px var(--sheet-hi) inset !important;
          box-shadow: 0 0 0 1000px var(--sheet-hi) inset !important;
  -webkit-text-fill-color: var(--ink) !important;
  caret-color: var(--ink);
  transition: background-color 9999s ease-in-out 0s;   /* stops the lavender flashing in */
}

.form__error { margin: 7px 0 0; font-size: 13px; color: var(--danger); }
.form__error--global { margin-top: 14px; }

/* Honeypot. display:none ONLY - off-screen positioning stays an autofill
   target in Chrome/Edge, which fills it and silently blocks real signups. */
.hp-row { display: none !important; }

.form__row--check { margin: 20px 0 22px; }
.form__check {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-soft);
  cursor: pointer;
}
.form__check input {
  flex: 0 0 auto;
  width: 17px; height: 17px;
  margin: 1px 0 0;
  accent-color: var(--red);
  cursor: pointer;
}
.form__check a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.form__check a:hover { color: var(--red); }

.form__resend {
  margin: 16px 0 0;
  font-size: 13px;
  color: var(--ink-soft);
  text-align: center;
}
.form__resend-btn {
  font: inherit;
  color: var(--red);
  background: none;
  border: 0;
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.form__resend-btn:disabled { color: var(--ink-faint); cursor: default; text-decoration: none; }

/* ---------- buttons ---------- */
.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 16px 18px;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(.8rem, 2.9vw, .9rem);
  letter-spacing: clamp(.08em, .5vw, .16em);
  text-transform: uppercase;
  white-space: nowrap;            /* shrink the type before it can ever wrap */
  text-align: center;
  text-decoration: none;          /* <a class="btn"> needs this, <button> doesn't */
  border: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: background-color .18s ease, transform .12s ease;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: default; }
/* White on the red: 4.85:1. Ink on the red would be 3.1:1 and fail. */
.btn--primary { color: #FFFFFF; background: var(--red); }
.btn--primary:hover:not(:disabled) { background: var(--red-deep); }
.btn--whatsapp {
  color: #06301A;
  background: var(--whatsapp);
  margin-top: 6px;
}
.btn--whatsapp:hover { filter: brightness(1.05); }
.btn__icon { flex: 0 0 auto; width: 19px; height: 19px; }

.wa-hook { margin: 20px 0 12px; font-size: 13.5px; color: var(--ink-soft); }
.wa-hook strong { color: var(--ink); font-weight: 700; }

/* ============================================================
   intl-tel-input v25
   ============================================================ */
.iti { width: 100%; display: block; }
/* app.js re-measures and sets padding-left inline; this is the sane default
   before it runs. Anything >= 80px breaks 320-390px viewports. */
.iti input.form__input { padding-left: calc(52px + 0.7rem); }
.iti__country-container { z-index: 3; }
.iti--inline-dropdown .iti__dropdown-content { z-index: 50; }
/* Until the vendor stylesheet loads, the hidden state does not exist and the
   whole list plus search box flashes open on first paint. */
.iti__dropdown-content.iti__hide { display: none !important; }

.iti__dropdown-content {
  background: var(--sheet-hi);
  border: 1px solid var(--line);
  border-radius: 3px;
  box-shadow: 0 26px 56px -22px rgba(23,23,26,.28);
  overflow: hidden;
}
.iti__search-input {
  /* Keep the vendor's horizontal padding reservation: 30px left clears the
     absolutely positioned search icon, 28px right clears the clear button. A
     padding SHORTHAND that drops them puts the magnifier on top of the
     placeholder text. Set the vertical values, keep the horizontal ones. */
  padding: 10px 30px 10px 32px;
  width: 100%;
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink);
  background: var(--sheet-hi);
  border: 0;
  border-bottom: 1px solid var(--line);
}
.iti__search-input::placeholder { color: var(--ink-faint); }
.iti__search-input:focus { outline: none; background: #FAFAF9; }
.iti__country-list { background: var(--sheet-hi); max-height: 240px; }
.iti__country {
  padding: 9px 12px;
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink);
}
.iti__country:hover,
.iti__country.iti__highlight { background: rgba(214,48,52,.08); }
.iti__dial-code { color: var(--ink-soft); }
.iti__country-name { color: var(--ink); }
.iti__selected-country { border-radius: 2px 0 0 2px; }
.iti__selected-country:hover,
.iti__selected-country-primary:hover { background: rgba(214,48,52,.06); }
.iti__selected-dial-code { color: var(--ink); font-family: var(--body); font-size: 15px; }
.iti__arrow { border-top-color: var(--ink-soft); }
.iti__arrow--up { border-bottom-color: var(--ink-soft); }

/* ============================================================
   FOOTER - standard fleet band (basslayerz pattern, incl. the pill)
   ============================================================ */
.foot {
  flex-shrink: 0;
  width: 100%;
  margin: 0;
  padding: 20px clamp(18px, 4vw, 44px) 28px;
  background: rgba(255,255,255,.5);
  border-top: 1px solid var(--line);
  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; color: var(--ink-soft); letter-spacing: .02em; }
.foot__legal a { color: var(--ink-soft); text-decoration: none; }
.foot__legal a:hover { color: var(--red); }

/* Accessibility link, as a small pill rather than plain footer text. The
   client asked for a button and for it to be small: a pill with the standard
   glyph is more findable than a text link for the people who actually need it,
   without taking any more room. Shares the credit pill's shape on purpose. */
.foot__links { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.a11y-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: border-color .18s ease, color .18s ease;
}
.a11y-btn:hover { border-color: var(--red); color: var(--ink); }
.a11y-btn svg { width: 13px; height: 13px; flex: 0 0 auto; }

/* The credit sits in a PILL - copy the CSS, not just the markup. */
.site-built { margin: 0; }
.site-built a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: border-color .18s ease, color .18s ease;
}
.site-built a:hover { border-color: var(--red); color: var(--ink); }
/* The credit logo is a WHITE wordmark with a LIGHT TEAL roundel, drawn for
   dark bands. This is a light build, and invert() rotates that teal to red -
   it renders muddy maroon. Darken and saturate instead: this lands on ~#2E5053,
   7.83:1 on the sheet, hue intact. */
.site-built img { display: block; filter: brightness(.36) saturate(1.45); }

/* ============================================================
   RESPONSIVE
   Aspect-ratio thresholds, not width alone.
   ============================================================ */

/* --- two column: poster left, panel right --- */
@media (min-width: 900px) and (min-aspect-ratio: 7/10) {
  .stage__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 470px);
    gap: clamp(40px, 5vw, 76px);
    align-items: center;
  }
  .bill   { justify-self: end; max-width: 520px; }
  .signup { justify-self: start; }
  .foot   { justify-content: space-between; }
}

@media (max-width: 899px) {
  .foot { justify-content: center; text-align: center; }
  .foot__left { justify-content: center; }
}

/* Phones: stack the footer rather than relying on the flex row wrapping.
   Around 390px the copyright + "built by" row is JUST wide enough to fill the
   band, so centring it is indistinguishable from it running edge to edge - it
   reads as left-aligned even though justify-content is centre. Below 480px,
   force a centred column so every width stacks the same way instead of
   flipping at whatever width the text happens to overflow. */
@media (max-width: 480px) {
  .foot {
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding-bottom: 24px;
  }
  .foot__left {
    flex-direction: column;
    align-items: center;
    gap: 12px;
  }
  /* Portrait phones: hold the poster back so the form clears the fold. It is
     4:5, so every 10vw of width costs 12.5vw of height. */
  .bill { max-width: min(330px, 66vw); }
  .stage { padding-top: clamp(18px, 3vw, 56px); }
  .stage__inner { gap: 24px; }
  .panel__title { font-size: clamp(1.6rem, 8vw, 2rem); }
}

/* --- landscape phones are a first-class layout ---
   A rotated phone (844x390, 932x430, 667x375) satisfies both conditions above
   while having almost no height, so the poster and panel would render cramped
   and the page would scroll badly. Compact side-by-side, poster height-capped,
   tighter type. Placed AFTER the desktop blocks so it wins at equal specificity. */
@media (min-width: 640px) and (min-aspect-ratio: 7/10) and (max-height: 520px) {
  .stage { padding: 14px clamp(12px, 3vw, 26px); align-items: flex-start; }
  .stage__inner {
    grid-template-columns: minmax(0, .78fr) minmax(0, 1fr);
    gap: 22px;
    align-items: start;
  }
  .bill { justify-self: center; max-width: none; min-height: 0; }
  /* width:auto has nothing capping the HORIZONTAL size, so a 4:5 sheet scales
     off its own ratio and runs under the panel on tall viewports. max-width is
     load-bearing here, not tidying. */
  .bill__poster { max-height: calc(100svh - 40px); width: auto; max-width: 100%; margin: 0 auto; }
  .signup { justify-self: stretch; max-width: none; min-height: 0; }
  .spine { margin-bottom: 14px; }
  .panel__title { font-size: 1.28rem; margin-bottom: 9px; letter-spacing: .07em; }
  .panel__lede { font-size: 13px; margin-bottom: 7px; }
  .panel__lede--last { margin-bottom: 13px; }
  .form__row { margin-bottom: 10px; }
  .form__input { padding: 10px 13px; }
  .form__row--check { margin: 12px 0 14px; }
  .btn { padding: 12px 16px; }
  .iti__country-list { max-height: 150px; }
}

/* --- small phones --- */
@media (max-width: 400px) {
  .stage { padding-left: 16px; padding-right: 16px; }
}

/* ============================================================
   ACCESSIBILITY
   ============================================================ */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
