/* ============================================================
   Diablo Padel — layout B.

   The video owns the whole screen. Text hugs the top and the bottom, and the
   middle of the frame stays clear. Same palette, same type, same one-screen
   rule, and the same form contract as layout A, so script.js runs unchanged.

   The one real cost is in .stage-video below: full bleed upscales a 9:16 clip
   on a landscape screen, where the split layout downscaled it.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
html { scrollbar-width: none; }
::-webkit-scrollbar { width: 0; height: 0; }

body {
  margin: 0;
  background: var(--shadow);
  color: var(--parchment);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { display: block; max-width: 100%; }

/* An author `display` beats the user agent's [hidden] rule, so .sheet's
   display:grid kept the invisible overlay laid over the page, swallowing every
   click on the button underneath. Restate it with weight. */
[hidden] { display: none !important; }
button, input { font: inherit; color: inherit; }

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

:root {
  --iron:      #D12200;
  --shadow:    #151314;
  --parchment: #F2F2F2;

  --iron-deep: #A61B00;
  --line:      rgba(242, 242, 242, 0.14);
  --line-lit:  rgba(242, 242, 242, 0.30);
  --muted:     rgba(242, 242, 242, 0.66);
  --dim:       rgba(242, 242, 242, 0.46);

  --font-serif: 'Grenze', Georgia, serif;
  --font-body:  'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* ---- Type scale ----
     Five roles, and every piece of text takes one of them. The brand book sets
     small labels in Lato with wide tracking, so navigation, the eyebrow, field
     labels and the back link all share one treatment. Body copy is the only
     sentence-case, untracked text on the page. */
  --fs-label:     12px;    /* Lato 700, uppercase, tracked */
  --fs-small:     13.5px;  /* supporting body copy */
  --fs-body:      16px;    /* inputs; 16px also stops iOS focus zoom */
  --fs-action:    15px;    /* the button */
  --track-label:  0.18em;
  --track-action: 0.06em;

  --pad: clamp(20px, 3.4vw, 56px);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------- Stage ---------- */

.stage {
  position: relative;
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: clamp(16px, 2.4vh, 32px);
  padding: var(--pad);
  overflow: hidden;
}

/* ---------- The court, full bleed ---------- */

.stage-media { position: absolute; inset: 0; z-index: 0; background: var(--shadow); }

/* The clip is 1080x1920. Covering a landscape screen crops it to a narrow
   horizontal band and scales it UP about 1.3x, where the split layout scaled it
   down. object-position keeps the racket and the player inside that band. */
.stage-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
}

/* Dark at both ends, clear through the middle: the text sits in the dark, the
   court stays visible where nothing is written over it. */
.stage-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(21, 19, 20, 0.88) 0%,
    rgba(21, 19, 20, 0.52) 26%,
    rgba(21, 19, 20, 0.22) 46%,
    rgba(21, 19, 20, 0.58) 74%,
    rgba(21, 19, 20, 0.93) 100%
  );
}

/* One label treatment, shared by every small piece of interface text. */
.topnav a,
.tracker-label,
.field label,
.sheet-back {
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

/* ---------- Bands ---------- */

.band { position: relative; z-index: 1; }

.band--top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px 40px;
  flex-wrap: wrap;
}

.brand img { width: clamp(132px, 12vw, 190px); height: auto; }
.brand a { display: block; border-radius: 3px; }
.brand a:focus-visible { outline: 2px solid var(--line-lit); outline-offset: 6px; }

.topnav { display: flex; gap: 8px 28px; flex-wrap: wrap; }

.topnav a {
  color: var(--muted);
  text-decoration: none;
  padding: 6px 0;
  border-bottom: 1px solid transparent;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.topnav a:hover { color: var(--parchment); border-bottom-color: var(--line-lit); }
.topnav a:focus-visible { outline: 2px solid var(--line-lit); outline-offset: 4px; }

/* ---------- The headline, hard against the top ---------- */

.band--head { align-self: start; padding-top: clamp(10px, 3vh, 36px); }

/* The date sits under the headline, so it carries the gap above, not below.
   It is the one label that reads as a subhead: bigger and brighter than the
   nav, still Lato, bold, uppercase and tracked. */
.eyebrow {
  margin: clamp(14px, 2.2vh, 24px) 0 0;
  font-family: var(--font-body);
  font-size: clamp(15px, 1.35vw, 20px);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--parchment);
}

/* Three outlined lines. The widest, "THE BAY AREA'S", is 11.93x its height
   (scripts/outline-headline.py prints the ratio), so the cap is the column
   width over 12.1: the line then fits at every viewport without wrapping.
   The 12vh ceiling keeps the button and the meter under it on one screen on
   short laptop viewports. */
