/* Taiv ad preview. Brand tokens mirror the Studio login page and
   taiv-deck-studio shell.css: dark indigo ground, Tech White ink, ONE violet
   accent, hairline cards. Coral and orchid appear only in the backdrop glow. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('vendor/inter.woff2') format('woff2');
}

:root {
  --indigo: #0a0420;
  --surface: #1a1040;
  --overlay: #160f33;
  --white: #f5f7fa;
  --uv: #6f3fee;
  --p100: #9b6eff;
  --coral: #fa9479;
  --orchid: #c775a4;
  --hairline: rgba(255, 255, 255, 0.08);
  --hairline-strong: rgba(255, 255, 255, 0.12);
  --muted: color-mix(in srgb, var(--white) 55%, transparent);
  --muted-soft: color-mix(in srgb, var(--white) 70%, transparent);
  --r-marketing: 1rem;
  --r-surface: 0.7rem;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --max: 68rem;
}

* {
  box-sizing: border-box;
  margin: 0;
}
[hidden] {
  display: none !important;
}
html {
  color-scheme: dark;
  background: var(--indigo);
}
body {
  font-family:
    'Inter',
    system-ui,
    -apple-system,
    sans-serif;
  background: var(--indigo);
  color: var(--white);
  line-height: 1.5;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}
a {
  color: inherit;
}
button,
input,
textarea {
  font: inherit;
  color: inherit;
}
img {
  max-width: 100%;
  display: block;
}
em {
  font-style: normal;
  color: var(--p100);
}

/* Backdrop: the gateway's field grid engine, ripple mode, behind everything. */
.fieldgrid {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  --mx: 70%;
  --my: 35%;
  pointer-events: none;
}
.fieldgrid__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.fieldgrid__glow {
  position: absolute;
  inset: -20% -10% auto auto;
  width: 70%;
  height: 100%;
  background:
    radial-gradient(
      38% 46% at 72% 40%,
      color-mix(in srgb, var(--uv) 45%, transparent),
      transparent 70%
    ),
    radial-gradient(
      30% 34% at 84% 66%,
      color-mix(in srgb, var(--orchid) 26%, transparent),
      transparent 72%
    ),
    radial-gradient(
      26% 30% at 60% 20%,
      color-mix(in srgb, var(--coral) 16%, transparent),
      transparent 74%
    );
  filter: blur(30px);
  opacity: 0.85;
}

.page {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100dvh;
}

/* Header */
.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.9rem clamp(1.25rem, 4vw, 3rem);
  gap: 1rem;
}
.top__logo {
  width: 5.6rem;
  height: auto;
}
.top__actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.top__hint {
  font-size: 0.78rem;
  color: var(--muted-soft);
}
@media (max-width: 700px) {
  .top__hint {
    display: none;
  }
}
.top__share {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  height: 2.1rem;
  padding: 0 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  transition:
    color 0.15s,
    border-color 0.15s;
}
.top__share:hover,
.top__share.is-copied {
  color: var(--white);
  border-color: color-mix(in srgb, var(--uv) 55%, transparent);
}
.top__admin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
  color: var(--muted);
  transition:
    color 0.15s,
    border-color 0.15s,
    transform 0.4s;
}
.top__admin:hover {
  color: var(--white);
  border-color: color-mix(in srgb, var(--uv) 55%, transparent);
  transform: rotate(45deg);
}

main {
  width: min(var(--max), 100%);
  margin: 0 auto;
  padding: 0.5rem clamp(1.25rem, 4vw, 3rem) 1.5rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 0;
}

/* Hero */
.hero {
  text-align: center;
  padding: clamp(1.5rem, 5vw, 4rem) 0 2rem;
}
h1 {
  font-size: clamp(2rem, 4.4vw, 3.1rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.08;
}
.sub {
  margin: 1rem auto 0;
  max-width: 34rem;
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  font-weight: 300;
  color: var(--muted-soft);
}

/* Card */
.card {
  border-radius: var(--r-marketing);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--overlay) 86%, transparent);
  box-shadow:
    0 1.8rem 4rem rgba(0, 0, 0, 0.45),
    0 0 4rem color-mix(in srgb, var(--uv) 14%, transparent);
  padding: clamp(1.4rem, 3vw, 2.2rem);
}
.form-card {
  width: min(34rem, 100%);
  margin: 0 auto;
}

/* Step 1: the brand, with suggestions from the advertiser list (brands.json). */
.suggest {
  position: relative;
}
.suggest__list {
  /* In the flow, not floating: it must never cover the Continue button. */
  margin: -0.6rem 0 1rem;
  padding: 0.3rem;
  list-style: none;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--overlay) 96%, transparent);
  box-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(12px);
}
.suggest__list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0.55rem 0.7rem;
  border-radius: 0.45rem;
  cursor: pointer;
  font-weight: 500;
}
.suggest__list li small {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.8rem;
}
.suggest__list li:hover,
.suggest__list li.is-active {
  background: color-mix(in srgb, var(--uv) 28%, transparent);
}

/* "Or give us your website": the second way into step 1 (design note 0002). */
.orsite {
  margin-top: 1rem;
}
.orsite__rule {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  color: var(--muted);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.orsite__rule::before,
.orsite__rule::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--hairline-strong);
}
.orsite__lead {
  margin: 0.8rem 0 0.5rem;
  color: var(--muted-soft);
  font-size: 0.95rem;
}
.orsite__row {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
}
.field--grow {
  flex: 1;
}
.orsite__row .btn {
  white-space: nowrap;
}
.brief {
  margin-bottom: 0.4rem;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.9rem;
  padding: 0.8rem 0.9rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
}
/* The logo: the site's own icon, else Google's favicon for the domain,
   else the brand's initial. White ground: most marks are drawn for one. */
