/* =============================================================================
   UltiGameMate — authored global stylesheet
   Single source for everything that is NOT an app-shell component.
   Loaded after tokens.css, before components.css.
   App screens (sidebar + .app-main) are styled in components.css.
   Dark by default, light via :root[data-theme='light']. All values come
   from tokens.css.
   ============================================================================= */

/* --- 1. reset + base --------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-block-size: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: clip; /* safety net: nothing should scroll the page sideways */
  background: var(--bg-page);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--fz-body);
  font-weight: 400;
  line-height: var(--lh-body);
  letter-spacing: 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* faint green aurora across the top of every page. A fixed pseudo-element
   rather than background-attachment:fixed (janky/ignored on iOS); z-index -1
   keeps it under all in-flow content but above the canvas background. */
body::before {
  content: '';
  position: fixed;
  inset: 0 0 auto;
  z-index: -1;
  block-size: 34rem;
  background: var(--aurora);
  pointer-events: none;
}

/* per-theme media (e.g. blog screenshots shipped in both themes): only the
   one matching the active theme shows; without JS (no data-theme) it's dark */
:root:not([data-theme='light']) .theme-light-only,
:root[data-theme='light'] .theme-dark-only {
  display: none;
}

img,
svg,
video {
  max-inline-size: 100%;
  block-size: auto;
}

/* duotone icons (partials/icon.liquid, js/icons.js): the silhouette layer is
   a tinted fill under the stroke. Tune per context with --icon-duo. */
.icon .duo {
  fill: currentColor;
  stroke: none;
  opacity: var(--icon-duo);
}

::selection {
  background: color-mix(in srgb, var(--accent-hi) 30%, transparent);
  color: var(--text-primary);
}

::placeholder {
  color: var(--text-muted);
}

:focus-visible {
  outline: 2px solid var(--accent-hi);
  outline-offset: var(--space-3xs);
}

@view-transition {
  navigation: auto;
}

/* --- 2. typography (global — app screens included) ------------------------- */
h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: var(--lh-snug);
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-heading);
  text-wrap: balance;
}

h1 {
  font-size: var(--fz-2xl);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
}

h2 {
  font-size: var(--fz-xl);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
}

h3 {
  font-size: var(--fz-lg);
}

h4 {
  font-size: var(--fz-md);
}

h5,
h6 {
  font-size: var(--fz-body);
}

p {
  margin: 0;
}

strong,
b {
  color: var(--text-primary);
  font-weight: 700;
}

small,
.fz-sm {
  font-size: var(--fz-sm);
}

sup {
  font-size: 0.62em;
  line-height: 0;
  vertical-align: super;
  font-family: var(--font-mono);
}

code,
kbd,
samp {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

main:not(.app-main) .articles ul {
  margin-block-end: var(--space-2xl);
}

/* prose blocks inside content pages + un-migrated app content pages
   (a bare <section> straight inside .app-main: rules / leagues / profile) */
main:not(.app-main) :is(p, li),
.app-main > section:not([class]) :is(p, li) {
  font-family: var(--font-body);
  font-size: var(--fz-body);
  line-height: var(--lh-body);
  text-wrap: pretty;
}

.app-main > section:not([class]) {
  display: flow-root;
}

/* the app column is wide (--w-app) for cards and tables; running text on
   the prose screens (rules / leagues / profile) keeps a readable measure */
.app-main > section:not([class]) :is(p, li) {
  max-inline-size: 72ch;
}

.app-main > section:not([class]) p {
  margin-block: 0 var(--flow-md);
}

.app-main > section:not([class]) :is(ul, ol) {
  margin-block: 0 var(--flow-md);
  padding-inline-start: var(--indent-list);
}

.app-main > section:not([class]) li {
  margin-block: var(--flow-3xs) 0;
}

.app-main > section:not([class]) li::marker {
  color: var(--accent-lo);
}

.app-main > section:not([class]) :is(h2, h3, h4) {
  margin-block: var(--flow-lg) var(--flow-2xs);
}

.app-main > section:not([class]) > :first-child {
  margin-block-start: 0;
}

main:not(.app-main) {
  --flow: var(--flow-md);
}

main:not(.app-main) h1 {
  margin-block-end: var(--flow-3xs);

  /* hero titles: white shading into mint */
  background: var(--grad-text-accent);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* h2 carries the section break now that <hr> is gone */
main:not(.app-main) h2 {
  margin-block: var(--flow-xl) var(--flow-2xs);
}

main:not(.app-main) :is(h1, h2) + h2 {
  margin-block-start: var(--flow-sm);
}

main:not(.app-main) h3 {
  margin-block: var(--flow-lg) var(--flow-3xs);
}

main:not(.app-main) h4 {
  margin-block: var(--flow-md) var(--flow-3xs);
}

main:not(.app-main) p {
  margin-block: 0 var(--flow);
}

main:not(.app-main) :is(ul, ol) {
  margin-block: 0 var(--flow);
  padding-inline-start: var(--indent-list);
}

main:not(.app-main) li {
  margin-block: var(--flow-3xs) 0;
}

main:not(.app-main) li::marker {
  color: var(--accent-lo);
}

/* --- 3. links — two treatments ------------------------------------------- */
a {
  color: var(--accent-hi);
  text-decoration: none;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  transition: color var(--dur) var(--ease);
}

a:is(:hover, :focus-visible) {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
}

/* links inside flowing text always carry an underline — but not buttons or
   action links that happen to sit inside a <p> (e.g. <p><a class="btn">…) */
:is(main, section, dialog, .app-main)
  :is(p, li)
  a:not(.btn, .cta, .link, [class*='btn--'], [class*='cta--']) {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent-hi) 40%, transparent);
}

