/* components.css — reusable UI kit */

/* Panels / cards */
.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
  padding: var(--s-5);
}
.panel-head { display: flex; align-items: baseline; gap: var(--s-3); margin-bottom: var(--s-3); }
.panel-title { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg); }

/* Buttons */
.btn {
  font-family: var(--font-body); font-size: var(--fs-sm); font-weight: 700;
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--ink);
  padding: var(--s-2) var(--s-4); border-radius: var(--r-md); cursor: pointer;
  transition: transform var(--t-fast) var(--ease), background var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
}
.btn:hover { border-color: var(--accent-300); box-shadow: var(--shadow-sm); }
.btn:active { transform: translateY(1px); }
.btn-accent { background: var(--accent); border-color: var(--accent-700); color: #fff; }
.btn-accent:hover { background: var(--accent-700); }
.btn-honors { background: var(--honors); border-color: var(--honors-700); color: #fff; }
.btn-honors:hover { background: var(--honors-700); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--accent-700); }
.btn-ghost:hover { background: var(--accent-050); box-shadow: none; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-sm { font-size: var(--fs-xs); padding: var(--s-1) var(--s-3); }

/* Tabs */
.tabs { display: flex; gap: var(--s-1); border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.tab {
  appearance: none; background: none; border: none; cursor: pointer;
  font-family: var(--font-body); font-size: var(--fs-sm); font-weight: 700; color: var(--muted);
  padding: var(--s-3) var(--s-4); border-bottom: 3px solid transparent; margin-bottom: -1px;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.tab:hover { color: var(--ink-2); }
.tab[aria-selected="true"] { color: var(--accent-700); border-bottom-color: var(--accent); }

/* Badges + pills */
.badge {
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 700;
  background: var(--accent-050); color: var(--accent-700);
  border: 1px solid var(--accent-100); border-radius: var(--r-sm);
  padding: 2px 7px; white-space: nowrap;
}
.badge-honors { background: var(--honors-050); color: var(--honors-700); border-color: var(--honors-100); }
.pill {
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 700;
  border-radius: var(--r-pill); padding: 2px 10px; letter-spacing: .04em;
}
.pill-ready   { background: var(--success-050); color: var(--success); }
.pill-planned { background: var(--surface-3); color: var(--muted); }

/* Fields */
label { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2); }
.field { display: flex; flex-direction: column; gap: var(--s-2); }
input[type="number"], input[type="text"], select {
  font-family: var(--font-mono); font-size: var(--fs-md); color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); padding: var(--s-2) var(--s-3); width: 100%;
}
input[type="number"]:focus, select:focus { border-color: var(--accent); background: #fff; }

/* Range slider */
input[type="range"] { width: 100%; accent-color: var(--accent); height: 26px; }

/* Honors toggle switch */
.switch { display: inline-flex; align-items: center; gap: var(--s-3); cursor: pointer; user-select: none; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 46px; height: 26px; border-radius: var(--r-pill); background: var(--border-strong);
  position: relative; transition: background var(--t-med) var(--ease); flex: none;
}
.switch .track::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: 50%; background: #fff; box-shadow: var(--shadow-sm);
  transition: transform var(--t-med) var(--ease);
}
.switch input:checked + .track { background: var(--honors); }
.switch input:checked + .track::after { transform: translateX(20px); }
.switch input:focus-visible + .track { outline: 3px solid var(--accent-300); outline-offset: 2px; }
.switch .label-text { font-weight: 700; font-size: var(--fs-sm); }

/* Honors-only blocks */
.honors-block {
  border-left: 3px solid var(--honors); background: var(--honors-050);
  border-radius: 0 var(--r-md) var(--r-md) 0; padding: var(--s-4); margin-top: var(--s-4);
}
.honors-tag {
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 700;
  color: var(--honors-700); letter-spacing: .12em; text-transform: uppercase;
}

/* Feedback callouts */
.note { border-radius: var(--r-md); padding: var(--s-3) var(--s-4); font-size: var(--fs-sm); border: 1px solid; }
.note-ok   { background: var(--success-050); border-color: #bfe0cd; color: #1f6b41; }
.note-warn { background: var(--warn-050);   border-color: #e6d49a; color: #7c5d11; }
.note-bad  { background: var(--danger-050); border-color: #e6bbae; color: #8a3320; }
.note-info { background: var(--accent-050); border-color: var(--accent-100); color: var(--accent-700); }

/* Data table */
table.data { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
table.data th, table.data td { text-align: left; padding: var(--s-2) var(--s-3); border-bottom: 1px solid var(--border); }
table.data th { font-family: var(--font-mono); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
table.data td.num, table.data th.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Stat readout */
.stat { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--s-3) var(--s-4); }
.stat .k { font-size: var(--fs-xs); color: var(--muted); font-family: var(--font-mono); text-transform: uppercase; letter-spacing: .08em; }
.stat .v { font-family: var(--font-mono); font-size: var(--fs-xl); font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }

/* ===== Live dial (x-gauge) — a half-circle dashboard gauge per number =====
   Paired with the .stat card it explains: the card carries the figure, the gauge
   carries which side of the baseline it sits on and which way the last control
   move pushed it. See shared/js/gauge.js for the axis reasoning (a multiplier
   gets a LOG axis centred on its baseline, so x1/2 and x2 are symmetric) and for
   the arc geometry, which is pure and node-tested.

   COLOUR IS CATEGORICAL. The hue says which quantity a gauge reads, so a row of
   them is told apart at a glance. It never says whether the value is good, so
   each arc keeps ONE hue across its whole travel. Direction is carried three
   other ways: which side of the baseline mark the coloured sweep grows from, an
   arrow glyph, and a word. Tones live in tokens.css. */
.dial {
  display: block; margin-top: var(--s-1);
  --dial-hue: var(--dial-teal);
  --dial-hue-deep: var(--dial-teal-deep);
}
.stat .dial { margin-top: 0; }
.dial[data-tone="indigo"] { --dial-hue: var(--dial-indigo); --dial-hue-deep: var(--dial-indigo-deep); }
.dial[data-tone="green"]  { --dial-hue: var(--dial-green);  --dial-hue-deep: var(--dial-green-deep); }
.dial[data-tone="plum"]   { --dial-hue: var(--dial-plum);   --dial-hue-deep: var(--dial-plum-deep); }
.dial[data-tone="slate"]  { --dial-hue: var(--dial-slate);  --dial-hue-deep: var(--dial-slate-deep); }

/* The face. Capped so three of these fit one .stat-row without the row taking
   over a laptop screen, and so a gauge in a full-width panel stays
   instrument-sized instead of ballooning. Stroke width and tick font size come
   from DIAL_GEOM as SVG attributes, not from here: the label positions are
   computed against them, so they have to have one owner. */
.dial-face { display: block; width: 100%; max-width: 150px; margin: 0 auto; overflow: visible; }

.dial-arc-track { stroke: var(--surface-3); }
.dial-arc-fill {
  stroke: var(--dial-hue);
  transition: stroke-dasharray var(--t-med) var(--ease), stroke-dashoffset var(--t-med) var(--ease);
}
/* Off-scale: the far sliver darkens, and .dial-read says "off the top of the
   dial" in words, so a pinned needle never reads as an exact maximum. */
.dial-arc-cap { stroke: var(--dial-hue-deep); opacity: 0; }
.dial[data-over="hi"] .dial-arc-cap,
.dial[data-over="lo"] .dial-arc-cap { opacity: 1; }

/* The baseline the "x" is measured from. Crosses the arc, so it reads as a datum
   on the scale and not as one more tick outside it. */
.dial-arc-ref { stroke: var(--ink-2); stroke-width: 1.4; }
.dial-tick-mark { stroke: var(--border-strong); stroke-width: 1.2; }

/* Where the reading sat before the last control move: a hollow bead riding the
   arc, so it never competes with the needle for "this is the value". */
.dial-ghost {
  opacity: 0;
  transition: opacity var(--t-med) var(--ease), transform var(--t-med) var(--ease);
}
.dial-ghost circle { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1.4; }
.dial.is-moving .dial-ghost { opacity: .9; }
.dial-needle {
  stroke: var(--ink); stroke-width: 2.2; stroke-linecap: round;
  transition: transform var(--t-med) var(--ease);
}
.dial-hub { fill: var(--ink); }

.dial-tick {
  font-family: var(--font-mono); fill: var(--muted);
  font-variant-numeric: tabular-nums;
}
.dial-tick.is-ref { fill: var(--ink-2); font-weight: 700; }
/* The linear track needed a container query here to drop intermediate labels on
   a narrow card. The arc does not: the two ends sit BELOW the baseline while
   everything between rides the arc, so the rows that used to collide are now
   separated by construction. Label geometry and text size are both in viewBox
   units, so the spacing is scale-invariant and every tick can stay. */

/* Stacked and centred under the gauge face, the way an instrument's digital
   readout sits under its dial. Pulled up tight against the arc: the face already
   carries whitespace below its end labels. */
.dial-foot {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  text-align: center;
}
.dial-trend {
  display: inline-flex; align-items: baseline; gap: 4px; flex: none;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 700;
  letter-spacing: .04em; border-radius: var(--r-sm); padding: 1px 7px;
  opacity: 0; transition: opacity var(--t-med) var(--ease);
  /* Flat fallback first, then tinted to match its own gauge so the chip and the
     arc read as one instrument. */
  color: var(--dial-hue-deep); background: var(--surface-3); border: 1px solid var(--border);
  background: color-mix(in srgb, var(--dial-hue) 13%, transparent);
  border-color: color-mix(in srgb, var(--dial-hue) 32%, transparent);
}
.dial.is-moving .dial-trend { opacity: 1; }
.dial-arrow { font-size: .8em; line-height: 1; }
.dial-read { font-size: var(--fs-2xs); color: var(--ink-2); line-height: 1.35; }

/* Gauges need a little more room than a plain stat row, but not much: the face
   caps at 150px, so 186px is enough for it plus the card's own padding. Keeping
   this tight is what lets three gauge cards share one row on a laptop instead of
   wrapping and pushing the panel off the bottom of the screen. */
.stat-row.has-dials { grid-template-columns: repeat(auto-fit, minmax(186px, 1fr)); }
/* A gauge card is taller than a bare number, so it gets less padding back. */
.stat:has(> .dial) { padding: var(--s-3); }

/* ===== "Feel a mole" powers-of-ten zoom (shared by U5 and U5a) =====
   Pairs with shared/js/molezoom.js. The dot field is a string-built SVG
   fragment, so the only styling it needs is the dot fill. */
/* Mechanic D: "Feel a mole" zoom */
.zoom-stage {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--s-3); margin-top: var(--s-3);
}
.zoom-svg { display: block; width: 100%; height: auto; }
.zoom-dots circle { fill: var(--accent); }
.zoom-readout { display: flex; align-items: baseline; gap: var(--s-2); margin-top: var(--s-4); }
.zoom-count { font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-2xl); color: var(--accent-700); }
/* The exponent is a raised run of ORDINARY digits, not a Unicode superscript: the
   mono face carries 1/2/3 but not 0 or 4-9, so 10^6 would swap fonts mid-number.
   Offset with position rather than vertical-align:super so raising it cannot grow
   the line box and shove the readout row apart. */
.zoom-count sup { font-size: .58em; vertical-align: baseline; position: relative; top: -.46em; }
.zoom-unit { font-size: var(--fs-md); color: var(--muted); }
.zoom-slider { width: 100%; }
.zoom-analogy { margin-top: var(--s-3); font-size: var(--fs-md); font-weight: 600; }

/* Particle token visualization */
.tokenfield { display: flex; flex-direction: column; gap: var(--s-3); }
.tokenrow { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.tokenrow .rowlabel { width: 92px; flex: none; font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-sm); }
.tokens { display: flex; flex-wrap: wrap; gap: 5px; }
.token {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 9px; font-weight: 700; color: #fff;
  box-shadow: inset 0 -3px 6px rgba(0,0,0,.18);
  animation: pop var(--t-med) var(--ease) both;
}
@keyframes pop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* Element-cell unit cards (periodic-table vernacular) */
.cell-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--s-4); }
.cell {
  position: relative; display: flex; flex-direction: column; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--s-4);
  min-height: 230px; box-shadow: var(--shadow-sm); color: var(--ink);
  transition: transform var(--t-med) var(--ease), box-shadow var(--t-med), border-color var(--t-med);
  overflow: hidden;
}
a.cell:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--accent-300); text-decoration: none; }
a.cell.is-planned { cursor: default; }
a.cell.is-planned:hover { transform: none; box-shadow: var(--shadow-sm); border-color: var(--border); }
.cell.is-planned { opacity: .72; }
.cell .num { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--muted); }
.cell .abbr { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-xl); color: var(--accent-700); line-height: 1; margin: var(--s-1) 0 var(--s-1); }
.cell .ct { font-weight: 700; font-size: var(--fs-sm); margin-bottom: var(--s-3); }
.cell .hook {
  font-size: var(--fs-sm); line-height: 1.45; color: var(--ink-2); font-weight: 700;
  font-family: var(--font-display);
}
.cell .foot { margin-top: auto; padding-top: var(--s-3); display: flex; justify-content: flex-start; align-items: center; }
.cell .casewrap { display: inline-flex; align-items: center; gap: var(--s-2); min-width: 0; }
.cell .case-ico {
  flex: none; width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent-050); color: var(--accent-700); font-size: 7px;
  transition: background var(--t-fast), color var(--t-fast);
}
a.cell:hover .case-ico { background: var(--accent); color: #fff; }
.cell .case-label {
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 700; color: var(--accent-700);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cell .case-label.muted { color: var(--muted); }
.cell .accentbar { position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--accent), var(--accent-300)); }
.cell.is-planned .accentbar { background: var(--border-strong); }