.brief__logo {
  position: relative;
  width: 3rem;
  height: 3rem;
  border-radius: 0.65rem;
  background: #fff;
  display: grid;
  place-items: center;
  overflow: hidden;
  flex: none;
}
.brief__logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 0.25rem;
}
.brief__logo b {
  font-size: 1.3rem;
  font-weight: 800;
  color: var(--indigo);
}
.brief__logo img:not([hidden]) + b {
  display: none;
}
.brief__text {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}
.brief__name {
  width: 100%;
  min-width: 0;
  padding: 0.1rem 0;
  border: 0;
  border-bottom: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--white);
  font: inherit;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.brief__name:hover {
  border-bottom-color: var(--hairline-strong);
}
.brief__name:focus {
  outline: 0;
  border-bottom-color: var(--p100);
}
.brief__site {
  color: var(--muted);
  font-size: 0.82rem;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.brief__site:hover {
  color: var(--muted-soft);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.brief__swatches {
  display: flex;
  gap: 0.3rem;
  flex: none;
}
.brief__swatches i {
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
}

/* The brand's current creative: up to three found frames and a fourth
   tile to upload your own (Dylan, 2026-09-04). Picking one IS an upload. */
.picks {
  margin-top: 0.9rem;
}
.picks__lead {
  margin: 0 0 0.5rem;
  color: var(--muted-soft);
  font-size: 0.9rem;
}
/* Two across, so a found frame is big enough to recognise (Dylan). */
.picks__grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
}
/* The arrows on the found pair's outer edges, at the top row's middle. */
.picks__arrow {
  position: absolute;
  top: calc(25% - 0.15rem);
  transform: translateY(-50%);
  width: 1.9rem;
  height: 1.9rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
  background: rgba(10, 4, 32, 0.88);
  color: var(--white);
  cursor: pointer;
  z-index: 2;
  transition:
    border-color 0.15s,
    transform 0.2s var(--ease);
}
.picks__arrow svg {
  width: 1rem;
  height: 1rem;
}
.picks__arrow:hover {
  border-color: var(--p100);
  transform: translateY(-50%) scale(1.06);
}
.picks__arrow--prev {
  left: -0.8rem;
}
.picks__arrow--next {
  right: -0.8rem;
}
.pick {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 0.5rem;
  border: 1px solid var(--hairline-strong);
  background: #06031a;
  overflow: hidden;
  padding: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease,
    transform 0.2s var(--ease);
}
.pick:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--p100) 50%, var(--hairline-strong));
}
.pick.is-picked {
  border-color: var(--p100);
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--p100) 55%, transparent),
    0 0 1.4rem color-mix(in srgb, var(--uv) 45%, transparent);
}
.pick img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.pick__tag {
  position: absolute;
  left: 0.5rem;
  bottom: 0.45rem;
  right: 0.5rem;
  font-size: 0.75rem;
  line-height: 1.2;
  color: var(--white);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}
.pick--skeleton {
  background: linear-gradient(90deg, #120c30, #1c1346, #120c30);
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
  cursor: default;
}
@keyframes shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}
.pick--upload {
  display: grid;
  place-items: center;
  border-style: dashed;
  background: transparent;
  color: var(--muted-soft);
  font-size: 0.85rem;
  font-weight: 500;
  text-align: center;
  padding: 0.3rem;
}
.pick--upload svg {
  width: 1.6rem;
  height: 1.6rem;
  margin-bottom: 0.3rem;
}
/* The tile's children take no drag events, so dragleave does not flicker
   as the file crosses the icon and the label. */
.pick--upload > span {
  pointer-events: none;
}
/* A file held over the Upload tile. */
.pick.is-over {
  border-style: solid;
  border-color: var(--p100);
  background: color-mix(in srgb, var(--uv) 20%, transparent);
  color: var(--white);
  transform: scale(1.02);
}
.pick--generate {
  color: var(--p100);
  border-color: color-mix(in srgb, var(--p100) 35%, var(--hairline-strong));
}
.picks__draw {
  margin: 0.6rem 0 0;
  color: var(--muted);
  font-size: 0.85rem;
}
.linkbtn--quiet {
  color: var(--muted-soft);
  text-decoration: none;
  margin-left: 0.4rem;
}
.linkbtn--quiet:hover {
  color: var(--white);
}
.picks__grid {
  margin-top: 0.3rem;
}
.brief + .error {
  margin-top: 0.4rem;
}
#picksTitle {
  margin-top: 1.2rem;
}
.linkbtn {
  background: none;
  border: 0;
  padding: 0;
  color: var(--p100);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.step {
  animation: rise 0.45s var(--ease) both;
}
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.step h2 {
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 0.35rem;
}
.step p.hint {
  color: var(--muted);
  font-size: 0.92rem;
  margin-bottom: 1.1rem;
}

/* Drop zone */
.drop {
  display: grid;
  place-items: center;
  gap: 0.4rem;
  min-height: 12rem;
  padding: 1.2rem;
  border: 1.5px dashed color-mix(in srgb, var(--white) 25%, transparent);
  border-radius: var(--r-surface);
  background: color-mix(in srgb, var(--surface) 55%, transparent);
  cursor: pointer;
  text-align: center;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
  position: relative;
  overflow: hidden;
}
.drop:hover,
.drop.is-over {
  border-color: var(--p100);
  background: color-mix(in srgb, var(--uv) 12%, var(--surface));
}
.drop input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.drop__icon {
  width: 2.4rem;
  height: 2.4rem;
  color: var(--p100);
}
.drop__title {
  font-weight: 600;
}
.drop__sub {
  color: var(--muted);
  font-size: 0.88rem;
}
.drop.has-image {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 0;
  padding: 0.75rem 1rem;
  border-style: solid;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  text-align: left;
}
.drop__ok {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  font-size: 0.95rem;
}
.drop__ok svg {
  width: 1.1rem;
  height: 1.1rem;
  color: var(--p100);
}
.drop__change {
  font-size: 0.8rem;
  font-weight: 600;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  pointer-events: none;
}

/* The uploaded ad, above the card, for the rest of the form. */
.stack {
  width: min(34rem, 100%);
  margin: 0 auto;
}
.stack .form-card {
  width: 100%;
  margin: 0;
}
.ad-preview {
  /* Compact: it sits above the email card, and must leave it on screen. */
  max-width: min(100%, calc(28vh * 16 / 9));
  margin: 0 auto 1rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  overflow: hidden;
  background: #000;
  aspect-ratio: 16 / 9;
  box-shadow:
    0 1.2rem 3rem rgba(0, 0, 0, 0.5),
    0 0 4rem color-mix(in srgb, var(--uv) 16%, transparent);
  animation: rise 0.45s var(--ease) both;
}
.ad-preview img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Fields */
.field {
  display: block;
  margin-bottom: 1rem;
}
.field span {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted-soft);
  margin-bottom: 0.4rem;
}
.field input,
.field textarea {
  width: 100%;
  padding: 0.8rem 0.95rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--indigo) 70%, transparent);
  outline: none;
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.field input:focus,
.field textarea:focus {
  border-color: var(--uv);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--uv) 30%, transparent);
}
.field textarea {
  min-height: 5.5rem;
  resize: vertical;
}
.field--optional span::after {
  content: ' (optional)';
  font-weight: 400;
  color: var(--muted);
}
.fields-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 0.9rem;
}
@media (max-width: 30rem) {
  .fields-2 {
    grid-template-columns: 1fr;
  }
}
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.4rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  transition:
    transform 0.15s var(--ease),
    box-shadow 0.15s ease,
    background 0.15s ease,
    opacity 0.15s ease;
}
.btn:hover {
  background: var(--surface);
}
.btn:disabled {
  opacity: 0.5;
  cursor: default;
}
.btn--primary {
  background: var(--uv);
  border-color: var(--uv);
  color: #fff;
}
.btn--primary:hover:not(:disabled) {
  background: color-mix(in srgb, var(--uv) 85%, white);
  box-shadow: 0 0.6rem 2rem color-mix(in srgb, var(--uv) 45%, transparent);
  transform: translateY(-1px);
}
.btn--ghost {
  background: transparent;
}
.btn--block {
  width: 100%;
}
.actions {
  display: flex;
  gap: 0.7rem;
  margin-top: 1.2rem;
  flex-wrap: wrap;
}
.actions .btn:first-child {
  flex: 1;
}
.fine {
  margin-top: 0.9rem;
  font-size: 0.82rem;
  color: var(--muted);
}
.error {
  margin-top: 0.9rem;
  border-radius: var(--r-surface);
  border: 1px solid color-mix(in srgb, var(--coral) 45%, transparent);
  background: color-mix(in srgb, var(--coral) 10%, transparent);
  padding: 0.65rem 0.9rem;
  font-size: 0.9rem;
  color: color-mix(in srgb, var(--coral) 80%, var(--white));
}

