/* Composition: the single layout authority. Columns, gutters, breakpoints and
   section rhythm live here and nowhere else. Skin is app.css, state is reactive.css. */

/* Full-bleed arena haze. Always behind copy, never intercepts pointers. */
body::after {
  content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: var(--arena) 62% center / cover no-repeat;
  opacity: calc(.26 + var(--env-intensity, .15) * .34);
  transform: scale(1.06);
  transition: opacity var(--dur-slow) var(--ease-out);
}
#app { position: relative; z-index: var(--z-content); }
main { min-height: 68vh; padding: 0 0 48px; }
header, footer { padding-inline: var(--scene-gutter); background: transparent; }
main > .test-banner { margin: 0; padding: 8px var(--scene-gutter); border-left: 0; border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--coal) 90%, transparent); }
.test-banner strong { font-size: var(--text-sm); }
.test-banner p { display: inline; margin-left: 16px; font-size: var(--text-xs); }

/* ── Hero — asymmetric full-bleed. Copy left, live ring right, ticket under copy.
   Paint order inside .hero is explicit, because ::before/::after share z-index 0
   with any un-set child: marks 1, copy and ring and ticket 2, scroll cue 3. ── */
.hero {
  position: relative; width: 100%; min-height: 100vh; min-height: 100dvh;
  display: grid; grid-template-columns: var(--hero-columns);
  grid-template-areas: 'copy live' 'prize live';
  column-gap: clamp(40px, 6vw, 160px); row-gap: clamp(24px, 4vh, 48px);
  align-content: center; align-items: start;
  padding: clamp(56px, 9vh, 132px) var(--scene-gutter) clamp(72px, 10vh, 148px);
  overflow: clip;
}
/* Scorch line across the top of the ring — the page's one hard horizontal. */
.hero-topline { position: relative; }
.hero-topline::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; pointer-events: none;
  background: linear-gradient(90deg, var(--ember) 0%, color-mix(in srgb, var(--ember-dark) 60%, transparent) 34%, transparent 88%);
}
.hero::before {
  content: ''; position: absolute; inset: -6%; pointer-events: none; z-index: 0;
  background: var(--arena) 58% center / cover no-repeat;
  opacity: .3; animation: atmosphere-drift 26s ease-in-out infinite alternate;
}
.hero::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background:
    linear-gradient(94deg, color-mix(in srgb, var(--coal) 90%, transparent) 10%, color-mix(in srgb, var(--coal) 42%, transparent) 52%, transparent 76%),
    linear-gradient(0deg, var(--coal) 2%, transparent 30%),
    radial-gradient(ellipse 60% 50% at 92% 30%, var(--scorch), transparent 68%);
}
/* Corner warning marks — the only place the mark asset is used. */
.hero-marks { position: absolute; inset: clamp(14px, 2vw, 30px); z-index: 1; pointer-events: none; }
.hero-marks::before, .hero-marks::after {
  content: ''; position: absolute; width: clamp(38px, 4vw, 68px); height: clamp(38px, 4vw, 68px);
  background: var(--warn-mark) center / contain no-repeat; opacity: .8;
}
.hero-marks::before { top: 0; left: 0; }
.hero-marks::after { right: 0; bottom: 0; transform: rotate(180deg); }

.hero-body { grid-area: copy; position: relative; z-index: 2; width: 100%; max-width: 1080px; }
.hero-topline {
  display: flex; flex-wrap: wrap; align-items: center; gap: clamp(12px, 2vw, 28px);
  padding-bottom: 14px; border-bottom: 1px solid var(--line-hot);
  color: var(--muted); font: var(--text-xs) var(--number-font); letter-spacing: .16em; text-transform: uppercase;
}
.registration-state { color: var(--muted); font-size: var(--text-xs); letter-spacing: .1em; }
.registration-state[data-state="open"] { color: var(--paper); }
.registration-state[data-state="open"]::before {
  content: ''; display: inline-block; width: 6px; height: 6px; margin-inline-end: 8px;
  background: var(--ember); animation: breathe 3s ease-in-out infinite;
}
.hero h1 { margin: clamp(24px, 4.6vh, 60px) 0 clamp(18px, 2.6vh, 34px); }
/* The wordmark scales to the column, not to a font size, so it holds its shape
   from a 360px phone to a 3840px wall. */