/* keep component links flat regardless of surrounding context */
:is(main, section, dialog, .app-main) :is(p, li) :is(a.btn, a.cta, a.link) {
  text-decoration: none;
}

/* chrome links (nav / footer): muted, colour shift only */
:is(.site-nav, .site-footer__nav, header nav, footer nav) a {
  color: var(--text-secondary);
  text-decoration: none;
}

:is(.site-nav, .site-footer__nav, header nav, footer nav) a:is(:hover, :focus-visible) {
  color: var(--text-primary);
  text-decoration: none;
}

/* standalone action link ("View all scores →") — one class */
.link {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--accent-hi);
  text-decoration: none;
  text-transform: none;
  cursor: pointer;
}

.link:is(:hover, :focus-visible) {
  text-decoration: underline;
}

.link--sm {
  font-size: var(--fz-sm);
}

.link--muted {
  color: var(--text-secondary);
}

.link--muted:is(:hover, :focus-visible) {
  color: var(--text-primary);
}

.link svg {
  inline-size: 1em;
  block-size: 1em;
}

/* --- 3b. surfaces — one shiny-border system for every card-like box --------
   Layered backgrounds: a top sheen, an optional translucent tint, an opaque
   fill (all clipped to the padding box) and a lit-from-the-top gradient edge
   painted into the transparent 1px border. No pseudo-elements, and the edge
   follows border-radius.
   Components never set `background`/`border` on a surface — they set these
   custom properties instead:
     --_fill  opaque base colour (default --bg-card; hover -> --bg-elevated)
     --_tint  translucent wash on top (selected -> --accent-wash, boost -> --gold-wash)
     --_edge  border gradient (--edge, --edge-hover, --edge-accent, --edge-gold)
   Keep --_fill opaque: a translucent fill lets the border-box edge gradient
   show through the whole card. Washes always go in --_tint.
   :where() = zero specificity, so every component rule still wins. */
@property --_fill {
  syntax: '<color>';
  inherits: false;
  initial-value: transparent;
}

@property --_tint {
  syntax: '<color>';
  inherits: false;
  initial-value: transparent;
}

