/* Standard Application Mode — the shared shell, and now a CONSUMER of the token
 * layer rather than a second, disagreeing copy of it.
 *
 * WHAT CHANGED AND WHY IT LOOKS LIKE A DELETION. lw-tokens.css is linked first
 * and declares the approved palette, type scale, spacing, radii, motion and
 * layout. This file used to re-declare 33 of those names — 18 of them with
 * DIFFERENT values — and because it loads second it silently won every one. The
 * token layer was loaded and inert. Removing the duplicates is what activates
 * it, and it is why the diff here is mostly `:root` shrinking:
 *
 *   type scale      12/13/15/16/18/22/28/38  ->  12.5/14/16/17/20/25/32/44
 *   content width   1340                      ->  1420 (--content-wide)
 *   wide width      1440                      ->  1560 (--content-max)
 *   gutter          48 / 32 / 24              ->  40 / 28 / 18
 *   phone tier      520                       ->  560
 *   focus ring      gold at 78% alpha         ->  a solid 2px --ds-gold outline
 *   control motion  140ms                     ->  130ms
 *
 * THE SEMANTIC INVERSION IS THE LARGEST VISIBLE CHANGE, and it is deliberate:
 *
 *   BLUE  = the operational primary ACTION. Always available.
 *   GOLD  = SELECTED / current / important. A state the user chose.
 *   RED   = destructive, enemy, invalid.
 *   GREEN = confirmed success.
 *
 * Standard Mode had these backwards — gold-filled primary buttons and blue-tinted
 * selection — while the approved Desert Storm workspace had them this way round.
 * Two shells of one product disagreeing about what a colour MEANS is worse than
 * either convention, and the approved surface wins. Gold could be mistaken for
 * "enabled"; blue cannot.
 *
 * app.css still loads after this file and re-declares roughly fifty of these
 * selectors. The component duplicates it carried have been removed there in the
 * same commit — a foundation that is overridden two files later is not a
 * foundation.
 */

:root {
  color-scheme: dark;

  /* The shipped families, from the token layer (tokens/fonts.css), which
     self-hosts all four under /static/fonts.

     --font-label is now the MONO family. It was the body family, deliberately,
     while this was a typography-only step; the label role in this design system
     is "anything the machine produced" — section labels, telemetry, counts,
     legends — and that role is mono. */
  --font-sans: var(--ds-font-body);
  --font-label: var(--ds-font-mono);
  --font-mono: var(--ds-font-mono);
  --font-display: var(--ds-font-display);

  /* --- Surfaces. Names kept, values re-pointed at the graphite ladder. ------ */
  --page-bg: var(--ds-bg);
  --page-bg-elevated: var(--ds-frame);
  --nav-bg: color-mix(in srgb, var(--ds-header) 88%, transparent);
  --section-surface: var(--ds-panel);
  --card-surface: var(--ds-panel);
  --raised-surface: var(--ds-hover);
  --stat-surface: var(--ds-panel-2);
  --input-surface: var(--ds-inset);
  --verdict-surface: var(--ds-panel-2);

  /* Solid hairline hexes, not alpha over a neutral: alpha is unpredictable over
     a translucent parent, and the sticky bar is one. */
  --border-subtle: var(--ds-line);
  --border-strong: var(--ds-line-strong);
  --border-active: var(--ds-gold-line);
  --border-hover: var(--ds-line-hover);

  --text-primary: var(--ds-text);
  --text-headline: var(--ds-bright);
  --text-secondary: var(--ds-soft);
  --text-muted: var(--ds-muted);
  --text-faint: var(--ds-faint);
  --text-on-accent: var(--ds-on-gold);
  --text-on-action: var(--ds-on-blue);

  /* --accent-primary is the SELECTED accent, and it is gold. The primary ACTION
     is --action, and it is blue. They were the same token before, which is
     precisely how the two meanings got confused. */
  --accent-primary: var(--ds-gold);
  --accent-hover: var(--ds-gold-strong);
  --accent-dim: var(--ds-gold-dim);
  --action: var(--ds-blue);
  --action-hover: var(--ds-blue-hover);
  --action-text: var(--ds-blue-text);
  --positive: var(--ds-green);
  --warning: var(--ds-amber);
  --danger: var(--ds-red);
  --danger-text: var(--ds-red-text);
  --information: var(--ds-blue-text);

  /* The battlefield's two sides are PLACES, not states, and they keep the
     workspace's own colours so a player reads the same side the same way on
     every surface. */
  --side-attacker: var(--ds-side-ours);
  --side-attacker-soft: var(--ds-blue-soft);
  --side-defender: var(--ds-side-enemy);
  --side-defender-soft: var(--ds-red-soft);

  --shadow-soft: var(--shadow-panel);
  --shadow-raised: var(--shadow-float);

  /* Compatibility aliases for the existing production stylesheets. These are the
     migration seam and are removed once every consumer has moved. */
  --bg: var(--page-bg);
  --surface: var(--section-surface);
  --surface-2: var(--card-surface);
  --surface-3: var(--page-bg-elevated);
  --surface-soft: var(--stat-surface);
  --text: var(--text-primary);
  --text-soft: var(--text-secondary);
  --muted: var(--text-muted);
  --line: var(--border-strong);
  --line-soft: var(--border-subtle);
  --accent: var(--accent-primary);
  --accent-strong: var(--accent-hover);
  --attack: var(--side-attacker);
  --attack-soft: var(--side-attacker-soft);
  --defense: var(--side-defender);
  --defense-soft: var(--side-defender-soft);
  --good: var(--positive);
  --warn: var(--warning);
  --bad: var(--danger);
  --shadow: var(--shadow-soft);
  --radius: var(--radius-md);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-padding-top: calc(var(--sticky-header-height) + var(--space-5));
}