.headline {
  --cap: min(clamp(28px, calc((100vw - 2 * var(--pad)) / 12.1), 100px), 12vh);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: calc(var(--cap) * 0.14);
  color: var(--parchment);
}

.word svg { height: var(--cap); width: auto; }
.word + .word { margin-left: calc(var(--cap) * 0.11); }

/* ---------- The offer, right under the date ---------- */

.offer {
  display: grid;
  justify-items: start;
  gap: 12px;
  margin-top: clamp(22px, 3.4vh, 40px);
}

.cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: min(100%, 380px);
  min-height: 62px;
  padding: 16px 18px 16px 26px;
  border: 0;
  border-radius: 4px;
  background: var(--iron);
  color: var(--parchment);
  font-weight: 900;
  font-size: var(--fs-action);
  letter-spacing: var(--track-action);
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.24s var(--ease), transform 0.24s var(--ease);
}

.cta:hover { background: var(--iron-deep); transform: translate3d(0, -1px, 0); }
.cta:active { transform: scale(0.985); }
.cta:focus-visible { outline: 2px solid var(--parchment); outline-offset: 3px; }
.cta[disabled] { cursor: progress; opacity: 0.72; transform: none; }

/* ---------- The glint on the hero button ----------
   A conic-gradient wedge spins inside the button while it slides side to side.
   A backdrop sits on top of it, inset by --cut, so only a hairline of the wedge
   shows: the light reads as a glint travelling round the edge, not a flash
   across the face. The whole thing is decoration, so it is aria-hidden and
   never intercepts the click. Hero button only, not the submit button. */

.cta--shimmer {
  --cut: 1px;
  --speed: 3.4s;
  --shimmer-color: #FFE9E4;
  --spread: 90deg;
  position: relative;
  z-index: 0;
  overflow: hidden;
  isolation: isolate;
}

/* Negative z-index paints over the button's own background but under its text,
   which is what puts the glint between the fill and the label. */
.cta-glint {
  position: absolute;
  inset: 0;
  z-index: -30;
  overflow: visible;
  container-type: size;
  filter: blur(2px);
  pointer-events: none;
}

.cta-glint > span {
  position: absolute;
  inset: 0;
  height: 100cqh;
  aspect-ratio: 1;
  animation: glint-slide var(--speed) ease-in-out infinite alternate;
}

.cta-glint > span::before {
  content: "";
  position: absolute;
  inset: -100%;
  background: conic-gradient(
    from calc(270deg - (var(--spread) * 0.5)),
    transparent 0,
    var(--shimmer-color) var(--spread),
    transparent var(--spread));
  animation: glint-spin calc(var(--speed) * 2) infinite linear;
}

/* The backdrop. Same fill as the button, inset by --cut, so it leaves exactly
   a --cut-wide ring of the wedge visible. It has to track the hover colour,
   because it is what you are actually looking at. */
.cta--shimmer::after {
  content: "";
  position: absolute;
  z-index: -20;
  inset: var(--cut);
  border-radius: inherit;
  background: var(--iron);
  transition: background 0.24s var(--ease);
  pointer-events: none;
}

.cta--shimmer:hover::after { background: var(--iron-deep); }
.cta--shimmer[disabled]::after { background: var(--iron); }

@keyframes glint-slide {
  to { transform: translate(calc(100cqw - 100%), 0); }
}

@keyframes glint-spin {
  0%       { transform: translateZ(0) rotate(0); }
  15%, 35% { transform: translateZ(0) rotate(90deg); }
  65%, 85% { transform: translateZ(0) rotate(270deg); }
  100%     { transform: translateZ(0) rotate(360deg); }
}

.cta-price {
  padding-left: 18px;
  border-left: 1px solid rgba(242, 242, 242, 0.34);
  font-size: var(--fs-action);
  letter-spacing: var(--track-action);
}

/* The meter: the founding group as a loading bar. It fills as spots are
   claimed, so the red reads as people who already pressed the red button and
   the dark remainder is what is still open. The fill scales instead of
   resizing, which keeps the update off the layout thread, and a light sweeps
   along it so the bar reads as live rather than printed. */
.tracker {
  width: min(100%, 380px);
  display: grid;
  gap: 10px;
}

/* display:grid outranks the user agent's [hidden] rule, the same trap .sheet
   fell into once. */
.tracker[hidden] { display: none; }

.tracker-label {
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  color: var(--muted);
}

.tracker-label strong { color: var(--parchment); }

.tracker-bar {
  height: 10px;
  border-radius: 5px;
  background: rgba(242, 242, 242, 0.16);
  box-shadow: inset 0 1px 0 rgba(242, 242, 242, 0.08);
  overflow: hidden;
}

