/* ==========================================================================
   NIDDAK - design system
   Direction: "desert-noir geometric luxury" - night-indigo grounds, brass/
   gold ornament, four elemental rival hues (Ember / Tide / Gale / Stone).
   One typeface (Cairo) carries true EN/AR parity - no faux-Arabic Latin font.
   All spacing/position uses logical properties so [dir="rtl"] mirrors free.
   ========================================================================== */

/* ---- tokens ------------------------------------------------------------ */
:root{
  color-scheme: dark;

  /* grounds */
  --void:        #07080f;
  --bg-0:        #0b0d17;
  --bg-1:        #12162a;
  --bg-2:        #1a2038;
  --panel:       #1b2138cc;
  --panel-solid: #1b2138;
  --panel-hi:    #232b47;
  --hairline:    #ffffff14;
  --hairline-hi: #ffffff26;

  /* ink */
  --ink:       #f4efe6;
  --ink-dim:   #c7c2d6;
  --ink-faint: #8e93b0;
  --ink-mute:  #5a5f7a;

  /* brass / gold - premium, currency, Throne, rarity ceiling */
  --gold:        #d4a24e;
  --gold-bright: #f2c572;
  --gold-dim:    #8a6b34;
  --gold-ink:    #241a06;

  /* rival elements */
  --ember:       #e4572e;
  --ember-glow:  #ff8a5c;
  --ember-ink:   #2a0f08;
  --tide:        #2fb6a5;
  --tide-glow:   #63e6d4;
  --tide-ink:    #06201d;
  --gale:        #8fa6d6;
  --gale-glow:   #c1d1ff;
  --gale-ink:    #0d1730;
  --stone:       #93a066;
  --stone-glow:  #c3d597;
  --stone-ink:   #171b0c;

  /* rarity */
  --rarity-common:    #9aa0b4;
  --rarity-rare:      #4fb8e0;
  --rarity-epic:      #a876d6;
  --rarity-legendary: #f2c572;

  /* semantic */
  --success: var(--tide);
  --danger:  var(--ember);
  --info:    var(--gale);

  /* type */
  --font-ui: "Cairo", "Cairo Play", system-ui, sans-serif;
  --fs-2xs: 0.6875rem;
  --fs-xs:  0.75rem;
  --fs-sm:  0.8125rem;
  --fs-md:  0.9375rem;
  --fs-lg:  1.0625rem;
  --fs-xl:  1.25rem;
  --fs-2xl: 1.5625rem;
  --fs-3xl: 2rem;
  --fs-4xl: clamp(2.25rem, 5vw + 1rem, 3.4rem);
  --fs-hero: clamp(2.6rem, 9vw + 1rem, 5.6rem);
  --lh-tight: 1.08;
  --lh-snug:  1.28;
  --lh-normal: 1.55;

  /* space (4px base) */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.25rem;
  --sp-6: 1.5rem;
  --sp-8: 2rem;
  --sp-10: 2.5rem;
  --sp-12: 3rem;
  --sp-16: 4rem;
  --sp-20: 5rem;
  --sp-24: 6rem;

  /* shape */
  --radius-sm: 6px;
  --radius-md: 12px;
  --radius-lg: 18px;
  --radius-xl: 26px;
  --radius-pill: 999px;
  --cut: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  --cut-sm: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);

  /* elevation */
  --shadow-sm: 0 1px 2px #00000066;
  --shadow-md: 0 8px 24px -8px #000000aa, 0 2px 8px #00000066;
  --shadow-lg: 0 24px 60px -16px #000000cc, 0 4px 16px #00000088;
  --glow-gold: 0 0 0 1px #d4a24e55, 0 0 24px -4px #d4a24e99;

  /* motion */
  --ease-out: cubic-bezier(.16,.84,.44,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --dur-fast: 140ms;
  --dur-med: 320ms;
  --dur-slow: 640ms;

  /* structure */
  --shell-max: 1180px;
  --z-toast: 900;
  --z-modal: 800;
  --z-overlay: 700;
  --z-header: 600;

  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-i-s: env(safe-area-inset-left, 0px);
  --safe-i-e: env(safe-area-inset-right, 0px);
}

/* Durations alone are not enough. A staggered reveal holds an element
   invisible through its delay, so collapsing only the durations left a
   reduced-motion player watching the round report arrive over most of two
   seconds of nothing happening. */
@media (prefers-reduced-motion: reduce){
  :root{ --dur-fast: 1ms; --dur-med: 1ms; --dur-slow: 1ms; }
  *{ animation-delay: 0ms !important; }
}
.reduce-motion, .reduce-motion *{ animation-duration: 1ms !important; animation-delay: 0ms !important; transition-duration: 1ms !important; scroll-behavior: auto !important; }

/* ---- reset --------------------------------------------------------------*/
*, *::before, *::after{ box-sizing: border-box; }
html, body{ height: 100%; }
/* Installed to a home screen there is no address bar to rubber-band against,
   so the bounce just detaches the whole app from the top of the display and
   shows the page background behind it. Fine in a tab, wrong in an app. */