/* The example under the hero: a rotating stage of Taiv's own bracket on
   real venues. Not clickable; it is a picture of what you get. */
.example {
  width: min(52rem, 100%);
  margin: 2.5rem auto 0;
}
.tile--intro {
  animation: none;
  box-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.45);
}
.tile--intro .stage__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 40%;
}

/* The wait: a full-screen scene with the copy over it. */
.wait {
  position: fixed;
  inset: 0;
  z-index: 5;
  background: var(--indigo);
  opacity: 0;
  transition: opacity 0.6s ease;
}
.wait.is-on {
  opacity: 1;
}
/* The landing: the overlay goes clear so the results page shows through
   while the venue photo slides away and the board comes in. */
.wait.is-landing {
  background: transparent;
  transition:
    opacity 0.6s ease,
    background 0.5s ease;
}
.wait.is-landing .wait__bg,
.wait.is-landing .fieldgrid,
.wait.is-landing .wait__vignette,
.wait.is-landing .wait__copy,
.wait.is-landing .wait__logo {
  opacity: 0;
  transition: opacity 0.5s ease;
}
/* The blurred venue behind the field grid (Deck Studio's backdrop), held
   down towards the indigo so the grid and the TVs still read over it. */
.wait__bg {
  position: absolute;
  inset: 0;
  background: url('assets/venue-backdrop.webp') center 30% / cover no-repeat;
  opacity: 0.4;
  transition:
    opacity 1s ease 0.2s,
    transform 1.8s var(--ease) 0.2s;
}
/* The takeover (Dylan): the form fades, the overlay's indigo comes up, the
   bar photo rises through it and settles, the row fades in, then the card
   slides up from the bottom edge. Each part is a staged transition from
   the overlay's resting state to .is-on. */
.wait:not(.is-on) .wait__bg {
  opacity: 0;
  transform: scale(1.06);
}
.wait .tvfield {
  transition: opacity 0.8s ease 0.5s;
}
.wait:not(.is-on) .tvfield {
  opacity: 0;
}
.view.is-fading {
  opacity: 0;
  transform: translateY(-12px);
  transition:
    opacity 0.45s ease,
    transform 0.45s var(--ease);
}
.wait__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(10, 4, 32, 0.25), rgba(10, 4, 32, 0.8));
}
.wait .fieldgrid {
  position: absolute;
  --mx: 50%;
  --my: 42%;
  transition: opacity 0.4s ease;
}
.wait .fieldgrid__glow {
  inset: auto -10% -20% auto;
  width: 80%;
  opacity: 0.6;
}
.wait__vignette,
.wait__copy,
.wait__logo {
  transition: opacity 0.4s ease;
}

/* The field of TVs. The bezel, the collapse and the flash line are Deck
   Studio's wall TV (`.wtv` in its styles.css), renamed. A CSS grid until
   the first change of formation; then wait.js poses each TV itself under
   the field's one perspective. */
/* The scene: every TV, the globe and the venue photo are fixed elements,
   posed by wait.js each frame under one perspective. The field is its own
   stacking context, so the card above it overlays the lot. */
.tvfield {
  position: absolute;
  inset: 0;
  z-index: 1;
  perspective: 1400px;
  --tvw: 480px;
}
/* A TV: the deck's bubble, sized from --tvw so the bezel scales with it. */
.tv {
  position: fixed;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  transform-style: preserve-3d;
  --depth: calc(var(--tvw) * 0.028);
  --r: calc(var(--tvw) * 0.024);
  border-radius: var(--r);
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: var(--indigo);
  padding: calc(var(--tvw) * 0.011);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.04),
    0 1.2rem 3rem rgba(0, 0, 0, 0.55);
  will-change: transform;
  transition:
    opacity 0.4s ease,
    padding 0.5s ease,
    border-color 0.5s ease,
    box-shadow 0.5s ease;
}
.tv__scr {
  position: relative;
  display: block;
  backface-visibility: hidden;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: calc(var(--tvw) * 0.016);
  background-color: #06031a;
  background-size: cover;
  background-position: center;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
  /* The CRT collapse is a vertical scale, not a clip-path: inside the set's
     3D context (preserve-3d, backface hidden) Chrome would not animate the
     clip, so the screen snapped and only the flash line was seen (Dylan). A
     transform always composites and animates. */
  transform: scaleY(1);
  transform-origin: 50% 50%;
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
  /* Safari: clip an animated child to the rounded screen. */
  -webkit-mask-image: -webkit-radial-gradient(#fff, #000);
}
.tv__scr.is-off {
  transform: scaleY(0.01);
}
/* Waiting for its first picture: open, dark, the studio's loading sweep
   across it. The sweep is a real child, not a pseudo-element: inside the
   set's 3D context Safari did not paint an animated ::after at all (Dylan,
   iPhone), and the mask forces the rounded overflow to clip it. */
.tv__shine {
  display: none;
  position: absolute;
  top: -30%;
  bottom: -30%;
  left: 0;
  width: 60%;
  pointer-events: none;
  will-change: transform;
}
.tv__scr.is-idle .tv__shine {
  display: block;
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--p100) 20%, transparent) 50%,
    transparent
  );
  animation: tvsweep 2.4s linear infinite;
}
/* The ad, before the bracket: the same sweep, faint and white, over the picture. */
.tv__scr.is-waiting .tv__shine {
  display: block;
  width: 50%;
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--white) 9%, transparent) 50%,
    transparent
  );
  animation: tvsweep 3.4s linear infinite;
}
@keyframes tvsweep {
  from {
    transform: translateX(-140%) skewX(-20deg);
  }
  to {
    transform: translateX(210%) skewX(-20deg);
  }
}
.tv__line {
  position: absolute;
  left: 0.22rem;
  right: 0.22rem;
  top: 50%;
  height: 2px;
  transform: translateY(-50%) scaleX(0.4);
  border-radius: 2px;
  background: var(--white);
  box-shadow: 0 0 10px 1px color-mix(in srgb, var(--white) 80%, transparent);
  opacity: 0;
  transition:
    opacity 0.16s ease,
    transform 0.26s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}