:where(
  .match-card,
  .pick-option,
  .match-score-card,
  .stat-tile,
  .boost-pill,
  .round-tab,
  .twrap,
  .result-card,
  .card,
  .pick,
  .select,
  details,
  dialog,
  .sidebar__profile,
  .banner--sticky,
  .combobox__list
) {
  --_fill: var(--bg-card);
  --_tint: transparent;
  --_edge: var(--edge);
  --_sheen: var(--sheen);

  /* the drop shadow is a property too, so clickable surfaces can swap in
     the raised/hover/pressed shadows (components.css) and state rules can
     stack a glow on top with `box-shadow: var(--_shadow), <glow>` */
  --_shadow: var(--shadow-card);

  /* named so a rule that must out-rank a class-level `background`/`border`
     (e.g. .banner--sticky over .banner) can re-assert it in one line */
  --_surface:
    var(--_sheen) padding-box, linear-gradient(var(--_tint), var(--_tint)) padding-box,
    linear-gradient(var(--_fill), var(--_fill)) padding-box, var(--_edge) border-box;
  border: var(--border-hairline) solid transparent;
  background: var(--_surface);
  box-shadow: var(--_shadow);

  /* --_fill/--_tint are registered colours (@property), so hovers fade */
  transition:
    --_fill var(--dur) var(--ease),
    --_tint var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

/* --- 4. buttons — one system ------------------------------------------- */
.btn,
.cta:not(.cta--x) {
  --_bg: var(--bg-elevated);
  --_fg: var(--text-primary);
  --_bd: transparent;
  --_sheen: linear-gradient(145deg, rgb(255 255 255 / 0.08), transparent 60%);

  /* extruded from the page (outer neumorphism, tokens.css) */
  --_shadow: var(--shadow-raised-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-sm);
  min-inline-size: 0;

  /* Not margin-block-start: this shorthand's specificity (.cta:not(.cta--x),
     two classes) beats the admin/app spacing rule's margin-block-start
     (components.css, one class + one type selector), silently cancelling it
     and sticking the button to whatever precedes it. Leaving block-start
     unset here means nothing competes with that rule's declaration; the
     initial value (0) still applies everywhere this component's own rule
     doesn't override it. */
  margin-inline: 0;
  margin-block-end: 0;

  /* one normal size everywhere (the login page's Google button); only the
     main nav's Sign in uses the compact --sm below */
  padding: var(--pad-xl) var(--pad-3xl);
  border: var(--border-hairline) solid var(--_bd);
  border-block-start-color: var(--_bd-top, var(--_bd));
  border-radius: var(--radius-sm);

  /* --_sheen may be several layers; the last layer stays a plain colour so
     the hover ring's color-mix(var(--_bg)) below keeps working */
  background: var(--_sheen), var(--_bg);
  box-shadow: var(--_shadow);
  color: var(--_fg);
  font-family: var(--font-body);
  font-size: var(--fz-md);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--tracking-label);
  text-transform: none;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    filter var(--dur) var(--ease),
    background var(--dur) var(--ease),
    border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

/* Hover: a glow ring in the button's own fill colour + a touch brighter.
   No transform — a moving target flickers when the cursor approaches from below. */
.btn:is(:hover, :focus-visible),
.cta:not(.cta--x):is(:hover, :focus-visible) {
  filter: brightness(1.12);
  box-shadow:
    var(--_shadow),
    0 0 0 4px color-mix(in srgb, var(--_bg) 35%, transparent);
  text-decoration: none;
}

/* ghost / secondary buttons fill in on hover (transparent → solid) */
.btn--ghost:is(:hover, :focus-visible),
.cta--alt:is(:hover, :focus-visible),
.cta--inline:is(:hover, :focus-visible),
.cta--ghost:is(:hover, :focus-visible) {
  --_bg: var(--bg-elevated);
  --_fg: var(--text-primary);
}

/* pressed: the extruded button sinks into a dent */
.btn:active,
.cta:not(.cta--x):active {
  filter: brightness(1);
  box-shadow: var(--shadow-pressed);
}

.btn:disabled,
.btn[disabled],
.cta:disabled,
.cta[disabled] {
  opacity: 0.5;
  filter: none;
  cursor: not-allowed;
}

/* primary: mint -> green gradient fill, a glassy top highlight, a lit top
   edge and a soft green glow underneath */
.btn--primary,
.cta:not(.cta--alt, .cta--inline, .cta--share, .cta--ghost, .cta--x) {
  --_bg: var(--accent-hi);
  --_fg: var(--accent-ink);
  --_bd: color-mix(in srgb, var(--accent-lo) 70%, transparent);
  --_bd-top: color-mix(in srgb, var(--accent-bright) 90%, white);
  --_sheen:
    linear-gradient(180deg, rgb(255 255 255 / 0.22), transparent 55%),
    linear-gradient(180deg, var(--accent-bright), var(--accent-hi) 55%, var(--accent-lo));
  --_shadow: var(--inset-hi), var(--shadow-raised-sm), var(--glow-accent);
  font-weight: 700;
}

.btn--primary:is(:hover, :focus-visible),
.cta:not(.cta--alt, .cta--inline, .cta--share, .cta--ghost, .cta--x):is(:hover, :focus-visible) {
  --_bg: var(--accent-bright);
  filter: brightness(1.08) saturate(1.05);
}

/* ghost: glassy transparent fill with a hairline lit brighter along the top */
.btn--ghost,
.cta--alt,
.cta--inline,
.cta--ghost {
  --_bg: transparent;
  --_fg: var(--text-secondary);
  --_bd: var(--line-strong);
  --_sheen: linear-gradient(180deg, rgb(255 255 255 / 0.04), transparent 70%);
}

.btn--ghost:is(:hover, :focus-visible),
.cta--alt:is(:hover, :focus-visible),
.cta--ghost:is(:hover, :focus-visible) {
  --_fg: var(--text-primary);
}

/* on light, a transparent ghost barely registers against the page — give
   the secondary button a card fill, darker label and a soft lift, still
   clearly a step below the green primary */
:root[data-theme='light'] :is(.btn--ghost, .cta--alt) {
  --_bg: var(--bg-card);
  --_fg: var(--text-primary);
  --_bd: var(--line-strong);
  --_shadow: var(--shadow-raised-sm);
}

/* two buttons side by side in running content (Calculate + Reset, Yes/No,
   Copy link + Share) — flex/grid button rows space themselves with gap */
:is(.btn, .cta:not(.cta--x)) + :is(.btn, .cta:not(.cta--x)) {
  margin-inline-start: var(--space-sm);
}

.dialog-actions :is(.btn, .cta:not(.cta--x)) + :is(.btn, .cta:not(.cta--x)) {
  margin-inline-start: 0;
}

/* compact: main nav only (nav-public Sign in) — every other button is normal size */
.btn--sm,
.cta--small {
  padding: var(--pad-sm) var(--pad-xl);
  font-size: var(--fz-xs);
}

.btn--block,
.cta--block {
  display: flex;
  inline-size: 100%;
}

.btn--sticky,
.cta--sticky {
  position: sticky;
  inset-block-end: var(--space-md);
}

.cta--share {
  --_bg: transparent;
  --_fg: var(--accent-hi);
  --_bd: color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: var(--radius-pill);
}

:is(.btn, .cta):has(img) img,
:is(.btn, .cta) svg {
  inline-size: 1.15em;
  block-size: 1.15em;
  flex: none;
}

/* transient states set by window.runButton / flashButton */
.cta.done,
.cta.error,
.cta.running,
.btn.done,
.btn.error,
.btn.running {
  position: relative;
  color: transparent;
  pointer-events: none;
  cursor: default;
}

.cta.done::after,
.cta.error::after,
.cta.running::after,
.btn.done::after,
.btn.error::after,
.btn.running::after {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--_fg, var(--text-primary));
}

.cta.done::after,
.btn.done::after {
  content: '✔ Done';
}

.cta.error::after,
.btn.error::after {
  content: '✕ Error';
}

.cta.running::after,
.btn.running::after {
  content: '…';
}

/* small square icon button — banner dismiss, dialog close */
.icon-btn,
.cta--x,
.close-x {
  display: inline-grid;
  place-items: center;
  inline-size: 2.25rem;
  block-size: 2.25rem;
  flex: none;
  margin: 0;
  padding: 0;

  /* a small raised key (clickable = raised, tokens.css): domed fill, a
     bevelled border lit top-left, extruded shadow; presses in on :active */
  border: var(--border-hairline) solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--sheen-convex), var(--bg-elevated);
  box-shadow: var(--shadow-raised-sm);
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--fz-md);
  line-height: 1;
  cursor: pointer;
  transition:
    box-shadow var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

.icon-btn:is(:hover, :focus-visible),
.cta--x:is(:hover, :focus-visible),
.close-x:is(:hover, :focus-visible) {
  box-shadow: var(--shadow-raised);
  color: var(--text-primary);
}

.icon-btn:active,
.cta--x:active,
.close-x:active {
  box-shadow: var(--shadow-pressed);
}

.icon-btn svg,
.cta--x svg,
.close-x svg {
  inline-size: var(--icon-md);
  block-size: var(--icon-md);
}