.title-mark { display: block; width: min(100%, clamp(300px, 50vw, 1000px)); height: auto; }
.intro { font-size: clamp(16px, 1.4vw, 30px); letter-spacing: .06em; }
.intro p:last-child { color: color-mix(in srgb, var(--paper) 52%, transparent); }
.ash-whisper {
  min-height: 1.4em; margin: clamp(14px, 2vh, 24px) 0 0;
  font: var(--text-xs) var(--number-font); letter-spacing: .18em;
  color: color-mix(in srgb, var(--muted) 80%, var(--ember));
}
.hero .actions { display: grid; grid-template-columns: 1.35fr 1fr; gap: 10px; max-width: 580px; margin-top: clamp(22px, 3.4vh, 44px); }
.hero .actions .primary { min-height: 58px; font-size: 16px; }
.hero .hint { max-width: 46ch; margin-top: 14px; }

/* Champion ticket, stated on the first screen and dramatised again below. */
.prize {
  grid-area: prize; position: relative; z-index: 2; display: flex; align-items: stretch; overflow: hidden;
  width: 100%; max-width: 580px; margin: 0;
  border: 1px solid var(--line); background: color-mix(in srgb, var(--coal) 55%, transparent);
}
.prize-stub { flex: 0 0 5px; background: var(--ember); }
.prize-main { flex: 1; min-width: 0; padding: clamp(14px, 1.6vw, 22px) clamp(16px, 2vw, 26px); }
.prize-value { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; margin: 8px 0 0; line-height: 1; }
.prize-value small { font: 500 17px var(--number-font); color: var(--muted); }
.prize-value strong { font: 700 clamp(44px, 4vw, 74px)/1 var(--number-font); letter-spacing: -.03em; }
.prize-value span { font: 500 var(--text-xs) var(--number-font); letter-spacing: .1em; color: var(--ember); }
.prize-main p { margin: 8px 0 0; font-size: var(--text-xs); color: var(--muted); }
.prize .prize-en { margin-top: 10px; font: var(--text-xs) var(--number-font); letter-spacing: .14em; color: var(--dim); }
.prize-line { max-width: 40ch; font-size: var(--text-md); color: var(--muted); }
.prize-en { font: var(--text-xs) var(--number-font); letter-spacing: .24em; color: color-mix(in srgb, var(--muted) 80%, transparent); }
.prize::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 20%, var(--glow) 50%, transparent 80%);
  transform: translateX(-120%);
}
.prize:hover::after, .prize.revealed::after { animation: scarlet-sweep 1.4s var(--ease-out) both; }

/* ── Live ring — the right column. Numbers are the loudest thing on the page. ── */
#live-status {
  grid-area: live; position: relative; z-index: 2; align-self: center;
  display: grid; align-content: center; justify-items: end; gap: clamp(16px, 2.4vh, 30px);
  width: 100%; padding-inline-start: clamp(20px, 2.6vw, 56px);
  border-inline-start: 1px solid var(--line); text-align: right;
}
/* Ember bloom behind the live ring — its strength is the registration capacity,
   so the page literally heats up as the tournament fills. */
#live-status::before {
  content: ''; position: absolute; inset: -12% -8%; z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse 68% 52% at 76% 40%,
    color-mix(in srgb, var(--ember) calc(var(--env-scarlet) * 34%), transparent), transparent 72%);
  filter: blur(24px);
  transition: background var(--dur-slow) var(--ease-out);
}
.live-head { display: grid; justify-items: end; gap: 8px; }
.live-head > span:first-child {
  font: 500 var(--text-sm) var(--number-font); letter-spacing: .22em; text-transform: uppercase; color: var(--ember);
  text-shadow: 0 0 18px color-mix(in srgb, var(--ember) calc(var(--env-scarlet) * 70%), transparent);
}
.live-whisper { font: var(--text-xs) var(--number-font); letter-spacing: .14em; color: var(--muted); }
.stats {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 30px) clamp(12px, 1.6vw, 26px);
  width: 100%; margin: 0; padding: 0; border: 0;
}
.stat { padding: 0; border: 0; background: none; }
.stat strong {
  display: flex; align-items: baseline; justify-content: flex-end; gap: 4px;
  font-family: var(--number-font); font-variant-numeric: tabular-nums;
}
.stat:first-child { grid-column: 1 / -1; padding-bottom: clamp(14px, 2vh, 22px); border-bottom: 1px solid var(--line); }
.stat:first-child strong { font-size: clamp(66px, 10vw, 190px); font-weight: 500; line-height: .88; letter-spacing: -.045em; }
.stat:first-child small { font-size: clamp(20px, 2vw, 40px); color: var(--muted); }
.stat:not(:first-child) strong { font-size: clamp(26px, 2.6vw, 58px); font-weight: 500; line-height: 1; }
.stat > span { display: block; margin-top: 8px; font-size: var(--text-xs); letter-spacing: .12em; color: var(--muted); }
.stat[data-state="hot"] strong, .stat[data-state="full"] strong, html.env-warning .stat:first-child strong { color: var(--ember); }
.stats.near-cap progress.capacity-meter::-webkit-progress-value { box-shadow: 0 0 18px var(--glow); }
.stats.near-cap progress.capacity-meter::-moz-progress-bar { box-shadow: 0 0 18px var(--glow); }
progress.capacity-meter {
  appearance: none; width: 100%; height: 3px; margin: 0; border: 0; padding: 0;
  background: color-mix(in srgb, var(--paper) 10%, transparent); color: var(--ember);
}
progress.capacity-meter::-webkit-progress-bar { background: color-mix(in srgb, var(--paper) 10%, transparent); }
progress.capacity-meter::-webkit-progress-value { background: linear-gradient(90deg, var(--ember-dark), var(--ember)); }
progress.capacity-meter::-moz-progress-bar { background: var(--ember); }
.status-empty { display: grid; align-content: center; justify-items: end; gap: 12px; min-height: 180px; color: var(--muted); }