.tv.is-flash .tv__line {
  opacity: 1;
  transform: translateY(-50%) scaleX(1);
}
/* The set's body: four side faces standing back from the bezel by --depth,
   and a back face at that depth carrying the same picture, turned to read
   the right way round from behind. A solid slab from every angle; edge-on
   to the wall the sides vanish. */
.tv__back {
  position: absolute;
  inset: 0;
  border-radius: var(--r);
  border: 1px solid rgba(255, 255, 255, 0.15);
  background-color: var(--indigo);
  background-size: cover;
  background-position: center;
  background-origin: content-box;
  background-clip: content-box;
  padding: calc(var(--tvw) * 0.011);
  transform: translateZ(calc(-1 * var(--depth))) rotateY(180deg);
  backface-visibility: hidden;
  pointer-events: none;
}
.tv__side {
  position: absolute;
  background: #150e38;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  backface-visibility: visible;
  pointer-events: none;
}
/* The side faces stop short of the corners by the bezel's radius: run to
   the corner, they poked past the rounding as sharp edges (Dylan). What is
   left at each corner is dark on dark and does not read. */
.tv__side--l,
.tv__side--r {
  top: var(--r);
  width: var(--depth);
  height: calc(100% - 2 * var(--r));
  transform-origin: 0 50%;
  transform: rotateY(90deg);
}
.tv__side--l {
  left: 0;
}
.tv__side--r {
  left: 100%;
  background: #1b1346;
}
.tv__side--t,
.tv__side--b {
  left: var(--r);
  width: calc(100% - 2 * var(--r));
  height: var(--depth);
  transform-origin: 50% 0;
  transform: rotateX(-90deg);
}
.tv__side--t {
  top: 0;
  background: #1e1650;
}
.tv__side--b {
  top: 100%;
  background: #100a2c;
}
/* The corners: the side faces stop short of them by the radius, and a
   chamfer face bridges each gap, standing on the chord of the bezel's
   rounding. Without it the gaps read as holes from an angle (Dylan). The
   chord of a quarter circle of radius r is r times root 2; its midpoint is
   half r in from the corner both ways. Hinged on its top edge like the
   other faces, then turned onto the chord. */
.tv__c {
  width: calc(var(--r) * 1.4142);
  height: var(--depth);
  transform-origin: 50% 0;
  background: #170f3f;
}
.tv__c--tl {
  left: calc(var(--r) * 0.5 - var(--r) * 0.7071);
  top: calc(var(--r) * 0.5);
  transform: rotateZ(-45deg) rotateX(-90deg);
}
.tv__c--tr {
  left: calc(100% - var(--r) * 0.5 - var(--r) * 0.7071);
  top: calc(var(--r) * 0.5);
  transform: rotateZ(45deg) rotateX(-90deg);
}
.tv__c--br {
  left: calc(100% - var(--r) * 0.5 - var(--r) * 0.7071);
  top: calc(100% - var(--r) * 0.5);
  transform: rotateZ(-45deg) rotateX(-90deg);
}
.tv__c--bl {
  left: calc(var(--r) * 0.5 - var(--r) * 0.7071);
  top: calc(100% - var(--r) * 0.5);
  transform: rotateZ(45deg) rotateX(-90deg);
}
.tv.is-out {
  opacity: 0;
}

/* The venue photo the TVs land on. Sat under them (z 900, the TVs start at
   1000), then shrunk into the results page's stage. */
.tvvenue {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 900;
  transform-origin: 0 0;
  transform: translate(var(--vx, 0px), var(--vy, 0px)) scale(var(--vs, 1));
  border-radius: var(--r-surface);
  overflow: hidden;
  background: #000;
  box-shadow:
    0 2rem 5rem rgba(0, 0, 0, 0.6),
    0 0 6rem color-mix(in srgb, var(--uv) 25%, transparent);
  opacity: 0;
  pointer-events: none;
  /* The slide in from the right, and the slide away to the left. */
  transition: transform 1.1s var(--ease);
}
.tvvenue.is-parked {
  transition: none;
}
.tvvenue.is-on {
  opacity: 1;
}
.tvvenue.is-leaving {
  transition: transform 0.8s cubic-bezier(0.5, 0, 0.85, 0.35);
}
.tvvenue img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* A screen in the venue photo: a 16:9 box carried onto the screen's four
   corners (matrix3d), showing the game, then black (the break), then gone
   so the ad already on the photo beneath shows through. */
.tvset {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  background: #000;
  overflow: hidden;
  opacity: 1;
  transition: opacity 0.9s ease;
}
.tvset canvas {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 1;
  transition: opacity 0.6s ease;
}
.tvset.is-black canvas {
  opacity: 0;
}
/* The one video that decodes the game for every screen: never seen itself. */
.tvclip {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.tvset.is-ad {
  opacity: 0;
}

/* The network globe, floating at the centre of the ring. Fixed from the
   start so the wall's grid never has to place it; drawn only in the ring. */
.tvglobe {
  position: fixed;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  opacity: 0;
  transition: opacity 0.9s ease;
  pointer-events: none;
  will-change: transform;
}
.tvglobe.is-on {
  opacity: 1;
}
.tvglobe canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.55;
  transition: opacity 1.2s ease;
}
/* Lit by the brackets: the grid at full strength over a purple glow. */
.tvglobe::before {
  content: '';
  position: absolute;
  inset: 14%;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--uv) 55%, transparent),
    color-mix(in srgb, var(--uv) 18%, transparent) 45%,
    transparent 72%
  );
  filter: blur(28px);
  opacity: 0;
  transition: opacity 1.4s ease;
}
.tvglobe.is-lit canvas {
  opacity: 1;
}
.tvglobe.is-lit::before {
  opacity: 1;
}
.wait__vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(70% 60% at 50% 45%, transparent 40%, rgba(10, 4, 32, 0.85) 100%),
    linear-gradient(to top, rgba(10, 4, 32, 0.95), transparent 45%);
}
/* One card for everything below the scene: the stage, the bar with the
   quip on it, the note and the clock, so they read as a single instrument.
   Anchored: it rises out of the bottom edge, rounded only on top. The
   language is the page's .card (overlay glass, the UV bloom) with a lit
   top edge and a faint sheen, deepening towards the page's bottom. */