html{
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
  overscroll-behavior-y: none;
}
body{
  margin: 0;
  font-family: var(--font-ui);
  background: var(--bg-0);
  color: var(--ink);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
img, svg{ display: block; max-width: 100%; }
button, input, select, textarea{ font: inherit; color: inherit; }
button{ background: none; border: 0; cursor: pointer; }
/* Navigation in a game should not read as prose hyperlinks. The base rule
   set colour but left the browser's default underline, so `.brand` and
   `.account-btn` each had to opt out by hand and the nav tabs never did.
   Clearing it here fixes both bars at once; anything that genuinely wants to
   look like a link (`.link-btn`) still asks for the underline explicitly. */
a{ color: inherit; text-decoration: none; }
ul{ margin: 0; padding: 0; list-style: none; }
h1,h2,h3,h4,p{ margin: 0; }
:focus{ outline: none; }
:focus-visible{ outline: 2px solid var(--gold-bright); outline-offset: 3px; border-radius: 4px; }
::selection{ background: var(--gold); color: var(--gold-ink); }

.visually-hidden{
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* numerals stay tabular so costs/HP don't jitter, in either script */
.num{ font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* ---- backdrop atmosphere -------------------------------------------------*/
.app{
  position: relative;
  min-height: 100dvh;
  isolation: isolate;
}
.app::before{
  content: "";
  position: fixed; inset: 0; z-index: -2;
  background:
    radial-gradient(60vw 45vh at 18% -6%, #3a2c5a55, transparent 60%),
    radial-gradient(70vw 55vh at 108% 8%, #4a2a2255, transparent 60%),
    radial-gradient(90vw 70vh at 50% 118%, #16324a66, transparent 60%),
    linear-gradient(180deg, var(--void), var(--bg-0) 40%, var(--bg-1) 100%);
}
.app::after{
  content: "";
  position: fixed; inset: 0; z-index: -1; opacity: .5; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
}

/* subtle 8-point lattice used behind panels/hero */
.lattice{
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64' viewBox='0 0 64 64'%3E%3Cg fill='none' stroke='%23d4a24e' stroke-opacity='0.16' stroke-width='1'%3E%3Cpath d='M32 2 44 20 62 32 44 44 32 62 20 44 2 32 20 20 Z'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 64px 64px;
}

/* ==========================================================================
   layout shell
   ========================================================================== */
.screen{
  min-height: 100dvh;
  width: 100%;
  min-width: 0;
  overflow-x: clip;
  display: flex;
  flex-direction: column;
  /* No padding-top here any more. The header is sticky, and a sticky element
     pins to the top of the scrollport, not to the inside of its padded parent.
     In Safari the browser chrome hid that; installed to the home screen there
     is no chrome, so the header slid under the Dynamic Island the moment the
     page scrolled. The inset moved into the header itself, which is the only
     element that is ever up there. */
  padding-bottom: var(--safe-b);
}
.shell-header{
  position: sticky; top: 0; z-index: var(--z-header);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: calc(var(--sp-3) + var(--safe-t)) max(var(--sp-4), var(--safe-i-s)) var(--sp-3) max(var(--sp-4), var(--safe-i-e));
  padding-inline-start: max(var(--sp-4), var(--safe-i-s));
  padding-inline-end: max(var(--sp-4), var(--safe-i-e));
  background: linear-gradient(180deg, #0b0d17f0, #0b0d17c0 70%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hairline);
}
/* The wordmark is the way back to the main page, so it is a navigation control
   and not a logo that happens to be clickable. Its natural height is the 26px
   mark, which is a small thing to hit with a thumb; the flex centring keeps it
   looking identical while the target grows to something a hand can find. */
.shell-header .brand{
  display: flex; align-items: center; gap: var(--sp-2);
  min-height: 44px; padding-inline-end: var(--sp-1);
  font-weight: 900; letter-spacing: .06em; font-size: var(--fs-lg);
  color: var(--ink);
  text-decoration: none;
}
.shell-header .brand .mark{ width: 26px; height: 26px; flex: none; }
.shell-header nav{
  display: none;
  gap: var(--sp-1);
  margin-inline-start: var(--sp-4);
}
.shell-header .spacer{ flex: 1; }
.shell-header .util{ display: flex; align-items: center; gap: var(--sp-2); }

@media (min-width: 1024px){
  .shell-header nav{ display: flex; }
}

.nav-link{
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm); font-weight: 700; color: var(--ink-dim);
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
  white-space: nowrap;
}
.nav-link:hover{ color: var(--ink); background: var(--hairline); }
.nav-link.active{ color: var(--gold-bright); background: #d4a24e1a; }

.main{
  flex: 1;
  width: 100%;
  min-width: 0;
  max-width: var(--shell-max);
  margin-inline: auto;
  padding-inline: max(var(--sp-4), var(--safe-i-s));
}
.main.bleed{ max-width: none; padding-inline: 0; }

.bottom-tabbar{
  position: sticky; bottom: 0; z-index: var(--z-header);
  display: flex; justify-content: space-around;
  padding: var(--sp-2) max(var(--sp-2), var(--safe-i-s)) calc(var(--sp-2) + var(--safe-b));
  background: linear-gradient(0deg, #0b0d17f5, #0b0d17d0 80%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--hairline);
}
@media (min-width: 1024px){ .bottom-tabbar{ display: none; } }

.tab-link{
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: var(--sp-1) var(--sp-3);
  font-size: var(--fs-2xs); font-weight: 700; color: var(--ink-faint);
  min-width: 56px; min-height: 44px; justify-content: center;
  border-radius: var(--radius-md);
}
.tab-link svg{ width: 22px; height: 22px; }
.tab-link.active{ color: var(--gold-bright); }
.tab-link.active svg{ filter: drop-shadow(0 0 6px #d4a24e88); }

/* ---- language / util controls ------------------------------------------ */
.lang-toggle{
  display: flex; border: 1px solid var(--hairline-hi); border-radius: var(--radius-pill);
  overflow: hidden; font-weight: 800;
  /* Was --fs-2xs, which made EN/AR the smallest text on the screen. The target
     was already fixed to 44px, but the label inside it stayed 11px on the one
     control half this audience reaches for first. */
  font-size: var(--fs-xs);
}
.lang-toggle button{
  /* 32px failed the 44px touch minimum, on the one control an Arabic-first
     player reaches for first. */
  padding: var(--sp-1) var(--sp-3); color: var(--ink-faint);
  min-height: 44px; min-width: 44px;
  transition: color var(--dur-fast), background var(--dur-fast);
}
.lang-toggle button.active{ background: var(--gold); color: var(--gold-ink); }

.icon-btn{
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: var(--radius-pill);
  color: var(--ink-dim); border: 1px solid transparent;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.icon-btn:hover{ background: var(--hairline); color: var(--ink); }
.icon-btn svg{ width: 20px; height: 20px; }

/* ==========================================================================
   buttons
   ========================================================================== */
.btn{
  --btn-fg: var(--ink);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 48px; padding-inline: var(--sp-6);
  border-radius: var(--radius-pill);
  font-weight: 800; font-size: var(--fs-md); letter-spacing: .01em;
  color: var(--btn-fg);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast), filter var(--dur-fast), background var(--dur-fast);
  border: 1px solid transparent;
  white-space: nowrap;
}
.btn:active{ transform: scale(.97); }
/* A blanket opacity fade turned the gold primary into a muddy olive that
   read as broken rather than waiting, and dropped its near-black label
   (#241a06) far below readable contrast. Disabled now gets its own calm
   surface with legible text, so "not yet" looks deliberate. */
.btn:disabled{ cursor: not-allowed; }
.btn-primary:disabled{
  background: var(--panel-hi); color: var(--ink-faint);
  border: 1px solid var(--hairline-hi); box-shadow: none; filter: none;
}
.btn-ghost:disabled, .btn-outline:disabled{ opacity: .5; filter: none; }

.btn-primary{
  --btn-fg: var(--gold-ink);
  background: linear-gradient(180deg, var(--gold-bright), var(--gold));
  box-shadow: 0 10px 24px -10px #d4a24e77, inset 0 1px 0 #ffffff55;
}
.btn-primary:hover:not(:disabled){ filter: brightness(1.06); box-shadow: 0 14px 30px -10px #d4a24e99, inset 0 1px 0 #ffffff66; }

.btn-ghost{
  background: var(--panel);
  border-color: var(--hairline-hi);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.btn-ghost:hover:not(:disabled){ background: var(--panel-hi); border-color: var(--gold-dim); }

.btn-outline{
  background: transparent; border-color: var(--gold-dim); color: var(--gold-bright);
}
.btn-outline:hover:not(:disabled){ background: #d4a24e14; border-color: var(--gold); }

.btn-danger{ background: linear-gradient(180deg, var(--ember-glow), var(--ember)); color: #2a0f08; }

.btn-sm{ min-height: 38px; padding-inline: var(--sp-4); font-size: var(--fs-sm); }
.btn-lg{ min-height: 56px; padding-inline: var(--sp-8); font-size: var(--fs-lg); }
.btn-block{ width: 100%; }
.btn-icon-only{ width: 44px; height: 44px; padding: 0; border-radius: var(--radius-pill); }

/* ==========================================================================
   panels / cards (UI chrome, not game-cards)
   ========================================================================== */
.panel{
  background: var(--panel);
  border: 1px solid var(--hairline-hi);
  border-radius: var(--radius-lg);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.panel-solid{ background: var(--panel-solid); }
.panel-pad{ padding: var(--sp-5); }

.chip{
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill);
  font-size: var(--fs-2xs); font-weight: 800; letter-spacing: .03em;
  background: var(--hairline); color: var(--ink-dim); border: 1px solid var(--hairline-hi);
}
.chip-gold{ background: #d4a24e22; color: var(--gold-bright); border-color: #d4a24e55; }
.chip-ember{ background: #e4572e22; color: var(--ember-glow); border-color: #e4572e55; }
.chip-tide{ background: #2fb6a522; color: var(--tide-glow); border-color: #2fb6a555; }

/* section headings used across screens */
.eyebrow{
  font-size: var(--fs-2xs); font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--gold-bright); display: flex; align-items: center; gap: var(--sp-2);
}
.eyebrow::before{
  content: ""; width: 6px; height: 6px; flex: none;
  border: 1px solid var(--gold-dim); transform: rotate(45deg);
  background: color-mix(in srgb, var(--gold) 16%, transparent);
}
.section-title{ font-size: var(--fs-2xl); font-weight: 900; margin-top: var(--sp-2); line-height: var(--lh-tight); }

/* ==========================================================================
   toast
   ========================================================================== */
.toast-root{
  position: fixed; z-index: var(--z-toast);
  top: calc(var(--sp-4) + var(--safe-t));
  inset-inline: 0;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  pointer-events: none;
}
.toast{
  pointer-events: auto;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  background: var(--panel-solid); border: 1px solid var(--hairline-hi);
  border-radius: var(--radius-pill); box-shadow: var(--shadow-md);
  font-size: var(--fs-sm); font-weight: 700;
  animation: toast-in var(--dur-med) var(--ease-spring);
  max-width: calc(100vw - 2 * var(--sp-4));
}
.toast.leaving{ animation: toast-out var(--dur-med) var(--ease-out) forwards; }
@keyframes toast-in{ from{ opacity: 0; transform: translateY(-12px) scale(.95);} to{ opacity:1; transform:none; } }
@keyframes toast-out{ to{ opacity: 0; transform: translateY(-8px) scale(.96);} }

/* ==========================================================================
   generic helpers
   ========================================================================== */
.stack{ display: flex; flex-direction: column; }
.row{ display: flex; align-items: center; }
.gap-1{ gap: var(--sp-1); } .gap-2{ gap: var(--sp-2); } .gap-3{ gap: var(--sp-3); }
.gap-4{ gap: var(--sp-4); } .gap-6{ gap: var(--sp-6); }
.muted{ color: var(--ink-faint); }
.dim{ color: var(--ink-dim); }
.center{ display: flex; align-items: center; justify-content: center; }
.text-center{ text-align: center; }
.mt-2{ margin-top: var(--sp-2);} .mt-3{ margin-top: var(--sp-3);} .mt-4{ margin-top: var(--sp-4);}
.mt-6{ margin-top: var(--sp-6);} .mt-8{ margin-top: var(--sp-8);}

.divider{ height: 1px; background: var(--hairline); border: 0; }

.skeleton{
  background: linear-gradient(90deg, var(--panel-hi) 25%, #2a3358 37%, var(--panel-hi) 63%);
  background-size: 400% 100%; animation: shimmer 1.4s ease infinite;
  border-radius: var(--radius-md);
}
@keyframes shimmer{ 0%{ background-position: 100% 0; } 100%{ background-position: 0 0; } }

/* ==========================================================================
   landing
   ========================================================================== */
.landing{ display: flex; flex-direction: column; }

.landing-hero{
  position: relative;
  min-height: min(92vh, 920px);
  display: flex; align-items: flex-end;
  padding-inline: max(var(--sp-4), var(--safe-i-s));
  padding-block-end: var(--sp-12);
  overflow: clip;
}
.landing-hero-art{ position: absolute; inset: 0; z-index: -1; }
.landing-hero-art img{
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 28%;
  display: block;
}
.landing-hero-scrim{
  position: absolute; inset: 0;
  background:
    linear-gradient(0deg, var(--void) 14%, #07080fe6 44%, #07080fb3 62%, #07080f4d 82%, transparent 100%),
    linear-gradient(100deg, #07080fcc 0%, #07080f66 38%, transparent 62%);
}
.landing-hero-inner{ position: relative; max-width: 760px; display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-5); }
.landing-title{
  font-size: var(--fs-hero); font-weight: 900; line-height: var(--lh-tight); letter-spacing: -.01em;
  display: flex; flex-direction: column;
}
.landing-title .line{
  color: var(--ink);
  text-shadow: 0 2px 20px #000000cc, 0 1px 2px #000000;
  opacity: 0; transform: translateY(14px);
  animation: line-in var(--dur-slow) var(--ease-out) forwards;
}
.landing-title .line:last-child{ color: var(--gold-bright); }
.landing-title .line:nth-child(2){ animation-delay: 90ms; }
@keyframes line-in{ to{ opacity: 1; transform: none; } }

.landing-sub{ font-size: var(--fs-lg); color: var(--ink-dim); max-width: 56ch; line-height: var(--lh-normal); }
.landing-cta-row{ display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-2); }

.landing-proof{ display: flex; gap: var(--sp-8); margin-top: var(--sp-6); flex-wrap: wrap; }
.proof-item{ display: flex; flex-direction: column; gap: 2px; }
.proof-value{ font-size: var(--fs-3xl); font-weight: 900; color: var(--gold-bright); font-variant-numeric: tabular-nums; }
.proof-label{ font-size: var(--fs-xs); color: var(--ink-faint); text-transform: uppercase; letter-spacing: .06em; }

@keyframes emblem-spin{ to{ transform: rotate(360deg); } }

@media (min-width: 1024px){
  .landing-hero{ padding-block-end: var(--sp-16); }
}

.landing-how{ padding-block: var(--sp-16); padding-inline: max(var(--sp-4), var(--safe-i-s)); max-width: var(--shell-max); margin-inline: auto; width: 100%; }
.how-grid{ display: grid; gap: var(--sp-5); margin-top: var(--sp-8); grid-template-columns: 1fr; }
@media (min-width: 768px){ .how-grid{ grid-template-columns: repeat(3, 1fr); } }
.how-card{
  border-radius: var(--radius-lg); background: var(--panel);
  border: 1px solid var(--hairline-hi); position: relative; overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast);
}
.how-card:hover{ transform: translateY(-3px); border-color: var(--gold-dim); }
.how-art{ height: 170px; overflow: hidden; background: var(--bg-1); }
.how-art img{
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%;
  transition: transform var(--dur-slow) var(--ease-out);
}
.how-card:hover .how-art img{ transform: scale(1.05); }
.how-card-body{ padding: var(--sp-5) var(--sp-6) var(--sp-6); }
.how-card h3{ font-size: var(--fs-xl); font-weight: 800; }
.how-card p{ color: var(--ink-dim); margin-top: var(--sp-2); line-height: var(--lh-normal); font-size: var(--fs-sm); }

.landing-world{
  margin: var(--sp-8) max(var(--sp-4), var(--safe-i-s)) 0; padding: var(--sp-8);
  max-width: calc(var(--shell-max) - 2 * var(--sp-4)); margin-inline: auto; width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-8);
  flex-wrap: wrap;
}
.landing-world .section-title{ max-width: 32ch; }
.landing-world p{ max-width: 46ch; margin-top: var(--sp-2); }
.world-crests{ flex: none; display: flex; }
.world-crests img{
  width: 92px; height: 92px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--gold-dim); background: var(--bg-1);
  box-shadow: 0 8px 24px -8px #000000cc;
  transition: transform var(--dur-fast) var(--ease-out);
}
.world-crests img + img{ margin-inline-start: -18px; }
.world-crests img:hover{ transform: translateY(-6px); z-index: 1; position: relative; }

.landing-footer{ padding: var(--sp-10) var(--sp-4) var(--sp-16); text-align: center; }

/* ==========================================================================
   onboarding
   ========================================================================== */
.onboarding-step{
  max-width: 860px; margin-inline: auto; padding-block: var(--sp-10) var(--sp-16);
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.onboarding-body{ max-width: 52ch; margin-top: var(--sp-2); }
.pick-grid{ display: grid; gap: var(--sp-4); width: 100%; margin-top: var(--sp-8); }
.pick-grid-2{ grid-template-columns: 1fr; }
.pick-grid-3{ grid-template-columns: 1fr; }
.pick-grid-4{ grid-template-columns: repeat(2, 1fr); }
@media (min-width: 640px){
  .pick-grid-2{ grid-template-columns: repeat(2, 1fr); }
  .pick-grid-3{ grid-template-columns: repeat(3, 1fr); }
  .pick-grid-4{ grid-template-columns: repeat(4, 1fr); }
}
.pick-card-sm{ padding: var(--sp-4); }
.pick-card-sm h3{ font-size: var(--fs-md); }

.pick-card{
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--sp-2);
  padding: var(--sp-6) var(--sp-4); border-radius: var(--radius-lg);
  background: var(--panel); border: 1.5px solid var(--hairline-hi);
  transition: border-color var(--dur-fast), transform var(--dur-fast), background var(--dur-fast);
}
.pick-card:hover{ border-color: var(--gold-dim); transform: translateY(-2px); }
.pick-card.selected{ border-color: var(--gold); background: #d4a24e14; box-shadow: var(--glow-gold); }
.pick-card h3{ font-size: var(--fs-lg); font-weight: 800; margin-top: var(--sp-2); }
.pick-card p{ font-size: var(--fs-sm); }
.pick-emblem svg{ display: block; }

.onboarding-actions{ display: flex; gap: var(--sp-3); margin-top: var(--sp-10); }

.champion-pick-card{
  display: flex; flex-direction: column; text-align: start; overflow: hidden;
  border-radius: var(--radius-lg); background: var(--panel-solid); border: 1.5px solid var(--hairline-hi);
  transition: border-color var(--dur-fast), transform var(--dur-fast), box-shadow var(--dur-fast);
}
.champion-pick-card:hover{ border-color: var(--gold-dim); transform: translateY(-2px); }
.champion-pick-card.selected{ border-color: var(--gold); box-shadow: var(--glow-gold); }
.champion-pick-art{ position: relative; aspect-ratio: 1 / 1; overflow: hidden; background: var(--bg-1); }
.champion-pick-art img{
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%; display: block;
  transition: transform var(--dur-slow) var(--ease-out);
}
.champion-pick-card:hover .champion-pick-art img{ transform: scale(1.04); }
.champion-pick-overlay{
  position: absolute; inset-inline: 0; bottom: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2);
  padding: var(--sp-8) var(--sp-5) var(--sp-4);
  background: linear-gradient(0deg, #07080fe6 30%, #07080f80 65%, transparent 100%);
}
.champion-pick-overlay h3{ font-size: var(--fs-xl); font-weight: 900; text-shadow: 0 2px 10px #000000cc; }
.champion-pick-cta{
  display: flex; align-items: center; justify-content: center; min-height: 46px;
  margin: var(--sp-3); border-radius: var(--radius-pill);
  background: linear-gradient(180deg, var(--gold-bright), var(--gold)); color: var(--gold-ink);
  font-size: var(--fs-md); font-weight: 900; letter-spacing: .02em;
  box-shadow: 0 8px 20px -8px #d4a24e88, inset 0 1px 0 #ffffff55;
  transition: filter var(--dur-fast);
}
.champion-pick-card:hover .champion-pick-cta, .champion-pick-card:focus-visible .champion-pick-cta{ filter: brightness(1.07); }

.faction-pick-card{
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--sp-2);
  padding: var(--sp-4); border-radius: var(--radius-lg);
  background: var(--panel-solid); border: 1.5px solid var(--hairline-hi);
  transition: border-color var(--dur-fast), transform var(--dur-fast), box-shadow var(--dur-fast);
}
.faction-pick-card:hover{ border-color: var(--gold-dim); transform: translateY(-2px); }
.faction-pick-card.selected{ border-color: var(--gold); box-shadow: var(--glow-gold); }
.faction-pick-art{ width: 84px; height: 84px; border-radius: 50%; overflow: hidden; background: var(--bg-1); }
.faction-pick-art img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.faction-pick-card h3{ font-size: var(--fs-md); font-weight: 800; margin-top: var(--sp-1); }
.faction-pick-card p{ font-size: var(--fs-sm); }

/* ==========================================================================
   hand cards (shared: mulligan + planning)
   ========================================================================== */
.hand-rail{
  display: flex; gap: var(--sp-3); overflow-x: auto; padding-block: var(--sp-2);
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
}
.hand-rail::-webkit-scrollbar{ height: 6px; }
.hand-rail-static{ justify-content: center; flex-wrap: wrap; overflow: visible; }

.hand-card{
  flex: none; width: 132px; min-height: 196px; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-1);
  padding: var(--sp-3); border-radius: var(--radius-md);
  background: var(--panel-solid); border: 1.5px solid var(--hairline-hi);
  text-align: center; position: relative;
  transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast), box-shadow var(--dur-fast), opacity var(--dur-fast);
}
/* The frame colour is the card's rarity. Common had no rule at all, so it
   fell through to the default hairline and read as a card that had lost its
   border rather than a card that is common. Every tier now states itself. */
.hand-card.rarity-common{ border-color: var(--rarity-common); }
.hand-card.rarity-rare{ border-color: var(--rarity-rare); }
.hand-card.rarity-epic{ border-color: var(--rarity-epic); }
.hand-card.rarity-legendary{ border-color: var(--rarity-legendary); box-shadow: 0 0 0 1px #f2c57233; }
.hand-card:not(:disabled):hover{ transform: translateY(-4px); }
.hand-card.selected{ border-color: var(--gold); box-shadow: var(--glow-gold); transform: translateY(-6px); }
/* opacity for unplayable cards lives with the blocked-reason rules below */
.hand-card:disabled{ cursor: not-allowed; }

.hand-card-art{
  width: 100%; height: 104px; overflow: hidden; border-radius: calc(var(--radius-md) - 4px);
  background: radial-gradient(circle at 50% 20%, #ffffff15, transparent 55%), var(--bg-1);
  border: 1px solid var(--hairline);
}
.hand-card-art img, .hand-card-art svg{ width: 100%; height: 100%; display: block; }
/* The cost badge carries a small Energy pip, the same shape the ENERGY meter
   uses. A bare gold number said nothing about what it counted; matching the
   meter's glyph ties "2" on the card to "1/1" above it without adding a word
   to a card that has no room for one. */
.hand-card-cost{
  position: absolute; top: 6px; inset-inline-start: 6px;
  min-width: 24px; height: 24px; padding-inline: 5px; border-radius: var(--radius-pill);
  background: linear-gradient(180deg, var(--gold-bright), var(--gold)); color: var(--gold-ink);
  display: flex; align-items: center; justify-content: center; gap: 3px;
  font-weight: 900; font-size: var(--fs-xs);
}
.cost-pip{
  inline-size: 5px; block-size: 11px; border-radius: 2px;
  background: var(--gold-ink); opacity: .55;
}
/* Two lines are always reserved for the name, whether or not it needs two.
   A one-line name used to pull its stat row up, so the numbers across a hand
   sat at three different heights and could not be compared at a glance, which
   is the one thing that row exists for. 2lh is exactly two lines of whatever
   this element's own line-height resolves to, so the mulligan's larger name
   type reserves its own two lines without a second number to maintain. */
.hand-card-name{
  font-size: var(--fs-xs); font-weight: 800; line-height: var(--lh-snug);
  min-height: calc(2em * var(--lh-snug));
  min-height: 2lh;
  display: flex; align-items: center; justify-content: center;
}
.hand-card-stats{ display: flex; gap: var(--sp-2); font-size: var(--fs-xs); font-weight: 900; color: var(--gold-bright); }
.hand-stat{ display: inline-flex; align-items: center; gap: 3px; }
.hand-stat svg{ width: 13px; height: 13px; }
.hand-stat-power{ color: var(--gold-bright); }
.hand-stat-guard{ color: var(--tide-glow); }
.hand-card-type{ margin-top: auto; font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-faint); }
.hand-card.tutorial-target{ border-color: var(--gold-bright); box-shadow: var(--glow-gold); animation: guided-card 1.4s var(--ease-in-out) infinite; }
.hand-card-tap-label, .territory-tap-label{
  position: absolute; z-index: 1; display: inline-flex; align-items: center; justify-content: center; min-height: 22px;
  padding-inline: 7px; border-radius: var(--radius-pill); background: var(--gold-bright); color: var(--gold-ink);
  font-size: 9px; font-weight: 900; letter-spacing: .08em; text-transform: uppercase; box-shadow: 0 2px 12px #00000055;
}
.hand-card-tap-label{ inset-block-start: 92px; inset-inline-end: 8px; }
@keyframes guided-card{ 50%{ transform: translateY(-7px); box-shadow: 0 0 28px -5px var(--gold-bright); } }

/* ==========================================================================
   mulligan
   ========================================================================== */
.mulligan-screen{
  position: relative; isolation: isolate; width: 100%; max-width: 1120px;
  min-height: calc(100svh - 82px); margin-inline: auto;
  padding-block: clamp(28px, 5vh, 64px);
  display: grid; grid-template-rows: auto auto auto; align-content: center;
  gap: clamp(20px, 4vh, 44px); text-align: center;
}
.mulligan-screen::before{
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: 8% 5% 14%;
  background:
    radial-gradient(ellipse at 50% 40%, #d4a24e13, transparent 46%),
    radial-gradient(ellipse at 50% 65%, #2fb6a510, transparent 54%);
}
.mulligan-head{ display: flex; flex-direction: column; align-items: center; }
.mulligan-head .eyebrow{ justify-content: center; }
.mulligan-head .section-title{
  margin-top: var(--sp-2); font-size: clamp(34px, 4.2vw, 52px);
  line-height: .98; text-wrap: balance;
}
.mulligan-hand-stage{ position: relative; min-width: 0; }
.mulligan-hand-stage::after{
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset-inline: 10%; bottom: -14px; height: 44px;
  background: radial-gradient(ellipse, #00000080, transparent 68%);
  filter: blur(8px);
}
.mulligan-screen .hand-rail-static{
  justify-content: center; flex-wrap: wrap; gap: clamp(10px, 1.5vw, 18px);
  overflow: visible; padding: var(--sp-3);
}
.mulligan-screen .hand-card{
  --card-accent: var(--rarity-common);
  width: clamp(154px, 16vw, 190px); min-height: clamp(238px, 24vw, 292px);
  gap: 6px; padding: 10px; overflow: hidden; isolation: isolate;
  border-width: 2px; border-radius: 15px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--card-accent) 9%, transparent), transparent 34%),
    linear-gradient(155deg, #20263d, #121624 72%);
  box-shadow: 0 18px 36px -24px #000, inset 0 1px 0 #ffffff10;
  animation: mulligan-deal 420ms var(--ease-out) backwards;
}
.mulligan-screen .hand-card.elem-ember{ --card-accent: var(--ember-glow); }
.mulligan-screen .hand-card.elem-tide{ --card-accent: var(--tide-glow); }
.mulligan-screen .hand-card.elem-gale{ --card-accent: var(--gale-glow); }
.mulligan-screen .hand-card.elem-stone{ --card-accent: var(--stone-glow); }
.mulligan-screen .hand-card.elem-neutral{ --card-accent: #d8d4c8; }
.mulligan-screen .hand-card::before{
  content: ""; position: absolute; inset: 4px; z-index: 2; pointer-events: none;
  border: 1px solid var(--card-accent); border-radius: 11px; opacity: .28;
}
.mulligan-screen .hand-card::after{
  content: ""; position: absolute; top: 0; inset-inline: 18%; z-index: 3;
  height: 3px; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--card-accent), transparent);
}
.mulligan-screen .hand-card:nth-child(2){ animation-delay: 55ms; }
.mulligan-screen .hand-card:nth-child(3){ animation-delay: 110ms; }
.mulligan-screen .hand-card:nth-child(4){ animation-delay: 165ms; }
@keyframes mulligan-deal{
  from{ opacity: 0; transform: translateY(18px) scale(.96); }
}
.mulligan-screen .hand-card:hover{ transform: none; }
.mulligan-screen .hand-card-art{
  height: auto; aspect-ratio: 1 / 1; border-radius: 9px;
  border-color: color-mix(in srgb, var(--card-accent) 28%, var(--hairline));
}
.mulligan-screen .hand-card-name{ font-size: var(--fs-sm); line-height: 1.15; }
.mulligan-screen .hand-card-type{ font-size: 10px; }
.mulligan-screen .hand-card-cost{ top: 8px; inset-inline-start: 8px; min-width: 32px; height: 32px; font-size: var(--fs-sm); }
/* What the opening hand can play on the first round, under the cards. */
.mulligan-note{
  margin: var(--sp-3) auto 0; max-width: 52ch; text-align: center; text-wrap: balance;
}
.mulligan-actions{
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
}
.mulligan-head .mulligan-exit-actions{ margin-top: var(--sp-3); }
.mulligan-primary-actions{
  display: grid; grid-template-columns: minmax(210px, 260px) minmax(250px, 330px);
  justify-content: center; gap: var(--sp-3);
}
.mulligan-primary-actions .btn{ min-height: 62px; }
.mulligan-actions .btn svg{ width: 18px; height: 18px; }
.mulligan-primary-actions .btn svg{ width: 20px; height: 20px; }
.mulligan-primary-actions .btn-primary{ box-shadow: 0 14px 34px -13px #d4a24e99, inset 0 1px 0 #ffffff66; }
.mulligan-exit-actions{
  display: flex; justify-content: center; gap: var(--sp-2); flex-wrap: wrap;
}
.mulligan-exit-actions .btn{
  min-height: 44px; padding-inline: var(--sp-5); font-size: var(--fs-sm);
}
.mulligan-exit-actions .btn svg{ width: 18px; height: 18px; }
.mulligan-quit-btn{
  color: var(--ember);
  border-color: color-mix(in srgb, var(--ember) 42%, var(--hairline-hi));
}
.mulligan-quit-btn:hover:not(:disabled){
  background: color-mix(in srgb, var(--ember) 12%, var(--panel-hi));
  border-color: var(--ember);
}
.tutorial-banner{ max-width: 52ch; margin-inline: auto; margin-top: var(--sp-2); }

@media (max-width: 767px){
  .mulligan-screen{
    min-height: calc(100svh - 120px); padding-block: var(--sp-4) 104px;
    align-content: start; gap: var(--sp-4);
  }
  .mulligan-screen::before{ inset: 0 -20% 18%; }
  .mulligan-head .section-title{ font-size: clamp(30px, 10vw, 40px); }
  /* Two rows of two, not a sideways scroller.
     The scroller never read as one. The fourth card sat half past the right
     edge, which looks clipped rather than swipeable, and a third of the
     screen directly below it was empty. The hand is exactly four cards and
     it is the only thing the screen is asking about, so all four are visible
     at once and the space below them is what they sit in. */
  .mulligan-screen .hand-rail-static{
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    justify-items: center; gap: 8px 10px;
    overflow: visible; padding: 0 var(--sp-3) var(--sp-2);
  }
  .mulligan-screen .hand-card{
    width: 100%; max-width: 150px; min-height: 0; padding: 7px; gap: 4px;
    border-width: 1.5px; border-radius: 12px;
  }
  .mulligan-screen .hand-card::before{ inset: 3px; border-radius: 9px; }
  .mulligan-screen .hand-card-art{ border-radius: 7px; }
  .mulligan-screen .hand-card-cost{ top: 6px; inset-inline-start: 6px; min-width: 28px; height: 28px; }
  .mulligan-screen .hand-card-name{ font-size: 11px; }
  .mulligan-screen .hand-card-readout{ gap: 2px; min-height: 34px; }
  /* Three lines, not two. At two, Sacrificial Brand lost the end of its only
     sentence in both languages, and in Arabic the clamped last line ran 3px
     past the card. Every card's effect text was measured here at 360 and
     390px in English and Arabic: three lines fits all of them uncut. */
  .mulligan-screen .hand-card-effect{
    min-height: 22px; font-size: 9px; line-height: 1.2;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .mulligan-actions{
    position: fixed; z-index: calc(var(--z-header) - 1);
    inset-inline: max(var(--sp-3), var(--safe-i-s));
    bottom: calc(70px + var(--safe-b));
    align-items: stretch; gap: 8px;
    padding: 7px; border: 1px solid var(--hairline-hi); border-radius: var(--radius-lg);
    background: #0b0d17f2; box-shadow: var(--shadow-lg);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  }
  .mulligan-primary-actions{
    grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: 8px;
  }
  .mulligan-primary-actions .btn{ min-width: 0; min-height: 50px; padding-inline: 10px; font-size: var(--fs-sm); }
  .mulligan-head .mulligan-exit-actions{ width: min(100%, 356px); margin-top: var(--sp-2); }
  .mulligan-exit-actions{
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  }
  .mulligan-exit-actions.single{ grid-template-columns: minmax(0, 1fr); }
  .mulligan-exit-actions .btn{
    min-width: 0; min-height: 42px; padding-inline: 8px;
    font-size: var(--fs-xs); white-space: normal; line-height: var(--lh-snug);
  }
  .mulligan-actions .btn svg{ width: 18px; height: 18px; }
}

/* ==========================================================================
   match screen
   ========================================================================== */
.match-screen{ display: flex; flex-direction: column; gap: var(--sp-3); padding-block: var(--sp-3) var(--sp-4); }

.match-topbar{ display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--sp-2); }
.champion-badge{ display: flex; align-items: center; gap: var(--sp-2); }
.champion-badge.side-player{ flex-direction: row-reverse; text-align: end; }
.champion-sigil{ flex: none; width: 40px; height: 40px; border-radius: 50%; overflow: hidden; background: var(--panel-solid); border: 1px solid var(--hairline-hi); }
.champion-sigil img{ width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; display: block; }
.champion-meta{ min-width: 0; flex: 1; }
.champion-name{ font-size: var(--fs-xs); font-weight: 800; color: var(--ink-dim); text-transform: uppercase; letter-spacing: .04em; }
.hp-bar{ width: 100%; max-width: 110px; height: 6px; border-radius: var(--radius-pill); background: var(--panel-hi); overflow: hidden; margin-top: 3px; }
.hp-fill{ height: 100%; background: linear-gradient(90deg, var(--ember), var(--ember-glow)); transition: width var(--dur-med) var(--ease-out); }
.side-bot .hp-fill{ background: linear-gradient(90deg, var(--tide), var(--tide-glow)); }
/* The bar is a block with a capped width, so text-align cannot move it. On the
   player side the name and the value are pushed to the end of a column that
   stretches across a whole grid track, and the bar stayed behind at the start
   of it: adrift in open space beside the Marks, reading as a stray meter that
   belonged to the round rather than as that player's health. An auto margin
   moves the box itself, and it is logical, so Arabic mirrors with it. */
.side-player .hp-bar{ margin-inline-start: auto; }
.hp-value{ display: flex; align-items: center; gap: 5px; font-size: 10.5px; color: var(--ink-faint); margin-top: 2px; }
.side-player .hp-value{ justify-content: flex-end; }
.hp-label{ display: inline-flex; align-items: center; gap: 3px; color: var(--ink-dim); }
.hp-label svg{ width: 10px; height: 10px; color: var(--ember-glow); fill: #ef765633; }
.side-bot .hp-label svg{ color: var(--tide-glow); fill: #64e3d333; }

.round-badge{ display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); }
.round-num{ font-size: var(--fs-xs); font-weight: 800; color: var(--ink-faint); white-space: nowrap; }
.marks-row{ display: flex; align-items: center; gap: var(--sp-2); }
.marks-side{ display: flex; gap: 4px; }
.mark-pip{ width: 10px; height: 10px; border-radius: 2px; background: var(--panel-hi); border: 1px solid var(--hairline-hi); transform: rotate(45deg); }
.mark-pip.filled{ background: var(--gold); border-color: var(--gold-bright); box-shadow: 0 0 8px -1px var(--gold); }
.marks-label{ font-size: 9px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-faint); }

.trials-block{ display: flex; flex-direction: column; gap: var(--sp-2); }
/* Quiet, because it is a standing rule and not an alert, but always present. A
   player who has to remember the win condition from the tutorial does not. */
.duel-goal{
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .04em;
  color: var(--ink-faint); text-transform: uppercase;
}
.duel-goal .goal-mark{ color: var(--gold); font-size: 11px; }
.trials-rail{ display: flex; gap: var(--sp-2); overflow-x: auto; }
.first-duel-goal{
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: 42px;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-md); background: #d4a24e12;
  border: 1px solid #d4a24e55; color: var(--gold-bright); font-size: var(--fs-sm); font-weight: 800;
}
.goal-mark{ font-size: var(--fs-md); }
.tutorial-guidance{
  display: flex; align-items: center; gap: var(--sp-2); min-height: 44px; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md); background: var(--panel-solid); border: 1px solid var(--hairline-hi); color: var(--ink);
}
.tutorial-step{ display: inline-flex; align-items: center; justify-content: center; min-width: 32px; height: 24px; border-radius: var(--radius-pill); background: var(--gold); color: var(--gold-ink); font-size: var(--fs-xs); font-weight: 900; }
.trial-chip{
  flex: 1 1 0; min-width: 148px; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  background: var(--panel); border: 1px solid var(--hairline-hi);
}
.trial-chip.claimed-player{ border-color: var(--tide); background: #2fb6a51a; }
.trial-chip.claimed-bot{ border-color: var(--ember); background: #e4572e1a; opacity: .75; }
.trial-name{ font-size: var(--fs-xs); font-weight: 800; }
.trial-desc{ font-size: 10.5px; color: var(--ink-faint); margin-top: 2px; line-height: var(--lh-snug); }
.trial-claimed{ font-size: 10px; font-weight: 800; color: var(--gold-bright); margin-top: 4px; text-transform: uppercase; letter-spacing: .05em; }

/* Board stays spatially LTR (Left Flank always physically left) even in an
   RTL page - §23.1: "coordinates mirror only if it doesn't break the spatial
   model", and a duel's Left/Throne/Right map is exactly that model. Only
   this grid's item order is pinned; text inside still reads naturally. */
.board{ display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); direction: ltr; }
.territory-col{
  display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2); position: relative;
  border-radius: var(--radius-md); background: var(--panel); border: 1.5px dashed transparent;
  min-height: 148px; overflow: hidden;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
[dir="rtl"] .territory-col{ direction: rtl; }
/* Each territory is a place you are fighting over, not a box the tokens sit
   in. The watermark that used to carry that idea was drawn at nine percent
   opacity, so what reached the screen was an empty panel with a smudge in it.

   The scene is five layers, furthest first: edges that fall away, a sky, a
   pool of ground light, a hairline horizon for the tokens to stand on, and
   the structure itself in the middle distance. Every layer carries its own
   alpha, so the stack sits at full opacity and no single number can flatten
   all of it at once again.

   The flanks are open ground under a star-lattice. The lattice is the brand's
   EIGHT-point star; it used to be a four-point one, which made it the only
   place on the board drawing a different star from the mark, the texture and
   the card borders.
    The Throne is lit, warm
   and architectural, because it is the thing worth taking. */
.territory-col::before{
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cg fill='none' stroke='%238fa6d6' stroke-opacity='.17' stroke-width='1.5'%3E%3Cpath d='M 50 6 L 62.9 18.9 L 81.1 18.9 L 81.1 37.1 L 94 50 L 81.1 62.9 L 81.1 81.1 L 62.9 81.1 L 50 94 L 37.1 81.1 L 18.9 81.1 L 18.9 62.9 L 6 50 L 18.9 37.1 L 18.9 18.9 L 37.1 18.9 Z'/%3E%3Cpath d='M 50 22.7 L 58 30.7 L 69.3 30.7 L 69.3 42 L 77.3 50 L 69.3 58 L 69.3 69.3 L 58 69.3 L 50 77.3 L 42 69.3 L 30.7 69.3 L 30.7 58 L 22.7 50 L 30.7 42 L 30.7 30.7 L 42 30.7 Z'/%3E%3C/g%3E%3C/svg%3E") center 52% / 152px auto no-repeat,
    linear-gradient(180deg, transparent 61%, #9fb6e614 61.4%, transparent 63%),
    radial-gradient(124% 42% at 50% 106%, #242c47, transparent 72%),
    radial-gradient(86% 60% at 50% 30%, #1b2239, transparent 78%),
    radial-gradient(108% 84% at 50% 48%, transparent 40%, #05070ee0 100%);
}
/* The scenery is positioned, so without a stacking order it paints over the
   numbers. z-index alone is enough here and `position: relative` would be
   actively wrong: the territory is a flex container, flex items honour z-index
   while static, and the tutorial's tap label is an absolutely positioned child
   that this selector would otherwise pull back into the flow. */
.territory-col > *{ z-index: 1; }

.territory-col:nth-child(2)::before{
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 120'%3E%3Cpath d='M14 118 V56 C14 28 32 14 50 6 C68 14 86 28 86 56 V118' fill='none' stroke='%23d4a24e' stroke-opacity='.42' stroke-width='2'/%3E%3Cpath d='M24 118 V58 C24 34 38 22 50 16 C62 22 76 34 76 58 V118' fill='none' stroke='%23d4a24e' stroke-opacity='.34' stroke-width='1'/%3E%3Ccircle cx='50' cy='52' r='5' fill='none' stroke='%23d4a24e' stroke-opacity='.5' stroke-width='1.5'/%3E%3C/svg%3E") center bottom -2px / auto 116px no-repeat,
    linear-gradient(180deg, transparent 61%, #f2c57218 61.4%, transparent 63%),
    radial-gradient(48% 40% at 50% 84%, #d4a24e3d, transparent 72%),
    radial-gradient(124% 42% at 50% 106%, #33283f, transparent 72%),
    radial-gradient(86% 60% at 50% 28%, #241f36, transparent 78%),
    radial-gradient(108% 84% at 50% 48%, transparent 40%, #06060fe0 100%);
}
.territory-col:nth-child(2) .territory-header{ color: var(--gold-bright); }
.territory-col:nth-child(2)::after{
  content: ""; position: absolute; top: 0; inset-inline: 18%; height: 2px; z-index: 2; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}

/* Who is holding this ground, said in colour and in position instead of by
   comparing two digits in a pill. The wash rises from the holder's own side of
   the board, so the side reads without depending on hue alone, and it is
   derived from the two numbers already on screen: nothing new is claimed. */
.territory-hold{
  position: absolute; inset: 0; pointer-events: none;
  opacity: 0; transition: opacity var(--dur-med) var(--ease-out);
}
.territory-col > .territory-hold{ z-index: 0; }
.territory-col.held-player .territory-hold,
.territory-col.held-bot .territory-hold{ opacity: 1; }
.territory-col.held-player .territory-hold{
  color: var(--ember-glow);
  background: linear-gradient(0deg, color-mix(in srgb, var(--ember) 30%, transparent), transparent 58%);
}
.territory-col.held-bot .territory-hold{
  color: var(--tide-glow);
  background: linear-gradient(180deg, color-mix(in srgb, var(--tide) 30%, transparent), transparent 58%);
}
.territory-hold::after{
  content: ""; position: absolute; inset-inline: 12%; height: 3px;
  background: linear-gradient(90deg, transparent, currentColor, transparent);
}
.territory-col.held-player .territory-hold::after{ bottom: 0; }
.territory-col.held-bot .territory-hold::after{ top: 0; }

.territory-col.drop-target{ border-color: var(--gold); cursor: pointer; }
.territory-col.drop-target:hover{ background: #d4a24e22; }
.territory-col.has-staged{
  border-color: var(--gold-dim); background: linear-gradient(180deg, #d4a24e16, var(--panel));
  box-shadow: inset 0 0 22px #d4a24e0c;
}
.territory-tap-label{ inset-block-start: 28px; inset-inline-start: 50%; transform: translateX(-50%); }
.first-duel .territory-col.tutorial-lane{ box-shadow: inset 0 0 0 1px #d4a24e33; }
.territory-header{ font-size: 10.5px; font-weight: 800; text-align: center; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .04em; }
.unit-row{ display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; min-height: 26px; }
.unit-token{
  min-width: 30px; height: 26px; padding-inline: 4px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 800;
  color: var(--void); background: var(--rarity-common);
}
.unit-token.elem-ember{ background: linear-gradient(180deg, var(--ember-glow), var(--ember)); }
.unit-token.elem-tide{ background: linear-gradient(180deg, var(--tide-glow), var(--tide)); }
.unit-token.elem-gale{ background: linear-gradient(180deg, var(--gale-glow), var(--gale)); }
.unit-token.elem-stone{ background: linear-gradient(180deg, var(--stone-glow), var(--stone)); }
.unit-token.elem-neutral{ background: linear-gradient(180deg, #e8e4d8, var(--rarity-common)); }
.unit-token.legal-target{ outline: 2px solid var(--gold-bright); outline-offset: 2px; cursor: pointer; animation: pulse-target 1.1s ease-in-out infinite; }
@keyframes pulse-target{ 50%{ outline-color: transparent; } }
.staged-unit-preview{
  position: relative; display: grid; grid-template-columns: 28px 1fr; grid-template-rows: 1fr auto;
  width: min(100%, 84px); min-height: 48px; overflow: hidden; border-radius: var(--radius-sm);
  border: 1px dashed var(--gold-bright); background: #0b0d17eb; color: var(--ink);
  box-shadow: 0 0 14px -6px var(--gold); animation: staged-in var(--dur-med) var(--ease-out);
}
@keyframes staged-in{ from{ opacity: 0; transform: translateY(5px) scale(.96); } }
.staged-unit-art{ grid-row: 1 / 3; width: 28px; height: 100%; overflow: hidden; opacity: .78; }
/* The child is an <img> for an illustrated card and an <svg> sigil for one
   without, and either may sit inside a .card-visual-frame span. Size the
   wrapper and let whatever lands inside it fill. */
.staged-unit-art > *{ display: block; width: 100%; height: 100%; object-fit: cover; }
.staged-unit-art svg{ display: block; width: 100%; height: 100%; }
.staged-unit-copy{ display: flex; align-items: center; justify-content: space-between; gap: 3px; min-width: 0; padding: 3px 4px 0; }
.staged-unit-copy strong{ font-size: 10px; color: var(--gold-bright); }
.staged-unit-state{ font-size: 7px; font-weight: 900; letter-spacing: .06em; text-transform: uppercase; color: var(--gold); }
.staged-unit-name{ min-width: 0; padding: 0 4px 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 8px; font-weight: 800; color: var(--ink-dim); }
.territory-power{
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: 800;
  width: fit-content; margin-inline: auto; margin-block: auto;
  padding: 3px var(--sp-3); border-radius: var(--radius-pill);
  background: #070911d9; border: 1px solid #ffffff1f;
  box-shadow: 0 2px 10px -4px #000;
}
.power-bot{ color: var(--tide-glow); } .power-player{ color: var(--ember-glow); } .vs{ color: var(--ink-faint); }
.power-player-total{ display: inline-flex; align-items: baseline; gap: 3px; }
.power-staged{ color: var(--gold-bright); font-size: .72em; }

.staged-tray{ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; padding: var(--sp-2) var(--sp-3); background: var(--panel); border-radius: var(--radius-md); border: 1px solid var(--hairline); }
.staged-tray.no-card-play{ border-color: var(--gold-dim); background: linear-gradient(180deg, #d4a24e14, var(--panel)); }
.staged-summary{ display: flex; flex: 1 1 260px; flex-direction: column; gap: 3px; min-width: 0; }
.staged-title{ font-size: 9px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-faint); }
.staged-chips{ display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.staged-chips.empty-state{ flex-direction: column; align-items: flex-start; gap: 2px; }
.staged-chip{ display: inline-flex; align-items: center; gap: 5px; min-height: 36px; padding-inline-start: var(--sp-2); border-radius: var(--radius-pill); background: var(--panel-hi); border: 1px solid var(--hairline-hi); font-size: var(--fs-xs); font-weight: 700; white-space: nowrap; }
.staged-card-name{ color: var(--ink); }
.staged-arrow{ color: var(--gold); }
[dir="rtl"] .staged-arrow{ transform: scaleX(-1); }
.staged-destination{ color: var(--gold-bright); }
.chip-remove{ display: inline-flex; align-items: center; justify-content: center; width: 44px; min-height: 44px; color: var(--ink-faint); font-size: var(--fs-md); line-height: 1; border-radius: 50%; }
.chip-remove:hover{ color: var(--ember-glow); }
.staged-empty{ font-size: var(--fs-xs); }
.staged-action-hint{
  max-width: 52ch; color: var(--ink); font-size: var(--fs-sm); font-weight: 800;
  line-height: 1.3; text-wrap: pretty; overflow-wrap: break-word;
}
.staged-tray.no-card-play .staged-action-hint{ color: var(--gold-bright); }
/* Energy is the number every card in hand is measured against, so it is
   named, spaced away from the staged chips, and readable at a glance. */
.energy-meter{
  display: flex; align-items: center; gap: var(--sp-3); flex: none;
  padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill);
  background: #d4a24e14; border: 1px solid var(--gold-dim);
}
.energy-title{
  font-size: var(--fs-2xs); font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--gold);
}
.energy-pips{ display: flex; gap: 4px; }
.energy-pip{
  width: 10px; height: 20px; border-radius: 3px;
  background: var(--bg-0); border: 1px solid var(--hairline-hi);
}
.energy-pip.filled{
  background: linear-gradient(180deg, var(--gold-bright), var(--gold));
  border-color: var(--gold-bright); box-shadow: 0 0 8px -2px var(--gold);
}
.energy-value{ font-size: var(--fs-md); font-weight: 800; color: var(--gold-bright); }

.action-bar{ display: flex; flex-direction: column; gap: var(--sp-2); position: sticky; bottom: calc(var(--sp-2) + var(--safe-b)); }
.action-bar-row{ display: flex; gap: var(--sp-2); }
.pill-btn{
  flex: 1; display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 44px; border-radius: var(--radius-pill); background: var(--panel-solid); border: 1px solid var(--hairline-hi);
  font-size: var(--fs-sm); font-weight: 800; color: var(--ink-dim);
}
.pill-btn svg{ width: 18px; height: 18px; }
.pill-btn:not(.disabled):hover{ border-color: var(--gold-dim); color: var(--ink); }
.pill-btn.disabled{ opacity: .4; cursor: not-allowed; }
.lock-btn{ display: flex; justify-content: space-between; }
.timer-badge{
  min-width: 30px; height: 26px; padding-inline: 6px; border-radius: var(--radius-pill);
  background: #00000030; display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-sm);
}
.pause-screen{ min-height: min(620px, calc(100dvh - 140px)); justify-content: center; }
.pause-panel{ display: flex; flex-direction: column; gap: var(--sp-2); }
.pause-actions{
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3); margin-top: var(--sp-4);
}
.pause-actions .btn{ min-width: 0; white-space: normal; text-align: center; line-height: var(--lh-snug); }

.inline-panel{ padding: var(--sp-4); border-radius: var(--radius-lg); background: var(--panel-solid); border: 1px solid var(--gold-dim); animation: panel-in var(--dur-med) var(--ease-out); }
@keyframes panel-in{ from{ opacity: 0; transform: translateY(6px);} to{ opacity: 1; transform: none; } }
.target-grid{ display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }

@media (min-width: 768px){
  .match-screen{ max-width: 720px; margin-inline: auto; }
}
@media (min-width: 1024px){
  .match-screen{ max-width: 860px; }
}

/* ========================================================================
   mobile duel layout

   The phone is the base interaction surface: a compact scoreboard, all
   three objectives and lanes visible at once, a horizontal hand, and one
   thumb dock above the primary navigation. Desktop expands this system.
   ======================================================================== */
@media (max-width: 767px){
  .main{
    padding-inline: max(var(--sp-3), var(--safe-i-s));
    padding-bottom: calc(70px + var(--safe-b));
  }

  .bottom-tabbar{
    position: fixed; inset-inline: 0; bottom: 0;
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
    height: calc(66px + var(--safe-b));
    padding: 6px max(4px, var(--safe-i-s)) calc(6px + var(--safe-b));
  }
  /* Rules remain available as a route, but a manual is not a primary game
     destination. Five stable tabs fit thumbs; six do not. */
  .bottom-tabbar .tab-link[data-route="rules"]{ display: none; }
  .tab-link{ min-width: 0; width: 100%; padding: 3px 1px; font-size: 9.5px; }
  .tab-link svg{ width: 21px; height: 21px; }

  .toast-root{ top: calc(58px + var(--safe-t)); padding-inline: var(--sp-3); }
  .toast{
    width: min(100%, 360px); min-height: 44px; padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-md); font-size: var(--fs-sm); line-height: var(--lh-snug);
  }

  .match-screen{
    width: 100%; min-width: 0; gap: var(--sp-2);
    padding-block: var(--sp-2) calc(74px + var(--sp-4));
  }
  .match-screen > *{ min-width: 0; max-width: 100%; }

  .match-topbar{ gap: 6px; }
  .champion-badge{ gap: 6px; }
  .champion-sigil{ width: 36px; height: 36px; }
  .champion-name{ font-size: 10px; }
  .hp-bar{ height: 5px; }
  .hp-value{ font-size: 10px; }
  .round-num{ font-size: 10px; }
  .marks-row{ gap: 6px; }
  .marks-label{ display: none; }

  .trials-rail{
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 5px; width: 100%; overflow: visible;
  }
  .trial-chip{ min-width: 0; padding: 7px 6px; }
  .trial-name{
    display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    font-size: 10px; line-height: 1.2; text-align: center;
  }
  .trial-desc{ display: none; }
  .trial-claimed{ text-align: center; font-size: 9px; }

  .board{ gap: 5px; width: 100%; }
  .territory-col{ min-width: 0; min-height: 118px; gap: 5px; padding: 6px 4px; border-radius: 10px; }
  .territory-header{ min-height: 24px; font-size: 9px; line-height: 1.2; }
  .territory-col::before{ background-size: 64px auto; }
  .territory-col:nth-child(2)::before{ background-size: auto 96px; }
  .territory-power{ gap: 6px; padding: 2px 7px; font-size: var(--fs-xs); }
  .unit-row{ min-height: 23px; gap: 3px; }
  .unit-token{ min-width: 27px; height: 23px; font-size: 10px; }

  .staged-tray{
    display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
    gap: var(--sp-2); padding: 6px 8px; flex-wrap: nowrap;
  }
  .staged-chips{ min-width: 0; overflow-x: auto; flex-wrap: nowrap; }
  .staged-chips.empty-state{ overflow: visible; flex-wrap: wrap; }
  .staged-empty{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .staged-action-hint{ max-width: 100%; font-size: 11px; line-height: 1.25; }
  .energy-meter{ gap: 6px; padding: 3px 8px; }
  .energy-title{ font-size: 9px; }
  .energy-pips{ gap: 2px; }
  .energy-pip{ width: 7px; height: 15px; }
  .energy-value{ font-size: var(--fs-sm); }

  .hand-rail{ width: 100%; max-width: 100%; min-width: 0; gap: 8px; padding-block: 6px; }
  .hand-rail::-webkit-scrollbar{ display: none; }
  .hand-card{ width: 112px; min-height: 166px; padding: 8px; }
  .hand-card-art{ height: 82px; }
  .hand-card-tap-label{ inset-block-start: 72px; }
  /* Two lines, clamped. nowrap plus centring overflows BOTH ends, so the
     ellipsis never shows and a long name reads as "th, the Unbroken l":
     cut at both ends with no sign it was cut. The box already reserves two
     lines, so wrapping into them costs no height. */
  .hand-card-name{
    max-width: 100%; overflow: hidden; white-space: normal; text-wrap: balance;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  }
  .hand-card-blocked{ font-size: 9px; }

  .action-bar{
    position: fixed; z-index: calc(var(--z-header) - 1);
    inset-inline: max(var(--sp-3), var(--safe-i-s));
    bottom: calc(70px + var(--safe-b));
    display: flex; flex-direction: row; align-items: center; gap: 8px;
    padding: 7px; border: 1px solid var(--hairline-hi); border-radius: var(--radius-lg);
    background: #0b0d17f2; box-shadow: var(--shadow-lg);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  }
  .action-bar-row{ display: contents; }
  /* The Read is a decision, not a button, so it takes its own line above the
     pills rather than becoming a fourth item in a row already sized to the
     pixel. `display: contents` on .action-bar-row flattens its children into
     this flex container, so the read bar has to claim a full basis and pull
     itself to the front explicitly. */
  .action-bar{ flex-wrap: wrap; }
  .read-bar{ flex: 1 0 100%; order: -1; padding: 6px; gap: 5px; }
  .read-lane{ min-height: 40px; padding: 4px 2px; }
  .read-hint{ font-size: 10px; }
  .pill-btn{
    flex: 1 1 0; width: auto; min-width: 46px; min-height: 46px;
    padding-inline: 7px; border-radius: var(--radius-md); font-size: 10px; line-height: 1.1;
  }
  .pill-btn span{ max-width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pill-btn svg{ width: 20px; height: 20px; }
  .lock-btn{
    flex: 2 1 0; min-width: 128px; min-height: 48px; justify-content: space-between;
    padding-inline: var(--sp-3); font-size: var(--fs-sm);
  }
  .pause-screen{ min-height: calc(100svh - 120px); padding-block-end: var(--sp-4); }
  .pause-actions{ grid-template-columns: 1fr; gap: var(--sp-2); }
  .pause-actions .btn{ min-height: 50px; }
  .inline-panel{ margin-bottom: var(--sp-2); }
}

@media (min-width: 640px) and (max-width: 767px){
  .hand-card{ width: 124px; min-height: 184px; }
  .hand-card-art{ height: 98px; }
}

/* What a won territory's surplus is for this round. Two states, decided before
   the lock, sitting beside the Energy meter because both say what the round is
   worth. */
.surplus-toggle{
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 4px 8px; border-radius: var(--radius-pill);
  background: var(--panel-solid); border: 1px solid var(--hairline);
}
.surplus-label{ font-size: var(--fs-xs); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-faint); }
.surplus-option{
  min-height: 32px; padding: 2px 12px; border-radius: var(--radius-pill);
  border: 1px solid transparent; background: transparent;
  font-size: var(--fs-xs); font-weight: 800; color: var(--ink-dim); cursor: pointer;
}
.surplus-option:hover{ color: var(--ink); }
.surplus-option.on{ background: var(--gold); border-color: var(--gold); color: var(--gold-ink); }

/* The duel's controls stay where the hand can reach them, on every screen.
   Above 768px the bar was static, so on any window shorter than the duel
   screen the round's only control sat below the fold — and a new round scrolls
   the page to the top of the board, so it started there every time. A player
   reported locking that "did nothing" and rounds going to the timer; the
   timeout diagnostic (`lock_state`) recorded exactly that: off_screen. The
   phone has had a dock all along; this is the same idea in flow, so nothing is
   covered once the page is at its foot. */
@media (min-width: 768px){
  .action-bar{
    position: sticky; bottom: calc(var(--sp-3) + var(--safe-b));
    z-index: calc(var(--z-header) - 1);
    padding: var(--sp-2); border-radius: var(--radius-lg);
    background: #0b0d17f2; border: 1px solid var(--hairline-hi);
    box-shadow: var(--shadow-lg);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  }
}

/* ==========================================================================
   round report
   ========================================================================== */
.report-list{ margin-top: var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-2); }
.report-line{
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--panel);
  font-size: var(--fs-sm); border-inline-start: 3px solid var(--hairline-hi);
  animation: report-in var(--dur-med) var(--ease-out) backwards;
}
/* --in-delay is set per row in match.js from the same constants the sound
   uses, so a row cannot land on a different beat from the noise it makes. */
.report-list > *{ animation-delay: var(--in-delay, 0ms); }
@keyframes report-in{ from{ opacity: 0; transform: translateY(8px); } }
.report-line.side-player{ border-inline-start-color: var(--ember); }
.report-line.side-bot{ border-inline-start-color: var(--tide); }
.report-line.muted{ color: var(--ink-faint); }
.report-line.destroyed .report-thumb{ filter: grayscale(1) brightness(.6); }
.report-line.destroyed .report-line-title{ text-decoration: line-through; text-decoration-color: var(--ember); }
.report-thumb{
  flex: none; width: 38px; height: 38px; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--bg-1); border: 1px solid var(--hairline-hi);
}
.report-thumb img, .report-thumb svg{ width: 100%; height: 100%; object-fit: cover; display: block; }
.report-line-text{ display: flex; flex-direction: column; min-width: 0; }
.report-line-title{ font-weight: 800; line-height: var(--lh-snug); }
.report-line-sub{ font-size: var(--fs-2xs); color: var(--ink-faint); }
.report-mark{
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-md);
  background: linear-gradient(100deg, #d4a24e2e, #d4a24e10);
  border: 1px solid var(--gold-dim);
  animation: mark-in var(--dur-slow) var(--ease-spring) backwards;
}
@keyframes mark-in{ from{ opacity: 0; transform: scale(.88); } }
.report-mark-gem{
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%; font-size: var(--fs-lg);
  background: linear-gradient(180deg, var(--gold-bright), var(--gold)); color: var(--gold-ink);
  box-shadow: 0 0 18px -2px var(--gold);
  /* The game is named for these. One arriving used to be a card fading in. */
  animation: gem-strike 900ms var(--ease-out) backwards;
  animation-delay: var(--in-delay, 0ms);
}
@keyframes gem-strike{
  0%{ opacity: 0; transform: scale(.35) rotate(-35deg); box-shadow: 0 0 0 0 #f2c57200; }
  55%{ opacity: 1; transform: scale(1.16) rotate(5deg); box-shadow: 0 0 34px 7px #f2c572a8; }
  100%{ transform: none; }
}
.report-mark strong{ display: block; font-size: var(--fs-md); color: var(--gold-bright); }
.report-mark-sub{ font-size: var(--fs-2xs); color: var(--ink-dim); text-transform: uppercase; letter-spacing: .06em; }

/* ==========================================================================
   the resolve: the round played back where it was fought
   ========================================================================== */
/* Opacity only. The dock inside it is fixed on a phone, and a transform on any
   ancestor would pin it to this box instead of the screen while the recap
   faded in, so it would appear mid-page and then jump down to the thumb. */
.resolve-recap{
  width: 100%; max-width: 560px; margin-inline: auto;
  animation: recap-in var(--dur-med) var(--ease-out) backwards;
  animation-delay: var(--in-delay, 0ms);
}
@keyframes recap-in{ from{ opacity: 0; } }
.resolve-recap-title{
  font-size: var(--fs-sm); font-weight: 800; text-align: center; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .1em;
}
/* The recap is the record, not the event. The board above it is the event, so
   the list is kept tight enough that it does not pull the eye off the thing it
   is describing. The board's own metrics are deliberately untouched: it has to
   be the same size here as it was while you were deciding, or the claim that
   it is the same board stops being true. */
.resolve-recap .report-list{ margin-top: var(--sp-3); }
.resolve-recap .report-line{ padding: 6px var(--sp-3); }
/* The way on. Under the report on a wide screen; on a phone the .action-bar
   rules make it the same fixed dock the lock button lives in. Hidden, not just
   transparent, until the report's own delay has passed: an invisible button
   still takes taps, and this one sits exactly where the thumb that locked the
   round already is. A skipped or redrawn round shows it at once. */
.resolve-dock{
  margin-top: var(--sp-4);
  animation: dock-in var(--dur-med) linear backwards;
  animation-delay: var(--in-delay, 0ms);
}
@keyframes dock-in{ from{ visibility: hidden; } }
.resolve-dock .btn-block{ margin-top: 0; }
.resolve-screen.settled .resolve-dock{ animation: none; }

/* Suppressed while the beats play, so the wash is watched arriving rather than
   found already there. Specificity has to beat .territory-col.held-*, which is
   why both holders are named rather than leaning on source order. */
.board.holds-hidden .territory-col.held-player .territory-hold,
.board.holds-hidden .territory-col.held-bot .territory-hold{ opacity: 0; }

/* The dead, put back on the ground they died on for as long as it takes to
   watch them go. They flare once before they drop: a unit is destroyed, which
   should look like something happening to it, not like a row being removed. */
.unit-token.ghost{
  opacity: .85; filter: grayscale(.65) brightness(.72);
  box-shadow: inset 0 0 0 1px #ffffff2e;
}
.unit-token.ghost.falling{ animation: token-fall 440ms var(--ease-out) forwards; }
@keyframes token-fall{
  0%{ opacity: .85; transform: none; filter: grayscale(.65) brightness(.72); }
  32%{ transform: translateY(-4px) scale(1.08); filter: grayscale(0) brightness(1.55); }
  100%{ opacity: 0; transform: translateY(18px) scale(.8) rotate(-8deg); filter: grayscale(1) brightness(.5); }
}

/* Ground changing hands, and a card arriving on it. Both are a single pulse on
   the territory rather than a lasting state, because the lasting state is the
   hold wash and two permanent signals for one fact is one too many. */
.territory-col.taken{ animation: territory-taken 900ms var(--ease-out); }
@keyframes territory-taken{
  0%{ box-shadow: inset 0 0 0 0 #f2c57200; }
  28%{ box-shadow: inset 0 0 36px 2px #f2c57259; }
  100%{ box-shadow: inset 0 0 0 0 #f2c57200; }
}
.territory-col.impact{ animation: territory-impact 600ms var(--ease-out); }
@keyframes territory-impact{
  0%{ box-shadow: inset 0 0 0 0 #d4a24e00; }
  20%{ box-shadow: inset 0 0 0 2px #f2c572aa, inset 0 0 30px 2px #d4a24e4d; }
  100%{ box-shadow: inset 0 0 0 0 #d4a24e00; }
}

/* The card in flight. Fixed to the viewport and outside the screen it came
   from, because the element it started in is destroyed by the redraw before
   this ever runs. */
.card-flight{
  position: fixed; z-index: 90; pointer-events: none;
  border-radius: var(--radius-md); overflow: hidden;
  border: 1.5px solid var(--gold-bright);
  box-shadow: 0 18px 40px -14px #000, 0 0 26px -6px var(--gold);
  will-change: transform, opacity;
}
.card-flight img, .card-flight svg{ width: 100%; height: 100%; object-fit: cover; display: block; }

/* A Mark arriving looked exactly like a Mark that had been sitting there since
   round two. It strikes now, on the same beat as its sound. */
.mark-pip.struck{
  animation: pip-strike 620ms var(--ease-spring) backwards;
  animation-delay: var(--in-delay, 0ms);
}
@keyframes pip-strike{
  0%{ transform: rotate(45deg) scale(.2); box-shadow: 0 0 0 0 #f2c57200; }
  55%{ transform: rotate(45deg) scale(1.55); box-shadow: 0 0 20px 5px #f2c572; }
  100%{ transform: rotate(45deg) scale(1); }
}

/* A round drawn finished: skipped, redrawn after a language switch, or under
   reduced motion. Nothing waits for a beat that has already happened. */
.resolve-screen.settled .resolve-recap,
.resolve-screen.settled .report-list > *,
.resolve-screen.settled .report-tip,
.resolve-screen.settled .report-mark-gem,
.resolve-screen.settled .mark-pip.struck,
.resolve-screen.settled .trial-chip.just-claimed,
.resolve-screen.settled .territory-col.taken{ animation: none; }

/* Arm C of the resolve FX test: the round drawn on a canvas over this board
   (src/render/fx). The canvas takes no taps and carries no words; the board
   under it is set back to where it stood at the lock and moves on each beat's
   impact. The screen is the canvas's positioning box. */
.resolve-screen{ position: relative; }
.resolve-screen .unit-token.fx-pending{ opacity: 0; }
.resolve-screen .unit-token.fx-arrive{ animation: fx-arrive 280ms var(--ease-out); }
@keyframes fx-arrive{ from{ opacity: 0; transform: translateY(-10px) scale(.9); } }
.resolve-screen .tok-stat.fx-hit{ animation: fx-stat-hit 340ms var(--ease-out); }
@keyframes fx-stat-hit{ 35%{ transform: scale(1.35); color: var(--gold-bright); } }
.resolve-screen .territory-power.fx-pill-pending .num{ visibility: hidden; }
.board.holds-hidden .territory-col.fx-held.held-player .territory-hold,
.board.holds-hidden .territory-col.fx-held.held-bot .territory-hold{ opacity: 1; transition: opacity 260ms var(--ease-out); }
.resolve-screen .trial-chip.fx-claim-pending .trial-claimed{ visibility: hidden; }
.resolve-screen[data-fx="pixi"] .hp-fill{ transition: width 260ms var(--ease-out); }
/* The FX test's one question on the results screen: asked once, answered with a tap. */
.clarity-question{ font-weight: 700; }
.clarity-actions{ display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }

/* ==========================================================================
   results
   ========================================================================== */
.results-screen{ max-width: 640px; margin-inline: auto; padding-block: var(--sp-8) var(--sp-16); display: flex; flex-direction: column; gap: var(--sp-5); }
.results-hero{
  position: relative; overflow: hidden; border-radius: var(--radius-xl);
  min-height: 300px; display: flex; align-items: flex-end; justify-content: center;
  border: 1px solid var(--hairline-hi); background: var(--panel);
}
.results-hero-art{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 12%;
  animation: hero-settle 900ms var(--ease-out);
}
@keyframes hero-settle{ from{ transform: scale(1.06); opacity: .4; } }
.results-screen.lost .results-hero-art{ filter: grayscale(.75) brightness(.55); }
.results-hero-scrim{
  position: absolute; inset: 0;
  background: linear-gradient(0deg, #07080ff2 8%, #07080f99 38%, #07080f26 70%, transparent 100%);
}
.results-screen.won .results-hero-scrim{
  background:
    radial-gradient(70% 60% at 50% 100%, #d4a24e30, transparent 65%),
    linear-gradient(0deg, #07080ff2 8%, #07080f99 38%, #07080f26 70%, transparent 100%);
}
.results-hero-content{ position: relative; text-align: center; padding: var(--sp-6) var(--sp-4) var(--sp-8); }
.results-title{ font-size: var(--fs-4xl); font-weight: 900; line-height: var(--lh-tight); text-shadow: 0 2px 16px #000000cc; }
.results-screen.won .results-title{ color: var(--gold-bright); }
.results-marks{ margin-top: var(--sp-2); font-size: var(--fs-lg); font-weight: 800; color: var(--ink-dim); }
.results-reason{ margin-top: var(--sp-1); font-size: var(--fs-xs); color: var(--ink-faint); text-transform: uppercase; letter-spacing: .08em; }
.first-duel-debrief{
  display: flex; flex-direction: column; gap: 3px; padding: var(--sp-4); border-radius: var(--radius-md);
  background: #d4a24e12; border: 1px solid #d4a24e4d; color: var(--ink-dim); font-size: var(--fs-sm);
}
.first-duel-debrief strong{ color: var(--gold-bright); }

.trial-results{ display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.trial-result{ display: flex; justify-content: space-between; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--panel-hi); font-size: var(--fs-sm); }
.trial-result.claimed-player{ box-shadow: inset 3px 0 0 var(--ember); }
.trial-result.claimed-bot{ box-shadow: inset 3px 0 0 var(--tide); }
.trial-result-who{ font-weight: 800; color: var(--gold-bright); }

.milestone-list{ display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.milestone-card{ display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: linear-gradient(90deg, #d4a24e22, transparent); border: 1px solid var(--gold-dim); }
.milestone-sigil{ flex: none; width: 44px; height: 44px; }
.milestone-name{ font-weight: 800; }
.milestone-tag{ font-size: var(--fs-2xs); color: var(--gold-bright); text-transform: uppercase; letter-spacing: .05em; }

.results-alliance-note{ text-align: center; }
.results-actions{ display: flex; gap: var(--sp-3); justify-content: center; flex-wrap: wrap; }

/* ==========================================================================
   collection
   ========================================================================== */
.collection-screen{ padding-block: var(--sp-6) var(--sp-16); }
.collection-head{ display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.deck-count-badge{ padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-pill); background: var(--panel); border: 1px solid var(--hairline-hi); font-weight: 800; font-size: var(--fs-sm); white-space: nowrap; }
.deck-count-badge.valid{ border-color: var(--tide); color: var(--tide-glow); background: #2fb6a51a; }

.filter-tabs{ display: flex; gap: var(--sp-2); margin-top: var(--sp-5); overflow-x: auto; padding-bottom: var(--sp-1); }
.filter-tab{ min-height: 44px; padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-pill); background: var(--panel); border: 1px solid var(--hairline-hi); font-size: var(--fs-sm); font-weight: 700; color: var(--ink-dim); white-space: nowrap; }
.filter-tab.active{ background: var(--gold); color: var(--gold-ink); border-color: var(--gold); }
.filter-tab.filter-neutral{ border-color: #9aa0b466; color: #d8d4c8; }
.filter-tab.filter-neutral.active{
  background: linear-gradient(180deg, #e8e4d8, var(--rarity-common));
  border-color: #e8e4d8; color: #171922;
  box-shadow: 0 0 0 1px #d8d4c833;
}

.coll-grid{ display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); margin-top: var(--sp-5); }
@media (min-width: 640px){ .coll-grid{ grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px){ .coll-grid{ grid-template-columns: repeat(5, 1fr); } }

.coll-card{
  position: relative; min-block-size: 238px;
  border-radius: var(--radius-md); background: var(--panel-solid);
  border: 1.5px solid var(--hairline-hi); overflow: hidden;
}
.coll-card::before{
  content: ""; position: absolute; z-index: 1; inset: 0 0 auto; block-size: 3px;
  background: var(--card-element, transparent); pointer-events: none;
}
.coll-card.elem-ember{ --card-element: var(--ember-glow); }
.coll-card.elem-tide{ --card-element: var(--tide-glow); }
.coll-card.elem-gale{ --card-element: var(--gale-glow); }
.coll-card.elem-stone{ --card-element: var(--stone-glow); }
.coll-card.elem-neutral{ --card-element: linear-gradient(90deg, var(--rarity-common), #e8e4d8, var(--rarity-common)); }
.coll-card.rarity-rare{ border-color: var(--rarity-rare); }
.coll-card.rarity-epic{ border-color: var(--rarity-epic); }
.coll-card.rarity-legendary{ border-color: var(--rarity-legendary); }
.coll-card-body{
  width: 100%; min-block-size: 238px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: var(--sp-3) var(--sp-3) 58px;
  text-align: center; position: relative;
}
.coll-card-sigil{ width: 64px; height: 64px; }
.coll-card-name{ font-size: var(--fs-xs); font-weight: 800; }
.coll-card-type{ font-size: 10px; color: var(--ink-faint); }
.evo-badge{ position: absolute; top: 4px; inset-inline-end: 4px; font-size: 9px; color: var(--gold-bright); letter-spacing: 1px; }
.coll-stepper{
  position: absolute; z-index: 2; inset-inline-end: var(--sp-2); inset-block-end: var(--sp-2);
  display: grid; grid-template-columns: 44px; align-items: center; gap: 4px;
}
.coll-stepper.has-copies{
  grid-template-columns: 44px 48px 44px;
  padding: 2px; border: 1px solid var(--hairline); border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--bg-2) 88%, transparent);
  box-shadow: 0 10px 24px -18px #000000;
}
.stepper-btn{
  width: 44px; height: 44px; border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: color-mix(in srgb, var(--panel-hi) 88%, transparent);
  font-size: var(--fs-lg); line-height: 1; font-weight: 900; color: var(--ink);
  box-shadow: 0 10px 22px -18px #000000;
}
.stepper-plus:not(:disabled){
  background: var(--gold);
  border-color: var(--gold-bright);
  color: var(--gold-ink);
}
.coll-stepper.has-copies .stepper-plus:not(:disabled){
  background: color-mix(in srgb, var(--gold) 24%, var(--panel-hi));
  color: var(--gold-bright);
}
.stepper-btn:not(:disabled):hover{
  background: color-mix(in srgb, var(--gold) 18%, var(--panel-hi));
  color: var(--gold-bright);
}
.stepper-btn:disabled{ opacity: .34; }
.stepper-count{ text-align: center; font-size: var(--fs-xs); color: var(--ink-faint); }

/* ==========================================================================
   passport
   ========================================================================== */
.passport-screen{ max-width: 560px; margin-inline: auto; padding-block: var(--sp-6) var(--sp-16); display: flex; flex-direction: column; gap: var(--sp-4); }
.passport-card{
  text-align: center; padding: var(--sp-8) var(--sp-6); border-radius: var(--radius-xl);
  background: radial-gradient(80% 60% at 50% 0%, #d4a24e1c, transparent), var(--panel);
  border: 1.5px solid var(--hairline-hi);
}
.passport-card.rarity-rare{ border-color: var(--rarity-rare); }
.passport-card.rarity-epic{ border-color: var(--rarity-epic); }
.passport-card.rarity-legendary{ border-color: var(--rarity-legendary); box-shadow: 0 0 40px -12px #f2c57255; }
.passport-sigil{ margin-inline: auto; width: 180px; height: 180px; }
.passport-name{ font-size: var(--fs-2xl); font-weight: 900; margin-top: var(--sp-3); }
.passport-flavor{ color: var(--ink-faint); font-style: italic; margin-top: var(--sp-1); }
.passport-chips{ display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; margin-top: var(--sp-4); }
.passport-meta .meta-row{ display: flex; justify-content: space-between; padding-block: var(--sp-2); border-bottom: 1px solid var(--hairline); font-size: var(--fs-sm); }
.passport-meta .meta-row:last-child{ border-bottom: 0; }
.milestone-rows{ display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.milestone-row{ display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--panel-hi); font-size: var(--fs-sm); color: var(--ink-faint); }
.milestone-row.unlocked{ color: var(--ink); background: #2fb6a51a; }
.milestone-dot{ width: 8px; height: 8px; border-radius: 50%; background: var(--ink-mute); }
.milestone-row.unlocked .milestone-dot{ background: var(--tide); }
.milestone-state{ margin-inline-start: auto; font-weight: 800; }
.passport-actions{ display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.passport-actions .btn{ flex: 1; }

/* ==========================================================================
   world / alliance front
   ========================================================================== */
.world-screen{ max-width: 760px; margin-inline: auto; padding-block: var(--sp-6) var(--sp-16); display: flex; flex-direction: column; gap: var(--sp-4); }
.front-hero{ display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-6); position: relative; overflow: hidden; }
.front-hero-watermark{
  position: absolute; inset-inline-end: -48px; top: 50%; transform: translateY(-50%);
  width: 240px; height: 240px; object-fit: cover; border-radius: 50%;
  opacity: .14; pointer-events: none;
}
.front-hero > div{ position: relative; }
.front-emblem{ flex: none; width: 90px; height: 90px; border-radius: 50%; overflow: hidden; border: 1.5px solid var(--gold-dim); }
.front-emblem img{ width: 100%; height: 100%; object-fit: cover; display: block; }
.world-cta{ font-size: var(--fs-lg); }
.stats-row{ display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-3); text-align: center; }
.stat-value{ font-size: var(--fs-2xl); font-weight: 900; color: var(--gold-bright); }
.stat-label{ font-size: var(--fs-2xs); color: var(--ink-faint); text-transform: uppercase; letter-spacing: .05em; margin-top: 2px; }
.front-rows{ display: flex; flex-direction: column; gap: var(--sp-4); margin-top: var(--sp-4); }
.front-row-head{ display: flex; justify-content: space-between; font-size: var(--fs-sm); font-weight: 700; margin-bottom: var(--sp-2); }
.front-status{ font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .05em; font-weight: 800; }
.status-leading{ color: var(--tide-glow); } .status-behind{ color: var(--ember-glow); } .status-contested{ color: var(--gold-bright); }
.front-bar{ height: 10px; border-radius: var(--radius-pill); background: var(--panel-hi); overflow: hidden; }
.front-bar-fill{ height: 100%; background: linear-gradient(90deg, var(--ember), var(--gold), var(--tide)); transition: width var(--dur-med) var(--ease-out); }
.alliance-footnote{ margin-top: var(--sp-4); font-size: var(--fs-xs); line-height: var(--lh-normal); }

/* ==========================================================================
   store
   ========================================================================== */
.store-screen{ padding-block: var(--sp-6) var(--sp-16); }
.store-head{ position: relative; }
.store-preview-badge{ position: absolute; top: 0; inset-inline-end: 0; }
.store-note{ max-width: 62ch; margin-top: var(--sp-2); font-size: var(--fs-xs); }
.offer-grid{ display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); margin-top: var(--sp-6); }
@media (min-width: 640px){ .offer-grid{ grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px){ .offer-grid{ grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1200px){ .offer-grid{ grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.offer-card{ min-width: 0; padding: var(--sp-4); border-radius: var(--radius-lg); background: var(--panel); border: 1px solid var(--hairline-hi); display: flex; flex-direction: column; gap: var(--sp-2); }
.offer-price{ font-size: var(--fs-xl); font-weight: 900; color: var(--gold-bright); }
.offer-card h3{ font-size: var(--fs-md); font-weight: 800; }
.offer-card p{ font-size: var(--fs-xs); flex: 1; }
.offer-badges{ display: flex; flex-wrap: wrap; gap: 4px; }
.offer-badges .chip{ font-size: 9.5px; padding: 2px var(--sp-2); }
.offer-card > .btn{ max-width: 100%; white-space: normal; }

/* ---- patron memberships --------------------------------------------------*/
.patron-section{
  max-width: 74rem;
  margin: var(--sp-12) auto 0;
  padding: clamp(var(--sp-4), 3vw, var(--sp-8));
  border: 1px solid rgba(242, 197, 114, .18);
  border-radius: var(--radius-xl);
  background:
    radial-gradient(circle at 50% -25%, rgba(242, 197, 114, .12), transparent 42%),
    rgba(12, 14, 25, .52);
}
.patron-heading{
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: var(--sp-6);
}
.patron-heading > div:first-child{ max-width: 42rem; }
.patron-heading .section-title{ margin-block: var(--sp-1); }
.patron-eyebrow{
  color: var(--gold-bright);
  font-size: var(--fs-2xs);
  font-weight: 900;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.patron-promises{ display: flex; flex-wrap: wrap; justify-content: end; gap: var(--sp-2); }
.patron-promises span{
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  padding-inline: var(--sp-3);
  border: 1px solid rgba(99, 230, 212, .3);
  border-radius: var(--radius-pill);
  color: var(--tide-glow);
  background: rgba(99, 230, 212, .06);
  font-size: var(--fs-2xs);
  font-weight: 800;
  white-space: nowrap;
}
.patron-promises span::before{ content: "✓"; margin-inline-end: 6px; }
.patron-grid{ display: grid; grid-template-columns: 1fr; gap: var(--sp-4); margin-top: var(--sp-6); }
@media (min-width: 700px){ .patron-grid{ grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1080px){ .patron-grid{ grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.offer-card.patron-card{
  position: relative;
  display: flex;
  padding: clamp(var(--sp-4), 2vw, var(--sp-6));
  border-color: rgba(242, 197, 114, .25);
  border-radius: var(--radius-xl);
  background:
    linear-gradient(155deg, rgba(242, 197, 114, .08), transparent 34%),
    var(--panel);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .16);
}
.offer-card.patron-card.is-recommended{
  border-color: rgba(99, 230, 212, .62);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .2), inset 0 2px 0 rgba(99, 230, 212, .45);
}
.patron-card-top{ display: flex; align-items: center; min-height: 52px; gap: var(--sp-2); }
.patron-card-top .offer-emblem{ margin-inline-end: auto; }
.patron-level, .patron-recommended{
  padding: 5px 9px;
  border: 1px solid var(--hairline-hi);
  border-radius: var(--radius-pill);
  color: var(--ink-faint);
  font-size: 9.5px;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.patron-recommended{ color: var(--tide-glow); border-color: rgba(99, 230, 212, .4); }
.patron-price{ display: flex; align-items: baseline; gap: var(--sp-2); margin-top: var(--sp-3); }
.patron-price strong{ color: var(--gold-bright); font-size: clamp(2rem, 4vw, 2.75rem); line-height: 1; }
.patron-price span{ color: var(--ink-faint); font-size: var(--fs-xs); font-weight: 700; }
.offer-card.patron-card h3{ margin-top: var(--sp-2); font-size: var(--fs-xl); line-height: var(--lh-snug); }
.offer-card.patron-card .patron-summary{ min-height: 4.5em; flex: none; line-height: var(--lh-normal); }
.patron-value-list{ list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-2); }
.patron-value-list li{ display: flex; align-items: start; gap: var(--sp-2); font-size: var(--fs-xs); line-height: var(--lh-normal); }
.patron-check{
  display: grid;
  place-items: center;
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  color: #081310;
  background: var(--tide-glow);
  font-size: 11px;
  font-weight: 900;
}
.patron-term{
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: auto;
  padding-top: var(--sp-4);
  color: var(--ink-faint);
  font-size: var(--fs-2xs);
  font-weight: 800;
}
.patron-card > .btn{ min-height: 48px; margin-top: var(--sp-3); }
.patron-details{
  align-self: center;
  padding: var(--sp-2);
  border: 0;
  color: var(--ink-dim);
  background: transparent;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 800;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.patron-details:hover{ color: var(--ink); }

.tier-contents{ font-size: var(--fs-xs); }
.tier-contents-h{ text-transform: uppercase; letter-spacing: .08em; font-size: 9.5px; }
.tier-contents ul{ list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: grid; gap: 3px; }
.tier-contents li{
  display: flex; gap: var(--sp-2); align-items: baseline; justify-content: space-between;
  padding-block: 2px; border-bottom: 1px solid var(--hairline-hi);
}
.tier-contents li:last-child{ border-bottom: 0; }
/* A component the player already holds, so the overlap is visible before they
   pay rather than discovered afterwards. */
.tier-contents li.is-held{ opacity: .55; }
.tier-contents li.is-held > span:first-child::before{ content: "✓ "; color: var(--gold-bright); }
.tier-term{ flex: none; font-size: 9.5px; opacity: .7; white-space: nowrap; }
.renew-note{ font-size: var(--fs-xs); }

.seat-count{ font-size: var(--fs-xs); font-weight: 700; color: var(--gold-bright); }
.seat-count.is-out{ color: inherit; opacity: .6; }

/* ---- deliberate confirmation ---------------------------------------------*/
.confirm-scrim{
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-4);
  background: rgba(0, 0, 0, .62);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  overflow-y: auto;
}
.confirm-sheet{ width: min(30rem, 100%); max-height: 100%; overflow-y: auto; }
.confirm-sheet .tier-contents li{ border-bottom-color: var(--hairline-hi); }
.confirm-fair{
  font-size: var(--fs-xs); font-weight: 700;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  border: 1px solid rgba(242, 197, 114, .35);
}
.confirm-warn{ font-size: var(--fs-xs); }

/* ---- account: lapsed benefits and legacy founder seats -------------------*/
.owned-chip.is-lapsed{ opacity: .55; }
.owned-chip.is-seat .owned-date{ color: var(--gold-bright); font-weight: 800; }
.refund-due{ border-color: rgba(242, 197, 114, .45); }

@media (max-width: 639px){
  .store-screen{ padding-block-start: var(--sp-4); }
  .store-head{ display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-2); align-items: start; }
  .store-head .section-title, .store-head .dim{ grid-column: 1; }
  .store-preview-badge{ position: static; grid-column: 2; grid-row: 1; }
  .store-note{ font-size: var(--fs-sm); line-height: var(--lh-normal); }
  .offer-grid{ margin-top: var(--sp-4); }
  .offer-card{
    display: grid; grid-template-columns: 64px minmax(0, 1fr);
    column-gap: var(--sp-3); row-gap: var(--sp-2);
    border-radius: var(--radius-md);
  }
  .offer-emblem{ grid-column: 1; grid-row: 1 / span 2; align-self: center; }
  .offer-card h3{ grid-column: 2; grid-row: 1; align-self: end; font-size: var(--fs-lg); line-height: var(--lh-snug); }
  .offer-price{ grid-column: 2; grid-row: 2; align-self: start; font-size: var(--fs-lg); }
  .offer-card > p, .offer-badges, .offer-card > .btn{ grid-column: 1 / -1; }
  .offer-card > p{ font-size: 1rem; line-height: var(--lh-normal); }
  .offer-badges{ gap: 6px; }
  .offer-badges .chip{ min-height: 28px; padding: 3px var(--sp-2); font-size: var(--fs-xs); }
  .offer-card > .btn{ min-height: 48px; margin-top: var(--sp-1); }
  .patron-section{ margin-top: var(--sp-8); padding: var(--sp-4); border-radius: var(--radius-lg); }
  .patron-heading{ display: block; }
  .patron-heading .section-title{ font-size: var(--fs-2xl); }
  .patron-promises{ justify-content: start; margin-top: var(--sp-3); gap: 6px; }
  .patron-promises span{ min-height: 28px; padding-inline: var(--sp-2); }
  .patron-grid{ margin-top: var(--sp-4); }
  .offer-card.patron-card{ display: flex; padding: var(--sp-4); border-radius: var(--radius-lg); }
  .offer-card.patron-card h3{ font-size: var(--fs-xl); }
  .offer-card.patron-card .patron-summary{ min-height: 0; font-size: var(--fs-sm); }
  .patron-price strong{ font-size: 2.25rem; }
  .patron-card > .btn{ margin-top: var(--sp-3); }
}

/* ==========================================================================
   rival hall
   ========================================================================== */
.hall-screen{ max-width: 760px; margin-inline: auto; padding-block: var(--sp-6) var(--sp-16); display: flex; flex-direction: column; gap: var(--sp-4); }
.hall-hero{ display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-6); }
.hall-emblem{ flex: none; width: 88px; height: 110px; border-radius: var(--radius-md); overflow: hidden; border: 1.5px solid var(--gold-dim); }
.hall-emblem img{ width: 100%; height: 100%; object-fit: cover; object-position: 50% 15%; display: block; }
.hall-chips{ display: flex; gap: var(--sp-2); margin-top: var(--sp-2); flex-wrap: wrap; }
.showcase-grid{ display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); margin-top: var(--sp-3); }
@media (min-width: 640px){ .showcase-grid{ grid-template-columns: repeat(6, 1fr); } }
.showcase-card{ display: flex; flex-direction: column; align-items: center; gap: 4px; padding: var(--sp-3); border-radius: var(--radius-md); background: var(--panel-hi); border: 1px solid var(--gold-dim); text-align: center; }
.showcase-name{ font-size: 10.5px; font-weight: 800; }
.showcase-tier{ font-size: 9px; color: var(--gold-bright); letter-spacing: 1px; }

/* ==========================================================================
   account + auth
   ========================================================================== */
.account-btn{
  position: relative; display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 40px; padding-inline: var(--sp-3); border-radius: var(--radius-pill);
  border: 1px solid var(--hairline-hi); color: var(--ink-dim);
  font-size: var(--fs-sm); font-weight: 800; text-decoration: none;
  transition: color var(--dur-fast), background var(--dur-fast), border-color var(--dur-fast);
}
.account-btn svg{ width: 18px; height: 18px; flex: none; }

/* Sound sits in the chrome because it is a device setting, not an account
   one, and signed out the Account screen is only reachable via a button
   labelled "Sign in" -- which nobody clicks to turn the music down. */
.sound-btn{
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex: none; padding: 0;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline-hi); background: transparent;
  color: var(--ink-dim); cursor: pointer;
  transition: color var(--dur-fast), background var(--dur-fast), border-color var(--dur-fast);
}
.sound-btn svg{ width: 19px; height: 19px; }
.sound-btn:hover{ color: var(--ink); background: var(--hairline); border-color: var(--gold-dim); }
.sound-btn.is-muted{ color: var(--ink-mute); }
.sound-btn.is-muted:hover{ color: var(--ink-dim); }
.account-btn:hover{ color: var(--ink); background: var(--hairline); border-color: var(--gold-dim); }
.account-btn.active{ color: var(--gold-bright); background: #d4a24e1a; border-color: var(--gold-dim); }
/* A guest has something to do here, so the button says so. */
.account-btn.needs-account{ color: var(--gold-bright); border-color: var(--gold-dim); background: #d4a24e14; }
.account-btn.needs-account::after{
  content: ""; position: absolute; top: 6px; inset-inline-end: 6px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--gold-bright); box-shadow: 0 0 8px var(--gold);
}
@media (max-width: 560px){
  .account-btn-label{ display: none; }
  .account-btn{ padding-inline: var(--sp-2); }
}

.guest-banner{
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5); border-radius: var(--radius-lg);
  background: linear-gradient(100deg, #d4a24e26, #d4a24e0d);
  border: 1px solid var(--gold-dim);
}
.guest-banner-text strong{ display: block; font-size: var(--fs-md); color: var(--gold-bright); }
.guest-banner-text p{ margin-top: 2px; font-size: var(--fs-sm); color: var(--ink-dim); max-width: 52ch; }
.guest-banner-actions{ display: flex; align-items: center; gap: var(--sp-3); flex: none; }

.sync-note{
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--ink-faint);
}
.sync-dot{
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--tide); box-shadow: 0 0 8px var(--tide);
}

.account-screen{
  max-width: 680px; margin-inline: auto; padding-block: var(--sp-6) var(--sp-16);
  display: flex; flex-direction: column; gap: var(--sp-4);
}
.account-id{ display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); }
.account-label{ font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .08em; }
.account-email{ font-size: var(--fs-lg); font-weight: 800; margin-top: 2px; word-break: break-all; }

.auth-form{ display: flex; flex-direction: column; }
.auth-form label{ font-size: var(--fs-xs); font-weight: 800; color: var(--ink-dim); margin-bottom: var(--sp-2); }
.field{
  width: 100%; min-height: 46px; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md); background: var(--bg-1);
  border: 1px solid var(--hairline-hi); color: var(--ink);
  /* 16px exactly, not --fs-md, which resolves to 15. Safari on iOS zooms the
     whole page when a focused input is under 16px, so tapping the email field
     threw the layout out and left the player to pinch back. One pixel. */
  font-size: 16px;
}
.field:focus-visible{ border-color: var(--gold); outline: none; box-shadow: var(--glow-gold); }
.link-btn{
  align-self: flex-start; color: var(--gold-bright); font-size: var(--fs-sm);
  font-weight: 700; text-decoration: underline; text-underline-offset: 3px;
  /* A bare underlined word is about 13px tall, which is half the 44px a thumb
     needs. The padding is invisible and makes it hittable; the look does not
     change. */
  display: inline-flex; align-items: center;
  min-height: 44px; padding-inline: var(--sp-2);
}
.form-msg{ margin-top: var(--sp-3); font-size: var(--fs-sm); min-height: 1.2em; }
.form-msg.error{ color: var(--ember-glow); }
.form-msg.ok{ color: var(--tide-glow); }

/* ---- why a card is greyed out ----------------------------------------- */
/* Sits under the stat readout on an unplayable card. Energy shortfalls are
   amber because they fix themselves next round; a card with nothing to
   target is the colder problem and reads muted. */
.hand-card-blocked{
  margin-block-start: auto;
  padding: 4px var(--sp-2) 0;
  font-size: var(--fs-2xs);
  font-weight: 700;
  line-height: 1.25;
  color: var(--ink-faint);
  text-align: center;
}
.hand-card-blocked.reason-energy{ color: var(--gold); }
.hand-card.unplayable{ opacity: .78; }
.hand-card.unplayable .hand-card-art{ opacity: .5; filter: grayscale(.35); }

/* ---- card variables, explained --------------------------------------- */
/* A bare "4/4" told a player nothing. Each stat now carries its name, its
   value and one line on why it matters. Power and Guard are marked because
   they are the two that decide duels and the two people misread. */
.passport-statkey{
  margin-block-start: var(--sp-2); text-align: center;
  font-size: var(--fs-2xs); letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-faint);
}

.stat-rows{ display: flex; flex-direction: column; margin-block-start: var(--sp-3); }
.stat-row{ padding: var(--sp-3) 0; }
.stat-row + .stat-row{ border-top: 1px solid var(--hairline); }
.stat-row-head{ display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }
.stat-row-label{
  font-size: var(--fs-2xs); letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 700;
}
.stat-row-value{ font-size: var(--fs-lg); font-weight: 800; color: var(--ink); }
.stat-row-hint{ margin-block-start: var(--sp-1); font-size: var(--fs-xs); color: var(--ink-dim); line-height: var(--lh-normal); }
.stat-row-key .stat-row-label{ color: var(--gold); }
.stat-row-key .stat-row-value{ color: var(--gold-bright); }

.keyword-rows{ display: flex; flex-direction: column; gap: var(--sp-3); margin-block-start: var(--sp-3); }
.keyword-row{
  padding: var(--sp-3); border-radius: var(--radius-md);
  background: var(--bg-2); border-inline-start: 3px solid var(--gold-dim);
}
.keyword-name{ display: block; font-weight: 800; font-size: var(--fs-md); color: var(--gold-bright); }
.keyword-desc{ margin-block-start: var(--sp-1); font-size: var(--fs-xs); color: var(--ink-dim); line-height: var(--lh-normal); }

/* A cleared rung gets its own banner on the results screen, or the ladder
   advances invisibly and the climb has no payoff. */
.tier-record{
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4); border-radius: var(--radius-md);
  background: linear-gradient(120deg, #d4a24e22, transparent);
  border: 1px solid var(--gold-dim);
}
.tier-record-badge{
  flex: none; inline-size: 44px; block-size: 44px;
  display: grid; place-items: center; border-radius: var(--radius-md);
  background: linear-gradient(135deg, var(--gold-dim), var(--gold));
  color: var(--gold-ink); font-size: var(--fs-lg); font-weight: 800;
}
.tier-record strong{ display: block; font-size: var(--fs-md); }
.tier-record .dim{ font-size: var(--fs-xs); }

/* ---- duel setup: rival roster + difficulty ladder ---------------------- */
/* The Play screen is a flex column and had no gap, so every child sat flush
   against the next one: the daily card touched the climb card, and "Choose
   your rival" started immediately under it with nothing between. A column of
   cards with no space between them reads as one object, not three choices. */
.setup-screen{ padding-bottom: var(--sp-8); gap: var(--sp-4); }
/* A heading opens a new section, so it gets more room above it than the items
   inside a section get between them. */
.setup-screen .section-title{ margin-block-start: var(--sp-6); }
.setup-screen .onboarding-body{ margin-top: 0; }
.setup-screen .pick-grid{ margin-top: var(--sp-2); }
.setup-screen .tier-rail{ margin-top: var(--sp-2); }
.setup-screen .onboarding-actions{ margin-top: var(--sp-4); }
.setup-heading{
  font-size: var(--fs-lg); font-weight: 800; margin-block-start: var(--sp-8);
  letter-spacing: .02em;
}
.setup-note{ font-size: var(--fs-xs); margin-block-start: var(--sp-2); }

/* The ladder reads as a row of rungs, so how far you have climbed is a
   glance rather than a number you have to interpret. */
.tier-rail{
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  margin-block-start: var(--sp-3);
}
.tier-dot{
  inline-size: 40px; block-size: 40px; flex: none;
  border-radius: var(--radius-md); border: 1px solid var(--hairline-hi);
  background: var(--bg-2); color: var(--ink-dim);
  font-family: var(--font-ui); font-size: var(--fs-sm); font-weight: 800;
  cursor: pointer; transition: transform var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.tier-dot:hover{ transform: translateY(-2px); border-color: var(--gold-dim); }
.tier-dot.selected{
  background: linear-gradient(135deg, var(--gold-dim), var(--gold));
  border-color: var(--gold-bright); color: var(--gold-ink);
  box-shadow: var(--glow-gold);
}

.chip-mute{ background: var(--bg-2); color: var(--ink-faint); border: 1px solid var(--hairline); }
.chip-gold{ background: #d4a24e22; color: var(--gold-bright); border: 1px solid var(--gold-dim); }
.pick-card-sm .chip{ margin-block-start: var(--sp-3); align-self: flex-start; }

.limit-row{ display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.limit-row .field{ flex: 1; min-width: 120px; }

/* ---- switches ----------------------------------------------------------
   The whole row is the hit target, not just the 52px pill. The knob moves on
   inset-inline-start rather than translateX so RTL flips it for free.        */
.switch-list{ display: flex; flex-direction: column; }
.switch-row{
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-2); border-radius: var(--radius-md);
  cursor: pointer; transition: background var(--dur-fast) var(--ease-out);
}
.switch-row:hover{ background: #ffffff08; }
.switch-row + .switch-row{ border-top: 1px solid var(--hairline); }

.switch-text{ display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.switch-text strong{ font-size: var(--fs-md); font-weight: 700; }
.switch-text .muted{ font-size: var(--fs-xs); }

.switch{ position: relative; flex: none; inline-size: 52px; block-size: 30px; }
/* The track stays 30px because that is what a switch should look like. The
   invisible input reaches past it to 44px, so what a thumb has to find is
   bigger than what the eye has to read. .switch is overflow-visible, so the
   extra reach is real and not clipped away by the parent. */
.switch-input{ position: absolute; inset: -7px 0; margin: 0; opacity: 0; cursor: pointer; z-index: 1; }
.switch-track{
  position: absolute; inset: 0; border-radius: var(--radius-pill);
  background: var(--bg-2); border: 1px solid var(--hairline-hi);
  transition: background var(--dur-med) var(--ease-out), border-color var(--dur-med) var(--ease-out);
}
.switch-track::after{
  content: ""; position: absolute; inset-block-start: 3px; inset-inline-start: 3px;
  inline-size: 22px; block-size: 22px; border-radius: 50%;
  background: var(--ink-faint); box-shadow: var(--shadow-sm);
  transition: inset-inline-start var(--dur-med) var(--ease-spring),
              background var(--dur-med) var(--ease-out);
}
.switch-input:checked + .switch-track{
  background: linear-gradient(135deg, var(--gold-dim), var(--gold));
  border-color: var(--gold-bright);
}
.switch-input:checked + .switch-track::after{ inset-inline-start: 25px; background: var(--gold-ink); }
.switch-input:focus-visible + .switch-track{ box-shadow: var(--glow-gold); }

.owned-grid{ display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.owned-chip{
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  background: var(--panel-hi); border: 1px solid var(--gold-dim); font-size: var(--fs-sm); font-weight: 700;
}
.owned-date{ font-size: var(--fs-2xs); font-weight: 500; }

.ledger-list{ display: flex; flex-direction: column; gap: var(--sp-2); }
.ledger-row{
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  background: var(--panel-hi); border-inline-start: 3px solid var(--hairline-hi);
}
.ledger-row.status-paid{ border-inline-start-color: var(--tide); }
.ledger-row.status-failed, .ledger-row.status-expired{ border-inline-start-color: var(--ember); }
.ledger-main{ display: flex; flex-direction: column; min-width: 0; }
.ledger-title{ font-weight: 700; font-size: var(--fs-sm); }
/* A timestamp is one long unbreakable-looking run of text in a flex row that
   also holds an amount. At 360px it overflowed its own box and the last few
   characters were cut with nothing to say they had been. `.ledger-main` is
   already min-width:0, so the fix is to let this line wrap into the space the
   row has rather than insisting on one line it cannot have. */
.ledger-sub{
  font-size: var(--fs-2xs);
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.35;
}
.ledger-right{ display: flex; align-items: center; gap: var(--sp-3); flex: none; }
.ledger-delta{ font-weight: 800; }
.ledger-delta.pos{ color: var(--tide-glow); }
.ledger-delta.neg{ color: var(--ember-glow); }
.order-status{
  font-size: var(--fs-2xs); font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  padding: 2px var(--sp-2); border-radius: var(--radius-pill); background: var(--panel-solid);
}
.order-status.s-paid{ color: var(--tide-glow); }
.order-status.s-failed, .order-status.s-expired{ color: var(--ember-glow); }
.order-status.s-created, .order-status.s-processing{ color: var(--ink-faint); }

.store-balance{
  display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-4);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-pill);
  background: #d4a24e14; border: 1px solid var(--gold-dim); width: fit-content;
}
.store-balance strong{ font-size: var(--fs-lg); color: var(--gold-bright); }
.offer-card.is-owned{ opacity: .72; border-color: var(--tide); }
.owned-flag{ color: var(--tide-glow); border-color: var(--tide); cursor: default; }

/* ==========================================================================
   rules / how to play
   ========================================================================== */
.rules-screen{
  max-width: 760px; margin-inline: auto; padding-block: var(--sp-6) var(--sp-16);
  display: flex; flex-direction: column; gap: var(--sp-6);
}
.rules-section{
  padding: var(--sp-5) var(--sp-6); border-radius: var(--radius-lg);
  background: var(--panel); border: 1px solid var(--hairline-hi);
}
.rules-h{
  font-size: var(--fs-xl); font-weight: 900; margin-bottom: var(--sp-3);
  display: flex; align-items: center; gap: var(--sp-2);
}
.rules-h::before{
  content: ""; width: 4px; height: 18px; border-radius: 2px; flex: none;
  background: linear-gradient(180deg, var(--gold-bright), var(--gold));
}
.rules-section p{ color: var(--ink-dim); line-height: var(--lh-normal); }
.rules-lead{ margin-bottom: var(--sp-4); }
.rules-note{ margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--gold-bright); }

.rules-goal{ display: flex; flex-direction: column; gap: var(--sp-3); }
.rules-goal-pill{
  display: inline-flex; align-items: center; gap: var(--sp-2); width: fit-content;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-pill);
  background: #d4a24e1f; border: 1px solid var(--gold-dim);
  color: var(--gold-bright); font-weight: 800;
}

.rules-steps{ display: flex; flex-direction: column; gap: var(--sp-3); counter-reset: none; }
.rules-step{ display: flex; gap: var(--sp-3); align-items: flex-start; }
.rules-step-n{
  flex: none; width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center; font-size: var(--fs-sm); font-weight: 900;
  background: var(--panel-hi); border: 1px solid var(--gold-dim); color: var(--gold-bright);
}
.rules-step strong{ display: block; }
.rules-step p{ font-size: var(--fs-sm); margin-top: 2px; }

.rules-board{ display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); margin-bottom: var(--sp-4); direction: ltr; }
.rules-lane{
  min-height: 66px; border-radius: var(--radius-md); display: grid; place-items: center;
  background: var(--panel-hi); border: 1px solid var(--hairline-hi);
  font-size: var(--fs-2xs); font-weight: 800; text-transform: uppercase;
  letter-spacing: .05em; color: var(--ink-faint); text-align: center; padding: var(--sp-2);
}
.rules-lane.is-throne{
  background: linear-gradient(180deg, #d4a24e26, var(--panel-hi));
  border-color: var(--gold-dim); color: var(--gold-bright);
}

.rules-energy{ display: flex; gap: var(--sp-2); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.rules-pip{
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  display: grid; place-items: center; font-weight: 900; font-size: var(--fs-sm);
  background: linear-gradient(180deg, var(--gold-bright), var(--gold)); color: var(--gold-ink);
}

.rules-types{ display: flex; flex-direction: column; gap: var(--sp-4); }
.rules-type{ display: flex; gap: var(--sp-4); align-items: center; }
.rules-type-art{
  flex: none; width: 64px; height: 64px; border-radius: var(--radius-md);
  overflow: hidden; background: var(--bg-1); border: 1px solid var(--hairline-hi);
}
.rules-type-art img, .rules-type-art svg{ width: 100%; height: 100%; object-fit: cover; display: block; }
.rules-type strong{ display: block; color: var(--gold-bright); }
.rules-type p{ font-size: var(--fs-sm); margin-top: 2px; }

.rules-grid{ display: grid; grid-template-columns: 1fr; gap: var(--sp-3); }
@media (min-width: 640px){ .rules-grid{ grid-template-columns: repeat(2, 1fr); } }
.rules-card{
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-md);
  background: var(--panel-hi); border-inline-start: 3px solid var(--gold-dim);
}
.rules-card strong{ display: block; font-size: var(--fs-sm); }
.rules-card p{ font-size: var(--fs-xs); margin-top: 3px; }

.rules-list{ display: flex; flex-direction: column; gap: var(--sp-3); }
.rules-list li{ display: flex; gap: var(--sp-3); align-items: flex-start; color: var(--ink-dim); }
.rules-list svg{ width: 18px; height: 18px; flex: none; margin-top: 2px; color: var(--gold-bright); }

.rules-fair{ background: linear-gradient(100deg, #2fb6a521, transparent); border-color: var(--tide); }
.rules-fair .rules-h::before{ background: linear-gradient(180deg, var(--tide-glow), var(--tide)); }
.rules-cta{ margin-top: var(--sp-2); }

/* Keep the five mobile destinations inside the smallest supported phone. */
@media (max-width: 420px){
  .tab-link{ min-width: 0; padding-inline: 1px; font-size: 9.5px; }
}

/* ==========================================================================
   RTL - logical properties handle most of it automatically; targeted fixes:
   ========================================================================== */
[dir="rtl"] .icon-flip{ transform: scaleX(-1); }

/* ---- the climb ---------------------------------------------------------
   The map reads bottom to top because that is the direction the word
   implies. Open nodes glow, the current one is ringed, spent ones recede. */
.run-screen{ display: flex; flex-direction: column; gap: var(--sp-4); padding-bottom: var(--sp-8); }
.run-hint{ font-size: var(--fs-sm); }

.run-header{ display: flex; align-items: center; gap: var(--sp-6); flex-wrap: wrap; }
.run-vigour{ flex: 1; min-width: 200px; }
.run-vigour-head{ display: flex; align-items: baseline; justify-content: space-between; }
.run-stat-label{ font-size: var(--fs-2xs); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); font-weight: 700; }
.run-stat-value{ font-size: var(--fs-lg); font-weight: 800; color: var(--ink); }
.run-vigour-bar{ margin-block-start: var(--sp-2); block-size: 10px; border-radius: var(--radius-pill); background: var(--bg-0); border: 1px solid var(--hairline-hi); overflow: hidden; }
.run-vigour-fill{ display: block; block-size: 100%; background: linear-gradient(90deg, var(--ember), var(--gold-bright)); transition: width var(--dur-med) var(--ease-out); }
.run-vigour-note{ margin-block-start: var(--sp-2); font-size: var(--fs-xs); color: var(--ink-dim); }
.run-tallies{ display: flex; gap: var(--sp-5); }
.run-tally{ display: flex; flex-direction: column; align-items: center; }

.run-map{ display: flex; flex-direction: column; gap: var(--sp-2); }
.map-floor{ display: flex; align-items: center; gap: var(--sp-3); }
/* ink-faint, not ink-mute. The floor number is a label a player reads to
   find themselves on the map, and ink-mute measures 3.09:1 against the
   ground it sits on. ink-mute stays in the palette for decoration and
   disabled states, where nothing has to be legible. */
.map-floor-num{ inline-size: 24px; text-align: end; font-size: var(--fs-2xs); color: var(--ink-faint); flex: none; }
.map-floor-nodes{ display: flex; gap: var(--sp-3); flex: 1; }
.map-node{
  flex: 1; display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 52px; padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md); border: 1px solid var(--hairline);
  /* ink-faint rather than ink-mute. A locked node is exempt from the
     contrast rule because it is an inactive control, but a map exists to
     be planned against and a boss you can see and cannot read is not
     doing its job. Reachable nodes go to full ink, so the difference
     still carries the affordance. */
  background: var(--bg-1); color: var(--ink-faint); font-weight: 800; font-size: var(--fs-xs);
  cursor: not-allowed; transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast);
}
.map-node svg{ width: 18px; height: 18px; }
.map-node.done{ opacity: .45; }
.map-node.open{ cursor: pointer; color: var(--ink); border-color: var(--gold-dim); background: var(--panel-solid); }
.map-node.open:hover{ transform: translateY(-2px); border-color: var(--gold); }
.map-node.here{ border-color: var(--gold-bright); color: var(--gold-bright); box-shadow: var(--glow-gold); }
.map-node.kind-elite.open{ border-color: var(--ember); color: var(--ember-glow); }
.map-node.kind-boss.open{ border-color: var(--ember-glow); color: var(--ember-glow); box-shadow: 0 0 20px -6px var(--ember); }
.map-node.kind-rest.open{ border-color: var(--tide); color: var(--tide-glow); }

.reward-grid{ display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.reward-card{
  flex: 1; min-width: 150px; display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--radius-lg);
  background: var(--panel-solid); border: 1px solid var(--hairline-hi); cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast);
}
.reward-card:hover{ transform: translateY(-4px); border-color: var(--gold); }
.reward-card-art{ inline-size: 100%; aspect-ratio: 1; border-radius: var(--radius-md); overflow: hidden; }
.reward-card-cost{ position: absolute; }
.reward-card-name{ font-weight: 800; text-align: center; }
.reward-card-stats{ font-size: var(--fs-xs); color: var(--ink-dim); font-weight: 700; }

.relic-grid{ display: flex; flex-direction: column; gap: var(--sp-3); }
.reward-relic{
  text-align: start; padding: var(--sp-4); border-radius: var(--radius-md);
  background: var(--panel-solid); border-inline-start: 3px solid var(--gold); border-block: 1px solid var(--hairline);
  border-inline-end: 1px solid var(--hairline); cursor: pointer;
}
.reward-relic:hover{ background: var(--panel-hi); }
.reward-relic strong{ display: block; color: var(--gold-bright); font-size: var(--fs-md); }
.reward-relic p{ margin-block-start: var(--sp-1); font-size: var(--fs-xs); }
.relic-row{ display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.relic-chip{ padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--bg-2); border: 1px solid var(--gold-dim); max-inline-size: 260px; }
.relic-chip strong{ display: block; font-size: var(--fs-sm); color: var(--gold-bright); }
.relic-chip .dim{ font-size: var(--fs-2xs); }

.rest-choices{ display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.rest-choice{
  flex: 1; min-width: 200px; text-align: start; padding: var(--sp-5);
  border-radius: var(--radius-lg); background: var(--panel-solid);
  border: 1px solid var(--hairline-hi); cursor: pointer;
}
.rest-choice:hover{ border-color: var(--gold); background: var(--panel-hi); }
.rest-choice strong{ display: block; font-size: var(--fs-lg); }
.rest-choice .dim{ font-size: var(--fs-xs); }
.rest-deck{ display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.rest-card{
  display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md); background: var(--bg-2); border: 1px solid var(--hairline);
  font-size: var(--fs-sm); font-weight: 700; cursor: pointer;
}
.rest-card:hover{ border-color: var(--ember); color: var(--ember-glow); }

.run-start-card{ display: flex; align-items: center; gap: var(--sp-4); }
.run-start-art{ inline-size: 84px; block-size: 84px; border-radius: var(--radius-md); object-fit: cover; flex: none; }

/* The door into the climb, on the screen players already open to play. */
.run-entry{
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  inline-size: 100%; text-align: start; padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius-lg); cursor: pointer;
  background: linear-gradient(120deg, #d4a24e22, var(--panel-solid));
  border: 1px solid var(--gold-dim);
  transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast);
}
.run-entry:hover{ transform: translateY(-2px); border-color: var(--gold); }
.run-entry strong{ display: block; font-size: var(--fs-lg); color: var(--gold-bright); }
.run-entry .dim{ font-size: var(--fs-xs); }
.run-entry svg{ width: 26px; height: 26px; color: var(--gold); flex: none; }

/* The selection prompt reuses the tutorial banner, minus the step counter. */
.tutorial-guidance.select-hint{ background: #d4a24e14; border-color: var(--gold-dim); }

/* Rarity key on the how-to-play page: the same four colours the card frames
   use, named, so the encoding is legible instead of guessable. */
.rarity-key{ display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-block-start: var(--sp-3); }
.rarity-chip{
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill);
  background: var(--bg-2); border: 1px solid var(--hairline);
  font-size: var(--fs-xs); font-weight: 700; color: var(--ink-dim);
}
.rarity-swatch{ inline-size: 12px; block-size: 12px; border-radius: 3px; border: 2px solid currentColor; }
.rarity-chip.rarity-common .rarity-swatch{ color: var(--rarity-common); }
.rarity-chip.rarity-rare .rarity-swatch{ color: var(--rarity-rare); }
.rarity-chip.rarity-epic .rarity-swatch{ color: var(--rarity-epic); }
.rarity-chip.rarity-legendary .rarity-swatch{ color: var(--rarity-legendary); }

/* A toast that asks for something gets a control, so the player is not told
   to reload and then left to find their own refresh button. */
.toast.toast-action{ display: flex; align-items: center; gap: var(--sp-3); }
.toast-btn{
  flex: none; padding: 4px var(--sp-3); border-radius: var(--radius-pill);
  background: var(--gold); color: var(--gold-ink);
  font-size: var(--fs-xs); font-weight: 800; cursor: pointer;
}
.toast-btn:hover{ background: var(--gold-bright); }

/* ==========================================================================
   rules: common questions
   ========================================================================== */
.faq-list{ display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-4); }
.faq-item{
  border: 1px solid var(--hairline-hi); border-radius: var(--radius-md);
  background: var(--panel); overflow: hidden;
}
.faq-item[open]{ border-color: var(--gold-dim); background: linear-gradient(180deg, #d4a24e10, var(--panel)); }
.faq-q{
  cursor: pointer; list-style: none; padding: var(--sp-3) var(--sp-4);
  min-height: 48px; display: flex; align-items: center; gap: var(--sp-3);
  font-weight: 800; font-size: var(--fs-sm); color: var(--ink);
}
.faq-q::-webkit-details-marker{ display: none; }
/* The chevron is drawn rather than typed so it turns with the panel and mirrors
   with the language, which a literal arrow character does neither of. */
.faq-q::after{
  content: ""; margin-inline-start: auto; flex: none;
  width: 9px; height: 9px; border-inline-end: 2px solid var(--gold); border-block-end: 2px solid var(--gold);
  transform: rotate(45deg); transition: transform var(--dur-fast) var(--ease-out);
}
.faq-item[open] .faq-q::after{ transform: rotate(-135deg); }
.faq-a{
  padding: 0 var(--sp-4) var(--sp-4); font-size: var(--fs-sm);
  color: var(--ink-dim); line-height: var(--lh-relaxed, 1.6);
}

/* ==========================================================================
   card market
   ========================================================================== */
.market-section{ margin-top: var(--sp-10); }
.market-heading{
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
}
.market-count{ margin-top: var(--sp-3); font-size: var(--fs-xs); }
.market-grid{
  margin-top: var(--sp-4);
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
}
.market-card{
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-3); border-radius: var(--radius-md);
  background: var(--panel-solid); border: 1.5px solid var(--hairline-hi);
  /* The frame is the rarity, the same language the hand uses, so a shelf and a
     hand are read the same way rather than each having its own vocabulary. */
}
.market-card.rarity-common{ border-color: var(--rarity-common); }
.market-card.rarity-rare{ border-color: var(--rarity-rare); }
.market-card.rarity-epic{ border-color: var(--rarity-epic); }
.market-card.rarity-legendary{ border-color: var(--rarity-legendary); box-shadow: 0 0 0 1px #f2c57233; }
.market-art{
  width: 100%; aspect-ratio: 1 / 1; overflow: hidden;
  border-radius: calc(var(--radius-md) - 4px);
  background: radial-gradient(circle at 50% 20%, #ffffff12, transparent 55%), var(--bg-1);
  border: 1px solid var(--hairline);
}
.market-art svg, .market-art img{ width: 100%; height: 100%; display: block; }
.market-body{ display: flex; flex-direction: column; gap: 5px; align-items: flex-start; }
/* Two lines always, whether the name needs them or not. A one-line name used
   to pull its rarity chip and both prices up, so a row of cards had its numbers
   at three different heights and could not be compared at a glance, which is
   the only thing a shelf of prices is for. Same reason the hand cards do it. */
.market-name{
  font-size: var(--fs-sm); font-weight: 800; line-height: var(--lh-snug);
  min-height: calc(2em * var(--lh-snug));
  min-height: 2lh;
}
.market-prices{ margin-top: auto; display: grid; gap: 5px; }
/* Disabled and looking it. A control that reads as live and refuses the tap is
   worse than one that never invited it. */
.market-prices .btn{
  justify-content: space-between; gap: var(--sp-2);
  padding-inline: var(--sp-3); min-height: 36px; font-size: var(--fs-xs);
  opacity: .55; cursor: not-allowed;
}
.market-prices .btn strong{ color: var(--gold-bright); }
.market-buy strong::after{ content: " ◈"; opacity: .8; }
.market-rent strong::after{ content: " ◈"; opacity: .8; }
.market-edition{ font-size: var(--fs-2xs); font-weight: 700; color: var(--gold); letter-spacing: .04em; }

/* Editions are treatments of the card's own illustration, not four different
   pictures of it. That is the point: the same fighter in a different dress
   reads as the same card, where four unrelated images would read as four
   cards. It also means the shelf needs no art that does not already exist. */
.market-card[data-edition="sunfast"] .market-art img{
  filter: sepia(.32) saturate(1.15) brightness(1.08) contrast(.96);
}
.market-card[data-edition="sunfast"] .market-art{
  box-shadow: inset 0 0 0 1px #f2c57259, inset 0 -28px 30px -26px #f2c572aa;
}
.market-card[data-edition="nightmarked"] .market-art img{
  filter: brightness(.62) contrast(1.18) saturate(.85);
}
.market-card[data-edition="nightmarked"] .market-art{
  position: relative;
  box-shadow: inset 0 0 0 1px #8fa6d64d, inset 0 0 34px -6px #2fb6a566;
}
.market-card[data-edition="gilded"] .market-art img{
  filter: sepia(.55) saturate(1.5) brightness(1.06) hue-rotate(-8deg);
}
.market-card[data-edition="gilded"] .market-art{
  box-shadow: inset 0 0 0 2px #f2c572, inset 0 0 30px -8px #f2c572cc;
}
/* Once an edition has a painting of its own, the colour treatment comes off:
   the picture already is the treatment, and leaving the filter on would apply
   it twice. The frame stays, because that is the part that says which edition
   this is at a glance. */
.market-card.painted .market-art img{ filter: none; }

/* ==========================================================================
   account: the reasons, stated where the decision gets made
   ========================================================================== */
.account-why h3{ font-size: var(--fs-md); font-weight: 800; }
.why-list{ margin-top: var(--sp-3); display: flex; flex-direction: column; gap: 7px; }
.why-list li{
  position: relative; padding-inline-start: 22px;
  font-size: var(--fs-sm); color: var(--ink-dim); line-height: var(--lh-snug);
}
/* The list marker is drawn rather than typed, so it mirrors with the language
   and matches the Mark shape the rest of the game uses. */
.why-list li::before{
  content: ""; position: absolute; inset-inline-start: 3px; top: .55em;
  width: 7px; height: 7px; border-radius: 2px;
  transform: translateY(-50%) rotate(45deg);
  background: var(--gold);
}
.account-why + .auth-form{
  margin-top: var(--sp-5); padding-top: var(--sp-5);
  border-top: 1px solid var(--hairline);
}

/* ==========================================================================
   touch targets, measured at 390px
   ==========================================================================
   The sound button was 40x40, the account button 36x40 and the patron
   disclosure 121x35. All close, none of them 44, and the first two live in the
   header where they are pressed most often. Min-height and min-width only, so
   nothing moves; the boxes just stop being smaller than a fingertip. */
.shell-header .sound-btn,
.shell-header .account-btn{ min-width: 44px; min-height: 44px; }
.patron-details{ min-height: 44px; }

/* The Trial a Mark came from, lit as the Mark lands. The rail used to exist
   only while planning, so winning one was announced by a pip in the header and
   nothing said which of the three had been won. */
.resolve-trials{ margin-bottom: var(--sp-2); }
.trial-chip.just-claimed{ animation: trial-won 900ms var(--ease-out); }
@keyframes trial-won{
  0%{ box-shadow: inset 0 0 0 0 #f2c57200; transform: none; }
  22%{ box-shadow: inset 0 0 0 2px #f2c572, inset 0 0 26px -4px #f2c5726b; transform: translateY(-2px); }
  100%{ box-shadow: inset 0 0 0 0 #f2c57200; transform: none; }
}

/* ---------------------------------------------------------------- floor conditions
   A condition bends a rule the player already knows, so it is stated in the
   same places the ordinary rules are: on the map node while choosing a route,
   and beside the round counter once the duel has started. Colour carries the
   direction, but never alone; the name and the sentence say it too. */
.map-node-cond{
  /* Two lines rather than one with an ellipsis. "A War of Blo..." and "A War
     of Craft" truncate to the same thing, and the whole point of putting the
     condition on the map is that the player can tell the routes apart. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  margin-top: 2px; overflow: hidden;
  font-size: var(--fs-2xs); font-weight: 700;
  letter-spacing: .02em; line-height: 1.15;
  max-width: 100%; text-wrap: balance;
}
.map-node.has-condition{ border-color: var(--hairline-hi); }
/* --ember-glow, not --ember. These labels are 11px at weight 700, which counts
   as small text, and small text needs 4.5:1. Ember measures 4.32 against the
   panel and 3.78 against the raised panel, so the one label a player most
   needs to read (this floor is going to hurt) was the one that failed. The
   glow is 6.84 and 6.00 on the same two grounds. */
.favour-up{ color: var(--tide); }
.favour-down{ color: var(--ember-glow); }
.favour-even{ color: var(--gold); }

.condition-strip{
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  margin-top: var(--sp-2); padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: var(--panel);
}
.condition-strip .condition-label{
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-faint);
}
.condition-strip .condition-name{ font-size: var(--fs-sm); font-weight: 800; }
.condition-strip .condition-desc{ font-size: var(--fs-xs); color: var(--ink-dim); }
.condition-strip.favour-up .condition-name{ color: var(--tide); }
.condition-strip.favour-down .condition-name{ color: var(--ember-glow); }
.condition-strip.favour-even .condition-name{ color: var(--gold); }

/* ---------------------------------------------------------------- daily duel
   Sits above the climb because it is the only thing on the screen that
   expires. The streak replaces the play chevron once there is one, so the
   number is the thing you see rather than a decoration beside it. */
.daily-entry .daily-cond{
  display: block; margin-top: 2px;
  font-size: var(--fs-2xs); font-weight: 700;
  letter-spacing: .04em; color: var(--gold);
}
.daily-entry.daily-done{ opacity: .72; }
.daily-streak{ display: flex; flex-direction: column; align-items: center; line-height: 1; }
.daily-streak-n{
  font-size: var(--fs-2xl); font-weight: 900; color: var(--gold-bright);
}
.daily-streak-label{
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-faint); margin-top: 2px;
}

/* ------------------------------------------------------------ seasonal front
   Four alliances share the map, so the bar shows four shares rather than a
   single you-versus-them fill. Colour identifies the alliance, but the numbers
   underneath say the same thing for anyone who cannot use the colour. */
.front-bar-stacked{ display: flex; overflow: hidden; }
.front-seg{ height: 100%; min-width: 2px; }
.front-seg-mine{ box-shadow: inset 0 0 0 1px var(--ink); }
.front-seg-empty{ width: 100%; background: var(--hairline); }
.front-row-foot{ margin-top: var(--sp-1); font-size: var(--fs-2xs); }
.front-row-today{
  border-inline-start: 2px solid var(--gold);
  padding-inline-start: var(--sp-2);
}
.front-today-tag{
  margin-inline-start: var(--sp-2);
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--gold);
}
.status-quiet{ color: var(--ink-faint); }

/* ------------------------------------------------------------------- ghosts
   The first thing in the Hall that somebody else made. Marked with the gold
   hairline the rest of the game uses for "this matters", not with a spooky
   treatment: a ghost is another player, not a special effect. */
.ghost-panel{ border-color: var(--hairline-hi); }
.ghost-panel .btn{ margin-top: var(--sp-3); }
.ghost-panel .muted{ margin-top: var(--sp-3); font-size: var(--fs-xs); }

/* ------------------------------------------------- board tokens, readable
   A token used to read "3/2" with the card name in a title attribute, which a
   phone never shows. Two numbers and a slash do not say which is which. The
   card already teaches a bolt for Power and a shield for Guard, so the board
   says it the same way. */
.unit-token{ gap: 5px; padding-inline: 5px; min-width: 44px; }
.tok-stat{ display: inline-flex; align-items: center; gap: 1px; line-height: 1; }
.tok-stat svg{ width: 9px; height: 9px; opacity: .78; }
/* A damaged unit shows it, rather than only reading lower than it started. */
.unit-token.hurt{ box-shadow: inset 0 0 0 1.5px #2a0f08aa; }
.unit-token.hurt .tok-stat:last-child{ font-weight: 900; }

/* ------------------------------------------------ round report: tip + hits
   The tip is advice about the round just played, so it sits under the list it
   is about, quieter than the events but not hidden. */
.report-tip{
  display: flex; gap: var(--sp-2); align-items: baseline;
  margin-block-start: var(--sp-3); padding-block-start: var(--sp-3);
  border-top: 1px solid var(--hairline);
  font-size: var(--fs-xs); line-height: var(--lh-normal); color: var(--ink-dim);
  animation: report-in var(--dur-med) var(--ease-out) backwards;
  animation-delay: var(--in-delay, 0ms);
}
.report-tip-label{
  flex: none; font-size: var(--fs-2xs); font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--gold);
}
/* A hit on your own Champion is the one line in the report that is about you
   losing something that is not a card, so it reads in the damage colour. */
.report-line.hit .report-line-title{ color: var(--ember-glow); font-weight: 900; }

/* --------------------------------------------- labels that must not clip
   Two overflows the new clipped-text check found, both invisible until
   something measured them.

   A clamped label inside a centred flex row inherits the centring, and a
   centred nowrap line puts the ellipsis at the end while the START spills out
   too, so the marker sits on the wrong side of the missing text. Aligning the
   label to the start makes the ellipsis mean what it looks like it means. */
.pill-btn span{ text-align: start; }
@media (max-width: 767px){
  /* 64px cut "Cinder Strike" by three pixels, which is exactly the width that
     looks like a rendering fault rather than a truncation. */
  .pill-btn span{ max-width: 92px; }
}

/* The lock button carries a label and a count and used to size for English.
   Arabic "قفل الاختيار" plus the count is 164px in a 140px button, so the
   count was riding on top of the last letter. The label shrinks, the count
   never does: the number is the part you cannot infer. */
.lock-btn{ gap: var(--sp-2); }
.lock-label{
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-align: start;
}
.lock-btn .timer-badge{ flex: none; }

/* ========================================================================
   autonomous appearance sets
   ======================================================================== */

/* Chronicle frames live inside the art box rather than changing card
   dimensions. A frame therefore cannot push a hand rail, Store shelf, or
   passport beyond its measured width. */
.card-visual-frame{
  --frame-a: var(--gold-bright); --frame-b: var(--gold-dim);
  position: relative; display: block; width: 100%; height: 100%;
  border-radius: inherit; overflow: hidden;
  box-shadow: inset 0 0 0 2px var(--frame-a), inset 0 0 0 5px #07080fb8;
}
.card-visual-frame::after{
  content: ""; position: absolute; inset: 4px; border: 1px solid var(--frame-b);
  border-radius: 5px; clip-path: var(--cut-sm); pointer-events: none;
  box-shadow: inset 0 0 18px #0008;
}
.card-visual-frame > img, .card-visual-frame > svg{ width: 100%; height: 100%; display: block; }
.frame-chronicle_ember{ --frame-a: #ffb077; --frame-b: #d44a25; }
.frame-chronicle_tide{ --frame-a: #78eadc; --frame-b: #238f89; }
.frame-chronicle_gale{ --frame-a: #d5defd; --frame-b: #7d8fc9; }
.frame-chronicle_stone{ --frame-a: #d6dda9; --frame-b: #788951; }

.faction-banner{
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 86px; height: 112px; color: var(--banner-glow);
  background: linear-gradient(145deg, var(--banner-base), var(--banner-dark) 68%);
  border: 1px solid var(--banner-glow); clip-path: polygon(0 0,100% 0,100% 82%,50% 100%,0 82%);
  box-shadow: inset 0 0 0 5px #07080f99, 0 12px 28px -14px var(--banner-base);
}
.faction-banner::before{ content: ""; position: absolute; inset: 8px 8px 24px; border: 1px solid currentColor; opacity: .55; }
.faction-banner-mark{ font-size: 2rem; text-shadow: 0 0 14px var(--banner-glow); }
.faction-banner.is-compact{ width: 34px; height: 46px; }
.faction-banner.is-compact .faction-banner-mark{ font-size: 1rem; }
.faction-banner.is-compact::before{ inset: 4px 4px 10px; }
.faction-card-back{ display: block; filter: drop-shadow(0 6px 7px #0008); }

/* Atelier */
.atelier-screen{
  max-width: 900px; margin-inline: auto; padding-block: var(--sp-6) var(--sp-16);
  display: flex; flex-direction: column; gap: var(--sp-4);
}
.atelier-head, .atelier-section-head{ display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.atelier-preview{
  min-height: 230px; padding: var(--sp-6); position: relative; overflow: hidden;
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-6); align-items: center;
  background: radial-gradient(circle at 24% 34%, #d4a24e22, transparent 34%), var(--panel);
}
.atelier-preview-card{ width: 150px; height: 150px; border-radius: var(--radius-md); overflow: hidden; z-index: 2; }
.atelier-preview-copy{ display: flex; flex-direction: column; gap: var(--sp-1); }
.atelier-preview-copy strong{ font-size: var(--fs-xl); }
.atelier-preview-banner{ position: absolute; top: -6px; inset-inline-end: 28px; opacity: .7; }
.atelier-preview-emblem{ position: absolute; inset-inline-start: 134px; bottom: 18px; width: 92px; height: 92px; filter: drop-shadow(0 5px 10px #000a); z-index: 3; }
.atelier-preview-back{ position: absolute; inset-inline-end: 128px; bottom: 18px; transform: rotate(7deg); opacity: .8; }
.atelier-options{ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); margin-top: var(--sp-2); }
.atelier-option{
  min-width: 0; min-height: 88px; padding: var(--sp-2); border-radius: var(--radius-md);
  display: flex; align-items: center; gap: var(--sp-3); text-align: start;
  color: var(--ink-dim); background: var(--bg-1); border: 1px solid var(--hairline-hi);
}
.atelier-option:hover, .atelier-option.is-selected{ color: var(--ink); border-color: var(--gold); background: #d4a24e12; }
.atelier-option.is-selected{ box-shadow: inset 0 0 0 1px var(--gold-dim); }
.atelier-option-visual{ flex: none; width: 64px; height: 64px; display: flex; align-items: center; justify-content: center; font-size: var(--fs-xl); }
.atelier-switch{
  min-height: 52px; display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3);
  background: var(--bg-1); border: 1px solid var(--hairline-hi); border-radius: var(--radius-md); font-weight: 800;
}
.atelier-switch input{ width: 32px; height: 32px; flex: none; accent-color: var(--gold); }
.atelier-decorations{ display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2); }
.atelier-decoration{
  min-height: 100px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-3); color: var(--ink-dim); background: var(--bg-1); border: 1px solid var(--hairline-hi); border-radius: var(--radius-md);
}
.atelier-decoration.is-selected{ color: var(--gold-bright); border-color: var(--gold); background: #d4a24e12; }
.decor-icon{ position: relative; display: block; width: 42px; height: 42px; }
.decor-lantern_pair::before, .decor-lantern_pair::after{ content: ""; position: absolute; top: 6px; width: 13px; height: 27px; border: 2px solid var(--gold); border-radius: 8px 8px 4px 4px; box-shadow: inset 0 0 10px #f2c572aa; }
.decor-lantern_pair::before{ left: 5px; }.decor-lantern_pair::after{ right: 5px; }
.decor-alliance_standard{ background: linear-gradient(145deg,var(--tide),#11263b); border: 2px solid var(--gold); clip-path: polygon(10% 0,90% 0,90% 78%,50% 100%,10% 78%); }
.decor-brass_astrolabe{ border: 2px solid var(--gold); border-radius: 50%; box-shadow: inset 0 0 0 7px #d4a24e22; }
.decor-brass_astrolabe::before, .decor-brass_astrolabe::after{ content: ""; position: absolute; background: var(--gold); left: 5px; right: 5px; height: 1px; top: 20px; }
.decor-brass_astrolabe::after{ transform: rotate(60deg); }

/* Hall ownership surfaces */
.hall-screen{ position: relative; }
.hall-screen > *:not(.hall-alcove-decor){ position: relative; z-index: 2; }
.hall-alcove::before{
  content: ""; position: absolute; z-index: 0; inset: 8px -34px 24px;
  border: 1px solid #d4a24e44; border-radius: 180px 180px var(--radius-xl) var(--radius-xl);
  background: radial-gradient(ellipse at 50% 4%, #d4a24e22, transparent 42%), linear-gradient(180deg,#1d1830cc,#0b0d17cc);
  pointer-events: none;
}
.hall-alcove-decor{ position: absolute; z-index: 1; inset: 0 -26px; pointer-events: none; }
.hall-decor{ position: absolute; display: block; }
.hall-decor.lantern-left, .hall-decor.lantern-right{ top: 98px; width: 22px; height: 38px; border: 2px solid var(--gold); border-radius: 12px 12px 5px 5px; box-shadow: 0 0 24px #f2c57288, inset 0 0 15px #f2c572aa; }
.hall-decor.lantern-left{ left: 5px; }.hall-decor.lantern-right{ right: 5px; }
.hall-decor.alliance-standard{ top: 22px; inset-inline-end: 44px; width: 58px; height: 92px; border: 1px solid var(--gold); clip-path: polygon(0 0,100% 0,100% 80%,50% 100%,0 80%); background: linear-gradient(150deg,var(--tide),#102b36); }
.hall-decor.standard-ember{ background: linear-gradient(150deg,var(--ember),#37150f); }
.hall-decor.standard-gale{ background: linear-gradient(150deg,var(--gale),#1b2345); }
.hall-decor.standard-stone{ background: linear-gradient(150deg,var(--stone),#28301b); }
.hall-decor.brass-astrolabe{ top: 360px; inset-inline-end: 12px; width: 70px; height: 70px; border: 2px solid var(--gold); border-radius: 50%; box-shadow: inset 0 0 0 12px #d4a24e1c; }
.hall-hero{ position: relative; overflow: hidden; flex-wrap: wrap; }
.hall-banner{ position: absolute; top: -6px; inset-inline-end: 24px; opacity: .55; }
.hall-emblem{ position: relative; }
.hall-profile-emblem{ position: absolute; width: 62px; height: 62px; inset-inline-end: -5px; bottom: -4px; filter: drop-shadow(0 4px 7px #000c); }
.hall-customize{ margin-inline-start: auto; z-index: 2; }

/* Smaller echoes keep the set visible outside its configuration screen. */
.account-identity{ display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.account-profile-emblem{ width: 58px; height: 58px; flex: none; }
.account-mini-banner{ flex: none; }
.account-appearance{ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.collection-deck-meta{ display: flex; align-items: center; gap: var(--sp-3); }
.collection-card-back{ width: 38px; height: 53px; }
.match-card-back{ flex: none; width: 28px; height: 39px; }
.match-screen{ position: relative; }
.faction-entrance{
  position: fixed; z-index: var(--z-overlay); inset: 0; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle,#12162add 0,#07080fcc 55%,transparent 78%);
  animation: faction-arrival 1150ms var(--ease-out) both;
}
.faction-entrance .faction-banner{ transform: scale(1.35); }
@keyframes faction-arrival{
  0%{ opacity: 0; transform: scale(.94); }
  18%,70%{ opacity: 1; transform: scale(1); }
  100%{ opacity: 0; transform: scale(1.03); }
}

@media (min-width: 700px){
  .atelier-options{ grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .atelier-option{ flex-direction: column; text-align: center; }
}
@media (max-width: 639px){
  .atelier-preview{ grid-template-columns: 118px 1fr; padding: var(--sp-4); gap: var(--sp-4); }
  .atelier-preview-card{ width: 118px; height: 118px; }
  .atelier-preview-emblem{ inset-inline-start: 98px; width: 70px; height: 70px; }
  .atelier-preview-back{ display: none; }
  .atelier-decorations{ grid-template-columns: 1fr; }
  .hall-alcove::before, .hall-alcove-decor{ inset-inline: 0; }
  .hall-banner{ inset-inline-end: 6px; opacity: .35; }
  .hall-customize{ width: 100%; }
  .account-id{ align-items: flex-start; }
  .account-mini-banner{ display: none; }
  .match-card-back{ display: none; }
}

/* ---------------------------------------------------------------- the Read
 *
 * Blueprint §8.2. Three lane buttons and two charge pips, sitting directly
 * above the lock button because the decision they belong to is the same one.
 * Sized to survive 360px in Arabic, where "الجناح الأيسر" is the widest label
 * in the game - hence the clamp on font-size and the min-height rather than a
 * fixed height, so a wrapped label grows the row instead of spilling out of it.
 */
.read-bar{
  border: 1px solid var(--hairline-hi);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--gale) 7%, transparent);
  padding: var(--sp-2);
  display: flex; flex-direction: column; gap: 6px;
}
.read-bar-head{ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.read-bar-label{
  font-family: var(--font-ui); font-weight: 800; font-size: var(--fs-xs);
  letter-spacing: .08em; text-transform: uppercase; color: var(--gale);
}
.read-charges{ display: inline-flex; gap: 4px; }
.read-pip{
  width: 8px; height: 8px; border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--gale) 55%, transparent);
  background: transparent;
}
.read-pip.lit{ background: var(--gale); }
/* Left is physically left in both languages, exactly as .board does it.
 * These three buttons ARE the board: a picker whose lanes run the other way
 * from the map above it asks the player to read one spatial model and click a
 * mirrored one. §22.2 draws this line explicitly - mirror the chrome, never
 * the coordinates. The label inside each button still reads in the page
 * direction, which is why the inner direction is restored. */
.read-lanes{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; direction: ltr; }
[dir="rtl"] .read-lane{ direction: rtl; }
.read-lane{
  min-height: 44px;                     /* §22.3 touch target */
  padding: 6px 4px;
  border: 1px solid var(--hairline-hi);
  border-radius: var(--radius-sm);
  background: var(--panel-solid);
  color: var(--ink-dim);
  font-family: var(--font-ui);
  font-size: clamp(11px, 3vw, var(--fs-xs));
  font-weight: 700;
  line-height: 1.15;
  cursor: pointer;
}
.read-lane:not(:disabled):hover{ border-color: var(--gale); color: var(--ink); }
.read-lane.picked{
  border-color: var(--gale);
  background: color-mix(in srgb, var(--gale) 22%, var(--panel));
  color: var(--ink);
  /* Never colour alone (§22.3): the picked lane also carries a mark. */
  box-shadow: inset 0 0 0 1px var(--gale);
}
.read-lane.picked::after{ content: " ◉"; }
.read-lane:disabled{ opacity: .45; cursor: not-allowed; }
.read-hint{ font-size: var(--fs-xs); line-height: 1.3; margin: 0; }

.report-line.read .report-line-title{ color: var(--gale); }
.report-thumb-glyph{
  display: grid; place-items: center;
  color: var(--gale); font-size: 20px;
}

/* ------------------------------------------------------- the Turning Point
 * §8.6. One sentence, given the weight of a heading rather than buried in a
 * stat list - it is the answer to the question a losing player actually has.
 */
.turning-point-line{
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.45;
  color: var(--ink);
}
.turning-point-line.dim{ color: var(--ink-dim); }

/* -------------------------------------------------- Climb v2 nodes (§11.2)
 *
 * Rumour, Rival Camp, Oath and Caravan. They share the run screen's panel
 * grammar rather than introducing four new ones: the map already teaches
 * "a bordered block is a choice", and a node that looks like nothing else in
 * the climb has to teach that again from scratch.
 */
.rumour-list{ display: flex; flex-direction: column; gap: var(--sp-2); }
.rumour-claim{
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); min-height: 44px;
  border-radius: var(--radius-md); background: var(--panel-solid);
  border: 1px solid var(--hairline-hi); text-align: start;
  font-size: var(--fs-sm); line-height: 1.4; color: var(--ink);
}
.rumour-claim.pick{ cursor: pointer; width: 100%; }
.rumour-claim.pick:hover{ border-color: var(--gold); background: var(--panel-hi); }
.rumour-verdict{
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 800; font-size: 13px;
  background: var(--hairline); color: var(--ink-dim);
}
/* The verdict glyph carries the answer as a shape, not only as a colour
   (§22.3), so a red/green blindness does not turn this node into a guess. */
.rumour-claim.is-false{ border-color: var(--ember); }
.rumour-claim.is-false .rumour-verdict{ background: var(--ember); color: #1a0d08; }
.rumour-claim.is-true .rumour-verdict{ background: var(--tide); color: #05201d; }
.rumour-claim.chosen{ box-shadow: 0 0 0 2px var(--gold-dim); }

.camp-tell strong{ display: block; font-size: var(--fs-lg); line-height: 1.35; }
.camp-tell .dim{ margin-top: var(--sp-2); font-size: var(--fs-xs); }

.oath-choice .oath-terms{
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-3); font-size: var(--fs-xs); color: var(--ink-dim);
}
.oath-choice .oath-reward{ color: var(--gold); font-weight: 700; }
.oath-outcome.kept{ border-inline-start: 3px solid var(--tide); }
.oath-outcome.broken{ border-inline-start: 3px solid var(--ember); }
.run-oath-strip{
  display: flex; align-items: center; gap: var(--sp-2);
  margin: var(--sp-3) 0 0; padding-top: var(--sp-3);
  border-top: 1px solid var(--hairline);
  font-size: var(--fs-xs); color: var(--gold);
}
.run-oath-strip svg{ width: 15px; height: 15px; flex: none; }

/* The four new map nodes need to be told apart at a glance from ten metres of
   scrolled map, so each gets its own accent rather than sharing the neutral. */
.map-node.kind-rumour{ border-color: color-mix(in srgb, var(--gale) 45%, var(--hairline-hi)); }
.map-node.kind-rivalCamp{ border-color: color-mix(in srgb, var(--tide) 45%, var(--hairline-hi)); }
.map-node.kind-oath{ border-color: color-mix(in srgb, var(--gold) 45%, var(--hairline-hi)); }
.map-node.kind-caravan{ border-color: color-mix(in srgb, var(--stone) 45%, var(--hairline-hi)); }

/* --------------------------------------------------- the challenge landing
 *
 * §13.1: "Share URL opens directly to a lightweight challenge landing state;
 * no marketing carousel." So this screen has a face, three numbers and one
 * button, and the shell is hidden behind it. Everything between the link and
 * the board is a place the invited player leaves.
 */
.challenge-screen{ display: flex; flex-direction: column; gap: var(--sp-3); padding-block: var(--sp-4); }
.challenge-hero{
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  min-height: 220px; display: flex; align-items: flex-end;
}
.challenge-art{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 22%;
}
.challenge-scrim{
  position: absolute; inset: 0;
  background: linear-gradient(180deg, #0b0d1700 20%, #0b0d17d9 78%, #0b0d17 100%);
}
.challenge-hero-text{ position: relative; padding: var(--sp-4); }
.challenge-name{
  margin: var(--sp-2) 0 0; font-size: var(--fs-2xl); line-height: 1.1;
  /* A display name is player-supplied. It is stripped of control characters
     and angle brackets on the way in, but a very long one must not push the
     hero wider than the phone. */
  overflow-wrap: anywhere;
}
.challenge-sub{ margin: var(--sp-2) 0 0; color: var(--ink-dim); font-size: var(--fs-sm); }
.challenge-legacy{ display: flex; justify-content: space-around; gap: var(--sp-3); }
.challenge-note{ text-align: center; font-size: var(--fs-xs); }

/* ------------------------------------------------------------- rivalries
 * §13.2. A series, not a leaderboard: the scoreline first, then the two
 * things about the matchup that are not just who won.
 */
.rivalry-panel{ text-align: center; }
.rivalry-score{
  font-size: var(--fs-3xl); font-weight: 800; line-height: 1.1;
  color: var(--gold-bright); margin-top: var(--sp-2);
}
.rivalry-stats{
  display: flex; justify-content: center; gap: var(--sp-5);
  margin-top: var(--sp-3); flex-wrap: wrap;
}

/* ------------------------------------------------ difficulty bands (§10.1)
 * The band names what kind of opponent this is; the tier number stays beside
 * it for anyone tuning against a specific rung. Each band gets its own accent
 * so the rail reads as four groups and a summit rather than thirteen dots.
 */
.band-line{
  display: flex; align-items: baseline; gap: var(--sp-3);
  margin-bottom: var(--sp-2);
}
.band-name{
  font-family: var(--font-ui); font-weight: 800; font-size: var(--fs-lg);
  letter-spacing: .02em; color: var(--band, var(--gold));
}
.band-tier{ font-size: var(--fs-xs); color: var(--ink-dim); }
.band-learner{ --band: var(--tide); }
.band-rival{ --band: var(--stone); }
.band-veteran{ --band: var(--gold); }
.band-master{ --band: var(--ember); }
.band-unmatched{ --band: var(--gold-bright); }

/* The rail, grouped by band. Colour is never the only cue: the dots keep
   their numbers, and the band is named in words directly above them. */
.tier-dot[data-band="learner"]{ border-color: color-mix(in srgb, var(--tide) 45%, var(--hairline-hi)); }
.tier-dot[data-band="rival"]{ border-color: color-mix(in srgb, var(--stone) 45%, var(--hairline-hi)); }
.tier-dot[data-band="veteran"]{ border-color: color-mix(in srgb, var(--gold) 45%, var(--hairline-hi)); }
.tier-dot[data-band="master"]{ border-color: color-mix(in srgb, var(--ember) 45%, var(--hairline-hi)); }
.tier-dot[data-band="unmatched"]{ border-color: var(--gold-bright); }

/* A tell bought at a Rival Camp, shown on the fight it was about (§11.2).
   Two or three words inside a map node; the full sentence lives in the
   node's accessible label. */
.map-node-tell{
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 4px; padding: 2px 6px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--tide) 18%, transparent);
  color: var(--tide); font-size: 10px; font-weight: 700; line-height: 1.2;
  max-width: 100%; overflow: hidden;
}
.map-node-tell svg{ width: 11px; height: 11px; flex: none; }
.map-node-tell span{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Concede (§8.5, "always available"). Deliberately the quietest control on
   the board: available on every round, and never the one a thumb finds first.
   Still a 44px target, because a control you cannot reliably hit is not
   available either. */
.concede-row{ display: flex; justify-content: center; margin-top: var(--sp-3); }
.concede-btn{
  min-height: 44px; padding-inline: var(--sp-4);
  background: none; border: 0;
  color: var(--ink-dim); opacity: .55;
  font-family: var(--font-ui); font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; cursor: pointer;
}
.concede-btn:hover, .concede-btn:focus-visible{ opacity: 1; color: var(--ember); }

/* The rivalry list in the Rival Hall (§13.2). One row per established series;
   the scoreline is the point, so it is the only thing sized up. */
.rivalry-list{ display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.rivalry-row{
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  background: var(--panel-hi); border: 1px solid var(--hairline);
}
.rivalry-row-main{ display: flex; flex-direction: column; min-width: 0; }
.rivalry-row-main strong{ font-size: var(--fs-sm); overflow-wrap: anywhere; }
.rivalry-row-main .dim{ font-size: var(--fs-xs); }
.rivalry-row-score{ flex: none; font-size: var(--fs-lg); font-weight: 800; color: var(--ink-dim); }
/* Ahead and behind get a colour, but the score itself is the information, so
   a reader who sees no colour at all loses nothing (§22.3). */
.rivalry-row-score.ahead{ color: var(--tide-glow); }
.rivalry-row-score.behind{ color: var(--ember-glow); }

/* ------------------------------------------------------ client guidance */
.faction-pick-card.suggested{ border-color: var(--gold); box-shadow: var(--glow-gold); }

.hand-card-readout{
  margin-top: auto;
  display: flex; flex-direction: column; gap: 4px; align-items: center;
  min-height: 42px; width: 100%;
}
.hand-card-readout .hand-card-stats,
.hand-card-readout .hand-card-type{ margin-top: 0; }
.hand-card-effect,
.coll-card-effect,
.reward-card-effect{
  margin: 0; color: var(--ink-dim); font-size: 10px; line-height: 1.25;
  max-width: 100%; overflow: visible; overflow-wrap: anywhere;
}
.hand-card-effect{ min-height: 38px; }
.coll-card-effect{ min-height: 40px; padding-inline: var(--sp-1); }
.reward-card-effect{ font-size: var(--fs-xs); min-height: 32px; }
.effect-rows{ display: grid; gap: var(--sp-2); }
.effect-row{
  margin: 0; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--gold) 9%, transparent);
  color: var(--ink-dim); font-size: var(--fs-sm);
}

.next-action-card{
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); border-color: color-mix(in srgb, var(--gold) 38%, var(--hairline));
}
.next-action-card h2{ margin: 2px 0 var(--sp-1); font-size: var(--fs-xl); }
.next-action-card p{ margin: 0; }
.mode-section{ margin-top: var(--sp-6); }
.mode-section .mode-grid{ margin-top: clamp(var(--sp-5), 2.4vw, var(--sp-8)); }
.mode-grid{
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-3);
}
.mode-card{
  min-height: 126px; padding: var(--sp-3);
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2);
  border: 1px solid var(--hairline-hi); border-radius: var(--radius-md);
  background: var(--panel-solid); color: var(--ink); text-align: start;
  cursor: pointer; transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.mode-card:hover{ transform: translateY(-2px); border-color: var(--gold-dim); }
.mode-card svg{ width: 24px; height: 24px; color: var(--gold); flex: none; }
.mode-card-title{ font-size: var(--fs-sm); font-weight: 900; }
.mode-card-body{ color: var(--ink-dim); font-size: var(--fs-xs); line-height: var(--lh-snug); }
.second-duel-setup .pick-card{ min-height: 170px; }
.second-duel-card{ cursor: default; }

.mode-status-screen{
  padding-block: var(--sp-6) var(--sp-16);
  display: flex; flex-direction: column; gap: var(--sp-5);
}
.mode-status-hero{
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-4); align-items: center;
}
.mode-status-icon{
  width: 72px; height: 72px; display: grid; place-items: center;
  border: 1px solid var(--gold-dim); border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--gold) 12%, var(--panel-solid));
  color: var(--gold-bright);
}
.mode-status-icon svg{ width: 32px; height: 32px; }
.mode-status-panel h3{ margin-bottom: var(--sp-2); }
.mode-bullets{
  margin: 0; padding-inline-start: 1.2rem;
  color: var(--ink-dim); font-size: var(--fs-sm); line-height: var(--lh-normal);
}
.mode-bullets li + li{ margin-top: var(--sp-1); }
.mode-wireframe{
  display: grid; gap: var(--sp-2); padding: var(--sp-3);
  border: 1px dashed var(--hairline-hi); border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--bg-2) 58%, transparent);
}
.mode-wire-row,
.bracket-slot{
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: 44px; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  color: var(--ink-dim); font-size: var(--fs-sm);
}
.mode-wire-row span:last-child{ color: var(--gold); font-weight: 800; }
.mode-actions{ justify-content: flex-start; }
.service-stack{ display: grid; gap: var(--sp-4); }
.service-grid{
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-4); align-items: start;
}
.service-card{ min-width: 0; }
.service-card-head{
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-3); min-width: 0;
}
.service-card-head h3{ margin: 0; overflow-wrap: anywhere; }
.service-card-head .chip{ flex: none; }
.service-stats{
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3); margin-top: var(--sp-4);
}
.service-list{ display: grid; gap: var(--sp-2); }
.service-list-row{
  min-height: 44px; width: 100%; padding: var(--sp-2) var(--sp-3);
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center; gap: var(--sp-2);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--panel-solid) 86%, transparent);
  color: var(--ink-dim); font-size: var(--fs-sm); text-align: start;
}
button.service-list-row{ cursor: pointer; }
button.service-list-row:hover,
.service-list-row.active{
  border-color: var(--gold-dim); color: var(--ink);
  background: color-mix(in srgb, var(--gold) 8%, var(--panel-solid));
}
.service-list-row > span:first-child{ min-width: 0; overflow-wrap: anywhere; color: var(--ink); font-weight: 800; }
.service-ranked-row{ grid-template-columns: minmax(0, 1fr) auto auto auto; }
.service-replay-row{ grid-template-columns: minmax(0, 1fr) auto auto auto; }
.front-season-row{ grid-template-columns: auto minmax(0, 1fr) auto auto; }
.front-season-head{
  align-items: baseline; justify-content: flex-start; gap: var(--sp-2);
  flex-wrap: wrap;
}
.front-season-head h3{ line-height: var(--lh-tight); }
.front-season-tag{
  display: inline-flex; align-items: center; min-block-size: 30px;
  padding-inline: var(--sp-3); border: 1px solid var(--hairline);
  border-radius: var(--radius-pill); background: #d4a24e14;
  color: var(--gold-bright); font-size: var(--fs-xs); font-weight: 800;
}
.service-room{ grid-template-columns: minmax(0, 1fr) auto; }
.service-match-row{ grid-template-columns: auto minmax(0, 1fr) auto auto; }
.ops-summary-grid{ grid-template-columns: repeat(5, minmax(0, 1fr)); }
.ops-group-stack{ display: grid; gap: var(--sp-2); }
.ops-group-line{
  display: grid; grid-template-columns: minmax(120px, .45fr) minmax(0, 1fr);
  gap: var(--sp-3); align-items: center;
  padding: var(--sp-2) var(--sp-3); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); background: color-mix(in srgb, var(--bg-2) 64%, transparent);
}
.ops-group-line strong{ font-size: var(--fs-sm); color: var(--ink); }
.ops-chip-list{ display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.ops-review-row{
  grid-template-columns: minmax(100px, .75fr) minmax(92px, .6fr) auto minmax(0, 1fr) auto;
  align-items: start;
}
.ops-note{
  min-width: 0; overflow-wrap: anywhere; color: var(--ink-dim);
  line-height: var(--lh-snug);
}
.ops-actions{ display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.ops-season-list{ max-height: 220px; overflow: auto; }
.ops-season-row{ grid-template-columns: minmax(96px, 1fr) minmax(0, 1.4fr) auto; }
.chip.s-info{ color: var(--ink-dim); }
.chip.s-review{ color: var(--gold-bright); }
.chip.s-high{ color: var(--ember-glow); border-color: color-mix(in srgb, var(--ember) 48%, var(--hairline)); }
.service-form{
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-2); align-items: center;
}
.service-form select,
.service-form input{
  min-height: 42px; min-width: 0; padding: 0 var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: var(--bg-2); color: var(--ink); font: inherit;
}
.service-form select{ min-width: 74px; }
.service-messages{ display: grid; gap: var(--sp-3); }
.service-message{
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-3); align-items: start; padding: var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--bg-2) 70%, transparent);
}
.service-message-main{ min-width: 0; }
.service-message-main p{
  margin: var(--sp-1) 0; color: var(--ink-dim);
  overflow-wrap: anywhere; line-height: var(--lh-normal);
}
.service-message-actions{ display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.service-bracket{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
.live-match-panel{ gap: var(--sp-3); }
.service-live-box{
  display: grid; gap: var(--sp-2); padding: var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--panel-solid) 88%, transparent);
}
.service-live-hand,
.service-live-draft{
  display: flex; flex-wrap: wrap; gap: var(--sp-2); min-width: 0;
}
.service-live-card{
  display: inline-flex; align-items: center; min-height: 32px;
  padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-sm);
  background: var(--bg-2); border: 1px solid var(--hairline);
  color: var(--ink-dim); font-size: var(--fs-xs); font-weight: 800;
  overflow-wrap: anywhere;
}
.service-live-card-row{
  display: grid; grid-template-columns: minmax(120px, .8fr) minmax(0, 1.2fr);
  gap: var(--sp-2); align-items: center; inline-size: 100%;
  padding: var(--sp-2); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); background: var(--bg-2);
}
.service-live-card-row > span:first-child{ min-width: 0; overflow-wrap: anywhere; font-weight: 800; }
.service-live-card-row > div{ display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-end; }
.service-live-toggle{ display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); font-weight: 800; }
.service-live-read{ justify-content: flex-start; }
.service-inline-empty{ border-top: 1px solid var(--hairline); padding-top: var(--sp-3); }
.chip.s-active,
.chip.s-open{ color: var(--tide-glow); }
.chip.s-completed{ color: var(--gold-bright); }
.chip.s-disputed{ color: var(--ember-glow); }
.chip.s-pending{ color: var(--ink-dim); }

.account-prompt{
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  border-color: color-mix(in srgb, var(--tide) 36%, var(--hairline));
}
.account-prompt h3{ margin: 0 0 var(--sp-1); }
.account-prompt p{ margin: 0; }
.account-prompt-actions{ display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.results-secondary-actions{
  display: flex; gap: var(--sp-3); justify-content: center; flex-wrap: wrap;
  margin-top: var(--sp-3);
}
.challenge-safety{
  display: flex; justify-content: center; gap: var(--sp-2); flex-wrap: wrap;
  margin-top: var(--sp-2);
}
.run-header-actions{ display: flex; justify-content: flex-end; }

.replay-rounds{ display: grid; gap: var(--sp-3); }
.replay-round{
  border: 1px solid var(--hairline); border-radius: var(--radius-md);
  background: var(--panel-solid); overflow: hidden;
}
.replay-round summary{
  min-height: 48px; padding: var(--sp-3) var(--sp-4);
  cursor: pointer; color: var(--gold-bright); font-weight: 900;
}
.replay-round ol{
  margin: 0; padding: 0 var(--sp-5) var(--sp-4) var(--sp-8);
  color: var(--ink-dim); font-size: var(--fs-sm); line-height: var(--lh-normal);
}
.replay-round li + li{ margin-top: var(--sp-2); }

@media (max-width: 860px){
  .mode-grid{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .service-grid{ grid-template-columns: 1fr; }
  .service-live-card-row{ grid-template-columns: 1fr; }
  .service-live-card-row > div{ justify-content: flex-start; }
  .next-action-card,
  .account-prompt{ align-items: stretch; flex-direction: column; }
  .next-action-card .btn,
  .account-prompt .btn{ width: 100%; }
  .account-prompt-actions{ width: 100%; }
}

@media (max-width: 520px){
  .mode-grid{ grid-template-columns: 1fr; }
  .mode-status-hero{ grid-template-columns: 1fr; }
  .mode-status-icon{ width: 56px; height: 56px; }
  .service-stats{ grid-template-columns: 1fr; }
  .service-list-row,
  .service-match-row,
  .ops-summary-grid,
  .ops-group-line,
  .ops-review-row,
  .service-message,
  .service-form{
    grid-template-columns: 1fr;
  }
  .service-list-row .btn,
  .service-form .btn{ width: 100%; }
  .service-bracket{ grid-template-columns: 1fr; }
}