/* Equation surface */
.eqn { background: var(--surface-2); border: 1px dashed var(--border-strong); border-radius: var(--r-md); padding: var(--s-4); text-align: center; font-size: 1.3rem; overflow-x: auto; }

/* Coefficient steppers for the balancer */
.coefbox { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; }
.coefbox .cf {
  width: 56px; text-align: center; font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-lg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: 2px;
}
.species { display: inline-flex; align-items: center; gap: 6px; font-size: 1.25rem; }
.balance-row { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; justify-content: center; }

.choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px,1fr)); gap: var(--s-3); }
.choice {
  text-align: left; padding: var(--s-3) var(--s-4); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); background: var(--surface); cursor: pointer; font-weight: 700; font-size: var(--fs-sm);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.choice:hover { border-color: var(--accent-300); }
.choice[data-state="on"]  { border-color: var(--accent); background: var(--accent-050); color: var(--accent-700); }
.choice[data-state="correct"] { border-color: var(--success); background: var(--success-050); color: #1f6b41; }
.choice[data-state="wrong"]   { border-color: var(--danger); background: var(--danger-050); color: #8a3320; }

[x-cloak] { display: none !important; }

/* Shared simulator layout (used by every unit) */
.sim-grid { display: grid; grid-template-columns: 1fr 300px; gap: var(--s-5); align-items: start; }
/* A grid item defaults to min-width:auto, so one wide child (a long equation, a fixed-width
   table or canvas) would push the whole grid past the viewport instead of scrolling inside
   its own box. Belongs with the layout it guards, not copied into each unit. */
.sim-grid > .stack { min-width: 0; }
@media (max-width: 880px) { .sim-grid { grid-template-columns: 1fr; } }
.se-panel { position: sticky; top: 84px; }
.se-item { padding: var(--s-3); border-radius: var(--r-md); border: 1px solid var(--border); margin-bottom: var(--s-2); transition: border-color var(--t-fast), background var(--t-fast); }
.se-item.active { border-color: var(--accent); background: var(--accent-050); }
.se-item .se-code { font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-sm); }
.se-item .se-text { font-size: var(--fs-xs); color: var(--ink-2); }
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-3); }
.eqn-arrow { font-family: var(--font-mono); font-size: 1.4rem; color: var(--muted); padding: 0 var(--s-1); }

