/* Home: a store style browse page on a #171717 ground. Sidebar, featured
   stream, games shelf, channel rounds, live grid, recordings. */

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

/* The platform's shell: colours, the floating header, section headings, cards.
   Every page carries class="app" on its body and inherits this. Page specific
   pieces (the premiere screens, the roster) live further down. */

.app {
  margin: 0;
  min-height: 100vh;
  color: var(--ink);
  font-family: var(--face);
  font-size: 15px;
  -webkit-font-smoothing: antialiased;
  background: var(--ground);
}

.app a { color: inherit; text-decoration: none; }
.app svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.app [hidden] { display: none !important; }
.app .muted { color: var(--muted); }
.app .small { font-size: 12.5px; }

/*
 * One page frame for the whole platform.
 *
 * There were two of these, `.page` here and `.wrap` in an older stylesheet, and
 * pages built against the wrong one had no max width or padding at all and ran
 * edge to edge. They are the same rule now, so a page cannot pick the wrong one.
 */
.page,
.wrap {
  max-width: 1560px;
  margin: 0 auto;
  padding: 26px 28px 60px;
}

/* Reading widths, for pages that are mostly text and numbers rather than art. */
.page.narrow,
.wrap.narrow { max-width: 1180px; }

/* ---------------- top bar ----------------
   Floating over the featured artwork rather than sitting in its own strip:
   navigation on the left, search and account on the right. */

.topbar {
  position: absolute;
  top: 26px;
  left: 28px;
  right: 28px;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 22px 26px;
}

.topbar.solid {
  position: sticky;
  background: rgba(23, 23, 23, .86);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--line);
  left: 0;
  right: 0;
  padding: 16px 54px;
}

.topbar.solid + .page { padding-top: 30px; }


.top-nav { display: flex; align-items: center; gap: 26px; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.top-nav::-webkit-scrollbar { display: none; }

.top-nav a {
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: .11em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(255, 255, 255, .58);
  transition: color .15s;
}

.top-nav a:hover { color: #fff; }
.top-nav a.active { color: #fff; }

.top-actions { margin-left: auto; display: flex; align-items: center; gap: 14px; flex: 0 0 auto; }

.top-search { display: flex; align-items: center; gap: 8px; border-radius: var(--r-pill); transition: background .2s; }
.top-search.open { background: rgba(255, 255, 255, .12); padding-right: 6px; backdrop-filter: blur(10px); }

.icon-btn {
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: rgba(255, 255, 255, .82);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: color .15s, background .15s;
}

.icon-btn:hover { color: #fff; background: rgba(255, 255, 255, .12); }
.icon-btn svg { width: 17px; height: 17px; }

#search-input {
  width: 190px;
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 13px;
  font-family: inherit;
  outline: none;
  padding: 6px 4px;
}

#search-input::placeholder { color: rgba(255, 255, 255, .45); }

.top-coins {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px 7px 10px;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: default;
  backdrop-filter: blur(10px);
  transition: background .15s, border-color .15s;
}

.top-coins .coin {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--gold-hi), #f5a623);
  box-shadow: inset 0 -1px 2px rgba(0, 0, 0, .28);
}

/* Only interactive when there is something to claim. */
.top-coins.ready { cursor: pointer; border-color: var(--gold-edge); }
.top-coins.ready:hover { background: var(--gold-dim); }
.top-coins.ready .coin { animation: coin-ready 1.8s ease-in-out infinite; }
.top-coins:disabled { opacity: .6; }

@keyframes coin-ready {
  0%, 100% { box-shadow: inset 0 -1px 2px rgba(0, 0, 0, .28), 0 0 0 0 rgba(255, 214, 51, .55); }
  50% { box-shadow: inset 0 -1px 2px rgba(0, 0, 0, .28), 0 0 0 5px rgba(255, 214, 51, 0); }
}

.top-me { display: block; border-radius: 50%; }

.app .ava {
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(140deg, var(--accent), #ec4899);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .28);
  transition: box-shadow .15s;
}

.top-me:hover .ava { box-shadow: 0 0 0 2px rgba(255, 255, 255, .7); }

/* ---------------- section headings ---------------- */

.row-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; margin: 0 0 14px; }
.row-head .muted { margin-left: auto; }
.row-head h2 { font-size: 19px; font-weight: 700; letter-spacing: -.015em; margin: 0; }
.main section + section { margin-top: 34px; }

/* ---------------- what is coming ----------------
   One frame, three nights, the reel filling all of it.

   Capped in width rather than height. At 16:9 the frame's height follows its
   width, so a cap on the width is what keeps it from becoming a wall of video
   on a large monitor, and it means the reel is never cropped: the box is
   exactly the shape of the thing inside it. */

.marquee {
  position: relative;
  /*
   * Sized to the window, so the whole frame is on screen without scrolling.
   * The header and the page's own padding come off the top, and a little is
   * left at the bottom so the edge of what follows shows and the page reads as
   * scrollable. Capped, or it becomes a wall of video on a tall monitor.
   */
  /*
   * As tall as the window actually leaves room for.
   *
   * --fit is measured by browse.js: the real distance from the top of the
   * window to the top of this frame, whatever the header happens to be on this
   * screen, minus a little so the edge of the next section shows. Guessing that
   * offset is what kept getting this wrong, since it changes with the
   * breakpoint and with whether somebody is signed in.
   *
   * The calc is the fallback for the moment before the script runs, and dvh
   * rather than vh because vh measures the viewport at its largest and counts
   * space that is not on screen.
   */
  height: min(600px, var(--fit, calc(100dvh - 165px)));
  min-height: 240px;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #000;
  border: 1px solid var(--line);
}

.marquee-screens { position: absolute; inset: 0; }

/* Every reel stays mounted and the current one is simply shown.
   
   Plainly display rather than a cross fade: an opacity transition puts the
   iframe on its own compositing layer, and a video inside a composited,
   clipped, isolated box renders as a black rectangle. Simpler here is also the
   only thing that actually paints. */
.marquee-screen { display: none; position: absolute; inset: 0; }
.marquee-screen.on { display: block; }

.marquee-screen iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 0;
  /*
   * Oversized well past covering, on purpose. YouTube draws its own title,
   * channel avatar, watermark and "More videos" panel into the corners of the
   * player, and no embed parameter removes them. Growing the frame until those
   * corners fall outside the box is what takes them off, and it is the only
   * thing that reliably does.
   */
  width: max(132%, 235vh);
  height: max(132%, 74.25vw);
  /* The reel is a poster that moves. Nothing in it is meant to be clicked, and
     a stray click should not open YouTube. */
  pointer-events: none;
}

/*
 * The fade the frame has always had: heavy down the left where the name sits,
 * lifting to nothing across the picture, with a little weight top and bottom so
 * the header above and the bar below both have something to sit on.
 */
.marquee-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(95deg, rgba(6, 6, 8, .96) 0%, rgba(6, 6, 8, .88) 26%, rgba(6, 6, 8, .35) 62%, rgba(6, 6, 8, .05) 100%),
    linear-gradient(0deg, rgba(6, 6, 8, .8) 0%, transparent 55%),
    linear-gradient(180deg, rgba(6, 6, 8, .72) 0%, transparent 22%);
}

