/* ==========================================================================
   COMPOSITION
   main.css owns the tokens, the rule-and-crosshair grammar, the card windows,
   the credential and the motion. This file owns where things sit now that the
   console carries the brand lockup and the rotating card, and it loads after
   main.css so its placement wins.

   The one-screen rule, restated:
   - 900px and up: nothing scrolls. The shell is exactly the window, the footer
     included, and the grid takes what the footer leaves.
   - Below 900px: the grid is exactly the (small) viewport, so the launch
     times and the whole console are on the first screen. The footer follows
     below and is the only thing a reader scrolls to.
   ========================================================================== */

/* ---- the brand lockup, the headline, the offer line ---------------------- */
.console__brand {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1vw, 15px);
  max-width: 100%;
  margin-bottom: clamp(14px, 3.2vh, 40px);
}
.console__mark {
  display: block;
  width: auto;
  height: clamp(34px, min(4.4vw, 6.6vh), 64px);
  margin: 0;
  flex: none;
}
.console__wordmark {
  width: clamp(92px, min(9.4vw, 14vh), 150px);
  height: auto;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
/* Sized against both axes: the room for the headline comes from height as
   much as width, and a wide short window is where a vw-only size breaks. */
.console__head {
  font-size: clamp(32px, min(4.6vw, 7.9vh), 74px);
  line-height: 1.02;
}
.console__box--head .note {
  margin-top: clamp(12px, 2.8vh, 40px);
  max-width: 40ch;
  font-size: clamp(10.5px, 0.9vw, 13px);
  line-height: 1.65;
  letter-spacing: 0.045em;
}

/* ---- the rotating card and the vault ------------------------------------- */
/* The demo box is a small cell of its own: a stage on top, a caption band
   underneath with a rule between them. The X runs corner to corner of the
   stage only, so every line in this box ends on another line, the same as
   the rest of the grid, and the caption text never sits on a diagonal. */
.console__box--demo {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  padding: 0;
  min-width: 0;
  min-height: 0;
  /* Its right edge is the console's own, so it draws only its bottom rule. */
  background-image: linear-gradient(var(--rule), var(--rule));
  background-position: left bottom;
  background-size: 100% 1px;
}

.privacy-stage {
  position: relative;
  min-height: 0;
  overflow: hidden;
}

/* The card, centred in the stage. Its box is inset from the stage edges; the
   image and the video are object-fit: contain inside it, and privacy.js reads
   that same geometry to lay the vault over the card exactly. */
.privacy-demo {
  position: absolute;
  inset: clamp(12px, 2vh, 22px) clamp(10px, 1vw, 16px);
}
.privacy-demo__poster,
.privacy-demo__video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
.privacy-demo__video { opacity: 0; background: transparent; }
.privacy-demo.is-playing .privacy-demo__video { opacity: 1; }
.privacy-demo.is-playing .privacy-demo__poster { opacity: 0; }

.privacy-vault {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  pointer-events: none;
}

/* The caption band. Its top rule is the stage's bottom edge. */
.privacy-bar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 34px;
  padding: 0 clamp(12px, 1.2vw, 18px);
  background-image: linear-gradient(var(--rule), var(--rule));
  background-repeat: no-repeat;
  background-position: left top;
  background-size: 100% 1px;
}
/* A crosshair where the band's rule meets the box's left edge - the same mark,
   made the same way, as every other cell's top-left corner. The right end gets
   none: nothing on the grid marks a line meeting the console's right edge, and
   card 06's crosshair sits a few pixels below that point and would half-cover
   one there. */
.privacy-bar::before {
  content: "";
  position: absolute;
  top: calc(var(--cross-clear) / -2);
  width: var(--cross-clear);
  height: var(--cross-clear);
  z-index: var(--z-cross);
  pointer-events: none;
  background-color: var(--black);
  background-image:
    linear-gradient(var(--cross), var(--cross)),
    linear-gradient(var(--cross), var(--cross));
  background-repeat: no-repeat;
  background-size: var(--cross-arm) 1px, 1px var(--cross-arm);
  background-position: center center, center center;
}
.privacy-bar::before { left: calc(var(--cross-clear) / -2); }