body {
  min-width: 320px;
  margin: 0;
  overflow-x: hidden;
  /* Never a flat colour: a gold bloom at 22% -10% fading by 34%, over a vertical
     graphite gradient. No patterns, no textures, no noise. */
  background:
    radial-gradient(circle at 22% -10%, rgba(217, 169, 63, 0.11), transparent 34%),
    linear-gradient(180deg, #0c1119 0%, var(--ds-bg) 38%, #070a0f 100%);
  background-attachment: fixed;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-regular);
  line-height: var(--leading-body);
  text-rendering: geometricPrecision;
}

body.nav-open {
  overflow: hidden;
}

a {
  color: var(--action-text);
  text-decoration: none;
}

a:hover {
  color: var(--accent-hover);
}

/* Focus is ALWAYS an outline, never a colour or border swap — a swap is
   invisible on a control that already changes colour on hover. */
:focus-visible {
  outline: 2px solid var(--ds-gold);
  outline-offset: 2px;
}

::selection {
  color: var(--text-on-accent);
  background: var(--accent-hover);
}

[id] {
  scroll-margin-top: calc(var(--sticky-header-height) + var(--space-5));
}

.skip-link {
  position: fixed;
  inset-block-start: var(--space-3);
  inset-inline-start: var(--space-3);
  z-index: var(--z-skip-link);
  transform: translateY(-160%);
  border: 1px solid var(--ds-blue-line);
  border-radius: var(--radius-md);
  background: var(--action);
  color: var(--text-on-action);
  font-weight: var(--weight-bold);
  padding: 10px 14px;
  transition: transform var(--motion-fast) ease;
}

.skip-link:focus {
  transform: translateY(0);
}

/* ==========================================================================
   Chrome — the sticky bar, the brand lockup, navigation
   ========================================================================== */

.topbar {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-command-deck);
  min-height: var(--sticky-header-height);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--nav-bg);
  -webkit-backdrop-filter: var(--blur-chrome);
  backdrop-filter: var(--blur-chrome);
}

/* Blur is what lets the bar sit OVER content without becoming lighter than it.
   Where it is unavailable the bar goes solid rather than staying translucent. */
@supports not (backdrop-filter: blur(8px)) {
  .topbar {
    background: var(--ds-header);
  }
}