.scene-scroll {
  position: absolute; z-index: 3; bottom: clamp(18px, 3vh, 40px); left: var(--scene-gutter);
  display: flex; align-items: center; gap: 20px; min-height: 48px;
  font: var(--text-xs) var(--number-font); letter-spacing: .16em; color: var(--muted); text-decoration: none;
}
.scene-scroll span { display: block; width: 1px; height: 38px; background: var(--line); overflow: hidden; }
.scene-scroll span::after { content: ''; display: block; height: 16px; background: var(--ember); animation: scroll-signal 2.4s ease-in-out infinite; }

/* ── Continuous narrative. Every section below the hero shares one rhythm and one
   thread, so the page reads as a single descent rather than a deck of slides.
   No section claims a full viewport any more; spacing carries the pacing. ── */
.reactive-home { position: relative; }
.reactive-home::before {
  content: ''; position: absolute; top: 0; bottom: 0; z-index: 0; pointer-events: none;
  left: max(13px, calc(var(--scene-gutter) * .34)); width: 1px;
  background: linear-gradient(180deg,
    transparent 0,
    color-mix(in srgb, var(--ember-dark) 60%, transparent) 12%,
    color-mix(in srgb, var(--ember-dark) 60%, transparent) 88%,
    transparent 100%);
}
.scene { position: relative; z-index: 1; padding: clamp(72px, 11vh, 168px) var(--scene-gutter); }
/* Measures are in `em`, never `ch`. `ch` resolves against the container's own
   font-size, so a `62ch` head stayed 551px wide while the h2 inside grew to 78px
   and wrapped mid-phrase on every large screen. `em` scales with the text. */
.scene-head h2 { max-width: 13em; margin: 14px 0 16px; font-size: clamp(30px, 4.4vw, 78px); line-height: 1.1; }
.scene-lead { max-width: 26em; margin: 0; font-size: var(--text-md); line-height: 1.8; color: color-mix(in srgb, var(--paper) 78%, transparent); }

.fact-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(18px, 2.4vw, 44px); width: 100%; max-width: min(1560px, 100%); margin: clamp(34px, 5vh, 68px) auto 0; padding: 0; list-style: none; }
.fact { display: grid; gap: 6px; padding-top: 22px; border-top: 1px solid var(--line-hot); }
.fact-icon { width: 26px; height: 26px; color: var(--ember); }
.fact strong { font-family: var(--number-font); font-size: clamp(46px, 6vw, 100px); font-weight: 500; line-height: .95; letter-spacing: -.04em; }
.fact strong small { margin-left: 6px; font-size: .34em; color: var(--muted); }
.fact-label { font-size: var(--text-sm); font-weight: 700; }
.fact-note { font-size: var(--text-xs); color: var(--muted); }

