/*
 * SoundingScope — Component Styles (AutoOutlook neo-brutalist)
 *
 * Built on tokens.css. Square corners, thick ink borders, hard offset
 * shadows, uppercase display headings, mono labels. Keeps the class names the
 * existing HTML/JS already reference (.app-shell, .card, .segmented, .slider,
 * .reveal-row, .result-row, etc.) so only the look changes.
 */

/* The `hidden` attribute always wins over the display rules below. */
[hidden] {
  display: none !important;
}

/* ========================================================================
 * App layout — centered column + page shell
 * ===================================================================== */
.app-shell {
  width: 100%;
  max-width: var(--content-max-width-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
  box-sizing: border-box;
}

/* Plain header row — NOT a nav bar: title far-left, settings far-right.
   Aligned to the same content column as the cards below; space-between pushes
   the title and settings to opposite edges. */
.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-4) 0;
}

.app-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.app-title {
  margin: 0;
  color: var(--ink);
}

/* Main content rhythm. Kept tight so the play view (chart + forecast form)
   fits within the viewport without scrolling on a typical laptop. */
main.app-shell {
  padding-block: var(--space-4) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.app-status {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  line-height: var(--type-subhead-line);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  text-align: center;
}

/* Reset notice — a small "instrument footer" chip pinned to the center bottom
   of the play view. `margin-top: auto` drops it to the foot of the flex column;
   `align-self: center` centers it horizontally. Framed, mono, uppercase with an
   amber tick marker so it matches the chart-source / level-readout captions
   instead of reading as a loose line of body text. */
.reset-info {
  margin: var(--space-2) 0 0;
  margin-top: auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--surface-sunk);
  border: var(--border-w-thin) solid var(--ink);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  line-height: 1;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-muted);
}
.reset-info::before {
  content: "";
  width: 8px;
  height: 8px;
  flex: none;
  background: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}

/* ========================================================================
 * Cards / panels — retro-card: paper, 3px ink border, hard shadow, square
 * ===================================================================== */
.card {
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--space-6);
}

.section + .section {
  margin-top: var(--space-8);
}

/* Puzzle layout: the tall Skew-T chart occupies the full-height left column,
   while the right column stacks the forecast selections (top) and the hint
   panel (bottom). Putting the hint panel in the right column fills the slack
   beneath the (shorter) form rather than adding a new row under the chart, so
   the whole play view stays within the viewport without scrolling. */
.puzzle-card {
  display: grid;
  grid-template-columns: minmax(0, 2.3fr) minmax(340px, 1fr);
  grid-template-rows: auto auto;
  gap: var(--space-6);
  align-items: start;
}
.puzzle-card .chart-panel {
  grid-column: 1;
  grid-row: 1 / span 2;
}
.puzzle-card .selections-panel {
  grid-column: 2;
  grid-row: 1;
}
.puzzle-card .hint-panel-card {
  grid-column: 2;
  grid-row: 2;
}
/* After the day is played the form/hint are removed and this takes the right
   column beside the chart, so the result + countdown stay above the fold. */
.puzzle-card .completed-panel {
  grid-column: 2;
  grid-row: 1 / span 2;
}

/* Forecast selections column: a touch tighter than the default card so the
   risk / hazard / CAPE controls stack within the chart's height (no scroll). */
.selections-panel {
  padding: var(--space-5);
}

/* Hint panel sits under the form in the right column; keep it slim. */
.hint-panel-card {
  padding: var(--space-4);
}

/* Stack vertically on narrow viewports (chart on top, selections below). */
@media (max-width: 860px) {
  .puzzle-card {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    gap: var(--space-5);
  }
  /* Reset the desktop row/column spanning so the three cards flow in source
     order: chart, then the forecast form, then the hint panel. */
  .puzzle-card .chart-panel,
  .puzzle-card .selections-panel,
  .puzzle-card .hint-panel-card,
  .puzzle-card .completed-panel {
    grid-column: 1;
    grid-row: auto;
  }
}

/* Chart card: chart + provenance hint strip (the description). */
.chart-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  /* Positioning context for the floating level-inspection readout. */
  position: relative;
}

/* Chart view switch — a segmented control that swaps the Skew-T and the
   hodograph in and out of the same well. Two hard-framed buttons share one
   border; the active view is inverted (ink fill) like the rest of the
   brutalist button set. */