.wait__copy {
  position: absolute;
  left: calc(50% + var(--tsr-w, 0px) / 2);
  bottom: 0;
  transform: translateX(-50%);
  transition:
    transform 0.75s var(--ease) 0.6s,
    opacity 0.5s ease 0.6s;
  /* Over the scene: the field is its own stacking context at z 1, so this
     sits above every TV and the globe, whatever their depth. */
  z-index: 2;
  width: min(38rem, calc(100% - 2rem));
  padding: 1.6rem clamp(1.4rem, 4vw, 2.8rem) calc(1.6rem + env(safe-area-inset-bottom));
  text-align: center;
  border-radius: 1.3rem 1.3rem 0 0;
  border: 1px solid color-mix(in srgb, var(--p100) 22%, var(--hairline-strong));
  border-bottom: 0;
  background:
    radial-gradient(
      60% 55% at 50% 0%,
      color-mix(in srgb, var(--uv) 22%, transparent),
      transparent 70%
    ),
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--overlay) 78%, transparent),
      color-mix(in srgb, var(--indigo) 94%, transparent)
    );
  backdrop-filter: blur(22px) saturate(140%);
  -webkit-backdrop-filter: blur(22px) saturate(140%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 -1.2rem 4rem rgba(0, 0, 0, 0.45),
    0 0 5rem color-mix(in srgb, var(--uv) 16%, transparent);
}
/* The lit edge: a hairline of UV light along the top, brightest in the middle. */
.wait__copy::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 8%;
  right: 8%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--p100) 35%, var(--p100) 65%, transparent);
  opacity: 0.85;
  border-radius: 1px;
}
.wait__stage {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  min-height: 1.3em;
  color: var(--p100);
}
/* The loading bar, with the quip sat on it. The fill is app.js's guess at
   progress (no true figure exists: the bracket is one model call). */
.wait__bar {
  position: relative;
  margin: 0.95rem auto 0;
  width: 100%;
  min-height: 2.35rem;
  padding: 0.45rem 1.3rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.045);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
  overflow: hidden;
}
.wait__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--uv) 45%, transparent),
    color-mix(in srgb, var(--p100) 62%, transparent)
  );
  /* A bright head on the fill, the only hard edge on the card. */
  box-shadow:
    inset -1px 0 0 color-mix(in srgb, var(--white) 55%, transparent),
    0 0 1.4rem color-mix(in srgb, var(--uv) 55%, transparent);
  transition: width 0.5s linear;
}
.wait__quip {
  position: relative;
  font-size: 1.02rem;
  color: var(--white);
  font-weight: 300;
  min-height: 1.5em;
  transition: opacity 0.35s ease;
}
.wait__quip.is-swapping {
  opacity: 0;
}
.wait__meta {
  margin-top: 1rem;
  display: flex;
  justify-content: center;
  gap: 1.4rem;
  font-size: 0.82rem;
  letter-spacing: 0.01em;
  color: var(--muted);
}
/* The card, compact on a phone (Dylan): less padding, a smaller title,
   a shorter bar, the meta line small. */
@media (max-width: 700px) {
  .wait__copy {
    width: calc(100% - 1.2rem);
    padding: 0.95rem 1rem calc(0.9rem + env(safe-area-inset-bottom));
    border-radius: 1rem 1rem 0 0;
  }
  .wait__stage {
    font-size: 1.2rem;
  }
  .wait__bar {
    margin-top: 0.6rem;
    min-height: 2rem;
    padding: 0.35rem 1rem;
  }
  .wait__quip {
    font-size: 0.9rem;
  }
  .wait__meta {
    margin-top: 0.55rem;
    font-size: 0.74rem;
  }
}
.wait__meta b {
  font-weight: 600;
  color: var(--muted-soft);
  font-variant-numeric: tabular-nums;
}
/* Once the venue is in view the card goes and a thin strip takes its
   place at the foot of the page: the brand, and that this is a preview. */
.wait:not(.is-on) .wait__copy {
  opacity: 0;
  transform: translate(-50%, 110%);
}
.wait.is-venue .wait__copy {
  opacity: 0;
  transform: translate(-50%, 30px);
  transition:
    opacity 0.5s ease,
    transform 0.6s var(--ease);
  pointer-events: none;
}
.wait__strip {
  position: absolute;
  left: calc(50% + var(--tsr-w, 0px) / 2);
  bottom: 0;
  z-index: 2;
  transform: translate(-50%, 100%);
  width: min(38rem, calc(100% - 2rem));
  padding: 0.7rem 1.4rem calc(0.7rem + env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border-radius: 0.9rem 0.9rem 0 0;
  border: 1px solid color-mix(in srgb, var(--p100) 22%, var(--hairline-strong));
  border-bottom: 0;
  background: color-mix(in srgb, var(--indigo) 88%, transparent);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  color: var(--white);
  font-size: 0.95rem;
  font-weight: 600;
  opacity: 0;
  transition:
    opacity 0.5s ease 0.25s,
    transform 0.6s var(--ease) 0.25s;
}
.wait__strip small {
  color: var(--muted);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.wait.is-venue .wait__strip {
  opacity: 1;
  transform: translate(-50%, 0);
}
.wait.is-landing .wait__strip {
  opacity: 0;
}
.wait__logo {
  position: absolute;
  top: 1.4rem;
  /* Behind the gateway's rail (--tsr-w on the root), not under it. */
  left: calc(var(--tsr-w, 0px) + clamp(1.25rem, 4vw, 3rem));
  width: 5.2rem;
  opacity: 0.85;
}
.wait__poster {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 2rem;
}
.wait__poster img {
  max-width: min(36rem, 80vw);
  border-radius: var(--r-surface);
  box-shadow:
    0 2rem 5rem rgba(0, 0, 0, 0.6),
    0 0 6rem color-mix(in srgb, var(--uv) 30%, transparent);
}

/* Results */
/* The board waits on the page under the clearing overlay, then rises once
   the venue has slid away (see finishWait). */
.view.is-held {
  opacity: 0;
}
.view.is-in {
  animation: rise 0.7s var(--ease) both;
}
.results__head {
  text-align: center;
  padding: clamp(1rem, 4vw, 3rem) 0 1.6rem;
  animation: rise 0.6s var(--ease) both;
}
.results__head h1 {
  font-size: clamp(1.8rem, 4.4vw, 2.9rem);
}
.bracket-figure {
  margin: 0 auto 2.4rem;
  animation: rise 0.7s var(--ease) both;
}
.bracket-figure img {
  width: 100%;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: #000;
  box-shadow:
    0 2rem 5rem rgba(0, 0, 0, 0.55),
    0 0 6rem color-mix(in srgb, var(--uv) 22%, transparent);
}
.bracket-figure figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 0.9rem;
  color: var(--muted-soft);
  font-size: 0.92rem;
}
.bracket-figure .links {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.link-btn {
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: transparent;
  cursor: pointer;
  text-decoration: none;
  color: var(--white);
  transition: border-color 0.15s ease;
}
.link-btn:hover {
  border-color: var(--p100);
}

/* The results board (Dylan, 2026-09-04: the page felt floating, disconnected):
   one glass surface holds the bracket, the venues and the call to action,
   in the page's .card language, with a seam between the two halves and a
   footer row that spans both. */
.results__body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.2rem;
  padding: clamp(1rem, 2.4vw, 1.6rem);
  border-radius: var(--r-marketing);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--overlay) 86%, transparent);
  box-shadow:
    0 1.8rem 4rem rgba(0, 0, 0, 0.45),
    0 0 4rem color-mix(in srgb, var(--uv) 14%, transparent);
  animation: rise 0.6s var(--ease) both;
}
.results__foot {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--hairline);
}
.results__foot .btn {
  white-space: nowrap;
  padding: 0.7rem 1.2rem;
}
/* The caption and the quiet report link read as one block, so the row
   stays the caption on one side and the call to action on the other. */