.topbar-inner {
  width: min(var(--content-max), calc(100% - var(--shell-gutter)));
  min-height: var(--sticky-header-height);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

/* The lockup is the SYMBOL PLUS EDITABLE TEXT. The product name is never baked
   into the image, so the temporary mark can be replaced without touching the
   wordmark and a translator can change the words. */
.brand {
  display: inline-flex;
  min-width: 0;
  align-items: center;
  gap: 10px;
  color: var(--text-headline);
  font-weight: var(--weight-bold);
  letter-spacing: 0;
}

.brand:hover {
  color: var(--text-headline);
}

.brand-mark {
  display: inline-grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  border: 1px solid var(--ds-gold-line);
  border-radius: var(--radius-md);
  background: var(--ds-inset);
  color: var(--accent-primary);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  overflow: hidden;
}

/* The real symbol, as an <img> inside the same plate. Kept as an image rather
   than a background so it carries an alt of its own when it needs one and so a
   missing file is visible rather than silently blank. */
.brand-symbol {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.brand-text {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-brand);
  text-transform: uppercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Arabic has no condensed display face and positive tracking breaks its joined
   letterforms; the token layer swaps the family and base.css zeroes the tracking
   for .lw-* roles, and the brand word needs the same treatment by its own name. */
[dir="rtl"] .brand-text {
  font-family: var(--ds-font-body);
  letter-spacing: 0;
}

.navlinks {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  min-width: 0;
}

.navlinks a,
.link-button,
.nav-group > summary {
  min-height: var(--control-nav);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  padding: var(--space-2) var(--space-3);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--motion-fast) ease, border-color var(--motion-fast) ease, color var(--motion-fast) ease;
}

/* Rest -> hover: border, fill and label rise TOGETHER. The fill is the one
   literal in the chrome with no token: an opaque hover surface would read as
   heavier than the translucent bar it sits in. */
.navlinks a:hover,
.link-button:hover,
.nav-group > summary:hover {
  border-color: var(--border-subtle);
  background: rgba(255, 255, 255, 0.045);
  color: var(--text-primary);
}

/* SELECTED IS GOLD. This is the rule the whole inversion turns on: the nav entry
   for the page you are on is a state you chose, so it is gold — not the blue it
   used to be, which is the colour of a thing you can DO.

   TINTED gold is the correct register here — it answers "which view am I on".
   FILLED gold answers "which mode am I in" and belongs to the skip link and mode
   switches. The two must not be swapped. */
.navlinks a.is-active,
.navlinks a[aria-current="page"],
.nav-group.is-active > summary {
  border-color: var(--ds-gold-line);
  background: var(--ds-gold-soft);
  color: var(--accent-hover);
}

/* A selected control that is hovered goes brighter and STAYS gold. */
.navlinks a.is-active:hover,
.navlinks a[aria-current="page"]:hover {
  border-color: var(--accent-primary);
  background: var(--ds-gold-soft);
  color: var(--accent-hover);
}

/* A grouped area (Alliance Core, Progression). Pure-HTML disclosure so it is
   keyboard reachable with no script, and so it degrades to a plain list. */
.nav-group {
  position: relative;
}

.nav-group > summary {
  list-style: none;
}

.nav-group > summary::-webkit-details-marker {
  display: none;
}

.nav-group > summary::after {
  content: "\25BE";
  font-size: 10px;
  opacity: 0.7;
}

.nav-group[open] > summary {
  border-color: var(--border-hover);
  color: var(--text-primary);
}

.nav-group-panel {
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: calc(100% + 6px);
  z-index: var(--z-intel-drawer);
  min-width: 232px;
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 6px;
  list-style: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--ds-frame);
  box-shadow: var(--shadow-float);
}

.nav-group-panel a {
  justify-content: flex-start;
  width: 100%;
  min-height: var(--control-compact);
}

/* A product area the viewer has no access to, in the area switcher. Named so the
   user knows it exists, deliberately NOT a link, and it carries its state in words
   (the "no access" badge) rather than in colour alone. */
.nav-group-locked {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--control-compact);
  padding-inline: 10px;
  color: var(--text-faint);
  cursor: default;
}

.nav-group-label {
  padding: 6px 10px 4px;
  color: var(--text-faint);
  font-family: var(--font-label);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-section);
  text-transform: uppercase;
}

/* A quiet marker on a nav entry — a hint, never a second focal point. */
.nav-badge {
  margin-inline-start: 6px;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--ds-gold-line);
  border-radius: var(--radius-pill);
  background: var(--ds-gold-soft);
  color: var(--accent-hover);
  font-family: var(--font-label);
  font-size: var(--text-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-badge);
  line-height: 1;
  padding: 3px 6px;
  text-transform: uppercase;
}

[dir="rtl"] .nav-badge {
  letter-spacing: 0;
}

.menu-button {
  width: auto;
  min-height: var(--control-nav);
  min-width: var(--control-touch);
  flex: 0 0 auto;
  display: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--card-surface);
  color: var(--text-primary);
  cursor: pointer;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  padding: 8px 12px;
}

/* Early Access notice (base.html, role="status"). Normal flow, logical padding,
   centred, and the message is carried by the TEXT — the tint reinforces, it is
   never the only signal. */
.early-access-notice {
  border-bottom: 1px solid color-mix(in srgb, var(--warning) 45%, transparent);
  background: color-mix(in srgb, var(--warning) 12%, transparent);
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.45;
  padding: 7px var(--space-4);
  text-align: center;
}

/* Inside the authenticated application the strip stays available but stops
   competing with the page title: a signed-in operator has read it already.
   Public and prelaunch surfaces keep the full-weight strip above. */
body[data-authenticated] .early-access-notice {
  background: color-mix(in srgb, var(--warning) 7%, transparent);
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular);
  padding: 4px var(--space-4);
}

/* ==========================================================================
   Layout
   ========================================================================== */

.shell {
  width: min(var(--content-wide), calc(100% - var(--shell-gutter)));
  min-width: 0;
  margin: 0 auto;
  padding: var(--space-6) 0 var(--space-7);
}

.shell:focus {
  outline: none;
}