/* ===== Gamification layer (scenario + per-TEKS mastery) =====
   Reuses existing tokens. Copper stays Honors-only. Reward state is never
   color-only: every meter/badge is paired with .note or readout text in markup. */

/* Mission banner: one-line role + objective above the tabs */
.mission {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-4);
  background: var(--accent-050); border: 1px solid var(--accent-100);
  border-left: 4px solid var(--accent); border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4); margin-bottom: var(--s-4);
}
.mission-role {
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; color: var(--accent-700);
}
.mission-goal { font-size: var(--fs-sm); color: var(--ink-2); }

/* Mastery meter (a skill's run toward mastery) */
.meter {
  height: 7px; border-radius: var(--r-pill); background: var(--surface-3);
  overflow: hidden; margin-top: var(--s-2);
}
.meter-fill {
  height: 100%; width: 0; background: var(--accent); border-radius: inherit;
  transition: width var(--t-med) var(--ease);
}
.meter-fill.honors { background: var(--honors); }

/* Mastered SE row: success border + check (paired with the meter's text label) */
.se-item.mastered { border-color: var(--success); background: var(--success-050); }
.se-item.mastered .se-code::after { content: " \2713"; color: var(--success); }

/* Badges: locked vs earned (each carries its own word, never color alone) */
.badge.locked { background: var(--surface-3); color: var(--muted); border-color: var(--border); }
.badge.earned {
  background: var(--success-050); color: #1f6b41; border-color: #bfe0cd;
  animation: pop var(--t-med) var(--ease) both;
}
.badge.earned.honors { background: var(--honors-050); color: var(--honors-700); border-color: var(--honors-100); }