.results__note {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.1rem 0.6rem;
}
.results__note .linkbtn--quiet {
  margin-left: 0;
  font-size: 0.8rem;
  text-decoration: underline;
}
/* Nothing scrolls behind a full-screen overlay (the wait, the modal): on a
   phone the page under it rubber-banded and the browser bar came and went. */
html.is-locked,
html.is-locked body {
  overflow: hidden;
  height: 100%;
  overscroll-behavior: none;
}
.wait {
  touch-action: none;
}
/* The disclaimer under the caption: the bracket shown is a sketch. */
.results__disclaimer {
  flex-basis: 100%;
  margin: 0;
  color: var(--muted);
}
/* Thumbs up or down (Dylan, in place of a bare report link). The report
   stays, offered after a thumbs down. */
.vote {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.3rem;
  font-size: 0.8rem;
  color: var(--muted);
}
#voteQ {
  white-space: nowrap;
}
.vote__btn {
  display: inline-grid;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s,
    border-color 0.15s,
    transform 0.2s var(--ease);
}
.vote__btn svg {
  width: 1rem;
  height: 1rem;
}
.vote__btn:hover {
  color: var(--white);
  border-color: color-mix(in srgb, var(--uv) 55%, transparent);
  transform: translateY(-1px);
}
.vote__btn.is-picked {
  color: var(--white);
  background: color-mix(in srgb, var(--uv) 35%, transparent);
  border-color: var(--p100);
}
.vote__btn:disabled:not(.is-picked) {
  opacity: 0.4;
  cursor: default;
}
.tag--partial {
  border-color: color-mix(in srgb, #e0a33a 55%, transparent);
  color: #e0a33a;
}
/* Once it has been reported the link is a statement, not an offer. */
.results__note .linkbtn--quiet:disabled {
  text-decoration: none;
  cursor: default;
}
@media (max-width: 40rem) {
  .results__foot {
    flex-direction: column;
    align-items: stretch;
  }
}
.panel__title {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.5rem;
}
.panel__caption {
  font-size: 0.8rem;
  color: var(--muted-soft);
}
/* The caption and the call to action share one row under the bracket, so
   the button belongs to the panel rather than floating beneath it. */
.panel__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.8rem;
}
.panel__row .btn {
  white-space: nowrap;
  padding: 0.7rem 1.1rem;
}
@media (max-width: 40rem) {
  .panel__row {
    flex-direction: column;
    align-items: stretch;
  }
}
.tile {
  position: relative;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-surface);
  overflow: hidden;
  background: #000;
  aspect-ratio: 16 / 9;
}
.tile__open {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.tile__open img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 40%;
}
.tile--bracket .tile__open img {
  object-fit: contain;
}
/* The bracket sits in a TV bubble: the deck's bezel stroke around a screen. */
.tile--bracket {
  aspect-ratio: auto;
  padding: 0.3rem;
  border-radius: 0.8rem;
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: var(--indigo);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.04),
    0 1.5rem 4rem rgba(0, 0, 0, 0.5),
    0 0 5rem color-mix(in srgb, var(--uv) 18%, transparent);
}
.tile--bracket .tile__open {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: 0.5rem;
  overflow: hidden;
  background: #000;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.tile--bracket .tile__dl {
  right: 1rem;
  bottom: 1rem;
}
.tile__dl {
  position: absolute;
  right: 0.7rem;
  bottom: 0.7rem;
  width: 2.3rem;
  height: 2.3rem;
  /* Bigger on a phone, and on the venue tile up out of the stamp's corner.
     The bracket tile keeps it low: its top corner is the rail's headline. */
  @media (max-width: 700px) {
    width: 2.6rem;
    height: 2.6rem;
    .tile--stage & {
      top: 0.6rem;
      bottom: auto;
    }
  }
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(10, 4, 32, 0.82);
  border: 1px solid var(--hairline-strong);
  color: var(--white);
  opacity: 0;
  transition:
    opacity 0.2s ease,
    background 0.2s ease;
}
.tile__dl svg {
  width: 1.1rem;
  height: 1.1rem;
}
.tile:hover .tile__dl,
.tile__dl:focus-visible {
  opacity: 1;
}
.tile__dl:hover {
  background: var(--uv);
  border-color: var(--uv);
}
@media (hover: none) {
  .tile__dl {
    opacity: 1;
  }
}
.stage__img--next {
  opacity: 0;
  transition: opacity 0.6s ease;
}
.stage__img--next.is-visible {
  opacity: 1;
}
/* The venues' thumbnails sit in a strip under the stage, part of the same
   panel rather than a loose row. */
.thumbs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
  margin-top: 0.6rem;
  padding: 0.5rem;
  border-radius: var(--r-surface);
  background: rgba(0, 0, 0, 0.28);
  box-shadow: inset 0 0 0 1px var(--hairline);
}
.thumb {
  position: relative;
  padding: 0;
  border: 2px solid transparent;
  border-radius: calc(var(--r-surface) - 0.15rem);
  overflow: hidden;
  background: #000;
  cursor: pointer;
  aspect-ratio: 16 / 9;
  opacity: 0.6;
  transition:
    opacity 0.2s ease,
    border-color 0.2s ease;
}
.thumb:hover,
.thumb.is-active {
  opacity: 1;
}
.thumb.is-active {
  border-color: var(--uv);
}
.thumb img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 40%;
}

/* Lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 2rem;
  background: rgba(5, 2, 15, 0.92);
  cursor: zoom-out;
}
.lightbox img {
  max-width: 100%;
  max-height: calc(100vh - 6rem);
  border-radius: var(--r-surface);
  box-shadow: 0 2rem 6rem rgba(0, 0, 0, 0.7);
  cursor: default;
}
.lightbox__caption {
  position: absolute;
  left: 50%;
  bottom: 1.2rem;
  transform: translateX(-50%);
  font-size: 0.9rem;
  color: var(--muted-soft);
}
.lightbox__close {
  position: absolute;
  top: 1.2rem;
  right: 1.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: rgba(10, 4, 32, 0.7);
  cursor: pointer;
}

/* Talk to us modal */
.modal {
  position: fixed;
  inset: 0;
  z-index: 15;
  display: grid;
  place-items: center;
  padding: 1rem;
  background: rgba(5, 2, 15, 0.8);
  backdrop-filter: blur(6px);
}
.modal__card {
  position: relative;
  width: min(36rem, 100%);
  max-height: calc(100dvh - 2rem);
  overflow: auto;
}
/* The details step ran past the card on a laptop screen, so its button and
   Back sat against the clipped edge (Dylan): a shorter message box and a
   tighter frame bring it inside. On a phone the card still scrolls. */