.privacy-toggle {
  min-width: 44px;
  min-height: 34px;
  margin: 0 0 0 -2px;
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
  text-align: left;
  font: 9px/1.2 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.privacy-toggle[hidden] { display: none; }
.privacy-toggle:hover { color: var(--gold); }
.privacy-toggle:focus-visible { outline: 1px solid var(--gold); outline-offset: 2px; }

.privacy-angle {
  margin: 0 0 0 auto;
  white-space: nowrap;
  color: var(--ink-2);
  font: 9px/1.2 var(--font-mono);
  letter-spacing: 0.06em;
}
.privacy-angle > span { margin-right: 5px; color: var(--ink-3); text-transform: uppercase; }
.privacy-angle output { display: inline-block; min-width: 5ch; font-variant-numeric: tabular-nums; }

/* ---- the form rows -------------------------------------------------------- */
.console__box--field .form { width: 100%; min-width: 0; }
/* The signup button reads a step larger than the shared 12px. */
.console__pane--form .btn { font-size: 13.5px; }
.console__box--action { display: flex; align-items: center; }
.console__pane--issued .console__box { min-width: 0; }

/* ---- the opening times --------------------------------------------------- */
/* The launch instant on this city's wall clock is the cell's main line; the
   caption under it names the zone. */
.clock__time {
  color: var(--ink);
  text-transform: uppercase;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* "Los Angeles, USA" is the longest name and "Nov 1 · 12:00 PM" the longest
   time, and both have to stay on one line in a sixth of the window. Both are
   sized against the width that cell actually gets. */
.clock__city { white-space: nowrap; font-size: clamp(12px, 1.4vw, 17px); }
/* main.js writes each line twice; a phone swaps to the short pair. */
.clock__short { display: none; }
/* The launch date is set in gold wherever a line carries it: "Nov 1 · 3:00
   PM" on desktop, "Opens Nov 1" on a phone. */
.clock__date { color: var(--gold); }
.clock__off {
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ==========================================================================
   900px AND UP
   ========================================================================== */
@media (min-width: 900px) {
  /* The window, exactly. The grid is a flex item that may not shrink below
     its content, so if a window is ever too short for the console the page
     grows and scrolls rather than the console spilling over the footer. */
  .shell { height: 100dvh; min-height: 0; }
  .grid { grid-template-rows: auto repeat(3, minmax(min-content, 1fr)); }
  .console { min-height: 0; }

  .cell--card[data-idx="14"] { grid-column: 6; grid-row: 2; }
  .cell--card[data-idx="07"] { grid-column: 6; grid-row: 3; }
  .cell--card[data-idx="15"] { grid-column: 6; grid-row: 4; }

  .console__pane--form {
    grid-template-rows: minmax(0, 1fr) auto auto;
    min-height: 0;
  }
  .console__box--head   { grid-column: 1 / 3; grid-row: 1; justify-content: flex-start; min-height: 0; }
  .console__box--demo   { grid-column: 3;     grid-row: 1; }
  .console__box--field  { grid-column: 1 / -1; grid-row: 2; display: flex; align-items: center;
                          padding-top: clamp(10px, 1.6vh, 16px); padding-bottom: clamp(10px, 1.6vh, 16px); }
  .console__box--action { grid-column: 1 / 3; grid-row: 3;
                          padding-top: clamp(10px, 1.6vh, 16px); padding-bottom: clamp(10px, 1.6vh, 16px); }
  .console__box--status { grid-column: 3;     grid-row: 3;
                          padding-top: clamp(8px, 1.4vh, 14px); padding-bottom: clamp(8px, 1.4vh, 14px); }

  .console__pane--issued { align-content: center; }

  .cell--card { padding: 27px 18px; }
  .cell__index { top: 12px; left: 14px; font-size: 9px; }
  .crop { width: min(80cqw, 72cqh, 200px); }
  .plate { top: calc(100% + 12px); }
  .plate__txt { font-size: 8px; letter-spacing: 0.08em; min-width: calc(var(--len, 14) * (1ch + 0.08em)); }

  .console__box { padding: clamp(14px, 2.2vh, 28px) clamp(16px, 1.6vw, 28px); }
  .console__box--demo { padding: 0; }
}

/* Narrow desktop: the console is only half the window, so the action row
   gives the helper its own line under the button. */
@media (min-width: 900px) and (max-width: 1199px) {
  .clock__time { letter-spacing: 0.02em; font-size: clamp(10px, 1.12vw, 13px); }
  .clock__off { letter-spacing: 0.06em; }
  .console__brand { gap: 9px; }
  .console__box--head .note { font-size: 10.5px; }
  .console__pane--form { grid-template-rows: minmax(0, 1fr) auto auto auto; }
  .console__box--action { grid-column: 1 / -1; background-image: none; padding-bottom: 4px; }
  .console__box--status { grid-row: 4; grid-column: 1 / -1; padding-top: 2px; }
  .console__box--status::after,
  .console__box--action::after { display: none; }
}

/* Laptop-height windows (1366x768, 1280x800): the headline runs to three
   lines at its size here, and the space around it pays for the third one, so
   the lockup and the offer line close up before anything else gives. */
@media (min-width: 900px) and (max-height: 800px) {
  .console__brand { margin-bottom: clamp(10px, 2vh, 18px); }
  .console__box--head .note { margin-top: clamp(8px, 1.8vh, 16px); }
}

/* Short desktop windows: the launch-times bar, the foot and the credential
   give before anything scrolls. */
@media (min-width: 900px) and (max-height: 760px) {
  .cell--bar { padding-top: 10px; padding-bottom: 10px; }
  .clock { gap: 3px; }
  .clock__city { font-size: 13px; }
  .clock__off { letter-spacing: 0.05em; }
  .console__box--head .note { line-height: 1.5; }
  .form__input { padding-top: 10px; padding-bottom: 10px; }
  .btn { min-height: 44px; }
  .shell { gap: 10px; padding-bottom: 10px; }
  .foot__wordmark { height: 30px; }
  .foot__legal { font-size: 9px; line-height: 1.45; }
}

@media (min-width: 900px) and (max-height: 680px) {
  /* The countdown carries four lines; at this height its pip is the one that
     gives. */
  .clock__pip { display: none; }
  .cell--bar { padding-top: 8px; padding-bottom: 8px; }
  .console__pane--issued .console__box { padding-top: 10px; padding-bottom: 10px; }
  .cred__tape { height: 9px; }
  .cred__body { padding-top: 8px; padding-bottom: 8px; gap: 10px; }
  .cred__mark { margin-bottom: 4px; }
  .cred__body .cred__field-key { margin-top: 6px; }
  .cred__seq { font-size: 30px; }
  .cred__matrix { width: 42px; margin-top: 5px; }
  .cred__meta-item { padding-top: 5px; padding-bottom: 5px; }
  .cred__foot { padding-top: 5px; padding-bottom: 6px; }
  .cred__barcode { height: 18px; }
  .cred__marks img { height: 16px; }
  .ante__head { font-size: 17px; margin-top: 2px; }
  .ante__refund { margin-top: 6px; font-size: 11px; }
  .ante__act { margin-top: 8px; gap: 8px 14px; }
  .ante__fine { font-size: 9.5px; line-height: 1.45; }
  .btn--ante { min-height: 42px; padding-top: 10px; padding-bottom: 10px; }
  .console__box--head .note { font-size: 10px; }
}

/* ==========================================================================
   BELOW 900px
   ========================================================================== */
@media (max-width: 899px) {
  :root { --pad: clamp(12px, 3.6vw, 20px); }

  .shell { height: auto; min-height: 100svh; padding: 0 10px 18px; gap: 16px; }

  /* At least the small viewport, and exactly it whenever the content fits,
     which is the case at every phone size this page is tested at. minmax(auto,
     1fr) lets the console grow past the screen only as a last resort, instead
     of overlapping the footer. */
  .grid {
    flex: none;
    height: auto;
    min-height: 100svh;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: minmax(auto, 1fr) auto;
  }

  /* The console opens the page on a phone, so the headline and the signup
     are the first thing read. The three launch times close the grid under
     it, still on the first screen, in a form a third of a phone can hold:
     the city without its country, "12 PM PST", then "Opens Nov 1".

     The bar is off the window edge here, so its crosshairs come back; the
     console's first box is on the edge now and gives its one up instead. */
  .bar > .cell.clock { grid-row: 2; }
  .cell--bar::after { display: block; }
  .console::after,
  .console__box--head::after { display: none; }
  .cell--bar { padding: clamp(8px, 1.2svh, 12px) clamp(8px, 2.6vw, 12px); }
  .clock { gap: 3px; }
  .clock__pip { width: 6px; height: 6px; }
  .clock__country { display: none; }
  .clock__long { display: none; }
  .clock__short { display: inline; }
  .clock__city { font-size: clamp(12px, 3.5vw, 15px); font-stretch: 66%; }
  .clock__time { font-size: clamp(11px, 3.3vw, 13px); letter-spacing: 0.02em; }
  .clock__off { font-size: 8.5px; letter-spacing: 0.08em; }

  /* The deck steps out of the form state on a phone; it comes back around
     the credential after signup. */
  .cell--card[data-idx="01"],
  .cell--card[data-idx="02"],
  .cell--card[data-idx="03"],
  .cell--card[data-idx="04"],
  .cell--card[data-idx="05"],
  .cell--card[data-idx="06"],
  .cell--card[data-idx="07"],
  .cell--extra { display: none; }
  .cell--card { padding: 8px; align-items: end; }
  .crop { width: min(70cqh, 60px); }

  .console { grid-column: 1 / -1; grid-row: 1; min-height: 0; }

  .console__pane--form {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(128px, 1fr) auto auto auto;
  }
  .console__pane--form .console__box { grid-column: 1; padding: 10px var(--pad); border-right: 0; }

  .console__box--head { grid-row: 1; justify-content: flex-start; background-image: none; }
  /* It opens the page now, so it takes a little more air above the lockup. */
  .console__pane--form .console__box--head { padding-top: clamp(14px, 2.8svh, 26px); }
  .console__brand { gap: 10px; margin-bottom: clamp(10px, 1.8svh, 16px); }
  .console__mark { height: clamp(32px, 5.6svh, 48px); }
  .console__wordmark { width: clamp(88px, 14svh, 116px); }
  .console__head { font-size: clamp(30px, min(11.4vw, 6.4svh), 50px); max-width: none; width: 100%; line-height: 1.01; }
  .console__box--head .note { margin-top: clamp(8px, 1.5svh, 13px); max-width: 46ch; font-size: 10px; line-height: 1.55; letter-spacing: 0.03em; }

  /* On a phone the demo spans the console, so it takes a rule on both edges
     and the X ends on a rule at the top and the bottom. There is no caption
     band: the stage takes all the height, and the two controls sit in the
     stage's side margins, beside the card and between the arms of the X,
     where neither reaches. */
  .console__pane--form .console__box--demo {
    grid-row: 2;
    grid-template-rows: minmax(0, 1fr);
    padding: 0;
    background-image:
      linear-gradient(var(--rule), var(--rule)),
      linear-gradient(var(--rule), var(--rule));
    background-position: left top, left bottom;
    background-size: 100% 1px, 100% 1px;
  }
  /* The card as large as the stage allows. The render has a 5.2% transparent
     margin around the card, so the box is pulled past the stage's top and
     bottom by about that much, which leaves the visible card roughly 9px
     inside each rule. The stage clips the transparent overhang. The card is
     height-bound on every phone, so its sides stay clear of the margins. */
  .privacy-demo { inset: calc(10px - 5.8%) 0; }
  /* The video has no alpha: that transparent margin is solid black in it. The
     stage is kept a pixel inside the box's top and bottom rules, so the
     overhang it clips can never paint over them. */
  .console__pane--form .privacy-stage { margin: 1px 0; }

  .privacy-bar { display: contents; }
  .privacy-bar::before { display: none; }
  .privacy-toggle,
  .privacy-angle {
    position: absolute;
    top: 50%;
    z-index: 3;
    transform: translateY(-50%);
  }
  /* Pause stays on a phone: it is the only way to stop a loop that plays for
     good, and the only way to start it where Low Power Mode refuses autoplay. */
  .privacy-toggle { left: 4px; min-width: 44px; min-height: 44px; margin: 0; padding: 0 8px; }
  .privacy-angle { right: 12px; margin: 0; text-align: right; line-height: 1.5; }
  .privacy-angle > span { display: block; margin: 0; }

  .console__box--field { grid-row: 3; display: flex; align-items: center; background-image: none; }
  .console__pane--form .console__box--field { padding-top: clamp(8px, 1.4svh, 12px); padding-bottom: 6px; }
  .console__pane--form .console__box--action { grid-row: 4; padding-top: 4px; padding-bottom: 6px; background-image: none; }
  .console__pane--form .console__box--status { grid-row: 5; padding-top: 0; padding-bottom: clamp(8px, 1.4svh, 12px); }
  .console__box--action::after,
  .console__box--status::after { display: none; }

  .form { width: 100%; gap: 5px; }
  .form__label { font-size: 9px; }
  .form__input { width: 100%; font-size: 16px; height: 42px; padding: 9px 12px; }
  .console__pane--form .btn { min-height: 44px; padding: 12px; font-size: 12.5px; }
  .helper { font-size: 10px; letter-spacing: 0; line-height: 1.45; }
  .status { font-size: 10px; }

  /* The foot is below the fold on a phone, so it no longer has to be squeezed
     onto the first screen and can be set at a size people can read: 12px, in
     sentence case, rather than 8px capitals. It is most of the page's text,
     which is also why Lighthouse's legible-text check turns on it. */
  .foot { padding: 4px 3px; gap: 12px; }
  .foot__wordmark { height: 30px; }
  .foot__legal { font-size: 12px; line-height: 1.55; letter-spacing: 0.01em; text-transform: none; }
  .foot__links { flex-direction: row; align-items: center; gap: 20px; font-size: 12px; letter-spacing: 0.01em; text-transform: none; }
  .foot__links a { padding: 6px 0; }

  /* ---- after signup ----
     The launch times stay at the bottom. The credential and the offer are
     shorter than the form was, so two fragment rows, one above and one below,
     share what is left, and nothing is left blank. The upper row is on the
     window edge, so its crosshairs go the way the headline box's did. */
  [data-state="issued"] .grid {
    grid-template-rows: minmax(clamp(50px, 9.5svh, 84px), 1fr) auto minmax(clamp(50px, 9.5svh, 84px), 1fr) auto;
  }
  [data-state="issued"] .console { grid-row: 2; }
  [data-state="issued"] .console::after { display: block; }
  [data-state="issued"] .bar > .cell.clock { grid-row: 4; }
  [data-state="issued"] .cell--card[data-idx="01"] { grid-column: 1; grid-row: 1; }
  [data-state="issued"] .cell--card[data-idx="02"] { grid-column: 2; grid-row: 1; }
  [data-state="issued"] .cell--card[data-idx="03"] { grid-column: 3; grid-row: 1; }
  [data-state="issued"] .cell--card:is([data-idx="01"], [data-idx="02"], [data-idx="03"])::after { display: none; }
  [data-state="issued"] .cell--card[data-idx="01"],
  [data-state="issued"] .cell--card[data-idx="02"],
  [data-state="issued"] .cell--card[data-idx="03"],
  [data-state="issued"] .cell--card[data-idx="04"],
  [data-state="issued"] .cell--card[data-idx="05"],
  [data-state="issued"] .cell--card[data-idx="06"] { display: grid; align-items: center; }
  [data-state="issued"] .cell--card[data-idx="04"] { grid-column: 1; grid-row: 3; }
  [data-state="issued"] .cell--card[data-idx="05"] { grid-column: 2; grid-row: 3; }
  [data-state="issued"] .cell--card[data-idx="06"] { grid-column: 3; grid-row: 3; }
  .console__pane--issued { grid-template-rows: auto auto; align-content: start; }

  .cred__foot { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 8px; padding-left: 10px; padding-right: 10px; }
  .cred__terms { font-size: 8px; letter-spacing: 0.04em; }
  .cred__barcode { min-width: 0; gap: 1px; }
  .cred__barcode i { min-width: 1px; }
  .cred__marks { gap: 4px; max-width: 100%; }
  .cred__marks li { flex: none; }
  .cred__marks img { height: 16px; }
}

/* Short phones: the deck row gives before the console does. After signup the
   credential and the offer are shorter than the form was, so both deck rows
   stay and share what is left, exactly as on a tall phone. */
@media (max-width: 899px) and (max-height: 700px) {
  .console__brand { margin-bottom: 8px; }
  .console__head { font-size: clamp(28px, min(9.9vw, 5.9svh), 37px); }
  .console__box--head .note { font-size: 9.5px; line-height: 1.45; }
  .console__pane--form { grid-template-rows: auto minmax(112px, 1fr) auto auto auto; }

  [data-state="issued"] .grid {
    grid-template-rows: minmax(44px, 1fr) auto minmax(44px, 1fr) auto;
  }
}

@media (max-width: 899px) and (max-height: 600px) {
  .cell--bar { padding-top: 7px; padding-bottom: 7px; }
  .console__mark { height: 28px; }
  .console__wordmark { width: 84px; }
  .console__head { font-size: 27px; }
  .console__box--head .note { font-size: 9px; }
  .console__pane--form { grid-template-rows: auto minmax(104px, 1fr) auto auto auto; }

  /* After signup there is room for one fragment row, not two, so the times
     sit right under the offer. Their crosshairs punch 11.5px up into it, and
     the offer's fine print keeps that much air under its last line. */
  [data-state="issued"] .grid { grid-template-rows: minmax(40px, 1fr) auto auto; }
  [data-state="issued"] .bar > .cell.clock { grid-row: 3; }
  [data-state="issued"] .console__box--ante { padding-bottom: 12px; }
  [data-state="issued"] .cell--card[data-idx="04"],
  [data-state="issued"] .cell--card[data-idx="05"],
  [data-state="issued"] .cell--card[data-idx="06"] { display: none; }
}

/* ==========================================================================
   MOTION - the new pieces join the same single reveal as everything else.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .console__brand, .privacy-demo, .privacy-vault,
  .privacy-toggle, .privacy-angle, .clock__off {
    clip-path: inset(100% 0 0 0);
    transition: clip-path 640ms var(--ease) var(--t-art);
  }
  .is-ready :is(.console__brand, .privacy-demo, .privacy-vault,
  .privacy-toggle, .privacy-angle, .clock__off) { clip-path: inset(0 0 0 0); }

  .console__box--demo,
  .privacy-bar { background-size: 0 1px; transition: background-size 560ms var(--ease) var(--t-rule); }
  .is-ready .console__box--demo,
  .is-ready .privacy-bar { background-size: 100% 1px; }

  @media (max-width: 899px) {
    .console__pane--form .console__box--demo { background-size: 0 1px, 0 1px; }
    .is-ready .console__pane--form .console__box--demo { background-size: 100% 1px, 100% 1px; }
  }

  .privacy-demo__poster,
  .privacy-demo__video { transition: opacity 400ms var(--ease); }
}