/* ===== Scenario layer (brief -> tool -> commit -> verdict -> world-state) =====
   Outcomes are the primary feedback. Reuses semantic tokens; copper stays
   Honors-only; verdict tone is never color-only (each carries a headline word). */

/* Brief: the situation card above each stage's tool (role, goal, spec, why) */
.brief {
  background: var(--surface-2); border: 1px solid var(--border);
  border-left: 4px solid var(--accent); border-radius: var(--r-md);
  padding: var(--s-4); margin-bottom: var(--s-4);
}
.brief-role {
  display: block; font-family: var(--font-mono); font-size: var(--fs-xs);
  font-weight: 700; text-transform: uppercase; letter-spacing: .1em;
  color: var(--accent-700); margin-bottom: var(--s-2);
}
.brief-goal { font-size: var(--fs-sm); color: var(--ink); }
.brief-spec {
  font-size: var(--fs-sm); color: var(--ink-2); margin-top: var(--s-2);
  padding-left: var(--s-3); border-left: 2px solid var(--accent-300);
}
.brief-why { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--s-2); font-style: italic; }

/* Verdict: the consequence of committing (the main feedback) */
.verdict {
  border-radius: var(--r-md); padding: var(--s-4); margin-top: var(--s-4);
  border: 1px solid; display: flex; flex-direction: column; gap: var(--s-2);
  animation: rise var(--t-med) var(--ease) both;
}
.verdict-headline { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg); }
.verdict-detail { font-size: var(--fs-sm); line-height: var(--lh-body); }
.verdict-success { background: var(--success-050); border-color: #bfe0cd; color: #1f6b41; }
.verdict-warn    { background: var(--warn-050);    border-color: #e6d49a; color: #7c5d11; }
.verdict-fail    { background: var(--danger-050);  border-color: #e6bbae; color: #8a3320; }
@keyframes rise { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* Status reaction: a big emoji + state word that shows what the number DID */
.status { display: flex; align-items: center; gap: var(--s-3); }
.status-icon { font-size: 2.2rem; line-height: 1; }
.status-state {
  font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-md);
  letter-spacing: .06em;
}

/* Gauge: where a dose landed relative to the on-spec window (under | on | over) */
.gauge { display: flex; gap: 4px; margin-top: var(--s-1); }
.gauge-seg {
  flex: 1; text-align: center; padding: var(--s-1) var(--s-2);
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 700;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-3); color: var(--muted);
}
.gauge-seg.on   { background: var(--success-050); color: #1f6b41; border-color: #bfe0cd; }
.gauge-seg.miss { background: var(--danger-050);  color: #8a3320; border-color: #e6bbae; }

/* World-state: crew safety + the ship's log (session-local, the primary feedback) */
.worldstate { }
.crew-status { display: flex; align-items: center; gap: var(--s-4); margin-bottom: var(--s-4); }
.crew-face { font-size: 2.4rem; line-height: 1; flex: none; }
.crew-bar { flex: 1; }
.worldstate-list { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.worldstate-entry {
  display: flex; gap: var(--s-3); align-items: center;
  font-size: var(--fs-sm); padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md); border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong); background: var(--surface-2);
}
.worldstate-entry.good { border-left-color: var(--success); }
.worldstate-entry.warn { border-left-color: var(--warn); }
.worldstate-entry.bad  { border-left-color: var(--danger); }
.worldstate-entry .ws-icon { font-size: var(--fs-lg); flex: none; }
.worldstate-empty { font-size: var(--fs-sm); color: var(--muted); margin-top: var(--s-2); }

@media (prefers-reduced-motion: reduce) {
  .meter-fill { transition: none; }
  .badge.earned { animation: none; }
  .verdict { animation: none; }
  /* The gauge's reading stays truthful without the travel: the needle, the
     coloured sweep and the trend chip all snap, and the ghost needle (which only
     means anything as a fading trail) is dropped. */
  .dial-arc-fill, .dial-needle, .dial-ghost, .dial-trend { transition: none; }
  .dial-ghost { display: none !important; }
}