.chart-switch {
  display: inline-flex;
  align-self: flex-start;
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.chart-switch__btn {
  appearance: none;
  margin: 0;
  padding: var(--space-2) var(--space-4);
  border: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}
.chart-switch__btn + .chart-switch__btn {
  border-left: var(--border-w-thin) solid var(--ink);
}
.chart-switch__btn:hover {
  background: var(--surface-sunk);
}
.chart-switch__btn.is-active {
  background: var(--ink);
  color: var(--paper);
}

/* Each view is a fixed-size framed well; the Skew-T and the hodograph sit
   centered inside at their natural aspect ratio, so both views are exactly the
   same width and height while neither chart is distorted. This is also the
   positioning context for the overlays mounted over the chart (level-inspector
   readout, parcel path), so they hide with the view when it is swapped out. */
.chart-view {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* A fixed height plus a shared aspect ratio make both views identical in
     width AND height. Both charts now render landscape at this aspect, so each
     fills its frame with no matte. */
  height: min(72vh, 620px);
  aspect-ratio: 864 / 738;
  max-width: 100%;
  margin-inline: auto;
  background: #f5f1e8;
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

/* Each view fills the well; positioning context for overlays lives on
   .chart-view above. */

/* Sounding-source panel — a framed "instrument readout" attached beneath the
 * chart (Beginner only). Replaces the loose chip strip with a titled panel so
 * the provenance reads as a deliberate part of the chart, not an afterthought. */
.chart-source {
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: var(--surface-sunk);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

/* Header bar: inverted ink strip with a mono caption and an amber marker. */
.chart-source__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 700;
}

.chart-source__title::before {
  content: "";
  width: 9px;
  height: 9px;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--paper);
}

/* Hint cells — equal columns divided by hard rules, label stacked over value. */
.chart-hints {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

.chart-hint {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4);
  border-left: var(--border-w-thin) solid var(--ink);
}

/* No rule before the first *visible* cell. Leading cells may be hidden when a
 * value is absent, so cover those cases too (3 cells max). */
.chart-hint:first-child,
.chart-hint[hidden] + .chart-hint,
.chart-hint[hidden] + .chart-hint[hidden] + .chart-hint {
  border-left: 0;
}

.chart-hint__label {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
}

.chart-hint__value {
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  font-weight: 700;
  color: var(--ink);
  word-break: break-word;
}

/* Stack the cells vertically on narrow viewports so long model names fit. */
@media (max-width: 560px) {
  .chart-hints {
    grid-auto-flow: row;
    grid-auto-columns: auto;
  }
  .chart-hint {
    border-left: 0;
    border-top: var(--border-w-thin) solid var(--ink);
  }
  .chart-hint:first-child,
  .chart-hint[hidden] + .chart-hint,
  .chart-hint[hidden] + .chart-hint[hidden] + .chart-hint {
    border-top: 0;
  }
}

/* ========================================================================
 * Lapse-rate table — a framed "instrument readout" of the per-band lapse
 * rate, swapped into the chart well via the chart switch (the "Altitude"
 * view) in place of the Skew-T / hodograph. Shares the brutalist treatment of
 * the sounding-source panel: hard ink frame, an inverted header strip, mono
 * numerals, and zebra rows for scanability.
 * ===================================================================== */
/* Altitude (lapse-rate) view: the table is swapped into the same fixed well as
   the Skew-T / hodograph via the chart switch. Rather than floating as a nested
   card, the table fills the well edge-to-edge so the well's frame is its only
   border (no box-in-a-box, no empty margins). Override the flex centering the
   shared .chart-view rule applies to the image views. */
.chart-view--table {
  display: block;
  padding: 0;
  /* Never scroll: the table is sized to fill this fixed-height well exactly, so
     clip any sub-pixel spillover rather than showing a scrollbar. */
  overflow: hidden;
  background: var(--surface-sunk);
}

.lapse-rate-table-container {
  width: 100%;
  height: 100%;
  margin: 0;
  /* Stack the lapse-rate bands and the SRH summary in the fixed well. The SRH
     table keeps its natural size (so it is always visible) and the lapse-rate
     table fills the remaining space. */
  display: flex;
  flex-direction: column;
}

.lapse-rate-table {
  width: 100%;
  /* Fixed layout so the columns obey their set widths and the short, nowrap
     cell text can never force the table wider than its container. */
  table-layout: fixed;
  border-collapse: collapse;
  /* No own frame/shadow: the well (.chart-view) supplies the single border, so
     the table reads as part of the well rather than a card inside it. */
  background: var(--surface-sunk);
  /* Tabular figures keep the decimal columns aligned. */
  font-variant-numeric: tabular-nums;
}

/* The lapse-rate bands take the slack height; min-height:0 lets the table
   shrink within the well rather than forcing it to grow (and scroll). */
.lapse-rate-table:not(.srh-table) {
  flex: 1 1 auto;
  min-height: 0;
}

/* The SRH summary stays compact at the foot of the well, always visible, with
   a hard rule separating it from the bands above. */
.srh-table {
  flex: 0 0 auto;
  border-top: var(--border-w) solid var(--ink);
}

/* Caption: inverted ink strip with a mono title and an amber marker, matching
   the sounding-source header so the two readouts read as a set. Kept as a real
   table-caption (not display:flex, which dropped it below the header row), so
   it always sits at the very top of the table. */
.lapse-rate-table__caption {
  padding: var(--space-1) var(--space-3);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 700;
  text-align: left;
  caption-side: top;
  /* Keep the title on a single line so it never wraps onto the first data row;
     any spillover is clipped by the table's overflow:hidden. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lapse-rate-table__caption::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  width: 9px;
  height: 9px;
  margin-right: var(--space-2);
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--paper);
}

/* Column headers: mono uppercase labels on a recessed bar, divided from the
   body by a hard rule. The two columns meet at a center rule — the label header
   is right-aligned and the value header left-aligned — so each header sits
   directly over its column's figures (Req 8.4). */
.lapse-rate-table__th {
  padding: var(--space-1) var(--space-4);
  background: var(--surface);
  border-bottom: var(--border-w-thin) solid var(--ink);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  text-align: right;
}

.lapse-rate-table__th + .lapse-rate-table__th {
  text-align: left;
  border-left: 1px solid var(--hairline);
}

/* Body rows: hairline separators + a zebra wash so long bands stay scannable.
   Hovering a row lifts it with the accent so the player can track a band. */
.lapse-rate-table__row + .lapse-rate-table__row .lapse-rate-table__cell {
  border-top: 1px solid var(--hairline);
}

.lapse-rate-table__row:nth-child(even) {
  background: rgba(17, 17, 17, 0.03);
}

.lapse-rate-table__row:hover {
  background: var(--hover-tint);
}

.lapse-rate-table__cell {
  padding: var(--space-1) var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  line-height: var(--type-subhead-line);
  color: var(--ink);
  white-space: nowrap;
  /* Rows stretch to fill the well height, so center the text within each. */
  vertical-align: middle;
}

/* Center-hugging ledger: the altitude/layer label is right-aligned and the
   figure left-aligned, so the two columns meet at a center rule with symmetric
   whitespace on the outer edges — filling the full-width well without leaving a
   void between the columns. */
.lapse-rate-table__cell--altitude {
  color: var(--text);
  width: 50%;
  text-align: right;
}

.lapse-rate-table__cell--lapse-rate {
  width: 50%;
  text-align: left;
  font-weight: 700;
  border-left: 1px solid var(--hairline);
}

/* Unavailable bands: the figure is the non-numeric "—" indicator; dim it so it
   reads as "no value" rather than a real reading (distinct from 0.00). */
.lapse-rate-table__cell--lapse-rate.is-unavailable {
  color: var(--text-faint);
  font-weight: 400;
}

/* Status messages (no-data / load failure) sit beneath the frame. */
.lapse-rate-table__message {
  margin: var(--space-3) 0 0;
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

/* Zebra wash needs to flip in dark mode (the light-ink stripe is invisible on
   the dark "paper"). */
:root[data-theme="dark"] .lapse-rate-table__row:nth-child(even) {
  background: rgba(243, 239, 230, 0.04);
}

/* The SRH summary is a second compact table beneath the lapse-rate bands in
   the same panel; give it breathing room so the two readouts read as a stack
   rather than one run-on grid. */
.srh-table {
  margin-top: var(--space-4);
}

/* ========================================================================
 * Buttons — retro-button: square, uppercase display, hard shadow, press-shift
 * ===================================================================== */
.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 50px;
  padding: var(--space-3) var(--space-5);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-display);
  font-size: var(--type-headline-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.btn-primary:hover {
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 var(--shadow-color);
}
.btn-primary:active {
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 0 var(--shadow-color);
}
.btn-primary:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
  box-shadow: var(--shadow-sm);
}

/* Secondary / text buttons — amber accent fill, ink border. Accent (not paper)
   so they lift off the cream/dark card surfaces instead of reading as the same
   color as the background in either theme. */
.btn-secondary,
.btn-text {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 40px;
  padding: var(--space-2) var(--space-3);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-display);
  font-size: var(--type-subhead-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.btn-secondary:hover,
.btn-text:hover {
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 var(--shadow-color);
}
.btn-secondary:active,
.btn-text:active {
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 0 var(--shadow-color);
}

@media (min-width: 480px) {
  .btn-primary {
    width: auto;
    min-width: 220px;
  }
}

/* Dev-only reset affordance — small amber chip (dark ink label in both themes). */
.dev-reset {
  flex: none;
  min-height: 34px;
  padding: var(--space-1) var(--space-3);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--type-footnote-size);
  font-family: var(--font-mono);
}

/* ========================================================================
 * Forecast form — field rhythm + mono uppercase labels
 * ===================================================================== */
.forecast-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.field__label {
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink);
}

.field .hint {
  margin-top: 0;
}

/* ========================================================================
 * Segmented control — square cells, thick border, ink-filled selection
 * ===================================================================== */
.segmented {
  display: inline-flex;
  position: relative;
  width: 100%;
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: var(--surface-sunk);
  box-sizing: border-box;
}

.segmented__option {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: var(--space-2) var(--space-2);
  border: none;
  border-right: var(--border-w-thin) solid var(--ink);
  background: transparent;
  border-radius: 0;
  color: var(--text-muted);
  font-family: var(--font-display);
  font-size: var(--type-subhead-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}
.segmented__option:last-child {
  border-right: none;
}
.segmented__option:hover {
  background: var(--hover-tint);
  color: var(--ink);
}

/* Selected: amber accent highlight, dark ink label (legible in both themes). */
.segmented__option[aria-selected="true"],
.segmented__option.is-selected {
  background: var(--accent);
  color: var(--accent-ink);
}

/* ========================================================================
 * Storm_Risk_Level — escalating "risk ladder" (a scale, not buttons)
 * Seven connected steps whose bars grow with severity and fill up to the
 * selected level, mirroring an SPC outlook intensifying.
 * ===================================================================== */
.risk-scale {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  align-items: end;
  gap: var(--space-1);
  width: 100%;
  padding: var(--space-3) var(--space-3) var(--space-2);
  border: var(--border-w) solid var(--ink);
  background: var(--surface-sunk);
  box-sizing: border-box;
}

.risk-scale__step {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-1);
  min-width: 0;
  padding: var(--space-1) 0 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-display);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-standard);
}