/* --- 5. forms ---------------------------------------------------------- */
:is(input, select, textarea):not([type='checkbox'], [type='radio']) {
  inline-size: 100%;
  max-inline-size: 30rem;
  margin: 0;
  padding: var(--pad-md) var(--pad-lg);

  /* background-color, not the `background` shorthand: this selector's
     specificity (one attribute selector via :not()) beats the plain `select`
     rule below that paints the dropdown chevron via background-image — the
     shorthand would silently reset that sub-property back to none and the
     select would render with no chevron at all. */
  background-color: var(--bg-input);
  color: var(--text-primary);
  border: var(--border-hairline) solid var(--line-strong);
  border-radius: var(--radius-sm);

  /* sunken well: a shadow inside the top edge, a faint lit lip below */
  box-shadow: var(--shadow-well-input);
  font: inherit;
  font-family: var(--font-body);
  transition:
    border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}

textarea {
  max-inline-size: none;
  min-block-size: 6rem;
  resize: vertical;
}

:is(input, select, textarea):focus-visible {
  outline: 0;
  border-color: var(--accent-hi);
  box-shadow:
    var(--ring),
    0 0 20px -4px color-mix(in srgb, var(--accent-hi) 45%, transparent);
}

:is(input, select, textarea)[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

label {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fz-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-over);
  text-transform: uppercase;
  color: var(--text-secondary);
}

label + :is(input, select, textarea) {
  margin-block-start: var(--space-2xs);
}

select {
  appearance: none;
  background-image: var(
    --caret,
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239595a0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
  );
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 1.15rem;
  padding-inline-end: var(--space-2xl);
}

/* A dropdown is a control you press, so it's raised like every other
   clickable surface (outer neumorphism, tokens.css) rather than sunk into a
   well like a text input: domed fill under the caret, a bevelled border lit
   top-left, extruded shadow; hover lifts, open/active presses in.
   :not([multiple]) lifts specificity to (0,1,1) so this beats the shared
   input rule above; the :focus-visible rule is restated for the same reason. */
select:not([multiple]) {
  background-color: var(--bg-elevated);
  background-image:
    var(
      --caret,
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239595a0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
    ),
    var(--sheen-convex);
  background-repeat: no-repeat, no-repeat;
  background-position:
    right 0.7rem center,
    0 0;
  background-size:
    1.15rem,
    100% 100%;
  border-color: var(--line-strong);
  box-shadow: var(--shadow-raised-sm);
  cursor: pointer;
}

select:not([multiple]):hover:not([disabled]) {
  box-shadow: var(--shadow-raised);
}

select:not([multiple]):active:not([disabled]) {
  box-shadow: var(--shadow-pressed);
}

select:not([multiple]):focus-visible {
  border-color: var(--accent-hi);
  box-shadow: var(--ring), var(--shadow-raised-sm);
}

input[type*='datetime']::-webkit-calendar-picker-indicator {
  filter: invert(0.7);
  cursor: pointer;
}

input:is([type='checkbox'], [type='radio']) {
  accent-color: var(--accent-hi);
  inline-size: 1.15rem;
  block-size: 1.15rem;
  margin: 0;
  cursor: pointer;
}

/* Label wrapping its own checkbox — keeps box and text on one baseline. */
main:not(.app-main) .combobox__list {
  padding-block: var(--space-xs);
  padding-inline: var(--space-xs);
}

main:not(.app-main) .combobox__list li {
  margin: 0;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  cursor: pointer;
}

.checkbox-label:has(input:disabled) {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Not part of the surface system: the legend notch would sit over a
   continuous border-box gradient. Same lit-from-the-top look, done with a
   brighter top border colour and a sheen instead. */
fieldset {
  margin: 0 0 var(--space-lg);
  padding: var(--space-lg);
  border: var(--border-hairline) solid rgb(var(--rim-rgb) / 0.05);
  border-block-start-color: rgb(var(--rim-rgb) / 0.1);
  border-radius: var(--radius-card);
  background: var(--sheen), var(--bg-card);
  box-shadow: var(--shadow-card);
}

fieldset:has(.column) {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-md) var(--space-lg);
}

@media (max-width: 34rem) {
  fieldset:has(.column) {
    grid-template-columns: 1fr;
  }
}