/* Data-heavy routes: Product Center, Alliance Core, comparison and analytics
   results, Alliance Data, War Room, and the migration dashboards and tables.
   Calm forms and setup pages stay at --content-wide. */
.shell-wide {
  width: min(var(--content-max), calc(100% - var(--shell-gutter)));
}

.narrow {
  max-width: 520px;
  margin: var(--space-8) auto;
}

/* ==========================================================================
   Type roles
   ========================================================================== */

h1,
h2,
h3 {
  margin: 0;
  color: var(--text-headline);
  font-weight: var(--weight-bold);
  letter-spacing: 0;
  line-height: var(--leading-heading);
  overflow-wrap: anywhere;
}

h1 {
  font-size: clamp(var(--text-2xl), 3vw, var(--text-3xl));
}

h2 {
  font-size: var(--text-xl);
}

h3 {
  font-size: var(--text-lg);
}

/* PROSE IS MEASURED BY DEFAULT. 72ch is where a line stops being comfortable,
   and on a 1560px data page an unmeasured paragraph is unreadable. */
p {
  max-width: var(--content-readable);
  margin: 8px 0 0;
  color: var(--text-secondary);
  line-height: var(--leading-prose);
}

/* ...AND THE DEFAULT IS WRONG FOR A PARAGRAPH THAT IS LAYOUT RATHER THAN PROSE.
   A <p> inside a grid cell, a metric tile or a full-width note is sized by its
   container, and 72ch silently truncates it mid-cell — which reads as a broken
   panel, not as a typographic choice. It cost one lane a full-width note that
   stopped at 576px inside an 837px grid and leaked the battlefield raster
   through the gap.

   Opt out explicitly rather than guessing at container selectors: which
   paragraphs are prose is a question about the content, and only the template
   knows the answer. Uses the logical property so it also overrides in RTL. */
.lw-measure-none,
p.lw-measure-none {
  max-inline-size: none;
}

small,
.muted,
.metadata-line,
.search-status,
td small {
  color: var(--text-muted);
}

/* The mono section label with its 8x2 gold tick, drawn as a background gradient
   so it costs no element. Mirrored under RTL by moving the tick to the end. */
.section-label {
  display: block;
  margin: 0 0 8px;
  padding-inline-start: 14px;
  background: linear-gradient(var(--accent-primary), var(--accent-primary)) no-repeat 0 50% / 8px 2px;
  color: var(--text-faint);
  font-family: var(--font-label);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-section);
  line-height: 1;
  text-transform: uppercase;
}

[dir="rtl"] .section-label {
  background-position: 100% 50%;
  letter-spacing: 0;
}

.eyebrow {
  display: inline-block;
  margin-bottom: 7px;
  color: var(--accent-hover);
  font-family: var(--font-label);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
}

[dir="rtl"] .eyebrow {
  letter-spacing: 0;
}

.section-title,
.page-hero,
.profile-hero {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  margin-bottom: var(--space-5);
}

.compact-hero {
  margin-bottom: var(--space-6);
}

/* Breadcrumbs. Mono, tracked, and the separator is a real glyph the reader's
   direction rotates rather than mirrors. */
.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: var(--space-3);
  color: var(--text-faint);
  font-family: var(--font-label);
  font-size: var(--text-meta);
  letter-spacing: var(--track-crumb);
  text-transform: uppercase;
}

[dir="rtl"] .breadcrumbs {
  letter-spacing: 0;
}

.breadcrumbs a {
  color: var(--text-muted);
}

.breadcrumbs a:hover {
  color: var(--accent-hover);
}

.breadcrumbs [aria-current="page"] {
  color: var(--accent-primary);
}

.breadcrumbs-sep {
  color: var(--text-deep, var(--ds-deep));
}

[dir="rtl"] .breadcrumbs-sep {
  display: inline-block;
  transform: rotate(0.5turn);
}

/* ==========================================================================
   Surfaces
   ========================================================================== */

.panel,
.comparison-hero {
  min-width: 0;
  margin-bottom: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--section-surface);
  box-shadow: var(--shadow-rest);
  padding: var(--space-6);
}

/* The panel header vocabulary is FIXED: a 3x14 gold tick, a display-font title,
   then count badges, then icon buttons pushed out by margin-inline-start:auto. */
.panel-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
}

.panel-header::before {
  content: "";
  flex: 0 0 auto;
  width: 3px;
  height: 14px;
  border-radius: 1px;
  background: var(--accent-primary);
}

.panel-header h2,
.panel-header h3 {
  font-family: var(--font-display);
  font-size: var(--size-panel-title);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-title);
  text-transform: uppercase;
}

[dir="rtl"] .panel-header h2,
[dir="rtl"] .panel-header h3 {
  font-family: var(--ds-font-body);
  letter-spacing: 0;
}