/* Bars escalate in height with the ordinal step (None shortest, High tallest). */
.risk-scale__bar {
  width: 100%;
  height: calc(16px + var(--risk-step) * 8px);
  border: var(--border-w-thin) solid var(--ink);
  background: var(--paper);
  /* Border-box so thickening the border on selection doesn't resize the bar
     (which would otherwise shift it and clip against its neighbours). */
  box-sizing: border-box;
  transition: background-color var(--duration-fast) var(--ease-standard);
}

.risk-scale__index {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  color: var(--text-faint);
}

.risk-scale__name {
  font-size: var(--type-footnote-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.1;
  text-align: center;
  white-space: nowrap;
}

.risk-scale__step:hover .risk-scale__bar {
  background: var(--hover-tint-strong);
}
.risk-scale__step:hover {
  color: var(--ink);
}

/* Filled levels (selected and everything below it) take their SPC color. */
.risk-scale__step.is-active .risk-scale__bar {
  background: var(--risk-color);
}
.risk-scale__step.is-active {
  color: var(--ink);
}

/* The chosen level reads as the top of the meter with a bold ink cap. Lift it
   above its neighbours so the thicker border and hard-offset shadow are never
   clipped by the taller bars painted after it. */
.risk-scale__step.is-selected {
  position: relative;
  z-index: 1;
}
.risk-scale__step.is-selected .risk-scale__bar {
  border-width: var(--border-w);
  box-shadow: var(--shadow-sm);
}
.risk-scale__step.is-selected .risk-scale__name {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}

/* ========================================================================
 * Primary_Hazard — icon-card tile picker (a categorical grid, not buttons)
 * ===================================================================== */
.hazard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
  gap: var(--space-2);
  width: 100%;
}

/* Each hazard carries its own accent so the grid reads as a legend of
   threats, not six identical tiles. Falls back to muted ink for "None". */
.hazard-card {
  --hazard-accent: var(--text-muted);
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 80px;
  padding: var(--space-3) var(--space-2) var(--space-2);
  border: var(--border-w-thin) solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard),
    transform var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}

/* Accent stripe pinned to the top edge — the per-hazard color cue. */
.hazard-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 5px;
  background: var(--hazard-accent);
}

.hazard-card[data-value="Rain"]    { --hazard-accent: var(--signal-cyan); }
.hazard-card[data-value="Hail"]    { --hazard-accent: var(--signal-violet); }
.hazard-card[data-value="Wind"]    { --hazard-accent: var(--signal-lime); }
.hazard-card[data-value="Tornado"] { --hazard-accent: var(--signal-red); }
.hazard-card[data-value="Snow"]    { --hazard-accent: var(--navy); }

/* Dark mode: the deep violet (Hail) and navy (Snow) accents collapse into the
   dark page — their top stripe and icon chip all but vanish. Swap in brighter,
   frostier variants that keep each hazard's meaning and stay legible, and read
   correctly when the selected chip fills solid behind the dark glyph. */