legend {
  padding: 0;
  grid-column: 1 / -1;
  font-family: var(--font-body);
  font-size: var(--fz-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-over);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.column {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  min-inline-size: 0;
}

.column.separator {
  border-block-start: var(--border-hairline) solid var(--line);
  margin-block-start: var(--space-xs);
  padding-block-start: var(--space-lg);
}

.column small {
  color: var(--text-muted);
  font-size: var(--fz-xs);
}

form
  :is(input, select, textarea, .cta, .btn, button)
  + :is(input, select, textarea, .cta, .btn, button) {
  margin-block-start: var(--space-sm);
}

/* --- 6. tables ------------------------------------------------------ */
.twrap {
  inline-size: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-block: var(--space-lg);
  border-radius: var(--radius-card);
}

/* header row reads as a slightly raised band */
.twrap thead tr {
  background: linear-gradient(180deg, rgb(var(--rim-rgb) / 0.035), rgb(var(--rim-rgb) / 0.01));
}

/* a table hidden while its data loads (or because there's nothing to show)
   collapses its wrapper too, instead of leaving an empty styled box on screen */
.twrap:has(> table.hidden) {
  display: none;
}

.twrap table {
  inline-size: 100%;
  min-inline-size: 28rem;
  border-collapse: collapse;
  table-layout: auto;
  font-family: var(--font-body);
  font-size: var(--fz-sm);
}

.twrap :is(th, td) {
  padding: var(--pad-lg) var(--pad-xl);
  text-align: start;
  vertical-align: middle;
}

.twrap :is(th, td):first-child {
  white-space: nowrap;
}

.twrap th {
  color: var(--text-secondary);
  font-size: var(--fz-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-over);
  text-transform: uppercase;
  white-space: nowrap;
}

.twrap td {
  color: var(--text-body);
}

.twrap :is(thead, tbody) tr + tr :is(th, td),
.twrap tbody tr:first-child :is(th, td) {
  border-block-start: var(--border-hairline) solid var(--line);
}

.twrap tbody tr:hover {
  background: color-mix(in srgb, var(--bg-elevated) 60%, transparent);
}

.twrap .m,
.twrap td[colspan] {
  text-align: end;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.twrap .c {
  text-align: center;
}

.twrap :is(.current-user, tr.current-user) td {
  background: var(--accent-wash);
  color: var(--text-primary);
  font-weight: 700;
}

/* a glowing accent bar marks your own row */
.twrap :is(.current-user, tr.current-user) td:first-child {
  box-shadow: inset 3px 0 0 var(--accent-hi);
}

.twrap td img {
  display: inline-block;
  inline-size: 1.6rem;
  block-size: 1.6rem;
  vertical-align: middle;
}

.twrap .cta,
.twrap .btn {
  margin: 0;
}

/* empty table: show a resting message instead of a bare header */
.twrap table:not(:has(tbody tr)) thead {
  opacity: 0.5;
}

/* --- 7. announcement / install banner ----------------------------- */
.banner {
  border: 0;
  background: var(--accent-wash);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--fz-sm);
  text-align: center;
}

.banner--warning {
  background: var(--gold-wash);
}

.banner--error {
  background: color-mix(in srgb, var(--neg) 14%, transparent);
}

/* In-flow banner inside a form or section (the calculator's restore-draft
   prompt), in place of a floating toast. */
.banner--inline {
  border-radius: var(--radius-md);
  margin-block-end: var(--space-md);
}

/* Floating card, bottom-right, clear of the mobile tab bar. Used by the PWA
   install prompt (partials/install.liquid) and the onboarding walkthrough
   prompt (built in src/js/walkthrough.js). */
.banner--sticky {
  position: fixed;
  z-index: 45;
  inset-block-start: auto;
  inset-block-end: calc(var(--tabbar-h) + var(--space-md));
  inset-inline-start: auto;
  inset-inline-end: var(--space-md);
  inline-size: min(22rem, calc(100vw - 2 * var(--space-md)));
  --_fill: var(--bg-elevated);
  --_edge: var(--edge-hover);

  /* out-rank .banner's flat wash + border:0 */
  border: var(--border-hairline) solid transparent;
  background: var(--_surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  text-align: start;
}

@media (min-width: 64rem) {
  .banner--sticky {
    /* no tab bar on desktop */
    inset-block-end: var(--space-lg);
    inset-inline-end: var(--space-lg);
  }
}

.banner__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs) var(--space-sm);
  inline-size: min(var(--w-wide), 100%);
  margin-inline: auto;
  padding: 0.55rem var(--pad-inline);
}

.banner--sticky .banner__inner {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: var(--space-sm);
  inline-size: auto;
  margin: 0;
  padding: var(--space-md);

  /* keep the first line of text clear of the corner close button */
  padding-inline-end: calc(var(--space-md) + 1.5rem);
}

.banner--sticky .banner__message {
  color: var(--text-body);
  font-size: var(--fz-sm);
  line-height: var(--lh-ui);
}

.banner--sticky .banner__btn {
  flex: none;
}

.banner--sticky .banner__dismiss {
  position: absolute;
  inset-block-start: var(--space-2xs);
  inset-inline-end: var(--space-2xs);
  inline-size: 1.75rem;
  block-size: 1.75rem;
}

.banner--sticky .banner__dismiss svg {
  inline-size: var(--icon-sm);
  block-size: var(--icon-sm);
}

/* When the install prompt is already occupying the bottom-right slot, stack the
   walkthrough prompt above it. */
body:has(.banner--sticky#install-banner:not([style*='none'])) #walkthrough-banner {
  inset-block-end: calc(var(--tabbar-h) + var(--space-md) + 8.5rem);
}

@media (min-width: 64rem) {
  body:has(.banner--sticky#install-banner:not([style*='none'])) #walkthrough-banner {
    inset-block-end: calc(var(--space-lg) + 8.5rem);
  }
}

.banner__inner :is(p, a) {
  margin: 0;
  display: inline;
}

.banner__inner a {
  color: var(--accent-hi);
  text-decoration: underline;
}

/* --- 8. public header -------------------------------------------- */
.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 30;
  border: 0;
  background: color-mix(in srgb, var(--bg-page) 78%, transparent);
  backdrop-filter: blur(14px) saturate(1.3);
}

/* hairline under the bar that fades out at both ends, lit green mid-way */
.site-header::after {
  content: '';
  position: absolute;
  inset: auto 0 0;
  block-size: var(--border-hairline);
  background: linear-gradient(
    90deg,
    transparent,
    var(--line-strong) 20%,
    color-mix(in srgb, var(--accent-hi) 40%, transparent) 50%,
    var(--line-strong) 80%,
    transparent
  );
  pointer-events: none;
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--space-lg);
  inline-size: min(var(--w-wide), 100%);
  margin-inline: auto;
  padding: 0.8rem var(--pad-inline);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  text-decoration: none;
  color: var(--text-primary);
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
}

.brand :is(svg, img) {
  inline-size: 1.5rem;
  block-size: 1.5rem;
  border-radius: var(--radius-xs);
  color: var(--accent-hi);
  box-shadow:
    0 0 0 1px rgb(var(--rim-rgb) / 0.08),
    0 4px 14px -4px color-mix(in srgb, var(--accent-hi) 55%, transparent);
}

.brand__name {
  font-size: var(--fz-md);
}

/* "Ulti·Game·Mate" — highlight the middle so the wordplay reads */
.brand__accent {
  color: var(--accent-hi);
}