.panel-header .panel-actions {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.candidate-card,
.selected-card,
.list-card,
.metric-card,
.insight-card,
.summary-side,
.report-card,
.tier-card {
  min-width: 0;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--card-surface);
  box-shadow: var(--shadow-rest);
  padding: var(--space-4);
}

/* ==========================================================================
   Data
   ========================================================================== */

/* A figure that IS the content. Always tabular and bidi-isolated. */
.metric-band {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--border-subtle);
  overflow: hidden;
}

.metric-tile {
  display: grid;
  gap: 6px;
  align-content: start;
  padding: 14px 16px;
  background: var(--section-surface);
}

.metric-tile-term {
  color: var(--text-faint);
  font-family: var(--font-label);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-legend);
  text-transform: uppercase;
}

[dir="rtl"] .metric-tile-term {
  letter-spacing: 0;
}

.metric-tile-value {
  color: var(--text-headline);
  font-size: var(--text-data-sm);
  font-weight: var(--weight-bold);
  line-height: 1.1;
}

.metric-tile.is-selected .metric-tile-value {
  color: var(--accent-primary);
}

.metric-tile-note {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

/* A relationship between two figures. The bar is the evidence; the verdict block
   above it is the answer, and the answer comes first. */
.verdict-block {
  display: grid;
  gap: 6px;
  border: 1px solid var(--border-subtle);
  border-inline-start: 3px solid var(--accent-primary);
  border-radius: var(--radius-md);
  background: var(--verdict-surface);
  padding: var(--space-4) var(--space-5);
}

.verdict-block strong {
  color: var(--text-headline);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
}

.verdict-block small {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

.compare-bar {
  display: grid;
  gap: 6px;
  padding-block: 10px;
  border-bottom: 1px solid var(--border-subtle);
}

.compare-bar-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-sm);
}

.compare-bar-track {
  display: flex;
  height: 8px;
  border-radius: var(--radius-micro);
  background: var(--ds-inset);
  overflow: hidden;
}

.compare-bar-fill {
  height: 100%;
}

.compare-bar-fill.is-ours {
  background: var(--side-attacker);
}

.compare-bar-fill.is-theirs {
  background: var(--side-defender);
}

.table-wrap {
  width: 100%;
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  min-width: 0;
  border-bottom: 1px solid var(--border-subtle);
  padding: 11px 14px;
  text-align: start;
  vertical-align: middle;
}

th {
  background: var(--stat-surface);
  color: var(--text-faint);
  font-family: var(--font-label);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-legend);
  text-transform: uppercase;
}

[dir="rtl"] th {
  letter-spacing: 0;
}

td {
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

td strong,
th strong,
.numeric {
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

tbody tr:hover {
  background: var(--surface-hover);
}

/* A selected row is gold and OPAQUE. A translucent wash would let whatever is
   behind the table become the background of its text. */
tbody tr.is-selected {
  background: color-mix(in srgb, var(--accent-primary) 10%, var(--ds-panel));
}

code {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xs);
  background: var(--ds-inset);
  color: var(--action-text);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  padding: 2px 5px;
}

/* ==========================================================================
   Status
   ========================================================================== */

/* COLOUR IS NEVER THE ONLY SIGNAL: every pill carries a 6px dot as well as its
   word, so the state survives a monochrome print and a colour-blind reader. */
.status-pill,
.badge {
  min-height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  background: var(--stat-surface);
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: 1.2;
  padding: 4px 10px;
  text-align: center;
}

.status-pill::before,
.badge.has-dot::before {
  content: "";
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.status-pill.is-verified,
.status-pill.is-success,
.badge.is-success {
  border-color: var(--ds-green-line);
  background: var(--ds-green-soft);
  color: var(--positive);
}

.status-pill.is-warning,
.badge.is-warning {
  border-color: var(--ds-amber-line);
  background: var(--ds-amber-soft);
  color: var(--warning);
}

.status-pill.is-danger,
.badge.is-danger {
  border-color: var(--ds-red-line);
  background: var(--ds-red-soft);
  color: var(--danger-text);
}

.status-pill.is-selected,
.badge.is-selected {
  border-color: var(--ds-gold-line);
  background: var(--ds-gold-soft);
  color: var(--accent-hover);
}

.status-pill.is-action,
.badge.is-action {
  border-color: var(--ds-blue-line);
  background: var(--ds-blue-soft);
  color: var(--action-text);
}

.status-pill.attacker-soft {
  border-color: var(--ds-blue-line);
  background: var(--side-attacker-soft);
  color: var(--action-text);
}

.status-pill.defender-soft {
  border-color: var(--ds-red-line);
  background: var(--side-defender-soft);
  color: var(--danger-text);
}

.count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  border-radius: var(--radius-xs);
  background: var(--ds-inset);
  color: var(--text-secondary);
  font-family: var(--font-label);
  font-size: var(--text-meta);
  font-variant-numeric: tabular-nums;
  padding: 2px 6px;
}

.count-badge.is-selected {
  background: var(--ds-gold-soft);
  color: var(--accent-primary);
}

.hero-status,
.status-row,
.chip-row,
.metadata-line,
.button-row,
.candidate-heading,
.player-heading,
.report-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 9px;
}