:root[data-theme="dark"] .hazard-card[data-value="Hail"] { --hazard-accent: #c77dff; }
:root[data-theme="dark"] .hazard-card[data-value="Snow"] { --hazard-accent: #6cb6ff; }

/* Icon sits in a framed chip tinted with the hazard's accent. */
.hazard-card__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: var(--border-w-thin) solid var(--ink);
  background: color-mix(in srgb, var(--hazard-accent) 16%, var(--surface));
  color: color-mix(in srgb, var(--hazard-accent) 70%, var(--ink));
  transition: background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}

.hazard-card__icon {
  width: 22px;
  height: 22px;
  flex: none;
}

.hazard-card__label {
  font-family: var(--font-display);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  transition: color var(--duration-fast) var(--ease-standard);
}

.hazard-card:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--shadow-md, 4px 4px 0 0 var(--ink));
}
.hazard-card:hover .hazard-card__label {
  color: var(--ink);
}
.hazard-card:hover .hazard-card__glyph {
  background: color-mix(in srgb, var(--hazard-accent) 26%, var(--surface));
}

.hazard-card:focus-visible {
  outline: var(--border-w-thin) solid var(--hazard-accent);
  outline-offset: 2px;
}

/* Selected: the card adopts its hazard accent AND reads as physically pressed.
   The top stripe thickens, the icon chip fills solid, the label takes the
   accent, and — the key cue — the tile drops down-right into the spot its hard
   offset shadow occupied while that raised shadow flips to an inset one. The
   result is an unmistakable "pushed in" button, not just a recolored tile. */
.hazard-card.is-selected {
  border-color: var(--hazard-accent);
  background: color-mix(in srgb, var(--hazard-accent) 14%, var(--surface));
  transform: translate(3px, 3px);
  box-shadow: inset 4px 4px 0 0
    color-mix(in srgb, var(--hazard-accent) 42%, transparent);
}
.hazard-card.is-selected::before {
  height: 8px;
}
.hazard-card.is-selected .hazard-card__glyph {
  background: var(--hazard-accent);
  color: var(--paper);
  border-color: var(--ink);
}
.hazard-card.is-selected .hazard-card__label {
  color: color-mix(in srgb, var(--hazard-accent) 78%, var(--ink));
}
.hazard-card.is-selected:hover {
  /* Stay pressed on hover — a selected pick shouldn't pop back up when the
     cursor returns. Deepen the inset slightly for a little tactile feedback. */
  transform: translate(3px, 3px);
  box-shadow: inset 5px 5px 0 0
    color-mix(in srgb, var(--hazard-accent) 52%, transparent);
}
.field--mode .segmented {
  max-width: 300px;
}

.forecast-form .btn-primary {
  align-self: stretch;
}
@media (min-width: 480px) {
  .forecast-form .btn-primary {
    align-self: flex-start;
  }
}

/* ========================================================================
 * CAPE slider — value readout, instability badge, brutalist track + scale
 * ===================================================================== */
.slider {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Readout: large live value on the left, qualitative band pill on the right. */
.slider__readout {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.slider__value {
  font-family: var(--font-display);
  font-size: var(--type-title2-size);
  line-height: 1;
  font-weight: 800;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.slider__category {
  align-self: center;
  padding: var(--space-1) var(--space-2);
  border: var(--border-w-thin) solid var(--ink);
  background: var(--surface-sunk);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
}
.slider__category[data-level="weak"]     { background: var(--signal-lime);   color: var(--accent-ink); }
.slider__category[data-level="moderate"] { background: var(--signal-amber);  color: var(--accent-ink); }
.slider__category[data-level="strong"]   { background: var(--signal-orange); color: var(--accent-ink); }
.slider__category[data-level="extreme"]  { background: var(--signal-red);    color: #f8f4ec; }

/* Track holds the range input. */
.slider__track {
  position: relative;
  margin-top: var(--space-2);
}

.slider__input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 14px;
  margin: 0;
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: linear-gradient(
    to right,
    var(--accent) 0%,
    var(--accent) var(--slider-fill, 0%),
    var(--surface-sunk) var(--slider-fill, 0%),
    var(--surface-sunk) 100%
  );
  cursor: pointer;
  box-sizing: border-box;
}
.slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 26px;
  height: 26px;
  border-radius: var(--radius);
  background-image: linear-gradient(
    90deg,
    var(--signal-lime),
    var(--signal-amber),
    var(--signal-orange),
    var(--signal-red)
  );
  background-size: 400% 100%;
  background-position: var(--slider-fill, 0%) 0;
  border: var(--border-w) solid var(--ink);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  margin-top: -8px;
  transition: transform var(--duration-fast) var(--ease-standard);
}
.slider__input::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border-radius: var(--radius);
  background-image: linear-gradient(
    90deg,
    var(--signal-lime),
    var(--signal-amber),
    var(--signal-orange),
    var(--signal-red)
  );
  background-size: 400% 100%;
  background-position: var(--slider-fill, 0%) 0;
  border: var(--border-w) solid var(--ink);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-standard);
}
.slider__input::-moz-range-track {
  height: 14px;
  border-radius: var(--radius);
  background: transparent;
}
.slider__input:active::-webkit-slider-thumb {
  transform: scale(1.12);
}
.slider__input:active::-moz-range-thumb {
  transform: scale(1.12);
}

/* Scale axis: tick labels anchoring the 0–8000 J/kg range. */
.slider__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  color: var(--text-faint);
  letter-spacing: 0.04em;
}

/* ========================================================================
 * Hints (Beginner only) — mono caption beneath each control
 * ===================================================================== */
.hint {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--type-subhead-size);
  line-height: var(--type-subhead-line);
}
.is-pro .hint {
  display: none;
}

/* ========================================================================
 * Stats strip — bordered cells of mono numerals
 * ===================================================================== */
.stats-strip {
  display: flex;
  align-items: stretch;
  justify-content: space-around;
  padding: 0;
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.stats-strip__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  flex: 1 1 0;
  padding: var(--space-3) var(--space-2);
  text-align: center;
  border-right: var(--border-w-thin) solid var(--ink);
}
.stats-strip__item:last-child {
  border-right: none;
}

.stats-strip__value {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-family: var(--font-display);
  font-size: var(--type-title2-size);
  line-height: 1;
  font-weight: 800;
  color: var(--ink);
}