.site-header nav.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) clamp(0.75rem, 0.3rem + 1.6vw, 1.75rem);
  margin-inline-start: auto;
}

/* when the header wraps: brand ↔ Sign in on row 1, nav centred on its own row */
@media (max-width: 44rem) {
  .site-header__inner {
    row-gap: var(--space-xs);
    padding-block: var(--space-xs);
  }

  .site-header nav.site-nav {
    order: 1;
    flex-basis: 100%;
    margin-inline-start: 0;
    justify-content: center;
  }

  .site-header .btn {
    margin-inline-start: auto;
  }
}

.site-header .site-nav a {
  font-family: var(--font-body);
  font-size: var(--fz-sm);
  font-weight: 600;
}

/* current-page indicator */
.site-header .site-nav a[aria-current='page'] {
  color: var(--accent-hi);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
  text-decoration-color: currentColor;
}

.site-header .btn {
  flex: none;
}

/* Bottom rule under any non-site-header <header> — in practice just .page-head
   on app/admin screens now that the legacy admin header (nav-app.liquid) is
   gone. */
header:not(.site-header) {
  border-block-end: var(--border-hairline) solid var(--line);

  /* fades out towards the end instead of a hard full-width rule */
  border-image: linear-gradient(90deg, var(--line-strong), var(--line) 45%, transparent) 1;
}

/* --- 9. footers ------------------------------------------------ */
.site-footer {
  margin-block-start: var(--space-3xl);
  border: 0;
  border-block-start: var(--border-hairline) solid var(--line);
  border-image: linear-gradient(
      90deg,
      transparent,
      var(--line-strong) 30%,
      var(--line-strong) 70%,
      transparent
    )
    1;
  background: var(--bg-sunken);
}

.site-footer__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  inline-size: min(var(--w-wide), 100%);
  margin-inline: auto;
  padding: var(--space-2xl) var(--pad-inline);
}

.site-footer .brand__name {
  font-size: var(--fz-sm);
}

.site-footer__brand {
  margin-block-end: var(--flow-xs);
}

.site-footer__tag {
  margin: var(--flow-3xs) 0 var(--flow-2xs);
  color: var(--text-secondary);
  font-size: var(--fz-sm);
}

.site-footer__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-lg);
  margin-block: var(--gap-2xs) var(--flow-2xs);
}

.site-footer__nav a {
  font-family: var(--font-body);
  font-size: var(--fz-sm);
}

.site-footer__legal {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fz-xs);
}

.site-footer__legal a {
  color: var(--text-secondary);
}

/* shared footer markup (<footer> > <div> > logo + text columns), used by
   both footer-app.liquid and footer-public.liquid. */
footer:not(.site-footer) {
  border-block-start: var(--border-hairline) solid var(--line);
  border-image: linear-gradient(
      90deg,
      transparent,
      var(--line-strong) 30%,
      var(--line-strong) 70%,
      transparent
    )
    1;
  background: var(--bg-sunken);
}

footer:not(.site-footer) > div {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-md) var(--space-lg);
  inline-size: 100%;
  max-inline-size: var(--w-wide);
  margin-inline: auto;
  padding: var(--space-xl) var(--pad-inline);

  /* The mobile tab bar is position:fixed and floats over whatever's beneath
     it, including this footer once the page is scrolled all the way down —
     without this, its last row of links sits underneath the bar and can't
     be tapped. Reset below alongside the bar itself disappearing. */
  padding-block-end: calc(var(--tabbar-h) + var(--space-xl));
}

/* on desktop, signed in, the app footer runs the full width below the
   sidebar (sticky inside .app-shell, so it ends before the footer) and its
   content is anchored to the far left edge instead of centred. Public pages
   have no sidebar, so .app-footer scopes this to footer-app.liquid only —
   otherwise the public footer stopped being centred. `.app-shell ~` limits it
   further to pages that actually render the sidebar (the 404 page uses
   footer-app.liquid without one) and lifts specificity to (0,2,1) so it beats
   the base `footer:not(.site-footer) > div` (0,1,2) above. */
@media (min-width: 64rem) {
  .app-shell ~ .app-footer > div {
    max-inline-size: none;
    margin-inline: 0;
    padding-inline: var(--space-lg);
    padding-block-end: var(--space-xl);
  }
}

footer:not(.site-footer) img {
  inline-size: clamp(4rem, 3rem + 4vw, 5.5rem);
  block-size: auto;
  opacity: 0.9;
}

footer:not(.site-footer) div div {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

footer:not(.site-footer) p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fz-sm);
}

/* onboarding tour clip — framed like a card so it reads as a screen capture,
   not a stray image. Only ever inside the walkthrough dialog
   (src/_includes/partials/walkthrough-dialog.liquid); the dashboard and the two
   How-to-play pages open that dialog rather than embedding the clip inline. */
.tour-clip {
  overflow: hidden;
  max-inline-size: 40rem;
  border-radius: var(--radius-md);
  background: var(--bg-card);
}

.tour-clip :is(img, video) {
  display: block;
  inline-size: 100%;
  block-size: auto;
}

/* --- 10. results / calculator vocabulary (.picks/.pick/.game/...) --- */
.picks,
.cards {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-block: var(--space-md) 0;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--space-sm);
  align-items: start;
}

.pick,
.select {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-md);
  margin: 0;
  padding: var(--pad-card);
  border-radius: var(--radius-card);
}

.select {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.game,
.pick .game,
.select .game {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-sm);
  inline-size: auto;
  margin-inline: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--fz-sm);
  font-weight: 600;
  text-align: start;
}

/* inside a table, .game shrink-wraps to its own row's content width and is
   then centered within the cell — since content width varies row to row
   (team name length), each row's vs/score ends up centered on a different
   point instead of lining up down the column. Stretch it to the full cell
   width so the flexible name spans absorb that difference instead, keeping
   vs/score at one fixed horizontal position for every row. */