.metadata-line {
  margin: 12px 0;
  line-height: 1.55;
}

/* ==========================================================================
   Forms
   ========================================================================== */

label {
  display: grid;
  gap: 6px;
  min-width: 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

input,
select,
textarea {
  width: 100%;
  min-height: var(--control-input);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--input-surface);
  color: var(--text-primary);
  font: inherit;
  font-size: var(--text-sm);
  padding: 10px 12px;
  transition: var(--transition-control);
}

input:hover,
select:hover,
textarea:hover {
  border-color: var(--border-hover);
}

textarea {
  min-height: 96px;
  resize: vertical;
}

input::placeholder,
textarea::placeholder {
  color: var(--text-faint);
}

input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--danger);
}

/* A disabled control states its own SURFACE rather than fading. Opacity
   compounds against a translucent parent and makes contrast unpredictable. */
input:disabled,
select:disabled,
textarea:disabled {
  cursor: not-allowed;
  border-color: var(--disabled-border);
  background: var(--disabled-surface);
  color: var(--disabled-text);
}

.field-help {
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular);
}

.field-error {
  color: var(--danger-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

/* ==========================================================================
   Actions — BLUE IS THE PRIMARY. This is the inversion, stated once.
   ========================================================================== */

button,
.button {
  min-height: var(--control-standard);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid var(--ds-blue-deep);
  border-radius: var(--radius-sm);
  background: var(--action);
  color: var(--text-on-action);
  cursor: pointer;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: 1.2;
  padding: 10px 16px;
  text-align: center;
  /* background is deliberately EXCLUDED from the transition: a JS-toggled active
     state that animates its fill reads as stuck mid-transition. */
  transition: var(--transition-control);
}

button:hover,
.button:hover {
  border-color: var(--action-hover);
  background: var(--action-hover);
  color: var(--text-on-action);
}

/* The action's focus ring is the blue text tone, deliberately not the gold one:
   gold means selected, and a focused button is not a selected one. */
button:focus-visible,
.button:focus-visible {
  outline-color: var(--action-text);
}

button.secondary,
.button.secondary {
  border-color: var(--border-strong);
  background: var(--card-surface);
  color: var(--text-primary);
}

button.secondary:hover,
.button.secondary:hover {
  border-color: var(--border-hover);
  background: var(--surface-hover);
  color: var(--text-primary);
}

button.tertiary,
.button.tertiary,
button.ghost,
.button.ghost {
  border-color: transparent;
  background: transparent;
  color: var(--text-secondary);
}

button.tertiary:hover,
.button.tertiary:hover,
button.ghost:hover,
.button.ghost:hover {
  border-color: var(--border-subtle);
  background: var(--surface-hover);
  color: var(--text-primary);
}

/* SELECTED, not primary. A control the user has switched on. */
button.is-selected,
.button.is-selected,
button[aria-pressed="true"],
.button[aria-pressed="true"] {
  border-color: var(--ds-gold-line);
  background: color-mix(in srgb, var(--accent-primary) 14%, var(--ds-panel));
  color: var(--accent-hover);
}

button.danger,
.button.danger {
  border-color: var(--ds-red-line);
  background: var(--ds-red-soft);
  color: var(--danger-text);
}

button.danger:hover,
.button.danger:hover {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 18%, var(--ds-panel));
  color: var(--danger-text);
}

button:disabled,
.button[aria-disabled="true"] {
  cursor: not-allowed;
  border-color: var(--disabled-border);
  background: var(--disabled-surface);
  color: var(--disabled-text);
}

.icon-button {
  min-width: var(--control-standard);
  padding: 10px;
}

.compact-button {
  min-height: var(--control-compact);
  font-size: var(--text-xs);
  padding: 7px 11px;
}

/* ==========================================================================
   Tabs and segments
   ========================================================================== */

.tab-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  padding-bottom: var(--space-3);
}

.dashboard-tabs {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--ds-inset);
  padding: 6px;
}