.stats-strip__label {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  line-height: var(--type-footnote-line);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.stats-strip__glyph {
  display: inline-block;
  width: 0.95em;
  height: 0.95em;
  vertical-align: -0.1em;
  color: var(--signal-orange);
}

.icon {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ========================================================================
 * Truth_Reveal — a structured card: hero score, verdict chips, metric grid,
 * and readable outcome/why notes. (Lives inside the result popup; the overlay
 * layout is owned by .modal-overlay.)
 * ===================================================================== */

/* The card itself is full-bleed: the hero band runs edge to edge, and the
   inner sections carry their own horizontal padding. */
.reveal-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: 0;
  overflow: hidden;
}

/* Hero — score given top billing on an inverted ink band. */
.reveal-hero {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--paper);
}

.reveal-hero__label {
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  opacity: 0.7;
}

.reveal-hero__score {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--type-large-title-size);
  line-height: 1;
  font-weight: 800;
}
.reveal-hero__score.is-unavailable {
  opacity: 0.6;
  font-weight: 400;
}

.reveal-hero__max {
  font-family: var(--font-mono);
  font-size: var(--type-title2-size);
  font-weight: 500;
  opacity: 0.6;
}

/* Hint marker / penalty note — shown only on a hinted result (Req 2.1, 2.3).
   A bordered callout beneath the hero, with a mono marker and plain-language
   penalty line. Leak-free: it never carries a derived value or the answer. */
.reveal-hint {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-inline: var(--space-6);
  margin-bottom: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: var(--border-w-thin) solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface-muted, transparent);
}

.reveal-hint__marker {
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 700;
}

.reveal-hint__text {
  margin: 0;
  font-size: var(--type-footnote-size);
  color: var(--text-muted, inherit);
  text-align: left;
}

/* Inner sections share a common horizontal gutter. */
.reveal-verdict,
.reveal-metrics,
.reveal-notes,
.reveal-source {
  padding-inline: var(--space-6);
}
.reveal-notes {
  padding-bottom: var(--space-3);
}

/* Verdict — correct risk (color-coded) + primary hazard. */
.reveal-verdict {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}
@media (max-width: 480px) {
  .reveal-verdict {
    grid-template-columns: 1fr;
  }
}

.verdict-chip {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4);
  border: var(--border-w) solid var(--ink);
  background: var(--surface-sunk);
}

.verdict-chip__label {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.verdict-chip__value {
  font-family: var(--font-display);
  font-size: var(--type-title2-size);
  line-height: 1.1;
  font-weight: 700;
  color: var(--ink);
}
.verdict-chip__value.is-unavailable {
  color: var(--text-faint);
  font-style: italic;
  font-weight: 400;
}

/* Risk chip carries an SPC-colored bar on its leading edge. */
.verdict-chip--risk {
  border-left-width: 10px;
  border-left-color: var(--risk-accent, var(--ink));
}
.verdict-chip--risk[data-risk="none"] { --risk-accent: var(--risk-none); }
.verdict-chip--risk[data-risk="thunderstorm"] { --risk-accent: var(--risk-thunderstorm); }
.verdict-chip--risk[data-risk="marginal"] { --risk-accent: var(--risk-marginal); }
.verdict-chip--risk[data-risk="slight"] { --risk-accent: var(--risk-slight); }
.verdict-chip--risk[data-risk="enhanced"] { --risk-accent: var(--risk-enhanced); }
.verdict-chip--risk[data-risk="moderate"] { --risk-accent: var(--risk-moderate); }
.verdict-chip--risk[data-risk="high"] { --risk-accent: var(--risk-high); }

/* Metrics — the four derived values as a tile grid. */
.reveal-metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-3);
}
@media (max-width: 560px) {
  .reveal-metrics {
    grid-template-columns: repeat(2, 1fr);
  }
}

.metric-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
  border: var(--border-w-thin) solid var(--ink);
  background: var(--paper);
}

.metric-tile__label {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

.metric-tile__value {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px;
  font-family: var(--font-display);
  font-size: var(--type-headline-size);
  font-weight: 700;
  color: var(--ink);
}
.metric-tile__value.is-unavailable {
  color: var(--text-faint);
  font-style: italic;
  font-weight: 400;
}

.metric-tile__unit {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  font-weight: 500;
  color: var(--text-muted);
}

/* Notes — outcome + why, set as readable left-aligned prose. */
.reveal-notes {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.reveal-note {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-top: var(--space-3);
  border-top: var(--border-w-thin) solid var(--hairline);
}

.reveal-note__label {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.reveal-note__text {
  margin: 0;
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
  color: var(--text);
  text-align: left;
}
.reveal-note__text.is-unavailable {
  color: var(--text-faint);
  font-style: italic;
}

/* Source — which observation/event this sounding came from, with a link out
   to the public upper-air archive for real (RAOB) soundings. */
.reveal-source {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-top: var(--space-3);
  padding-bottom: var(--space-4);
  border-top: var(--border-w-thin) solid var(--hairline);
}

.reveal-source__label {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

/* One row per sounding — a plain stack for a single source, a numbered list
   when a puzzle carries several. */
.reveal-source__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
}
ol.reveal-source__list {
  list-style: decimal;
  padding-left: var(--space-5);
}
ol.reveal-source__list .reveal-source__item::marker {
  font-family: var(--font-mono);
  color: var(--text-muted);
}
.reveal-source__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.reveal-source__text {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
  color: var(--text);
  text-align: left;
}
.reveal-source[data-synthetic="true"] .reveal-source__text {
  color: var(--text-muted);
  font-style: italic;
}

.reveal-source__link {
  align-self: flex-start;
  font-family: var(--font-display);
  font-size: var(--type-footnote-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--accent-ink);
  background: var(--accent);
  padding: var(--space-1) var(--space-3);
  border: var(--border-w-thin) solid var(--ink);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}
.reveal-source__link:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--shadow-md, 4px 4px 0 0 var(--ink));
}
.reveal-source__link:focus-visible {
  outline: var(--border-w-thin) solid var(--ink);
  outline-offset: 2px;
}

/* Recorded-result lockout view still uses the simple label/value rows. */
.reveal-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-2);
  border-bottom: var(--border-w-thin) solid var(--hairline);
}
.reveal-row:last-child {
  border-bottom: none;
}