/* The bar sits on the picture, so it needs its own ground to stay readable
   over whatever frame happens to be behind it. */
.marquee-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 46px 30px 26px;
}

.marquee-who { min-width: 0; }

.marquee-name {
  display: block;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -.02em;
  color: #fff;
}

.marquee-title {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: rgba(255, 255, 255, .68);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.marquee-when {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-left: auto;
  flex: none;
}

.marquee-day {
  font-size: 15px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
}

.marquee-time {
  font-size: 15px;
  font-weight: 700;
  color: var(--yellow);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.marquee-soon {
  font-size: 12px;
  color: rgba(255, 255, 255, .6);
  white-space: nowrap;
}

.marquee-remind {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding: 11px 18px;
  border: 0;
  border-radius: var(--r-pill);
  background: #fff;
  color: #0a0a0a;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: background .15s, color .15s;
}

.marquee-remind svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.9; }
.marquee-remind:hover { background: rgba(255, 255, 255, .85); }

/* Set is a state, not a hover, so it changes colour rather than just shade. */
.marquee-remind.on { background: var(--yellow); color: #0a0a0a; }

/* ---------------- moving between them ---------------- */

.marquee-dots {
  position: absolute;
  left: 30px;
  bottom: 74px;
  z-index: 4;
  display: flex;
  align-items: center;
  gap: 9px;
}

.dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .34);
  cursor: pointer;
  transition: width .3s cubic-bezier(.22, .8, .3, 1), background .2s;
}

.dot:hover { background: rgba(255, 255, 255, .62); }

/* The current one stretches rather than only brightening, so which is which is
   obvious at a glance and not only by shade. */
.dot.on { width: 26px; background: #fff; }
.dot:focus-visible { outline: 2px solid rgba(255, 255, 255, .7); outline-offset: 3px; }

.marquee-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(10, 10, 10, .5);
  backdrop-filter: blur(8px);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  transition: opacity .2s, background .15s;
}

.marquee-arrow svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; }
.marquee-arrow.back { left: 18px; }
.marquee-arrow.next { right: 18px; }
.marquee-arrow:hover { background: rgba(10, 10, 10, .78); }

/* Hidden until wanted, so they do not sit on top of the picture the whole time.
   Focus counts as wanting them, or they would be unreachable by keyboard. */
.marquee:hover .marquee-arrow,
.marquee-arrow:focus-visible { opacity: 1; }

@media (max-width: 760px) {
  .marquee { height: min(420px, var(--fit, calc(100dvh - 150px))); }
  .marquee-scrim { background: linear-gradient(0deg, rgba(6, 6, 8, .95) 0%, rgba(6, 6, 8, .6) 45%, rgba(6, 6, 8, .1) 100%); }
  .marquee-bar { flex-wrap: wrap; gap: 12px; padding: 42px 16px 18px; }
  .marquee-when { margin-left: 0; width: 100%; }
  .marquee-remind { width: 100%; justify-content: center; }
  .marquee-dots { bottom: auto; top: 16px; left: 16px; }
  .marquee-arrow { display: none; }
  .marquee-name { font-size: 17px; }
}

/* A row of small facts separated by dots. Was the hero's, and outlived it. */
.meta-line { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 12px; font-size: 12.5px; color: rgba(255, 255, 255, .82); }
.meta-line span { display: inline-flex; align-items: center; }
.meta-line span + span::before { content: '•'; margin-right: 9px; color: rgba(255, 255, 255, .38); }

/* ---------------- grids ---------------- */

/* Three across, so a live stream gets a thumbnail big enough to read. */
.grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }

.app .card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: transform .15s, box-shadow .15s;
  display: block;
}

.app .card:hover { transform: translateY(-3px); border-color: rgba(255, 255, 255, .2); }