/* Schedule: four dates on a rail, the one happening now lit. */
.schedule-track { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 2.4vw, 40px); width: 100%; max-width: min(1560px, 100%); margin: clamp(34px, 5vh, 68px) auto 0; padding: 0; list-style: none; }
.schedule-phase { position: relative; display: grid; gap: 7px; align-content: start; padding-top: 26px; border-top: 1px solid var(--line); font-size: var(--text-sm); color: var(--muted); }
.schedule-phase .phase-mark { position: absolute; top: -4px; left: 0; width: 8px; height: 8px; background: var(--line); box-shadow: 0 0 0 4px var(--coal); }
.schedule-phase .phase-date { font-family: var(--number-font); font-size: var(--text-sm); letter-spacing: .14em; }
.schedule-phase strong { font-size: clamp(17px, 1.5vw, 26px); color: var(--paper); }
.schedule-phase .phase-note { font-size: var(--text-xs); }
.schedule-phase[data-state="done"] { color: color-mix(in srgb, var(--muted) 55%, transparent); }
.schedule-phase[data-state="done"] strong { color: color-mix(in srgb, var(--paper) 55%, transparent); }
.schedule-phase[data-state="now"] { border-top-color: var(--ember); color: var(--paper); }
.schedule-phase[data-state="now"] .phase-mark { background: var(--ember); box-shadow: 0 0 18px var(--glow); }
.schedule-phase[data-state="now"] strong { color: var(--ember); }
.schedule-phase .phase-now { font-size: var(--text-xs); letter-spacing: .2em; color: var(--ember); text-transform: uppercase; }
/* 賽況 (§22.4): the bot's phase, on the row it belongs to, under the 現在 marker when
   both are there. Ember like the marker, because it is the same kind of news — and
   dimmed on a finished row, where the note is history rather than a state. */
.schedule-phase .phase-match { font-size: var(--text-xs); color: var(--ember); }
.schedule-phase[data-state="done"] .phase-match { color: inherit; }
/* The same sentence on the team page and in the 後台, where it has no rail under it. */
.phase-line { margin-top: 14px; font-size: var(--text-sm); color: var(--ember); }
.schedule-phase[data-state="tbd"] { opacity: .55; }

/* One line of arithmetic under the hero buttons. Inline elements, not flex, so it
   follows whatever alignment the hero is using at this width. */
.hero-countdown { margin: 16px 0 0; font-family: var(--number-font); letter-spacing: .12em; color: var(--muted); }
.hero-countdown span { margin-right: 10px; font-size: var(--text-xs); letter-spacing: .2em; text-transform: uppercase; }
.hero-countdown strong { font-size: clamp(22px, 2.4vw, 38px); font-weight: 500; line-height: 1; color: var(--ember); }
.hero-countdown small { margin-left: 5px; font-size: var(--text-sm); }