.reveal-row__label {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

.reveal-row__value {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  text-align: right;
}
.reveal-row__value.is-unavailable {
  color: var(--text-faint);
  font-style: italic;
  font-weight: 400;
}

.recorded-result .type-headline {
  margin: 0 0 var(--space-3);
}

/* ========================================================================
 * Inline stats — streak / games shown beneath the result (not a popup)
 * ===================================================================== */
.reveal-stats {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  animation: reveal-in var(--duration-slow) var(--ease-standard) both;
}

.reveal-stats__title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  text-align: center;
}

/* ========================================================================
 * Sharing — emoji squares row + mono share string
 * ===================================================================== */
#sharing {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.result-row {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-mono);
  font-size: var(--type-title2-size);
}

.result-row__squares {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* Color-coded accuracy tiles (SVG), bordered to match the brutalist card. */
.share-square {
  display: block;
  width: 22px;
  height: 22px;
}
.share-square rect {
  stroke: var(--ink);
  stroke-width: 2.5;
}
.share-square--miss rect { fill: var(--signal-red); }
.share-square--low rect { fill: var(--signal-orange); }
.share-square--mid rect { fill: var(--signal-amber); }
.share-square--full rect { fill: var(--signal-lime); }

.share-string {
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  color: var(--text-muted);
  text-align: center;
  word-break: break-all;
}

/* ========================================================================
 * Reveal animation
 * ===================================================================== */
.reveal {
  animation: reveal-in var(--duration-slow) var(--ease-standard) both;
}
@keyframes reveal-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ========================================================================
 * Copy-confirmation toast — square ink banner
 * ===================================================================== */
.toast {
  position: fixed;
  left: 50%;
  bottom: var(--space-8);
  transform: translateX(-50%);
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0;
  transition: opacity var(--duration-standard) var(--ease-standard);
  pointer-events: none;
}
.toast.is-visible {
  opacity: 1;
}

/* ========================================================================
 * Chart image
 * ===================================================================== */
.chart-image,
.hodograph-image {
  display: block;
  /* Natural aspect ratio, capped to the framed well so the image box matches
     the rendered chart pixels exactly (the parcel overlay maps to this box).
     Centered inside the well by the .chart-view flex container. */
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--radius);
}

/* Client-side lifted-parcel overlay (Req 9.3). An SVG stretched over the chart
   image via preserveAspectRatio="none"; decorative and click-through so the
   level inspector keeps the hover. The dashed amber trace reads as the parcel
   path distinct from the chart's own red/green temperature/dewpoint lines. */
.parcel-overlay {
  position: absolute;
  pointer-events: none;
  overflow: visible;
}

.parcel-overlay__line {
  fill: none;
  stroke: var(--signal-amber, #f5a623);
  stroke-width: 2px;
  stroke-dasharray: 6 4;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: 0.9;
}

/* "Hodograph unavailable" note shown when no wind data / load failure / timeout
   (Req 4.2, 4.4, 4.5). Framed mono caption so it reads as an instrument state,
   not loose body text. */
.hodograph-message {
  margin: 0;
  padding: var(--space-4);
  border: var(--border-w-thin) dashed var(--ink);
  border-radius: var(--radius);
  background: var(--surface-sunk);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-align: center;
}

/* ========================================================================
 * Inline field / error message — danger red, mono
 * ===================================================================== */
.field-message {
  margin: 0;
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: var(--border-w-thin) solid var(--danger);
  background: rgba(239, 59, 44, 0.08);
  color: var(--danger);
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ========================================================================
 * Settings — header button + centered modal with toggle switches
 * ===================================================================== */
.settings-toggle {
  flex: none;
  min-height: 40px;
}
.settings-toggle__glyph {
  width: 16px;
  height: 16px;
  flex: none;
}

.settings-list {
  display: flex;
  flex-direction: column;
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-3);
  cursor: pointer;
  border-bottom: var(--border-w-thin) solid var(--hairline);
}
.setting-row:first-child {
  border-top: var(--border-w-thin) solid var(--hairline);
}

.setting-row__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.setting-row__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--type-headline-size);
  color: var(--ink);
}
.setting-row__hint {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  color: var(--text-muted);
}

.modal .dev-reset {
  align-self: flex-start;
  margin-top: var(--space-4);
}

/* Brutalist toggle switch (square track + square thumb). */
.switch {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  position: relative;
  width: 48px;
  height: 26px;
  margin: 0;
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: var(--surface-sunk);
  box-sizing: border-box;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.switch::after {
  content: "";
  position: absolute;
  top: 1px;
  left: 1px;
  width: 18px;
  height: 18px;
  background: var(--ink);
  transition: transform var(--duration-fast) var(--ease-standard);
}
.switch:checked {
  background: var(--accent);
}
.switch:checked::after {
  transform: translateX(22px);
  background: var(--accent-ink);
}

/* ========================================================================
 * Modal overlay + dialog (end-of-game stats popup)
 * ===================================================================== */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: var(--overlay);
  /* Blur the page behind the modal. */
  -webkit-backdrop-filter: blur(8px) saturate(115%);
  backdrop-filter: blur(8px) saturate(115%);
  animation: overlay-fade var(--duration-standard) var(--ease-standard) both;
}
@keyframes overlay-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.modal {
  position: relative;
  width: 100%;
  max-width: 440px;
  animation: reveal-in var(--duration-slow) var(--ease-standard) both;
}

.modal__title {
  margin: 0 0 var(--space-4);
  text-transform: uppercase;
}

.modal__close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: var(--border-w-thin) solid var(--ink);
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.modal__close:hover {
  background: var(--ink);
  color: var(--paper);
}

/* ========================================================================
 * Light-mode button legibility
 * In the light (default) theme solid-ink buttons hide their black border
 * against their own black fill, so give those a colored (amber) outline so the
 * edge reads. (Paper→accent fills are handled on the base rules for both
 * themes.) Scope these border swaps to light mode so the dark theme — where
 * ink is light and borders already show — is untouched.
 * ===================================================================== */
/* Ink-filled buttons / selected tiles: swap the invisible black border for an
   amber outline so the edge stands out instead of melting into the fill. */
:root:not([data-theme="dark"]) .btn-primary,
:root:not([data-theme="dark"]) .segmented__option[aria-selected="true"],
:root:not([data-theme="dark"]) .segmented__option.is-selected {
  border-color: var(--accent);
}