.shot { position: relative; aspect-ratio: 16 / 9; background: linear-gradient(140deg, #1a1a20, #0a0a0c); display: grid; place-items: center; }
.shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Generated artwork fills the whole tile, with the initials sitting on top. */
.shot .letters {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 42px;
  font-weight: 800;
  letter-spacing: .04em;
  color: rgba(255, 255, 255, .8);
  text-shadow: 0 2px 12px rgba(0, 0, 0, .3);
}

.tag-live {
  position: absolute;
  top: 12px;
  left: 12px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  background: var(--live);
  color: #fff;
}

.tag-live svg { width: 8px; height: 8px; animation: pulse 2s infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }

.tag-dur {
  position: absolute;
  bottom: 12px;
  right: 12px;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 7px;
  border-radius: var(--r-sm);
  background: rgba(10, 12, 22, .74);
  color: #fff;
}

.card-body { padding: 14px 16px 16px; }
.card-body b { display: block; font-size: 15.5px; font-weight: 650; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; min-height: 2.7em; }
.card-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 10px; }
.card-foot .who { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card-foot .count { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 650; color: var(--muted); flex: 0 0 auto; }
.card-foot .count svg { width: 14px; height: 14px; }

.empty-note { grid-column: 1 / -1; padding: 26px; border-radius: var(--r-lg); background: var(--glass); color: var(--muted); font-size: 13.5px; text-align: center; }

/* ---------------- games shelf ----------------
   Wide artwork with the name and its numbers sitting on the image. A row that
   scrolls rather than a grid that wraps. */

.games { display: flex; gap: 18px; overflow-x: auto; padding: 2px 2px 12px; scroll-snap-type: x proximity; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
.games::-webkit-scrollbar { height: 6px; }
.games::-webkit-scrollbar-track { background: transparent; }
.games::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: var(--r-sm); }
.games:hover::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .26); }

.game {
  position: relative;
  flex: 0 0 min(348px, 80vw);
  aspect-ratio: 16 / 10;
  border-radius: var(--r-lg);
  overflow: hidden;
  scroll-snap-align: start;
  transition: transform .15s;
}

.game:hover { transform: translateY(-3px); }

.game .art { position: absolute; inset: 0; display: block; }
.game .art img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The generated stand in, for a stream with no preview frame yet. Only the
   img was sized, so this rendered as a small mark in the corner. */
.game .art .letters {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  font-size: 44px;
  font-weight: 800;
  color: rgba(250, 250, 250, .22);
}

.game .scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, rgba(4, 4, 6, .94) 0%, rgba(4, 4, 6, .55) 32%, rgba(4, 4, 6, .05) 62%, transparent 100%);
}