.twrap .game {
  inline-size: 100%;
  margin-inline: 0;
}

.game:has(span:nth-child(5)) {
  display: grid;
  grid-template-columns: 1fr auto auto auto 1fr;
  align-items: center;
}

.game.round {
  grid-column: 1 / -1;
  inline-size: 100%;
  min-block-size: 3.5rem;
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
}

.game:is(button) {
  cursor: pointer;
}

.game:is(button):is(:hover, :focus-visible) {
  color: var(--accent-hi);
}

.game span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* the two team names are the only elements guaranteed to always be present
   (crest icons are conditional on clubIcon() finding a match) — giving them
   equal flex so the vs/score group between them stays centered regardless
   of name length or whether a crest rendered on either side */
.game span:first-of-type,
.game span:last-of-type {
  flex: 1 1 0;
  min-inline-size: 0;
}

.game span:first-of-type {
  text-align: end;
}

.game span:last-of-type {
  text-align: start;
}

.game img {
  flex: none;
  inline-size: 1.4em;
  block-size: 1.4em;
}

.game small {
  color: var(--text-muted);
  font-family: var(--font-body);
  font-weight: 400;
}

.game :is(strong) {
  color: var(--text-primary);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.score {
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* --- result card (home "example scores", results page) -------------------- */
.result-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-block: var(--space-md) 0;
}

.result-card {
  display: grid;
  gap: var(--space-sm);
  inline-size: 100%;
  margin: 0;
  padding: var(--pad-card) var(--space-lg);
  border-radius: var(--radius-card);
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.result-card:is(:hover, :focus-visible) {
  --_fill: var(--bg-elevated);
  --_edge: var(--edge-clickable-hover);
}

.result-card__head {
  text-align: center;
}

.result-card__stage {
  font-family: var(--font-body);
  font-size: var(--fz-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-over);
  text-transform: uppercase;
  color: var(--text-secondary);
  text-align: center;
}

.result-card__date {
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text-muted);
}

.result-card__match {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-sm) var(--space-md);
}

.result-card__team {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-inline-size: 0;
  font-family: var(--font-body);
  font-size: var(--fz-md);
  font-weight: 600;
  color: var(--text-primary);
}

.result-card__team:first-child {
  flex-direction: row-reverse;
}

/* team crest — a soft light halo (not a solid disc) so a dark-on-transparent
   logo (e.g. Spurs' navy crest) still separates from the dark page, without
   painting a flat chip behind every icon. No size here on purpose:
   window.clubIcon() (base.liquid) stamps this class onto every crest it
   renders, across many contexts that each already size their own icons
   (.game img, .pick-option__team img, .twrap td img, etc.) via HTML
   width/height or their own CSS — this only adds the glow. */
.crest {
  flex: none;
  object-fit: contain;
  mix-blend-mode: exclusion;
  filter: brightness(1.5);
}

/* crest inside a .game row (match-detail dialog title) — beat the generic
   `.game img` size rule and give it a touch more presence */
.game .crest {
  inline-size: 1.75rem;
  block-size: 1.75rem;
}

.result-card__score {
  padding: var(--pad-3xs) var(--pad-md);
  border: var(--border-hairline) solid rgb(var(--rim-rgb) / 0.05);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  box-shadow: var(--shadow-well);
  font-family: var(--font-mono);
  font-size: var(--fz-lg);
  font-weight: 700;
  color: var(--text-heading);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.result-card:is(:hover, :focus-visible) .result-card__score {
  background: var(--bg-page);
}

/* points badge fills in solid + pops on hover (transform only — no reflow) */
.result-card:is(:hover, :focus-visible) .points {
  background: linear-gradient(135deg, var(--accent-bright), var(--pos));
  color: var(--ink-on-bright);
  transform: scale(1.08);
}

.result-card__note {
  margin: 0;
  font-size: var(--fz-sm);
  color: var(--text-secondary);
  line-height: var(--lh-ui);
  text-align: center;
}

.points {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-2xs);
  margin: 0;
  padding: var(--pad-2xs) var(--pad-md);
  border-radius: var(--radius-pill);
  background: var(--pos-wash);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pos) 24%, transparent);
  color: var(--pos);
  font-family: var(--font-mono);
  font-size: var(--fz-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transition:
    background var(--dur) var(--ease),
    color var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

.points::before {
  content: none;
}

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-block: 0 var(--space-md);
}

.pill,
.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-xs);
  margin: 0;
  padding: var(--pad-xs) var(--pad-lg);
  border: var(--border-hairline) solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--sheen), var(--bg-card);
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--fz-xs);
  font-weight: 600;
  cursor: pointer;
}

.pill:has(input:checked),
.tag.active {
  background: var(--sheen), var(--accent-wash);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  border-block-start-color: color-mix(in srgb, var(--accent-bright) 70%, transparent);
  color: var(--accent-hi);
  box-shadow: var(--glow-accent);
}

.pill input,
.select input[type='checkbox'],
.cards input[type='checkbox'] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

:is(.select, .pill):has(input[disabled]) {
  opacity: 0.55;
  filter: grayscale(0.5);
}

.card {
  border-radius: var(--radius-card);
  padding: var(--pad-card);
}

.card:has(input:checked) {
  --_tint: var(--accent-wash);
  --_edge: var(--edge-accent);
}

.card time {
  font-size: var(--fz-xs);
  color: var(--text-muted);
}

.boost {
  margin: 0;
  padding: var(--pad-xs) var(--pad-lg);
  border: var(--border-hairline) solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--accent-hi);
  font-family: var(--font-body);
  font-size: var(--fz-xs);
  font-weight: 600;
  cursor: pointer;
}

.boost:is(:hover, :focus-visible) {
  background: var(--accent-wash);
}