/* The mode segmented control draws its selection with no outer border (cells
   are split by right-borders), so give the active cell an inset amber ring. */
:root:not([data-theme="dark"]) .segmented__option[aria-selected="true"],
:root:not([data-theme="dark"]) .segmented__option.is-selected {
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* ========================================================================
 * Result popup — Truth_Reveal + sharing + stats shown as a centered modal
 * over the main view. Wider than the settings modal and scrollable for tall
 * results; the inner cards (reveal, stats strip) provide their own framing.
 * ===================================================================== */
.result-modal {
  position: relative;
  width: 100%;
  max-width: 640px;
  max-height: calc(100vh - var(--space-6));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  animation: reveal-in var(--duration-slow) var(--ease-standard) both;
}

/* On a roomy viewport, widen the popup and lay the reveal content in two
   columns so the full result (stats, score, verdict, metrics, outcome, why,
   source) fits without scrolling. The score hero + hint note span the top;
   verdict/metrics stack on the left, the prose notes/source on the right.
   Each column is its own flex stack so they pack independently. */
@media (min-width: 720px) {
  .result-modal {
    max-width: 880px;
  }
  .result-modal .reveal-body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: var(--space-5);
    align-items: start;
  }
  /* Keep the four metric tiles at 2×2 inside the narrower left column. */
  .result-modal .reveal-metrics {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Leave room for the absolutely-positioned close button. */
.result-modal .modal__title {
  padding-right: var(--space-8);
  margin-bottom: var(--space-2);
}

/* The reveal card inside the popup shouldn't double up the framing. */
.result-modal #reveal .reveal-card {
  box-shadow: none;
}

/* Empty result containers shouldn't add a phantom gap (e.g. #reveal is empty
   in the lockout view; #recorded-result / #sharing are empty after a play). */
.result-modal #recorded-result:empty,
.result-modal #reveal:empty,
.result-modal #sharing:empty {
  display: none;
}

.result-modal #sharing {
  margin-top: 0;
}

/* "Back to main" sits full-width at the foot of the popup. */
.result-back {
  width: 100%;
  margin-top: var(--space-2);
}

/* ========================================================================
 * Completed panel — replaces the forecast form once the day is played; keeps
 * the chart on screen and offers a button to reopen the result popup.
 * ===================================================================== */
.completed-panel {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.completed-panel__title {
  margin: 0;
  color: var(--ink);
}

.completed-panel__hint {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--type-subhead-size);
  line-height: var(--type-subhead-line);
}

.completed-panel .btn-primary {
  margin-top: var(--space-2);
}
/* ========================================================================
 * Viewport-fit compaction — on shorter laptop screens the forecast form
 * (right column) could overflow the fold, forcing a scroll to reach the CAPE
 * slider and Submit. These height-scoped tweaks shrink the vertical rhythm so
 * the whole play view (chart + form) stays within the viewport. Two-column
 * desktop only (the narrow single-column layout already scrolls naturally).
 * ===================================================================== */
@media (min-width: 861px) and (max-height: 820px) {
  main.app-shell {
    padding-block: var(--space-3) var(--space-4);
    gap: var(--space-3);
  }
  .selections-panel {
    padding: var(--space-4);
  }
  .forecast-form {
    gap: var(--space-3);
  }
  .hazard-card {
    min-height: 68px;
  }
  .chart-view {
    max-height: calc(100vh - 168px);
  }
}

@media (min-width: 861px) and (max-height: 680px) {
  .hazard-card__glyph {
    width: 32px;
    height: 32px;
  }
  .hazard-card__icon {
    width: 18px;
    height: 18px;
  }
  .chart-view {
    max-height: calc(100vh - 150px);
  }
}
/* ========================================================================
 * Level inspector readout — a floating tooltip that follows the cursor over
 * the Skew-T and shows the nearest level's RAW pressure / temperature /
 * dewpoint (Req 3.1-3.6). Inverted ink card so it reads as an instrument
 * tooltip lifted off the chart; temperature/dewpoint are color-coded to match
 * the Skew-T's red/green trace lines. Never carries a derived value (Req 3.4).
 * ===================================================================== */
.level-readout {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 6;
  /* The tooltip is purely informational — never intercept the hover it
     describes, so the pointer keeps tracking levels smoothly. */
  pointer-events: none;
  min-width: 138px;
  max-width: 200px;
  padding: var(--space-2) var(--space-3) var(--space-3);
  background: var(--ink);
  color: var(--paper);
  border: var(--border-w-thin) solid var(--ink);
  box-shadow: var(--shadow-sm);
  will-change: left, top;
  transition: opacity var(--duration-fast) var(--ease-standard);
}

.level-readout[hidden] {
  /* Belt-and-suspenders: the global [hidden] rule already hides it. */
  display: none !important;
}

/* Mono caption banner — names the tooltip and carries an amber tick marker. */
.level-readout__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: var(--border-w-thin) solid rgba(255, 255, 255, 0.18);
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  line-height: 1;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  opacity: 0.85;
}
.level-readout__title::before {
  content: "";
  width: 8px;
  height: 8px;
  flex: none;
  background: var(--accent);
}

.level-readout__list {
  display: grid;
  gap: var(--space-1);
  margin: 0;
}

.level-readout__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}

.level-readout__term {
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  opacity: 0.62;
}

.level-readout__value {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--type-headline-size);
  line-height: 1.1;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Color-code to mirror the Skew-T ink: temperature red, dewpoint green. The
   pressure value stays paper-white as the neutral axis reference. */
.level-readout__row--temperature .level-readout__value {
  color: var(--signal-red);
}
.level-readout__row--dewpoint .level-readout__value {
  color: var(--signal-lime);
}

@media (prefers-reduced-motion: reduce) {
  .level-readout {
    transition: none;
  }
}

/* The Skew-T canvas stays white in BOTH themes, so the readout must remain a
   dark ink card to read against it. Without this, dark mode flips --ink to
   cream and --paper to near-black, turning the tooltip into a pale card that
   washes out over the white chart. Pin explicit dark values (and a dark offset
   shadow) so the hover stays a crisp, high-contrast instrument label. */