.game .body { position: absolute; left: 18px; right: 18px; bottom: 16px; color: #fff; }
.game .body b { display: block; font-size: 17.5px; font-weight: 700; letter-spacing: -.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.game .body i { display: block; margin-top: 4px; font-style: normal; font-size: 12.5px; color: rgba(255, 255, 255, .6); }

.game .crowd {
  position: absolute;
  top: 14px;
  left: 14px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: rgba(108, 76, 246, .92);
  color: #fff;
}

/* ---------------- narrower screens ---------------- */

@media (max-width: 1040px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .page { padding: 16px; }
  .topbar { top: 16px; left: 16px; right: 16px; gap: 12px; padding: 14px 14px 14px 4px; }
  .top-nav { gap: 18px; }
  #search-input { width: 120px; }
}

@media (max-width: 640px) {
  .grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------- channel rounds ---------------- */




/* ---------------- one recording ---------------- */

.app .back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 16px;
}

.app .back:hover { color: var(--ink); }
.app .back svg { width: 15px; height: 15px; }

.player-frame {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.player-frame video { width: 100%; height: 100%; display: block; object-fit: contain; background: #000; }

.watch-head { display: flex; align-items: flex-start; gap: 16px; margin-top: 20px; }
.watch-head-text { flex: 1; min-width: 0; }
.watch-head-text h1 { margin: 0; font-size: 23px; font-weight: 700; letter-spacing: -.02em; }
.watch-head .meta-line { color: var(--muted); }
.watch-head .meta-line span + span::before { color: rgba(255, 255, 255, .25); }
.watch-head-cta { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }

.ava.big { width: 46px; height: 46px; flex: 0 0 46px; font-size: 15px; box-shadow: none; }

.app .btn-ghost.danger { color: #ffb4a2; border-color: rgba(255, 180, 162, .3); }
.app .btn-ghost.danger:hover { background: rgba(242, 65, 90, .18); }

.tag-replay {
  position: absolute;
  top: 12px;
  left: 12px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  background: rgba(10, 12, 22, .78);
  color: #fff;
}

@media (max-width: 700px) {
  .watch-head { flex-wrap: wrap; }
  .watch-head-cta { width: 100%; }
}

/* ---------------- launch banner ----------------
   A wide strip under the featured stream. Artwork on the right, the copy on a
   scrim to the left so it stays readable whatever the art is doing. */

.promo {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  min-height: 216px;
  display: flex;
  align-items: center;
  isolation: isolate;
  background: linear-gradient(120deg, #1b1b22, #101014);
}

.promo-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; }

/*
 * Arkade has no cover art of its own yet, so it is drawn rather than shot:
 * the platform's own three colours, in the same skewed geometry as the mark.
 * Shorter than the launch banner under it, because it is a standing signpost
 * rather than an announcement, and two full height banners stacked would push
 * the streamers off the screen.
 */
.promo-arkade {
  min-height: 168px;
  background:
    radial-gradient(120% 180% at 82% 20%, rgba(244, 198, 60, .34), transparent 62%),
    radial-gradient(110% 160% at 96% 90%, rgba(0, 0, 190, .5), transparent 58%),
    linear-gradient(120deg, #141418, #0d0d10);
}

/* The bars that read as a cabinet, angled off the right edge. */
.promo-arkade::after {
  content: '';
  position: absolute;
  inset: 0 0 0 auto;
  width: 46%;
  pointer-events: none;
  background:
    repeating-linear-gradient(74deg,
      rgba(255, 255, 255, .07) 0 12px,
      transparent 12px 34px);
  mask-image: linear-gradient(90deg, transparent, #000 55%);
}

.promo-arkade .promo-scrim {
  background: linear-gradient(90deg, rgba(6, 6, 8, .92) 0%, rgba(6, 6, 8, .74) 38%, rgba(6, 6, 8, .12) 78%, transparent 100%);
}

.promo-arkade .promo-eyebrow { background: var(--yellow); color: #0a0a0a; }

.promo-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(6, 6, 8, .95) 0%, rgba(6, 6, 8, .86) 32%, rgba(6, 6, 8, .3) 66%, rgba(6, 6, 8, .05) 100%);
}

.promo-body { position: relative; padding: 28px 32px; max-width: 560px; color: #fff; }

.promo-eyebrow {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 5px 11px;
  border-radius: var(--r-sm);
  background: rgba(108, 76, 246, .92);
}

.promo-body h2 { margin: 14px 0 0; font-size: 28px; font-weight: 800; letter-spacing: -.025em; text-transform: uppercase; }
.promo-body p { margin: 9px 0 0; font-size: 13.5px; line-height: 1.55; color: rgba(255, 255, 255, .68); max-width: 44ch; }
.promo-body .btn-watch { margin-top: 18px; }
.promo-body .btn-watch svg { width: 14px; height: 14px; }

.promo-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 50%;
  background: rgba(20, 20, 24, .5);
  color: rgba(255, 255, 255, .7);
  display: grid;
  place-items: center;
  cursor: pointer;
  backdrop-filter: blur(8px);
}

.promo-close:hover { background: rgba(255, 255, 255, .18); color: #fff; }
.promo-close svg { width: 15px; height: 15px; }

@media (max-width: 700px) {
  .promo-body { padding: 22px 20px; max-width: none; }
  .promo-scrim { background: linear-gradient(0deg, rgba(6, 6, 8, .96) 0%, rgba(6, 6, 8, .88) 42%, rgba(6, 6, 8, .5) 72%, rgba(6, 6, 8, .18) 100%); }
  .promo { align-items: flex-end; min-height: 260px; }
}

/* ---------------- creator ---------------- */

.setup { margin-bottom: 26px; }

.setup .steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }

.setup .step {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card);
}

.setup .step .tick {
  width: 24px;
  height: 24px;
  flex: 0 0 24px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .2);
  display: grid;
  place-items: center;
  color: #0d0d0f;
}

.setup .step.done .tick { background: #6ee7a8; border-color: #6ee7a8; }
.setup .step.done .tick svg { width: 13px; height: 13px; stroke-width: 2.4; }
.setup .step b { display: block; font-size: 14px; font-weight: 650; }
.setup .step i { display: block; margin-top: 2px; font-style: normal; font-size: 12.5px; color: var(--muted); }
.setup .step .optional { margin-left: auto; font-size: 11px; color: var(--muted); }

.app .panel {
  padding: 22px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
  margin-bottom: 20px;
}

.app .panel h3 { margin: 0; font-size: 17px; font-weight: 700; letter-spacing: -.01em; }
.app .panel > p { margin: 6px 0 0; }
.app .panel-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 18px; }

.app .field { margin-top: 16px; }
.app .field label { display: block; font-size: 12.5px; font-weight: 600; color: var(--muted); margin-bottom: 6px; }

.app .field input {
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .04);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  outline: none;
}

.app .field input:focus { border-color: rgba(255, 255, 255, .3); }
.app .field input[readonly] { color: var(--muted); }
.app .hint { margin: 7px 0 0; font-size: 12px; color: var(--muted); }

.copyable { display: flex; gap: 8px; align-items: center; }
.copyable input { flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }

.app .btn-ghost.small { padding: 9px 14px; font-size: 12.5px; flex: 0 0 auto; }
.app .btn-ghost.small svg { width: 13px; height: 13px; }

.app .btn-main {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 22px;
  border: 0;
  border-radius: var(--r-pill);
  background: #fff;
  color: #111;
  font: inherit;
  font-size: 13.5px;
  font-weight: 650;
  cursor: pointer;
}

.app .btn-main:hover:not(:disabled) { background: #e9e9ee; }
.app .btn-main:disabled { opacity: .45; cursor: not-allowed; }
.app .btn-main svg { width: 13px; height: 13px; }

.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-top: 18px; }

.figure {
  padding: 16px;
  border-radius: var(--r-md);
  background: var(--glass);
  border: 1px solid var(--line);
}

.figure .k { display: block; font-size: 11.5px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.figure b { display: block; margin-top: 8px; font-size: 25px; font-weight: 750; letter-spacing: -.02em; }
.figure i { display: block; margin-top: 4px; font-style: normal; }

.ledger { margin-top: 20px; }
.ledger-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.ledger-table td { padding: 11px 0; border-top: 1px solid var(--line); }
.ledger-table .when { color: var(--muted); width: 120px; white-space: nowrap; }
.ledger-table .amount { text-align: right; font-weight: 700; white-space: nowrap; }
.ledger-table .amount.in { color: #6ee7a8; }
.ledger-table .amount.out { color: var(--muted); }

/* ---------------- studio ----------------
   The marquee and chat side by side, with the setup panels under the marquee, so
   the thing being watched is the thing at the top of the page. */

.studio { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 20px; align-items: start; }
.studio-head { align-items: center; }
.studio-head-cta { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.studio-head .back { margin-bottom: 0; }

.studio-frame { position: relative; background: #08080a; }
.studio-frame video { width: 100%; height: 100%; display: block; object-fit: contain; background: #08080a; }

.marquee-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  text-align: center;
  font-size: 13.5px;
  color: var(--muted);
  background: rgba(8, 8, 10, .82);
}

.badges { position: absolute; top: 14px; left: 14px; display: flex; flex-wrap: wrap; gap: 7px; }

.badges span {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: var(--r-sm);
  background: rgba(10, 12, 22, .78);
  color: rgba(255, 255, 255, .78);
  backdrop-filter: blur(6px);
}

.badges span.live { background: var(--live); color: #fff; }
.badges span.rec { background: rgba(242, 65, 90, .22); color: #ffb4a2; }

.marquee-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 16px; }
.marquee-controls .muted { margin-left: auto; }

.studio .figures { margin: 18px 0 20px; }
.studio .figure b { font-size: 22px; }
.studio .panel { margin-bottom: 18px; }

.field-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px; }
.app .field-row .field { margin-top: 16px; }
.field-row .grow { flex: 1; min-width: 200px; }

.app .field select {
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, .04);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  outline: none;
}

.app .field select:focus { border-color: rgba(255, 255, 255, .3); }

.check { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); cursor: pointer; }
.check input { width: 15px; height: 15px; accent-color: var(--accent); }

/* Chat sits in its own column and scrolls on its own, so a busy chat never
   pushes the setup panels off the page. */
.studio-chat {
  position: sticky;
  top: 96px;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 140px);
  min-height: 420px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
  overflow: hidden;
}

@media (max-width: 1080px) {
  .studio { grid-template-columns: minmax(0, 1fr); }
  .studio-chat { position: static; height: 420px; }
}

@media (max-width: 640px) {
  .studio-head-cta { width: 100%; margin: 8px 0 0; }
}

/* ---------------- chat ----------------
   Shared by the studio and the watch page, so a message looks the same
   whichever side of the stream you are on. */

.chat { display: flex; flex-direction: column; min-height: 0; }

.chat h3 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0;
  padding: 15px 16px;
  font-size: 14px;
  font-weight: 700;
  border-bottom: 1px solid var(--line);
}

.chat h3 .count { font-size: 11.5px; font-weight: 600; }
.chat .log { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.chat .msg { font-size: 13.5px; line-height: 1.5; word-wrap: break-word; overflow-wrap: anywhere; }
.chat .msg .who { font-weight: 700; color: #a794ff; }
.chat .msg.host .who { color: #f2b33d; }
.chat .msg.system { color: var(--muted); font-style: italic; font-size: 12.5px; }

.chat .compose { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); }

.chat .compose input {
  flex: 1;
  min-width: 0;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .04);
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
  outline: none;
}

.chat .compose input:focus { border-color: rgba(255, 255, 255, .3); }

.chat .compose button {
  flex: 0 0 auto;
  padding: 10px 18px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 650;
  cursor: pointer;
}

.chat .compose button:hover:not(:disabled) { background: var(--accent-hi); }
.chat .compose button:disabled, .chat .compose input:disabled { opacity: .5; cursor: not-allowed; }

.chat .log::-webkit-scrollbar { width: 8px; }
.chat .log::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .14); border-radius: var(--r-sm); }

/* Round avatars, used by the stream page's rail, its channel header and the
   lists under the player. Same shape as the shell's own .ava. */
.avatar {
  width: 36px;
  height: 36px;
  flex: 0 0 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(140deg, var(--accent), #ec4899);
  overflow: hidden;
}

.avatar img { width: 100%; height: 100%; object-fit: cover; }

/* ---------------- the wordmark ----------------
   Drawn with the system stack rather than a downloaded face, so it renders the
   same on a phone with no network as it does here, and so a stylesheet cannot
   be the thing that makes the brand disappear. The character comes from the
   cut, not the family: very heavy, tracked tight, and sheared forward. */

.wordmark {
  flex: none;
  font-size: 20px;
  font-weight: 900;
  letter-spacing: -.045em;
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
  transform: skewX(-9deg);
  transform-origin: left center;

  /* Gold, brighter at the top so it reads as lit rather than filled. */
  background: linear-gradient(168deg, var(--gold-hi) 8%, var(--gold) 58%, #f2a922 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;

  /* The glow sits behind the glyphs, not on them, so the letters stay crisp. */
  filter: drop-shadow(0 0 14px rgba(255, 214, 51, .28));
  transition: filter .2s, transform .2s;
}

.wordmark:hover {
  filter: drop-shadow(0 0 20px rgba(255, 214, 51, .5));
  transform: skewX(-9deg) translateY(-1px);
}

/* On the floating header the mark sits over video, so it needs its own
   contrast rather than borrowing the page background. */
.topbar:not(.solid) .wordmark {
  filter: drop-shadow(0 0 14px rgba(255, 214, 51, .3)) drop-shadow(0 2px 10px rgba(0, 0, 0, .85));
}

.topbar .top-nav { margin-left: 4px; }

@media (max-width: 640px) {
  .wordmark { font-size: 17px; }
  .topbar .top-nav { margin-left: 0; }
}

/* A visitor who is not signed in. A labelled button rather than an anonymous
   avatar, because on a showcase night most of the room has never been here. */

.top-signin {
  flex: none;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  background: var(--gold);
  color: #191400;
  font-size: 12.5px;
  font-weight: 750;
  text-decoration: none;
  white-space: nowrap;
  transition: background .18s, transform .18s;
}

.top-signin:hover { background: var(--gold-hi); transform: translateY(-1px); }

/* ===============================================================
   THE HOUSE AND THE CROWD

   The devices that carry the identity across every page. The house
   frames things; the crowd breaks the frame. Nothing below is
   decorative — each one marks a specific kind of moment.
   =============================================================== */

/*
 * The wordmark, restated against the new tokens.
 *
 * `background-image`, not the `background` shorthand: the shorthand resets
 * background-clip to border-box, which fills the box with gold instead of the
 * letters and loses the wordmark entirely.
 */
.wordmark {
  background-image: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--yellow);
  -webkit-text-fill-color: var(--yellow);
}

/* ---- ordered chrome: the house speaking ---- */

/*
 * A section header the machine printed. A hairline runs to the edge
 * of the container so the page reads as a grid being filled in
 * rather than a document being written.
 */
.sys-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 12px;
}

.sys-head h2,
.sys-head .sys-title {
  margin: 0;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  white-space: nowrap;
}

.sys-head::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* Corner ticks. Four small marks that suggest a frame without
   drawing one, the way a registration mark does. */
.ticked { position: relative; }

.ticked::before,
.ticked::after {
  content: '';
  position: absolute;
  width: 7px;
  height: 7px;
  border-color: var(--line-hard);
  border-style: solid;
  pointer-events: none;
}

.ticked::before { top: 8px; left: 8px; border-width: 1px 0 0 1px; }
.ticked::after { bottom: 8px; right: 8px; border-width: 0 1px 1px 0; }

/* ---- the break: the crowd arriving ---- */

/*
 * A value that moved because people did something. Saturated, mono,
 * and it flashes once when it changes rather than animating forever.
 */
.crowd-value {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--signal);
  font-weight: 700;
}

.crowd-value.surge { color: var(--surge); }
.crowd-value.volt { color: var(--volt); }
.crowd-value.toxic { color: var(--toxic); }

@keyframes struck {
  0% { transform: none; filter: none; }
  18% { transform: translateX(-2px) skewX(-6deg); filter: brightness(1.7); }
  100% { transform: none; filter: none; }
}

/* Applied for one beat when a number lands. The system flinching. */
.struck { animation: struck .42s cubic-bezier(.2, .8, .3, 1); }

/*
 * A band of colour behind a moment that matters. Deliberately not
 * a rounded pill: it is a printed block, cut square, slightly
 * sheared, sitting off the grid the rest of the page obeys.
 */
.band {
  display: inline-block;
  padding: 3px 10px 4px;
  background: var(--signal);
  color: #17140a;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  transform: skewX(-9deg);
}

.band > * { display: inline-block; transform: skewX(9deg); }
.band.surge { background: var(--surge); color: #2a0713; }
.band.volt { background: var(--volt); color: #100a26; }
.band.toxic { background: var(--toxic); color: #052012; }
.band.live { background: var(--live); color: #fff; }

/* Hairline grid overlay: the ordered world showing through. Very
   faint, and only on surfaces that are meant to feel mechanical. */
.gridded {
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 44px 44px;
  background-position: -1px -1px;
}

/* ===============================================================
   THE CHROME

   One header, every page. Three zones that never move: a
   contextual action left, the mode switch in the middle, the
   primary action right.

   Light, over a dark platform. That inversion is the identity's
   argument in its plainest form — the ordered surface the house
   runs on, laid over the world underneath.
   =============================================================== */

.chrome {
  position: sticky;
  top: 0;
  z-index: 60;
  /*
   * Pinned to the viewport, not to whatever box it happens to sit in. The
   * header is prepended to <body>, so a page that pads its body would
   * otherwise shift the header and it would sit in a different place on
   * every page. This makes that impossible rather than relying on nobody
   * ever adding padding again.
   */
  width: 100%;
  box-sizing: border-box;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  /* Sat tight against the top edge. The extra top padding drops the controls
     onto the artwork rather than against the frame of the window. */
  padding: 22px 14px 11px;

  /*
   * No bar. The controls float directly on whatever is behind them, so the
   * header takes nothing from the page and the artwork runs all the way up.
   * Each control carries its own contrast instead, which is why they all have
   * a shadow: a white pill on a white video frame would otherwise vanish.
   */
  background: transparent;
  border-bottom: 0;
}

/*
 * Placed explicitly, not by source order. With the middle control gone the
 * right zone fell into the centre column and the action ended up in the
 * middle of the bar.
 */
.chrome-left { grid-column: 1; justify-self: start; }
.chrome-tabs { grid-column: 2; }
.chrome-right { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 8px; }

/* left: the mark, or a way back out of wherever you are */

.chrome .chrome-mark,
.chrome .chrome-btn {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 20px;
  border-radius: var(--r-sm);
  background: var(--paper);
  box-shadow: 0 2px 14px rgba(0, 0, 0, .4);
  color: #101010;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  border: 0;
}

.chrome .chrome-mark {
  font-size: 15px;
  font-weight: 900;
  letter-spacing: -.04em;
  transform: skewX(-9deg);
  padding: 0 17px;
}

.chrome .chrome-mark > * { display: inline-block; transform: skewX(9deg); }
.chrome .chrome-btn:hover, .chrome-mark:hover { background: #f6f6f6; }

/* middle: the mode switch */

.chrome-tabs {
  justify-self: center;
  display: flex;
  align-items: stretch;
  height: 38px;
  padding: 0 4px;
  border-radius: var(--r-sm);
  background: var(--paper);
  box-shadow: 0 2px 14px rgba(0, 0, 0, .4);
}

.chrome .chrome-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0 15px;
  color: #8e8e8e;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: color .15s;
}

.chrome .chrome-tab:hover { color: #444; }
.chrome-tab.is-on { color: #111; }

/* The rule that marks where you are. Sits on the top edge of the
   control, hard and square, so it reads as a machine indicating a
   state rather than a link being decorated. */
.chrome-tab.is-on::before {
  content: '';
  position: absolute;
  top: 0;
  left: 12px;
  right: 12px;
  height: 2px;
  background: #101010;
}

/* right: coins, then the primary action */

.chrome .chrome-coins {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 38px;
  padding: 0 14px;
  border-radius: var(--r-sm);
  border: 0;
  background: var(--paper);
  box-shadow: 0 2px 14px rgba(0, 0, 0, .4);
  color: #101010;
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.chrome .chrome-coins:hover { background: #f6f6f6; }
.chrome .chrome-coins .coin {
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--yellow);
}

.chrome .chrome-go {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  height: 38px;
  padding: 0 18px;
  border-radius: var(--r-sm);
  /*
   * Signal, not black. On the reference the primary action was the darkest
   * thing because the bar was light; floating on a dark page that hierarchy
   * inverts and a black pill disappears. The loudest control should be the
   * brand colour anyway.
   */
  background: var(--yellow);
  box-shadow: 0 2px 16px rgba(0, 0, 0, .4);
  color: #101010;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  max-width: 210px;
  overflow: hidden;
}

.chrome .chrome-go:hover { background: var(--signal-hi); }
.chrome-dot { width: 7px; height: 7px; border-radius: 50%; background: #101010; flex: none; }

/*
 * The header floats, so the page behind it starts at the top and the artwork
 * runs the full height. Content pages still clear it, since text sliding under
 * a white pill is unreadable.
 */
/*
 * The header floats with no bar of its own, so the page can start close under
 * it. Content pages keep a little air; the home page pulls the featured frame
 * up tighter, since the artwork is meant to be the first thing you meet.
 */
.chrome + .page,
.chrome + .wrap { padding-top: 14px; }

.chrome + .page > .featured:first-child,
.chrome + .page .featured { margin-top: -6px; }

.chrome + .page.under,
body.under-chrome .chrome + * { margin-top: -62px; padding-top: 0; }

@media (max-width: 900px) {
  .chrome { grid-template-columns: auto 1fr auto; gap: 8px; padding: 16px 10px 9px; }
  .chrome-tabs { justify-self: center; overflow-x: auto; scrollbar-width: none; }
  .chrome-tabs::-webkit-scrollbar { display: none; }
  .chrome-tab { padding: 0 11px; font-size: 9.5px; }
  .chrome-go { max-width: 130px; }
}

/* ---------------- the streamer frames ----------------
   A card you pick from. Thin rule, black field, the person cut out and
   floating in it, their name printed along the bottom edge and the state
   called out in the corner. Deliberately not the live tile: that one is a
   thumbnail of a broadcast, this one is a portrait of a person. */

.frames {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
}

.frame {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  border: 1px solid var(--line-hard);
  background: #0b0b0b;
  overflow: hidden;
  text-decoration: none;
  color: var(--ink);
  transition: border-color .18s, transform .18s;
}

.frame:hover { border-color: var(--ink); transform: translateY(-3px); }
.frame.is-live { border-color: rgba(212, 41, 30, .55); }
.frame.is-live:hover { border-color: var(--red); }

/* corners */

.frame-state,
.frame-mark {
  position: absolute;
  top: 11px;
  z-index: 2;
  font-size: 9px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}

.frame-state { left: 12px; display: inline-flex; align-items: center; gap: 6px; }
.frame-mark { right: 12px; font-size: 11px; }

.frame.is-live .frame-state { color: var(--ink); }
.frame-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--red); }

/* The X sits in a box, the way it does on a slot that can be cleared. */
.frame-x {
  display: grid;
  place-items: center;
  width: 15px;
  height: 15px;
  border: 1px solid var(--line-hard);
  font-size: 8px;
  font-style: normal;
}

/* the portrait */

/*
 * The face fills the frame. No inset box and no plate behind it: a cutout
 * should look like a person standing in the card, not a photograph pinned
 * inside one. It runs under the corner marks and under the name, which is why
 * both of those sit above it with their own shadow.
 */
.frame-stage {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: end center;
}

.frame-art {
  width: 100%;
  height: 100%;
  /* Cover, so the face is as large as the frame allows. Anchored high so a
     head is never cropped at the jaw when the aspect ratios disagree. */
  object-fit: cover;
  object-position: 50% 18%;
}

/*
 * A cutout has no edges to hide, so it is contained rather than cropped and
 * stands on the floor of the frame. Marked with a class rather than sniffed,
 * because a transparent PNG and an opaque photograph want opposite treatment
 * and the file cannot tell us which it is.
 */
.frame-art.is-cutout {
  object-fit: contain;
  object-position: 50% 100%;
  filter: drop-shadow(0 16px 26px rgba(0, 0, 0, .95));
}

/* No portrait yet: initials on the black, with no plate behind them. */
.frame-art.is-generated {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: none !important;
}

.frame-initials { font-size: 46px; font-weight: 800; color: rgba(250, 250, 250, .16); }

/* The face runs the full frame now, so the marks on top of it need their own
   contrast rather than borrowing the card's background. */
.frame-state, .frame-mark, .frame-foot { text-shadow: 0 1px 8px rgba(0, 0, 0, .95); }

/* A scrim only where the type sits, so the name stays readable over a face. */
.frame::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 42%;
  background: linear-gradient(to top, rgba(6, 6, 6, .92), transparent);
  pointer-events: none;
  z-index: 1;
}

/* the printed edge */

.frame-foot {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8px;
}

.frame-name {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .07em;
  text-transform: uppercase;
  line-height: 1.15;
  min-width: 0;
}

/* The signature slot. On the reference this is the designer's hand; here it
   is what backing that person has been worth, which is the honest equivalent
   of an autograph on a collectible. */
.frame-sign {
  font-size: 10px;
  font-style: italic;
  color: var(--yellow);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.row-more {
  margin-left: auto;
  font-size: 11.5px;
  color: var(--muted);
  text-decoration: none;
}

.row-more:hover { color: var(--ink); }

@media (max-width: 1040px) {
  .frames { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .frames .frame:nth-child(n+4) { display: none; }
}

@media (max-width: 640px) {
  .frames { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .frames .frame:nth-child(n+3) { display: none; }
}


/* ---------------------------------------------------------------------------
   The guide
   
   The first thing on the page, and the one thing a stranger has to understand:
   that watching is worth something. So it is large, it is three words, and it
   moves once on arrival to draw the eye across it in the order it reads.
   
   The motion is entrance only. Nothing here loops, because a page that keeps
   moving while you are trying to read the rest of it is worse than a page that
   never moved at all.
   --------------------------------------------------------------------------- */

.guide {
  position: relative;
  margin: 0 0 20px;
  padding: 26px 52px 28px 26px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background:
    radial-gradient(90% 160% at 0% 0%, rgba(244, 198, 60, .13), transparent 58%),
    linear-gradient(160deg, #17171c, #0d0d10);
  overflow: hidden;
}

.guide-tabs { display: flex; gap: 6px; margin-bottom: 20px; }

.guide-tab {
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .18s ease, color .18s ease, border-color .18s ease;
}

.guide-tab:hover { color: #fff; border-color: rgba(255, 255, 255, .3); }
.guide-tab.is-on { background: var(--yellow); border-color: var(--yellow); color: #0a0a0a; }

.guide-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 26px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}

.guide-steps li {
  position: relative;
  /*
   * Held in the finished position by default. The animation only runs when the
   * list is marked in, so a browser that never applies it still shows the steps
   * rather than leaving them invisible at opacity 0.
   */
  opacity: 1;
  transform: none;
}

/*
 * The arrow between steps, drawn rather than typed, so it disappears cleanly
 * when the columns wrap and there is no next step beside it.
 */
.guide-steps li:not(:last-child)::after {
  content: '';
  position: absolute;
  top: 20px;
  right: -18px;
  width: 10px;
  height: 10px;
  border-top: 2px solid rgba(255, 255, 255, .16);
  border-right: 2px solid rgba(255, 255, 255, .16);
  transform: rotate(45deg);
}

/*
 * The symbol carries the meaning, the number carries the order.
 *
 * An icon alone cannot say which step comes first, and a number alone says
 * nothing about what the step is, so both are here: the symbol fills the disc
 * and the number sits on its edge as a small badge.
 */
.guide-num {
  position: relative;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--yellow);
  color: #0a0a0a;
}

.guide-num svg {
  width: 25px;
  height: 25px;
  /* The sprite is stroked, not filled, so it inherits weight rather than mass. */
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.guide-num i {
  position: absolute;
  right: -3px;
  bottom: -3px;
  display: grid;
  place-items: center;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: #0a0a0a;
  border: 1.5px solid #17171c;
  color: var(--yellow);
  font-style: normal;
  font-size: 10.5px;
  font-weight: 800;
  line-height: 1;
}

.guide-steps b {
  display: block;
  margin-top: 14px;
  font-size: 30px;
  font-weight: 900;
  letter-spacing: -.035em;
  line-height: 1;
  text-transform: uppercase;
}

.guide-detail {
  display: block;
  margin-top: 8px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
  /*
   * One line each. The copy is written short enough to fit, and the ellipsis is
   * only a backstop for a narrow column or a longer translation: a clipped line
   * reads better here than a step whose height jumps while its neighbours stay
   * put, which is what wrapping did to the row.
   */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * The run. Each step arrives a beat after the one before it, so the eye is
 * pulled across them in reading order rather than meeting all three at once.
 */
/*
 * The hidden state lives in the keyframes, never on the element.
 *
 * Setting opacity: 0 on the element and relying on the animation to bring it
 * back means anything that stops the animation running leaves the content
 * invisible for good: a backgrounded tab, a paused animation, an engine that
 * declines the rule. With the from state inside the keyframes and fill-mode
 * backwards, it is only ever applied while the animation is actually pending,
 * and the resting state of the element stays visible.
 */
.guide-steps.is-in li {
  animation: guide-rise .52s cubic-bezier(.22, .9, .3, 1) backwards;
  animation-delay: calc(var(--i) * 130ms);
}

.guide-steps.is-in .guide-num {
  animation: guide-pop .46s cubic-bezier(.2, 1.5, .4, 1) backwards;
  animation-delay: calc(var(--i) * 130ms + 60ms);
}

@keyframes guide-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes guide-pop {
  from { transform: scale(.4); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}

.guide-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .07);
  color: var(--muted);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
}

.guide-close:hover { background: rgba(255, 255, 255, .16); color: #fff; }

/*
 * Somebody who has asked for less movement gets the same layout with none of
 * it. The steps are already in their finished position, so this only has to
 * stop the animation being applied.
 */
@media (prefers-reduced-motion: reduce) {
  .guide-steps.is-in li,
  .guide-steps.is-in .guide-num { animation: none; opacity: 1; transform: none; }
}

@media (max-width: 760px) {
  .guide { padding: 20px 44px 22px 18px; }
  .guide-steps { gap: 18px; grid-template-columns: 1fr; }
  .guide-steps li:not(:last-child)::after { display: none; }
  .guide-steps b { font-size: 23px; margin-top: 10px; }
  .guide-num { width: 44px; height: 44px; }
  .guide-num svg { width: 21px; height: 21px; }
  .guide-num i { width: 17px; height: 17px; font-size: 9.5px; }
  .guide-detail { font-size: 12.5px; max-width: none; }
}



/*
 * Artwork in a guide step, when a step has any.
 *
 * The disc keeps its size and its number badge either way, so a step that gains
 * a picture does not change the shape of the row around it. The image fills the
 * circle rather than sitting inside it, because a small illustration with a
 * margin inside a coloured disc reads as a mistake.
 */
/*
 * The artwork covers the symbol rather than replacing it, so a missing file
 * uncovers the symbol instead of leaving a hole.
 */
.guide-num .guide-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 30%;
  /* Its own ground, so a transparent illustration is not sitting on yellow. */
  background: #101014;
}