.tracker-fill {
  position: relative;
  display: block;
  height: 100%;
  width: 100%;
  overflow: hidden;
  border-radius: inherit;
  background: var(--iron);
  transform: scaleX(var(--claimed, 0));
  transform-origin: left center;
  transition: transform 0.9s var(--ease);
}

.tracker-fill::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent 20%, rgba(242, 242, 242, 0.32) 50%, transparent 80%);
  transform: translate3d(-100%, 0, 0);
  animation: sweep 2.6s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

@keyframes sweep {
  to { transform: translate3d(100%, 0, 0); }
}

/* Only shown when the live count cannot be read: a line with no number in it. */
.tracker-fallback { margin: 0; font-size: var(--fs-small); color: var(--muted); }

/* ---------- The form, a card over the court ---------- */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  padding: var(--pad);
  background: rgba(21, 19, 20, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

@keyframes lift {
  from { opacity: 0; transform: translate3d(0, 18px, 0); }
  to   { opacity: 1; transform: none; }
}

.sheet-card {
  width: min(100%, 520px);
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(24px, 3.4vw, 40px);
  border: 1px solid var(--line);
  /* A 1px inner highlight reads as a real edge rather than a flat panel. */
  box-shadow: inset 0 1px 0 rgba(242, 242, 242, 0.08), 0 30px 70px -20px rgba(0, 0, 0, 0.7);
  border-radius: 8px;
  background: #1B1719;
  animation: lift 0.42s var(--ease) both;
}

.sheet-back {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0 0 18px -8px; padding: 8px;
  border: 0; background: none; color: var(--dim); cursor: pointer;
  transition: color 0.2s var(--ease);
}

.sheet-back:hover { color: var(--parchment); }
.sheet-back:focus-visible { outline: 2px solid var(--line-lit); outline-offset: 2px; }
.sheet-back svg { width: 14px; height: 14px; }

.sheet-title {
  margin: 0 0 6px;
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: clamp(26px, 3vw, 36px);
  line-height: 1.1;
}

.sheet-lede { margin: 0 0 24px; font-size: var(--fs-small); color: var(--muted); max-width: 42ch; }

.form { display: grid; gap: 15px; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.field { display: grid; gap: 7px; min-width: 0; }

.field label {
  color: var(--dim);
}

.field input {
  width: 100%; min-height: 52px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 4px;
  background: rgba(242, 242, 242, 0.05);
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}

.field input::placeholder { color: rgba(242, 242, 242, 0.3); }
.field input:hover { border-color: var(--line-lit); }
.field input:focus { outline: none; border-color: var(--parchment); background: rgba(242, 242, 242, 0.08); }
.field input[aria-invalid="true"] { border-color: var(--iron); }

.err { margin: 0; font-size: 12.5px; color: #FF6B4A; }
.err:empty { display: none; }

.cta--submit { width: 100%; margin-top: 4px; }
.form-note { margin: 2px 0 0; font-size: var(--fs-small); line-height: 1.5; color: var(--dim); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- Grain and toast ---------- */

.grain {
  position: fixed; inset: 0; z-index: 6; pointer-events: none;
  opacity: 0.045; 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'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

.toast {
  position: fixed; left: 50%; bottom: 26px; z-index: 7;
  max-width: min(92vw, 460px); padding: 13px 20px;
  border: 1px solid var(--line); border-radius: 4px; background: #201d1e;
  font-size: 14px; opacity: 0; pointer-events: none;
  transform: translate3d(-50%, 14px, 0);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.toast.show { opacity: 1; transform: translate3d(-50%, 0, 0); }

/* ---------- Narrow ---------- */

@media (max-width: 760px) {
  .band--top { justify-content: space-between; gap: 10px 24px; }
  .topnav { width: 100%; justify-content: space-between; gap: 8px 16px; font-size: 12.5px; }
  .offer { justify-items: stretch; }
  .cta, .tracker { width: 100%; }
  .stage-video { object-position: 50% 46%; }
}

/* Names stay paired down to the narrowest common phone. Stacking them costs
   about 90px, which is the difference between seeing the submit button and
   having to scroll for it. */
@media (max-width: 380px) {
  .row { grid-template-columns: 1fr; }
}

/* "Continue to checkout" plus the price wraps to two lines under ~420px. */
@media (max-width: 420px) {
  .cta { font-size: 13.5px; letter-spacing: 0.04em; padding-inline: 14px 16px; }
  .cta-price { padding-left: 14px; font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .cta-glint { display: none; }
  video.stage-video { display: none; }
  .stage-media { background: url("assets/court-wide.jpg") 50% 50% / cover no-repeat; }
}