.faq-list { max-width: 920px; margin: clamp(32px, 4.4vh, 60px) 0 0; }
.faq-item { border-top: 1px solid var(--line); }
.faq-item:last-child { border-bottom: 1px solid var(--line); }
.faq-item summary { position: relative; padding: 20px 46px 20px 0; cursor: pointer; list-style: none; font-size: var(--text-md); font-weight: 700; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: ''; position: absolute; right: 14px; top: 50%; width: 9px; height: 9px;
  border-right: 1.5px solid var(--ember); border-bottom: 1.5px solid var(--ember);
  transform: translateY(-70%) rotate(45deg); transition: transform var(--dur-base) var(--ease-out);
}
.faq-item[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq-item summary:hover { color: var(--ember); }
.faq-item p { max-width: 34em; margin: 0; padding: 0 0 24px; color: var(--muted); font-size: var(--text-sm); line-height: 1.85; }

/* The Q&A, grouped (2026-09-14). Six headings in the order somebody reads in — before
   registering, after registering, on the night — so a visitor scans the headings and
   opens one answer, instead of scrolling past thirty. The heading is the only thing that
   carries a mark, because the rows under it already have the chevron. */
/* The gap below the lead is here rather than on `.scene-lead`: that class is shared with
   three other scenes, and the first group heading is the only thing that ever follows it
   directly. Without it the heading reads as the third line of the lead. */
.qa-groups { max-width: 920px; margin: clamp(30px, 4.4vh, 60px) auto 0; }
.qa-group + .qa-group { margin-top: clamp(30px, 4vh, 54px); }
.qa-group .faq-list { margin-top: 12px; }
.qa-group-title {
  position: relative; margin: 0; padding-left: 16px;
  font-size: var(--text-md); font-weight: 700; letter-spacing: .04em;
}
.qa-group-title::before {
  content: ''; position: absolute; left: 0; top: .25em; bottom: .25em; width: 3px; background: var(--ember);
}
.qa-note { max-width: 920px; margin: clamp(30px, 4vh, 54px) auto 0; text-align: center; }
/* An anchor that can be linked to without being seen or read out: `#qa` has to land at
   the top of the section, and the section's own id is `#faq` for the links that were
   handed out before this block existed. */
.anchor-mark { display: block; height: 0; scroll-margin-top: 80px; }

/* The last thing on the page is the way in. */
.scene-final { padding-bottom: clamp(120px, 17vh, 240px); }
.scene-final h2 { margin: 14px 0 18px; font-size: clamp(42px, 6.6vw, 124px); line-height: 1; letter-spacing: -.035em; }
.scene-final .actions { margin-top: clamp(28px, 4.4vh, 52px); }
.scene-final .actions .primary { min-height: 62px; padding-inline: clamp(26px, 3vw, 54px); font-size: var(--text-md); }

/* ── Nothing hugs the left gutter with dead space beside it. ──
   Content columns are centred in the page, and the sections that are pure copy
   centre the text itself; a headline on the left half with an empty right half
   reads as a layout mistake, not as restraint. */
.scene-format .scene-head, .entry-morph .scene-head, .scene-schedule .scene-head { max-width: min(1560px, 100%); margin-inline: auto; }
.scene-faq .scene-head, .scene-faq .faq-list, .scene-faq .qa-groups { max-width: min(920px, 100%); margin-inline: auto; }

.scene-final { text-align: center; }
.scene-final .scene-head, .scene-final .scene-lead { margin-inline: auto; }
/* `text-align: center` centres the words inside their box, not the box itself.
   The h2 and the lead are the only children here with a `max-width` of their own,
   so they stayed pinned to the left edge while the eyebrow and the body text —
   inline-block, or carrying `margin: 0 auto` — centred. Centring the box is what
   the section actually needed. */
.scene-final .scene-head h2, .scene-final .scene-lead { margin-inline: auto; }
.scene-final .actions { justify-content: center; }
.my-teams { align-items: center; text-align: center; }

/* ── Reward scene — the emotional peak, still part of the same descent. ── */
.prize-scene {
  position: relative;
  display: grid; place-content: center; justify-items: center; gap: 10px;
  padding: clamp(96px, 15vh, 224px) var(--scene-gutter); text-align: center;
  background: radial-gradient(ellipse at center, color-mix(in srgb, var(--ember-dark) calc(var(--env-scarlet) * 62%), transparent), transparent 64%);
}
.prize-giant {
  font-family: var(--number-font); font-weight: 700;
  font-size: clamp(68px, 15.5vw, 240px); line-height: .88; letter-spacing: -.045em;
  text-shadow: 0 0 64px color-mix(in srgb, var(--ember) 38%, transparent);
}
.prize-giant small { display: block; font-size: .2em; letter-spacing: .22em; color: var(--ember); }
/* The giant figure runs at line-height .88, so its comma descends past the line
   box; without real clearance it collides with the split line underneath. */
.prize-split { margin: clamp(24px, 3vh, 46px) 0 18px; font: 500 clamp(15px, 2vw, 32px) var(--number-font); letter-spacing: .16em; color: var(--ember); }
.prize-scene h2 { font-size: clamp(26px, 3.4vw, 72px); margin: 0 0 14px; }

/* ── Entry procedure, laid across the flow instead of beside it. ── */
.entry-steps {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.6vw, 52px);
  width: 100%; max-width: min(1560px, 100%);
  margin: clamp(34px, 5vh, 68px) auto 0; padding: 0; list-style: none; counter-reset: entry;
}
.entry-morph li { position: relative; padding-top: 26px; border-top: 1px solid var(--line-hot); }
.entry-morph li::before {
  counter-increment: entry; content: '0' counter(entry);
  position: absolute; top: 20px; right: 0;
  font: 500 clamp(30px, 3.4vw, 66px)/1 var(--number-font);
  color: color-mix(in srgb, var(--ember) 32%, transparent);
}
.entry-mark { display: grid; place-items: center; width: 48px; height: 48px; margin-bottom: 16px; border: 1px solid var(--line-hot); color: var(--ember); background: color-mix(in srgb, var(--coal) 60%, transparent); }
.entry-morph li strong { display: block; font-size: clamp(19px, 1.7vw, 32px); }
.entry-morph li p { max-width: 30ch; margin: 10px 0 0; color: var(--muted); font-size: var(--text-sm); }
.entry-morph .actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: clamp(28px, 4vh, 48px); }

.my-teams a { border-bottom: 1px solid var(--line); align-self: stretch; }