#contact textarea {
  /* Two lines. Its rows would make it taller than the min-height alone. */
  height: 3.4rem;
  min-height: 3.4rem;
}
.modal__card h2 {
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  padding-right: 4rem;
}
.modal__lede {
  margin: 0.6rem 0 1.2rem;
  color: var(--muted-soft);
  font-weight: 300;
  font-size: 0.95rem;
}
/* Once the form is sent it describes questions nobody is being asked. */
.modal__card:has(#contact[hidden]) .modal__lede {
  display: none;
}
.modal__close {
  position: absolute;
  top: 1.1rem;
  right: 1.1rem;
  min-height: 2.5rem;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.4rem 0.8rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: transparent;
  cursor: pointer;
}
/* The modal is the site's /advertise funnel: a progress rail, one question
   at a time, then the details step. `.cstep` borrows `.step` for the same
   entrance the page's own stepper uses. */
.modal__progress {
  height: 3px;
  border-radius: 999px;
  background: var(--hairline-strong);
  overflow: hidden;
  margin-bottom: 1.4rem;
}
.modal__bar {
  height: 100%;
  width: 25%;
  border-radius: 999px;
  background: var(--uv);
  transition: width 0.3s var(--ease);
}
.cstep__q {
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 1rem;
}
.opts {
  display: grid;
  gap: 0.6rem;
}
.opts--two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (max-width: 30rem) {
  .opts--two {
    grid-template-columns: 1fr;
  }
}
.opt {
  display: block;
  position: relative;
  padding: 0.85rem 1rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--indigo) 70%, transparent);
  font-weight: 500;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease,
    transform 0.15s var(--ease);
}
.opt:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--p100) 50%, var(--hairline-strong));
}
/* Hidden to the eye, still focusable: the label is the control you see. */
.opt input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}
.opt:focus-within,
.opt:has(input:checked) {
  border-color: var(--p100);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--p100) 45%, transparent);
}
.cstep__back {
  margin-top: 1.1rem;
  font-size: 0.9rem;
}
.cstep__back--center {
  display: block;
  margin-inline: auto;
}
/* Already known from the preview: filled in, still editable. */
.field--known span::after {
  content: ' (from your preview)';
  font-weight: 400;
  color: var(--muted);
}

.thanks {
  padding: 1rem 0;
}
.thanks h3 {
  font-size: 1.3rem;
  font-weight: 600;
}
.thanks p {
  color: var(--muted-soft);
  margin-top: 0.4rem;
}
.thanks__steps {
  margin: 1rem 0 0;
  padding-left: 1.1rem;
  color: var(--muted-soft);
  font-size: 0.92rem;
  display: grid;
  gap: 0.35rem;
}

/* Error view */
.notice {
  width: min(34rem, 100%);
  margin: 2rem auto 0;
  text-align: center;
}
.notice h1 {
  font-size: clamp(1.6rem, 3.6vw, 2.4rem);
}
.notice p {
  margin-top: 0.8rem;
  color: var(--muted-soft);
}
.notice .actions {
  justify-content: center;
}
.notice .actions .btn:first-child {
  flex: 0 1 auto;
}
.notice .card {
  margin-top: 2rem;
  text-align: left;
}

footer {
  position: relative;
  z-index: 1;
  padding: 0.9rem clamp(1.25rem, 4vw, 3rem);
  font-size: 0.75rem;
  color: var(--muted);
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
footer a {
  text-decoration: none;
  color: var(--muted-soft);
}

/* Phones and narrow windows: the form ABOVE the example (Dylan), so the
   hero and the card fill the first screen and the example sits below it.
   The intro's box dissolves so its two children can be ordered against the
   form. The hero is smaller here so the card starts above the fold. */
@media (max-width: 63.99rem) {
  .split {
    display: flex;
    flex-direction: column;
  }
  .split .intro {
    display: contents;
  }
  .split .hero {
    order: 1;
    padding: 0.6rem 0 1rem;
  }
  .split .stack {
    order: 2;
  }
  .split .example {
    order: 3;
    margin-top: 2rem;
  }
  .split h1 {
    font-size: clamp(1.75rem, 7.5vw, 2.6rem);
  }
  .split .sub {
    margin-top: 0.7rem;
    font-size: 0.98rem;
  }
}
/* A phone, with Safari's bars showing, has about 660 pixels of height
   (Dylan, iPhone 16 Pro: "the page still scrolls"). Every step must end
   inside that: no example photo, a one-line footer, the hero on the first
   step only, so the ad-choosing card (the tallest) starts at the top. */
@media (max-width: 700px) {
  .split .example {
    display: none;
  }
  .split .hero {
    padding: 0.3rem 0 0.8rem;
  }
  .split h1 {
    font-size: clamp(1.6rem, 7vw, 2.2rem);
  }
  .split .sub {
    font-size: 0.92rem;
  }
  .split[data-step='2'] .hero,
  .split[data-step='3'] .hero {
    display: none;
  }
  .split .stack {
    margin-top: 0;
  }
  footer {
    padding: 0.5rem clamp(1.25rem, 4vw, 3rem);
    justify-content: flex-end;
  }
  footer span {
    display: none;
  }
  #picksLead {
    font-size: 0.84rem;
    margin-bottom: 0.35rem;
  }
}
/* The smallest phones (an SE, 559 pixels with the bars): the ad step's
   lead line goes, the brief card tightens, and the step fits. */
@media (max-width: 380px) {
  #picksLead {
    display: none;
  }
  #picksTitle {
    margin-top: 0.6rem;
    font-size: 1.15rem;
  }
  .brief {
    padding: 0.6rem;
  }
  .step .actions {
    margin-top: 0.7rem;
  }
}
/* Desktop: one viewport, no scroll. Phones and narrow windows keep the
   stacked layouts above and scroll. */
@media (min-width: 64rem) {
  .split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 31rem);
    gap: clamp(2rem, 4vw, 4rem);
    align-items: center;
    width: min(100%, calc((100dvh - 9rem) * 1.9));
    margin: 0 auto;
  }
  .split .hero {
    text-align: left;
    padding: 0 0 1.4rem;
  }
  .split .sub {
    margin-left: 0;
    max-width: 30rem;
  }
  .split .example {
    margin: 0;
    width: auto;
  }
  .split .stack {
    margin: 0;
    width: 100%;
  }

  /* The results page is wider than the form: the gallery earns it. */
  main:has(#viewResults:not([hidden])) {
    width: min(90rem, 100%);
  }
  /* Sized by height as well as width: the board (its padding, the seam, the
     thumbnail strip and the footer row) must end inside the viewport. */
  .results {
    width: min(84rem, 100%, calc((100dvh - 13rem) * 1.85));
    margin: 0 auto;
  }
  .results__head {
    text-align: left;
    padding: 0 0 0.6rem;
  }
  .results__head h1 {
    font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  }
  .results__body {
    grid-template-columns: 0.72fr 1fr;
    gap: 0;
    align-items: start;
  }
  /* The seam between the two halves; the shorter half centres its picture
     against the taller one rather than pinning it to the top. */
  .panel--bracket {
    padding-right: clamp(1rem, 2.4vw, 1.6rem);
    align-self: stretch;
    display: flex;
    flex-direction: column;
  }
  .panel--bracket .tile {
    margin: auto 0;
  }
  .panel--venues {
    padding-left: clamp(1rem, 2.4vw, 1.6rem);
    border-left: 1px solid var(--hairline);
  }
  .results__foot {
    margin-top: 1.2rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .step,
  .results__head,
  .bracket-figure,
  .tile {
    animation: none;
  }
  .wait {
    transition: none;
  }
}