:root[data-theme="dark"] .level-readout {
  background: #111111;
  color: #f8f4ec;
  border-color: #111111;
  box-shadow: 3px 3px 0 0 rgba(0, 0, 0, 0.45);
}

/* ========================================================================
 * Field hints as tooltips — the plain-language guidance now lives behind a
 * small "?" info button next to each label instead of a tall inline caption,
 * so the risk / hazard / CAPE controls stack within the viewport (no scroll).
 * The hint text stays in the DOM (role="tooltip", linked by aria-describedby)
 * for assistive tech; CSS reveals it on hover/focus.
 * ===================================================================== */
.field__header {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Small square info chip — brutalist, fills amber on hover/focus. */
.field__info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 18px;
  height: 18px;
  padding: 0;
  border: var(--border-w-thin) solid var(--ink);
  border-radius: var(--radius);
  background: var(--surface-sunk);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  transition: background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}
.field__info:hover,
.field__info:focus-visible {
  background: var(--accent);
  color: var(--accent-ink);
}

/* The tooltip itself: an inverted ink popover anchored under the header. It is
   absolutely positioned so it overlays the control below rather than taking
   vertical space. Hidden until the info button is hovered/focused. */
.field__hint {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 7;
  width: max-content;
  max-width: 260px;
  margin: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--ink);
  color: var(--paper);
  border: var(--border-w-thin) solid var(--ink);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-sans);
  font-size: var(--type-footnote-size);
  line-height: var(--type-subhead-line);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-2px);
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-standard),
    transform var(--duration-fast) var(--ease-standard),
    visibility var(--duration-fast) var(--ease-standard);
}

/* Caret nub connecting the tooltip up to the "?" button. A small ink square
   rotated 45° so it matches the brutalist border treatment. */
.field__hint::before {
  content: "";
  position: absolute;
  top: -5px;
  left: 14px;
  width: 9px;
  height: 9px;
  background: var(--ink);
  border-top: var(--border-w-thin) solid var(--ink);
  border-left: var(--border-w-thin) solid var(--ink);
  transform: rotate(45deg);
}

/* Right-aligned variant: tooltip flips so its right edge meets the header's,
   and the caret moves to the right so it still points back at the button. */
.field__hint--flip-right {
  left: auto;
  right: 0;
}
.field__hint--flip-right::before {
  left: auto;
  right: 14px;
}

.field__info:hover + .field__hint,
.field__info:focus-visible + .field__hint,
.field__hint:hover {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
}

/* Pro mode = no hints: hide both the info button and the tooltip. The
   existing `.is-pro .hint { display:none }` already covers the tooltip text;
   this also removes the button so the header reads as label-only. */
.is-pro .field__info {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .field__hint {
    transition: none;
  }
}
/* ========================================================================
 * Hint panel — the pre-guess "reveal one value (costs points)" control
 * (Req 1.1-1.3, 1.7, 1.9). Sits in its own card beneath the chart. The four
 * reveal buttons are brutalist chips that fill amber on hover; once a hint is
 * taken the panel locks (buttons disabled) and the single value shows in an
 * amber readout pill. Errors / unavailable states use a non-blocking note.
 * ===================================================================== */
.hint-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.hint-panel__heading {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--type-footnote-size);
  line-height: var(--type-subhead-line);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

.hint-panel__options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Reveal chip: bordered, hard-shadowed, fills amber on hover/focus. */
.hint-panel__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  padding: var(--space-1) var(--space-3);
  border: var(--border-w-thin) solid var(--ink);
  border-radius: var(--radius);
  background: var(--surface-sunk);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-display);
  font-size: var(--type-subhead-size);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard),
    background-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}
.hint-panel__option:hover:not(:disabled),
.hint-panel__option:focus-visible:not(:disabled) {
  background: var(--accent);
  color: var(--accent-ink);
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 var(--shadow-color);
}
.hint-panel__option:active:not(:disabled) {
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 0 var(--shadow-color);
}
.hint-panel__option:disabled {
  opacity: 0.38;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* The single revealed value — an amber readout pill so it reads as the payoff
   of spending the hint. Leak-free: only the requested value is ever shown. */
.hint-panel__readout {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-2) var(--space-4);
  border: var(--border-w) solid var(--ink);
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-mono);
  font-size: var(--type-headline-size);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Non-blocking error / unavailable note (Req 1.9). */
.hint-panel__message {
  margin: 0;
  color: var(--danger);
  font-family: var(--font-mono);
  font-size: var(--type-subhead-size);
  line-height: var(--type-subhead-line);
}

@media (prefers-reduced-motion: reduce) {
  .hint-panel__option {
    transition: none;
  }
}
/* ========================================================================
 * Result popup — extra compaction so the full reveal fits the viewport with
 * no scroll. Scoped to .result-modal so the rest of the app is untouched.
 * ===================================================================== */
.result-modal .modal__title {
  font-size: var(--type-headline-size);
  line-height: var(--type-headline-line);
}
.result-modal .reveal-stats {
  gap: var(--space-2);
}
.result-modal .stats-strip__item {
  padding: var(--space-2);
}
.result-modal .reveal-hero {
  padding-block: var(--space-2);
}
.result-modal .verdict-chip {
  padding: var(--space-2) var(--space-3);
}
.result-modal .metric-tile {
  padding: var(--space-2);
}
.result-modal .reveal-note {
  padding-top: var(--space-2);
}
/* The "Why" prose is the tallest block; tighten it to a compact size. */
.result-modal .reveal-note__text {
  font-size: var(--type-subhead-size);
  line-height: var(--type-subhead-line);
}
.result-modal .reveal-source {
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
}
.result-modal #sharing {
  gap: var(--space-2);
}
/* ========================================================================
 * Reveal body — wraps the verdict/metrics (left) and notes/source (right)
 * into two independent column stacks. Single column by default; the
 * min-width:720px rule above promotes it to a two-column grid in the popup.
 * ===================================================================== */
.reveal-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-inline: var(--space-6);
  padding-bottom: var(--space-4);
}
.reveal-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}
/* The body now owns the horizontal inset, so zero the per-section inline
   padding (they used to align themselves to the full-bleed hero). */
.reveal-body .reveal-verdict,
.reveal-body .reveal-metrics,
.reveal-body .reveal-notes,
.reveal-body .reveal-source {
  padding-inline: 0;
}