/* ── Flow — information left, controls right. ── */
.flow { margin: 48px var(--scene-gutter) 0; padding-bottom: 190px; }
.flow:not(.flow-split) { max-width: var(--form-width); margin-inline: auto; padding-inline: var(--gutter); }
.flow-split {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: var(--scene-gap); align-items: start;
  min-height: 88vh; min-height: 88dvh;
}
.flow-info { position: sticky; top: clamp(32px, 7vh, 72px); align-self: start; }
.step-number { margin-top: 12px; font: 500 clamp(46px, 5.4vw, 108px)/1 var(--number-font); letter-spacing: -.06em; color: var(--paper); }
.step-number small { font-size: 18px; letter-spacing: 0; color: var(--muted); }
.flow-kicker { margin: 0; font: 500 12px var(--number-font); letter-spacing: .24em; text-transform: uppercase; color: var(--muted); }
.flow-info > .hint { max-width: 32ch; margin-top: 14px; }
.flow-info .seat-progress { margin-top: 28px; max-width: 420px; }
.flow-signature { display: flex; gap: 12px; height: 140px; margin-top: 28px; overflow: hidden; }
.flow-signature i { display: block; width: 28px; height: 170px; margin-left: 28px; background: var(--ember-dark); transform: skew(-24deg); animation: blade-breathe 5s ease-in-out infinite; }
.flow-signature i:nth-child(2) { background: var(--ember); animation-delay: -.7s; }
.flow-signature i:nth-child(3) { animation-delay: -1.4s; }
.flow-inputs {
  position: relative; z-index: 2; width: 100%; max-width: 920px;
  padding: clamp(22px, 2.4vw, 42px);
  border: 1px solid var(--line); border-top: 2px solid var(--ember);
  background: color-mix(in srgb, var(--coal) 92%, transparent);
}
.flow-inputs .field-label { font-size: 16px; }
.flow-inputs input:not([type=checkbox]) { min-height: 58px; }
.flow-inputs .field:last-child, .flow-inputs fieldset:last-child { margin-bottom: 0; }
.field.ok .field-shell::after { animation: check-lock .3s var(--ease-out); }

.lineup { max-width: min(1100px, 100%); margin-inline: auto; }
main > #error:not(:empty) { margin: 20px var(--scene-gutter) 150px; }
.admin-login { max-width: var(--form-width); margin: 12px auto 0; padding-inline: 20px; }
.admin-teams, .admin-toolbar { margin-inline: var(--scene-gutter); }
.admin-toolbar { margin-block: 18px 24px; }
.home-dock { display: none; }

/* ── The desk — the create flow living on the home page. The hero gives up its full
   screen (the first field has to be on the first screen), the flow gives up the bottom
   padding it needed as a standalone screen, and the error line stays with the form. ── */
.hero.is-desk {
  min-height: 0; align-content: start;
  padding-block: clamp(40px, 6vh, 88px) clamp(28px, 4.4vh, 56px);
}
.hero.is-desk h1 { margin: clamp(14px, 2.4vh, 30px) 0 clamp(10px, 1.6vh, 20px); }
.hero.is-desk .title-mark { width: min(100%, clamp(240px, 34vw, 560px)); }
/* Nothing decorative here: the scroll cue, the ticket and the guest CTA all step
   aside, the login CTA included — the desk's own first step carries the same button. */
.hero.is-desk .ash-whisper,
.hero.is-desk .hero-actions,
.hero.is-desk .hero-login,
.hero.is-desk .hero-countdown,
.hero.is-desk .prize,
.hero.is-desk .scene-scroll { display: none; }
.reactive-home > .flow { padding-bottom: clamp(64px, 10vh, 120px); scroll-margin-top: clamp(16px, 3vh, 40px); }
.reactive-home > .flow.flow-split { min-height: 0; }
.reactive-home > #error:not(:empty) { margin: 18px var(--scene-gutter) 0; }
/* The guest's way in, under the hero copy: the one thing this page can offer
   someone who has not signed in, so it is a full-width thumb target. */
.hero-login { max-width: min(100%, 580px); margin-top: clamp(18px, 3vh, 30px); }
.hero-login .button { width: 100%; min-height: 56px; font-size: var(--text-md); }

/* ── Dock — fixed step rail for the flow, CTA bar on phones. ── */
.dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-dock);
  border-top: 1px solid var(--line); background: var(--coal);
  padding-bottom: env(safe-area-inset-bottom);
}
.dock-inner { max-width: min(720px, 100%); margin-inline: auto; padding: 14px var(--gutter); text-align: center; }
.steps { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px; }