.tab-button {
  min-height: var(--control-tab);
  border-color: transparent;
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.tab-button:hover {
  border-color: var(--border-subtle);
  background: var(--surface-hover);
  color: var(--text-primary);
}

/* The selected tab is gold and OPAQUE — it must be the least see-through control
   in the row, not the most. */
.tab-button.is-active,
.tab-button[aria-selected="true"] {
  border-color: var(--ds-gold-line);
  background: color-mix(in srgb, var(--accent-primary) 14%, var(--ds-panel));
  color: var(--accent-hover);
}

/* ==========================================================================
   Feedback
   ========================================================================== */

.notice,
.alert {
  border: 1px solid var(--border-subtle);
  border-inline-start: 3px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--stat-surface);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  padding: 12px 14px;
}

.notice.warning,
.alert.warning,
.alert.is-warning {
  border-color: var(--ds-amber-line);
  border-inline-start-color: var(--warning);
  background: var(--ds-amber-soft);
  color: var(--text-primary);
}

.notice.error,
.alert.error,
.alert.is-error,
.alert.is-danger {
  border-color: var(--ds-red-line);
  border-inline-start-color: var(--danger);
  background: var(--ds-red-soft);
  color: var(--text-primary);
}

.notice.success,
.alert.success,
.alert.is-success {
  border-color: var(--ds-green-line);
  border-inline-start-color: var(--positive);
  background: var(--ds-green-soft);
  color: var(--text-primary);
}

.notice.info,
.alert.info,
.alert.is-info {
  border-color: var(--ds-blue-line);
  border-inline-start-color: var(--action);
  background: var(--ds-blue-soft);
  color: var(--text-primary);
}

/* An empty well is dashed and shows what is behind it. That is the one place a
   see-through surface is correct: there is no text sitting on it that matters. */
.empty-state,
.selected-card.is-empty {
  display: grid;
  gap: 8px;
  justify-items: center;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: var(--space-6) var(--space-4);
  text-align: center;
}

.empty-state strong {
  color: var(--text-secondary);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

/* A non-blocking status channel: saved, failed, export progress. Never invisible
   and never a colour on its own. */
.status-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 22px;
  color: var(--text-muted);
  font-family: var(--font-label);
  font-size: var(--text-meta);
  letter-spacing: var(--track-title);
  text-transform: uppercase;
}

[dir="rtl"] .status-line {
  letter-spacing: 0;
}

.status-line.is-busy {
  color: var(--action-text);
}

.status-line.is-done {
  color: var(--positive);
}

.status-line.is-failed {
  color: var(--danger-text);
}

.info-note {
  color: var(--text-secondary);
}

.error-text {
  color: var(--danger-text);
}

/* ==========================================================================
   Dialogs
   ========================================================================== */

dialog,
.dialog {
  width: min(var(--dialog-width), calc(100% - var(--space-6)));
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--section-surface);
  box-shadow: var(--shadow-modal);
  color: var(--text-primary);
  padding: var(--space-6);
}

dialog::backdrop {
  background: var(--ds-scrim);
}

.dialog-wide {
  width: min(var(--dialog-width-wide), calc(100% - var(--space-6)));
}

.dialog-title {
  font-family: var(--font-display);
  font-size: var(--size-modal-title);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-modal);
  text-transform: uppercase;
}

[dir="rtl"] .dialog-title {
  font-family: var(--ds-font-body);
  letter-spacing: 0;
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.is-hidden {
  display: none !important;
}

[hidden] {
  display: none !important;
}

.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;
}

/* ==========================================================================
   Language selector: pure-HTML disclosure menu listing all supported locales.
   ========================================================================== */

.language-menu {
  position: relative;
}

.language-menu > summary {
  list-style: none;
  cursor: pointer;
  min-height: var(--control-nav);
  display: inline-flex;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.language-menu > summary::-webkit-details-marker { display: none; }

.language-menu[open] > summary,
.language-menu > summary:hover {
  border-color: var(--border-hover);
  color: var(--text-primary);
}

.language-menu > ul {
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: calc(100% + 6px);
  z-index: var(--z-intel-drawer);
  min-width: 178px;
  margin: 0;
  padding: 6px;
  list-style: none;
  display: grid;
  gap: 2px;
  background: var(--page-bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-float);
}

/* Each locale is a submit button in its own form, not a link: the return path
   travels in the body so a Desert Storm share token never lands in a URL. */
.language-menu > ul form { margin: 0; }

.language-menu > ul button {
  display: block;
  width: 100%;
  min-height: var(--control-compact);
  padding: 7px 10px;
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  text-align: start;
  cursor: pointer;
}

.language-menu > ul button:hover { background: var(--raised-surface); color: var(--text-primary); }

.language-menu > ul button.is-active {
  background: var(--ds-gold-soft);
  color: var(--accent-hover);
}

/* ==========================================================================
   Shared site footer: canonical platform identity + non-affiliation notice.
   ========================================================================== */

/* A compact application footer, not a marketing block: the two required lines
   (identity + non-affiliation) at meta size, tight leading, and no 72px of
   trailing air after every workflow. */
.site-footer {
  margin-top: var(--space-6);
  padding: var(--space-4) var(--space-6) var(--space-5);
  border-top: 1px solid var(--border-subtle);
  text-align: center;
}

.site-footer p {
  margin: 0 auto;
  max-width: 760px;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--text-muted);
}