/* Admin
   The private view at /admin (design note 0002, "Admin view"): everything
   generated and every inbound, on one dense page. Same tokens, same .card,
   .btn and .linkbtn as the public page; only the density differs, because
   this one is read, not walked through. */
.admin-body {
  background: var(--indigo);
}
.admin {
  position: relative;
  z-index: 1;
  width: min(96rem, 100%);
  margin: 0 auto;
  padding: 1.2rem clamp(1rem, 3vw, 2.2rem) 4rem;
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
}

/* Header: the name, the window, the search, the refresh. */
.admin__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.8rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--hairline);
}
.admin__title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.admin__title h1 {
  font-size: 1.25rem;
  letter-spacing: -0.01em;
}
.admin__controls {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.switch {
  display: inline-flex;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  overflow: hidden;
}
.switch__opt {
  background: none;
  border: 0;
  padding: 0.45rem 0.75rem;
  font-size: 0.82rem;
  color: var(--muted);
  cursor: pointer;
}
.switch__opt:hover {
  color: var(--white);
}
.switch__opt.is-on {
  background: color-mix(in srgb, var(--uv) 32%, transparent);
  color: var(--white);
}
.admin__search {
  width: 13rem;
  padding: 0.45rem 0.7rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--overlay) 80%, transparent);
  font-size: 0.85rem;
}
.admin__search::placeholder {
  color: var(--muted);
}
.btn--sm {
  padding: 0.45rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 500;
}

.admin__error {
  padding: 0.7rem 0.9rem;
  border-radius: var(--r-surface);
  border: 1px solid color-mix(in srgb, var(--coral) 45%, transparent);
  background: color-mix(in srgb, var(--coral) 12%, transparent);
  font-size: 0.88rem;
}
.admin__section {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}
.admin__h2 {
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted-soft);
}
.admin__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.switch--sm .switch__opt {
  padding: 0.3rem 0.6rem;
  font-size: 0.76rem;
}
.tag--internal {
  border-color: color-mix(in srgb, var(--uv) 55%, transparent);
  color: var(--p100);
}
.tag--public {
  color: var(--muted);
}
.admin__count {
  color: var(--muted);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}
.admin__empty {
  color: var(--muted);
  font-size: 0.9rem;
}

/* Tags: the source, the status, the lead kind, the red flag. */
.tag {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 0.35rem;
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  font-size: 0.72rem;
  line-height: 1.5;
  white-space: nowrap;
}
.tag--admin {
  border-color: color-mix(in srgb, var(--p100) 45%, transparent);
  color: var(--p100);
}
.tag--muted {
  color: var(--muted);
}
.tag--done,
.tag--contact {
  border-color: color-mix(in srgb, var(--p100) 40%, transparent);
  color: var(--p100);
}
.tag--running,
.tag--queued {
  color: var(--muted-soft);
}
.tag--error {
  border-color: color-mix(in srgb, var(--coral) 50%, transparent);
  color: var(--coral);
}
.tag--flagged {
  border-color: #ff5c5c;
  background: color-mix(in srgb, #ff5c5c 18%, transparent);
  color: #ff8d8d;
}

/* KPI strip */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.7rem;
}
.kpi {
  padding: 0.7rem 0.9rem;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--overlay) 70%, transparent);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.kpi__label {
  font-size: 0.72rem;
  color: var(--muted);
}
.kpi__value {
  font-size: 1.3rem;
  font-variant-numeric: tabular-nums;
}

/* Generated: one card per preview. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  gap: 0.9rem;
}
.admin-card {
  padding: 0.8rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  box-shadow: none;
}
.admin-card--flagged {
  border-color: color-mix(in srgb, #ff5c5c 45%, transparent);
}
.admin-card__shot {
  aspect-ratio: 16 / 9;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline);
  background: color-mix(in srgb, var(--indigo) 80%, black);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.admin-card__shot img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.admin-card__ph {
  font-size: 0.78rem;
  color: var(--muted);
}
.admin-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.admin-card__brand {
  font-size: 1rem;
  font-weight: 600;
}
.admin-card__badges {
  display: flex;
  gap: 0.3rem;
  flex-wrap: wrap;
}
.admin-card__meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.7rem;
  font-size: 0.8rem;
  margin: 0;
}
.admin-card__meta dt {
  color: var(--muted);
}
.admin-card__meta dd {
  margin: 0;
  overflow-wrap: anywhere;
}
.admin-card__error {
  font-size: 0.8rem;
  color: var(--coral);
  overflow-wrap: anywhere;
}
.admin-card__actions {
  display: flex;
  gap: 0.9rem;
  margin-top: auto;
  padding-top: 0.2rem;
  font-size: 0.85rem;
}
.linkbtn--danger {
  color: #ff8d8d;
}

/* Inbound: the table scrolls inside its container, never the page. */
.tablewrap {
  overflow-x: auto;
  border-radius: var(--r-surface);
  border: 1px solid var(--hairline-strong);
  background: color-mix(in srgb, var(--overlay) 70%, transparent);
}
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8rem;
  white-space: nowrap;
}
.table th,
.table td {
  text-align: left;
  padding: 0.5rem 0.7rem;
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}
.table th {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 600;
  position: sticky;
  top: 0;
  background: var(--overlay);
}
.table tbody tr:last-child td {
  border-bottom: 0;
}
.table tbody tr:hover {
  background: color-mix(in srgb, var(--uv) 8%, transparent);
}
.table__msg {
  /* The one column that wraps, so a note reads without stretching the row. */
  min-width: 14rem;
  max-width: 22rem;
  white-space: normal;
}
.table__sub {
  display: block;
  color: var(--muted);
  font-size: 0.7rem;
}

/* Missing brands: the advertiser list's to-do. */
.missing {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0.2rem 0.9rem;
  font-size: 0.85rem;
}
.missing li {
  display: flex;
  justify-content: space-between;
  gap: 0.7rem;
  padding: 0.25rem 0.5rem;
  border-radius: 0.35rem;
  background: color-mix(in srgb, var(--overlay) 55%, transparent);
}
.missing b {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 46rem) {
  .admin__controls {
    width: 100%;
  }
  .admin__search {
    flex: 1;
    width: auto;
  }
  .cards {
    grid-template-columns: 1fr;
  }
}