/* ── The guide sheet. One document, two arrangements.
   Until 2026-09-13 the sheet was a single 860px column at every width: fine for five
   short groups, hopeless once 比賽禁止事項 added twelve more clauses to read. The
   desk now gets a contents rail beside the prose instead of a row of chips above it.
   The rail is a fixed 13.5rem and the prose takes what is left, which is the whole
   point: the measure is decided by the column, not by the window, so a wider monitor
   buys a longer rail rather than a line the eye cannot follow back. Measured across
   1024–2560px that lands between 34 and 45 Chinese characters a line. The phone
   layout is untouched (see the 1023 block below) — it was never the problem. ── */
dialog {
  position: fixed; inset: 0; width: min(100% - 48px, 980px); max-height: min(88dvh, 900px);
  margin: auto; padding: clamp(24px, 2.2vw, 40px) clamp(22px, 2.6vw, 44px) 34px;
  overflow: auto;
}
.sheet-body { display: grid; grid-template-columns: minmax(0, 13.5rem) minmax(0, 1fr); column-gap: clamp(28px, 3vw, 56px); align-items: start; }
.sheet-main { min-width: 0; }
.sheet-rail { position: sticky; top: 0; }
.sheet-toc ul { display: grid; gap: 8px; }
.sheet-toc a { justify-content: flex-start; }
/* The band used to bleed past the sheet's own padding. Beside a rail it would bleed
   into the gap instead, so on a desk it stops at its column and the column's edges
   do the separating. */
.sheet-disclaimer { margin-inline: 0; }

@keyframes atmosphere-drift { from { transform: scale(1.04) translateX(-1.5%); } to { transform: scale(1.14) translateX(1.5%); } }
@keyframes digit-lock { from { transform: translateY(-15%); filter: blur(5px); } to { transform: none; filter: none; } }
@keyframes scarlet-sweep { to { transform: translateX(120%); } }
@keyframes scroll-signal { 0% { transform: translateY(-16px); } 70%, 100% { transform: translateY(40px); } }
@keyframes blade-breathe { 50% { transform: skew(-24deg) translateY(18px); opacity: .4; } }
@keyframes check-lock { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0); } }