.boost.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

details {
  border-radius: var(--radius-card);
  padding: var(--pad-lg) var(--pad-xl);
  font-family: var(--font-body);
}

details[open] {
  padding-block-end: var(--flow-sm);
}

summary {
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--text-primary);
  cursor: pointer;
}

.twrap:has(.saving) {
  position: relative;
  opacity: 0.7;
  pointer-events: none;
}

.twrap:has(.saving)::after {
  content: 'Saving…';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-card) 88%, transparent);
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--fz-sm);
  animation: ugm-pulse 1.2s ease-in-out infinite;
}

@keyframes ugm-pulse {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.55;
  }
}

/* --- 12. form status ------------------------------------------- */

/* Inline feedback line (ui.js setStatus): sits under the form or button the
   user acted on and stays until their next attempt — no floating toasts. */
.form-status {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fz-sm);
}

.form-status[data-type='error'] {
  color: var(--neg);
}

.form-status[hidden] {
  display: none;
}

/* --- 13. generic dialogs (score-dialog lives in components.css) --- */

/* Pinned near the top rather than centred: a centred modal grows in both
   directions when an error line or extra fields appear, so its buttons jump. */
dialog:not(.score-dialog) {
  margin: min(10vh, 5rem) auto auto;
  border-radius: var(--radius-lg);
  --_edge: var(--edge-hover);
  color: var(--text-body);
  box-shadow: var(--shadow-lg);
  padding: var(--space-lg);
  inline-size: min(34rem, calc(100vw - 2 * var(--space-md)));
}

/* The match-stats edit dialog packs several fieldsets and six action buttons
   in — the generic 34rem width is cramped for it specifically. */
#edit-dialog {
  inline-size: min(46rem, calc(100vw - 2 * var(--space-md)));
}

/* The walkthrough clip is a portrait phone screen-capture, so size the dialog
   to the video — capped to the viewport — rather than forcing a wide box, and
   let it scroll if head + clip + foot still can't fit. Selector carries a type
   so it matches the specificity of `dialog:not(.score-dialog)` above and wins
   on source order. */
dialog.walkthrough-dialog {
  inline-size: fit-content;
  max-inline-size: calc(100vw - 2 * var(--space-md));
  max-block-size: calc(100dvh - 2 * var(--space-md));
  overflow: auto;
}

.walkthrough-dialog__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-block-end: var(--space-md);
  font-weight: 600;
}

/* `dialog form[method='dialog']` adds a top margin (for footer close-forms that
   sit below content) — cancel it here so the × lines up with the title. Selector
   out-specifies that rule (class + type + attr). */
.walkthrough-dialog__head form[method='dialog'] {
  margin-block-start: 0;
}

/* wrap the portrait video tightly (no card-coloured gutters) and centre it */
.walkthrough-dialog .tour-clip {
  inline-size: fit-content;
  max-inline-size: 100%;
  margin-inline: auto;
}

/* drive the size off height so the dialog never outgrows the viewport; width
   follows from the video's intrinsic aspect ratio (its width/height attrs) */
.walkthrough-dialog .tour-clip video {
  block-size: min(80dvh, 50rem);
  inline-size: auto;
  max-inline-size: 100%;
  margin-inline: auto;
}

.walkthrough-dialog__foot {
  margin-block-start: var(--space-md);
  margin-block-end: 0;
  font-size: var(--fz-sm);
  color: var(--text-muted);
}

dialog::backdrop {
  background: rgb(5 5 8 / 0.6);
  backdrop-filter: blur(4px);
}

main:not(.app-main) dialog h2 {
  font-size: var(--fz-lg);
  margin-block-start: var(--space-sm);
  margin-block-end: var(--space-sm);
}

dialog form[method='dialog'] {
  margin-block-start: var(--space-md);
}

/* button row in a dialog footer (a whole method='dialog' form for simple
   confirm dialogs, or a wrapper div for forms with fields above the buttons) */
dialog form[method='dialog']:not(:has(fieldset, label)),
dialog .dialog-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--gap-sm);
}

.dialog-actions
  :is(input, select, textarea, .cta, .btn, button)
  + :is(input, select, textarea, .cta, .btn, button) {
  margin-block-start: unset;
}

dialog .twrap tbody td:last-of-type {
  text-align: right;
}

/* 5-column match-detail row inside a dialog collapses on narrow screens */
@media (max-width: 30rem) {
  dialog .game:has(span:nth-child(5)) {
    grid-template-columns: 1fr auto 1fr;
  }

  dialog .game:has(span:nth-child(5)) span:is(:nth-child(1), :nth-child(5)) {
    display: none;
  }
}

/* --- 14. blog ------------------------------------------------- */
section.blog {
  padding-block-start: var(--space-xl);
}

section.blog img {
  margin-block: var(--space-lg);
  border-radius: var(--radius-md);
  border: var(--border-hairline) solid var(--line);
}

/* --- 15. page layout (non-app pages) ------------------------- */
main {
  flex: 1;
  display: flex;
  flex-direction: column;
}

main:not(.app-main) {
  inline-size: 100%;
  max-inline-size: var(--w-wide);
  margin-inline: auto;
  padding: clamp(1.75rem, 1rem + 3vw, 3.5rem) var(--pad-inline) var(--space-3xl);
}

/* sections fill the frame so their left edge lines up with the header, footer
   and each other; only the running-text measure (p / li) is held narrower */
main:not(.app-main) > section {
  inline-size: 100%;
}

main:not(.app-main) > section + section {
  margin-block-start: var(--gap-section);
}

/* --- 16. utilities ----------------------------------------- */
.hidden,
[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: calc(var(--border-hairline) * -1);
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.text-muted {
  color: var(--text-muted);
}

.text-center {
  text-align: center;
}