.site-footer .site-footer-identity {
  color: var(--text-secondary);
}

.site-footer .site-footer-disclaimer {
  margin-top: 6px;
  color: var(--text-faint);
}

/* ==========================================================================
   Responsive. The phone tier is 560, not 520: the Desert Storm phone shell class
   is set from matchMedia("(max-width: 560px)"), and two numbers for one idea is
   how a control ends up styled for a shell it is not in.
   ========================================================================== */

@media (max-width: 1024px) {
  .topbar-inner {
    position: relative;
  }

  .menu-button {
    display: inline-flex;
  }

  /* Overflow rather than crush: below the tablet tier the whole nav becomes one
     panel of full-width rows, so a translated label never has to shrink to fit. */
  .navlinks {
    position: absolute;
    inset-block-start: calc(100% + 1px);
    inset-inline: 0;
    display: grid;
    justify-content: stretch;
    gap: var(--space-1);
    max-height: calc(100dvh - var(--sticky-header-height) - 8px);
    overflow-y: auto;
    border: 1px solid var(--border-subtle);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--ds-frame);
    box-shadow: var(--shadow-raised);
    padding: var(--space-3);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--motion-fast) ease, transform var(--motion-fast) ease;
  }

  .navlinks[data-open="true"] {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }

  /* Every row in the panel is a full-width, start-aligned, thumb-sized target.
     The logout button and the language summary were the two that were not: one
     stayed centred and the other stayed its own content width, so the panel read
     as a list with two things that had fallen out of it. */
  .navlinks a,
  .nav-group > summary,
  .navlinks .nav-logout-form,
  .navlinks .nav-logout-form button,
  .navlinks .language-menu,
  .navlinks .language-menu > summary {
    justify-content: flex-start;
    width: 100%;
    min-height: var(--control-touch);
  }

  .navlinks .language-menu > summary {
    font-size: var(--text-sm);
  }

  /* A disclosure inside an already-open panel does not need to float. */
  .nav-group-panel {
    position: static;
    box-shadow: none;
    background: transparent;
    border: 0;
    border-inline-start: 1px solid var(--border-subtle);
    border-radius: 0;
    margin-inline-start: 10px;
    padding-inline: 4px;
  }

  .language-menu > ul {
    position: static;
    box-shadow: none;
    border: 1px solid var(--border-subtle);
    margin-top: 6px;
  }

  .section-title,
  .page-hero,
  .profile-hero {
    display: grid;
  }
}

@media (max-width: 560px) {
  .topbar-inner {
    min-height: var(--sticky-header-height);
  }

  .brand-text {
    max-width: 168px;
    font-size: var(--text-md);
  }

  .shell {
    padding-top: var(--space-5);
  }

  .panel,
  .comparison-hero {
    padding: var(--space-4);
  }

  .button-row,
  .report-actions {
    align-items: stretch;
  }

  .button-row > *,
  .report-actions > * {
    flex: 1 1 100%;
  }

  /* Full-width primary actions on a phone. Scoped away from anything that lives
     inside a flex row of its own — a declared width becomes the flex basis, and
     a 100% basis makes a control claim its whole row. */
  button,
  .button {
    width: 100%;
  }

  .button-row .compact-button,
  .status-row button,
  .chip-row button,
  .panel-header button,
  .breadcrumbs button,
  .language-menu > summary,
  .menu-button,
  .icon-button {
    width: auto;
  }

  .site-footer {
    /* Compact on phones too — this later same-specificity rule would
       otherwise quietly restore the large footer the base rule just shed. */
    margin-top: var(--space-5);
    padding: var(--space-3) var(--space-3) var(--space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.001ms !important;
  }
}

@media print {
  :root {
    color-scheme: light;
  }

  body {
    background: #ffffff !important;
    color: #111827 !important;
    font-size: 12px;
  }

  .skip-link,
  .topbar,
  .no-print,
  .menu-button {
    display: none !important;
  }

  .shell {
    width: 100%;
    padding: 0;
  }

  .panel,
  .comparison-hero,
  .report-card,
  .metric-card {
    break-inside: avoid;
    border-color: #d1d5db !important;
    background: #ffffff !important;
    box-shadow: none !important;
    color: #111827 !important;
  }

  a,
  .muted,
  p,
  small,
  .eyebrow,
  .metadata-line,
  .status-pill {
    color: #374151 !important;
  }
}