/* ── Breakpoints. One file, one ladder: 2200 up, then 1023 / 720 / 600 / 400 down. ── */
@media (min-width: 2200px) {
  .hero { grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); }
  /* The rail can afford to grow here; the prose column still cannot, which is why
     only the rail's track moves. */
  dialog { width: min(100% - 96px, 1160px); }
  .sheet-body { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }
  .hero-body { max-width: 1400px; }
  #live-status { max-width: 1040px; }
  .scene { padding-inline: var(--scene-gutter); }
  .fact-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 1023px) {
  header, footer { padding-inline: var(--gutter); }
  /* The sheet returns to exactly the one column it has always been: chips in a row
     above the prose, the disclaimer bleeding past the padding, 860px at its widest. */
  dialog { width: min(100% - 32px, 860px); padding: 22px var(--gutter) 30px; }
  .sheet-body { display: block; }
  .sheet-rail { position: static; }
  .sheet-toc ul { display: flex; flex-wrap: wrap; gap: 8px; }
  .sheet-disclaimer { margin-inline: calc(var(--gutter) * -1); }
  main > .test-banner { padding: 10px var(--gutter); }
  .test-banner p { display: block; margin: 4px 0 0; }
  .hero {
    grid-template-columns: 1fr; grid-template-areas: 'copy' 'live' 'prize';
    row-gap: clamp(22px, 3.4vh, 36px); align-content: start;
    padding: clamp(28px, 6vh, 56px) var(--gutter) 132px;
  }
  .hero-marks { display: none; }
  .hero-body { max-width: none; }
  .hero h1 { margin: 24px 0 16px; }
  .hero-topline { justify-content: space-between; gap: 10px; }
  .title-mark { width: 100%; }
  .intro { font-size: 15px; }
  .hero .actions { display: none; }
  .prize { max-width: none; }
  #live-status {
    gap: 18px; padding: 22px 0 0; border-inline-start: 0; border-top: 1px solid var(--line);
    text-align: left; justify-items: start;
  }
  .live-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; justify-items: start; }
  .live-head > span:first-child { font-size: var(--text-sm); }
  .stat strong { justify-content: flex-start; }
  .stats { grid-template-columns: minmax(0, 1.25fr) repeat(3, minmax(0, 1fr)); gap: 10px; }
  .stat:first-child { grid-column: auto; padding-bottom: 0; border-bottom: 0; }
  .stat:first-child strong { font-size: clamp(32px, 10.5vw, 52px); }
  .stat:first-child small { font-size: 14px; }
  .stat:not(:first-child) strong { font-size: clamp(18px, 5.4vw, 28px); }
  .stat > span { margin-top: 6px; font-size: var(--text-xs); letter-spacing: .06em; }
  .status-empty { justify-items: start; min-height: 132px; }
  .scene-scroll { left: var(--gutter); bottom: 104px; }
  .scene-scroll span { height: 24px; }
  .scene { padding: clamp(56px, 9vh, 96px) var(--gutter); }
  .scene-head h2 { font-size: clamp(28px, 7.4vw, 44px); }
  .reactive-home::before { left: 8px; }
  .fact-row { grid-template-columns: 1fr; gap: 0; margin-top: 30px; }
  .fact { grid-template-columns: auto 1fr; grid-template-areas: 'icon value' 'icon label' 'icon note'; column-gap: 16px; row-gap: 2px; align-items: center; padding: 18px 0; border-top: 1px solid var(--line-hot); }
  .fact-icon { grid-area: icon; width: 30px; height: 30px; }
  .fact strong { grid-area: value; font-size: clamp(38px, 13vw, 64px); }
  .fact-label { grid-area: label; }
  .fact-note { grid-area: note; }
  .scene-final h2 { font-size: clamp(40px, 13vw, 76px); }
  .scene-final .actions { display: grid; grid-template-columns: 1fr; }
  .entry-steps { grid-template-columns: 1fr; gap: 0; margin-top: 30px; }
  .entry-morph li { padding: 22px 0 22px 0; }
  .entry-morph li::before { top: 20px; font-size: 30px; }
  .entry-morph li strong { font-size: 20px; }
  .entry-morph .actions { margin-top: 24px; }
  .prize-scene { padding: clamp(72px, 12vh, 112px) var(--gutter); }
  .prize-scene h2 { font-size: 30px; }
  .entry-morph .actions { display: none; }
  .my-teams { padding: 48px var(--gutter); }
  .flow { margin: 28px var(--gutter) 0; padding-bottom: 170px; }
  .flow-split { grid-template-columns: 1fr; gap: 20px; min-height: 0; }
  .flow-info { position: static; }
  .flow-info h2 { font-size: 32px; margin: 12px 0; }
  .step-number { margin-top: 8px; font-size: 42px; }
  .step-number small { font-size: 14px; }
  .flow-info > .hint { max-width: 40ch; }
  .flow-signature { display: none; }
  .flow-inputs { max-width: none; padding: 20px 16px; background: color-mix(in srgb, var(--coal) 94%, transparent); }
  .home-dock {
    position: fixed; inset-inline: 0; bottom: 0; z-index: var(--z-dock);
    display: flex; gap: 8px;
    padding: 10px var(--gutter) max(10px, env(safe-area-inset-bottom));
    border-top: 1px solid var(--line); background: var(--coal);
  }
  .home-dock .button { flex: 1; min-height: 50px; padding-inline: 10px; font-size: 14px; }
  body:has(.home-dock) footer { padding-bottom: 96px; }
  /* The desk on a phone: the hero is a heading rather than a screen, so the form
     follows immediately and the standalone-flow bottom padding goes with it. */
  .hero.is-desk { padding: 18px var(--gutter) 20px; }
  .hero.is-desk h1 { margin: 14px 0 10px; }
  .reactive-home > .flow { margin-top: 18px; padding-bottom: 120px; }
  /* On a phone the step panel would push the first field past the fold, and it
     repeats what the dock's step rail already says — so it steps aside and the
     field arrives with the visit. The desk on a wide screen keeps it. */
  .reactive-home > .flow .flow-info { display: none; }
  /* Same reason, one block up: the wordmark and the hint already say what this
     page is and what to do, so the intro line goes rather than the form. */
  .hero.is-desk .intro { display: none; }
}

@media (max-width: 720px) {
  .stage-choices { grid-template-columns: 1fr; }
  .stage-option { min-height: 76px; }
  .roster-node { grid-template-columns: 14px 1fr; }
  .roster-node span:last-child { grid-column: 2; grid-row: auto; text-align: left; }
  /* Two dates per row: four across would leave each one too narrow to read the
     note under the label. */
  .schedule-track { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px 18px; }
}

@media (max-width: 600px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 12px; }
  .stat:first-child { grid-column: 1 / -1; }
  .choices, .choices.platforms { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .choices.platforms { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  footer { flex-wrap: wrap; font-size: 10px; }
}

@media (max-width: 400px) {
  .steps { gap: 6px; font-size: 11px; }
  .choices, .choices.platforms { grid-template-columns: 1fr; }
  .schedule-track { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  body::after { transform: none !important; }
}
