/*
 * Layout for the conditions screen. Every color, size, radius, shadow and
 * spacing value is a var(--...) from tokens.generated.css, which is generated
 * from the design package: this file decides arrangement, the package decides
 * appearance, and conformance/discipline.test.ts enforces the split.
 *
 * The six literals this file is allowed (and the test's allowlist cites the
 * same reasons):
 *   402px  the design width, tokens.json $meta.designWidth, which the token
 *          generator drops with the rest of the $meta bookkeeping
 *   20px   the spine column, stated in screens/01 "Grid: 20px | 92px | 1fr |
 *          auto" and carried by no token
 *   1px    hairline borders and dividers, which the package draws at 1 px and
 *          gives no token for
 *   5px    the height of the range sheet's wet-to-dry scale, screens/03
 *          ("Wet-to-dry gradient scale, 5 px"), no token
 *   4px    the width of that scale's ink marker, from the same sentence
 *          ("a 4x19 px ink marker positioned by ratio"), and the height of
 *          the sheet grabber, which the package colors and never dimensions
 *   19px   the marker's height, from the same sentence
 *
 * Every other length and color is a var(--...), and each one must be the
 * token that MEANS the thing being set. A token that merely happens to hold
 * the right number is a borrowed token, and it breaks the moment the package
 * recalibrates the thing it was actually about.
 *
 * Posture: one faithful centered mobile column, package pixels 1:1. No
 * breakpoints and no invented desktop design (owner decision, August 11).
 */

html {
  background: var(--color-surface-canvas);
}

body {
  margin: 0;
  background: var(--color-surface-canvas);
  color: var(--color-text-primary);
  font-family: var(--type-family);
  font-size: var(--type-scale-body-size);
  line-height: 1.45;
}

#app {
  width: min(402px, 100vw);
  margin-inline: auto;
  overflow-x: hidden;
}

button {
  appearance: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.figure,
.value,
.band-elevation,
.inline-delta {
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------- header */

/*
 * The art zone holds the title row and the banner stack, so it grows by the
 * stack's own height and the scrim's near-solid stops stay above the hero
 * (screens/01, F87). Gradient and scrim only: there is no ridge art in this
 * repo and none is invented.
 */
.header-zone {
  position: relative;
  min-height: var(--space-header-art-height-base);
  padding: var(--space-header-top-inset) var(--space-screen-padding-x) 0;
  box-sizing: border-box;
}

.header-art,
.header-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.header-art {
  background: var(--color-header-gradient-stowe);
}

.header-scrim {
  background: var(--color-header-scrim);
}

.title-row {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-inline-gap);
  padding-bottom: var(--space-stack-gap);
}

.screen-title {
  margin: 0;
  font-size: var(--type-scale-screen-title-size);
  font-weight: var(--type-scale-screen-title-weight);
  letter-spacing: var(--type-scale-screen-title-tracking);
}

.header-meta {
  margin: 0;
  color: var(--color-text-header-meta);
  font-size: var(--type-scale-meta-size);
}

.delay-chip {
  display: flex;
  align-self: center;
  align-items: center;
  gap: var(--space-marker-gap);
  margin: 0;
  padding: var(--space-marker-gap) var(--space-inline-gap);
  border-radius: var(--radius-pill);
  background: var(--color-delay-fill);
  color: var(--color-delay-text);
  font-size: var(--type-scale-caption-strong-size);
  font-weight: var(--type-scale-caption-strong-weight);
}

.delay-glyph {
  height: var(--type-scale-meta-size);
  width: auto;
  color: var(--color-delay-glyph);
}

/* --------------------------------------------------------------- banners */

.banner-stack {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-inline-gap);
}

.banner {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  padding: var(--space-inline-gap) var(--space-card-padding-x);
  border-radius: var(--radius-inner-card);
  font-size: var(--type-scale-body-size);
}

.banner--neutral {
  flex-direction: column;
  align-items: flex-start;
  border: 1px solid var(--color-banner-neutral-border);
  background: var(--color-banner-neutral-surface);
  color: var(--color-text-secondary);
}

.banner--alert {
  border: 1px solid var(--color-banner-alert-border);
  background: var(--color-banner-alert-surface);
  color: var(--color-provenance-rejected);
  font-weight: var(--type-scale-body-emphasis-weight);
}

.banner--alert .chevron {
  margin-left: auto;
}

.banner-detail {
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-caption-size);
}

.alert-glyph {
  height: var(--type-scale-body-strong-size);
  width: auto;
  flex: none;
}

/* ------------------------------------------------------------------ body */

.screen-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-stack-gap);
  padding: 0 var(--space-screen-padding-x) var(--space-header-top-inset);
}

.card {
  padding: var(--space-card-padding-y) var(--space-card-padding-x);
  border: 1px solid var(--color-surface-border);
  border-radius: var(--radius-card);
  background: var(--color-surface-card);
  box-shadow: var(--elevation-card);
}

/* ------------------------------------------------------------------ hero */

.hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-inline-gap);
  padding: var(--space-inline-gap) 0 var(--space-card-padding-y);
}

.hero-sentence {
  font-size: var(--type-scale-hero-size);
  font-weight: var(--type-scale-hero-weight);
  line-height: var(--type-scale-hero-line-height);
  letter-spacing: var(--type-scale-hero-tracking);
  text-wrap: pretty;
}

.hero-subline {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  color: var(--color-text-on-header);
  font-size: var(--type-scale-caption-size);
}

/* --------------------------------------------------------------- markers */

.marker {
  flex: none;
}

.marker--band {
  width: var(--band-spine-dot-size);
  height: var(--band-spine-dot-size);
}

.marker--hero {
  width: var(--marker-placement-inline-size-large);
  height: var(--marker-placement-inline-size-large);
}

.marker--caption {
  width: var(--marker-placement-inline-size-small);
  height: var(--marker-placement-inline-size-small);
}

.marker--observed {
  color: var(--color-provenance-measured);
}

.marker--forecast {
  color: var(--color-provenance-forecast);
}

.marker--derived {
  color: var(--color-provenance-derived);
}

.marker--sensorDerived {
  color: var(--color-provenance-sensor-derived);
}

.chevron {
  height: var(--type-scale-body-size);
  width: auto;
  flex: none;
  color: var(--color-text-chevron);
}

/* ------------------------------------------------------- window selector */

.window-selector {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-inline-gap);
}

/*
 * screens/01 flags this for the build: the pill is 31 px tall and its touch
 * slop has to reach the 44 px minimum. The slop is a transparent overlay so
 * the visual pill keeps the package's height while the tappable box clears
 * the minimum, instead of a 44 px pill the design never drew.
 */
.pill {
  position: relative;
  display: flex;
  align-items: center;
  padding: var(--space-marker-gap) var(--space-card-padding-x);
  border: 1px solid var(--color-surface-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface-card);
  color: var(--color-text-secondary);
  font-size: var(--type-scale-caption-strong-size);
}

.pill::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: var(--hit-target-minimum);
  transform: translateY(-50%);
}

.pill--selected {
  border-color: var(--color-text-primary);
  background: var(--color-text-primary);
  color: var(--color-text-on-dark);
  font-weight: var(--type-scale-caption-strong-weight);
}

/* ---------------------------------------------------------- band matrix */

.band-matrix {
  display: flex;
  flex-direction: column;
  padding-top: 0;
  padding-bottom: 0;
}

.band-row {
  display: grid;
  grid-template-columns: 20px var(--band-label-column-width) 1fr auto;
  align-items: center;
  column-gap: var(--space-inline-gap);
  padding: var(--space-row-padding-y) 0;
  border-bottom: 1px solid var(--color-surface-divider);
}

.band-row:last-child {
  border-bottom: 0;
}

.spine {
  display: flex;
  flex-direction: column;
  align-items: center;
  align-self: stretch;
}

.spine-line {
  width: var(--band-spine-line-width);
  background: var(--color-surface-border);
}

.spine-line--above {
  flex: 1;
  margin-bottom: var(--space-marker-gap);
}

.spine-line--below {
  flex: 1;
  margin-top: var(--space-marker-gap);
}

.band-name {
  display: block;
  font-size: var(--type-scale-label-size);
  font-weight: var(--type-scale-label-weight);
  line-height: 1.15;
}

.band-elevation {
  display: block;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-micro-label-size);
}

.band-value .value {
  font-size: var(--type-scale-band-value-size);
  font-weight: var(--type-scale-band-value-weight);
}

.value .unit {
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-unit-size);
  font-weight: var(--type-scale-unit-weight);
}

.inline-delta {
  margin-left: var(--space-marker-gap);
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

.provenance-label {
  display: block;
  font-size: var(--type-scale-label-provenance-size);
  font-weight: var(--type-scale-label-provenance-weight);
}

.provenance-label--observed {
  color: var(--color-provenance-measured);
}

.provenance-label--forecast {
  color: var(--color-provenance-forecast);
}

.provenance-label--derived {
  color: var(--color-provenance-derived);
}

.provenance-label--sensorDerived {
  color: var(--color-provenance-sensor-derived);
}

.row-chevron {
  display: flex;
  align-items: center;
}

/* -------------------------------------------------------------- tomorrow */

.tomorrow-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-inline-gap);
  width: 100%;
}

.row-label {
  font-size: var(--type-scale-label-size);
  font-weight: var(--type-scale-label-weight);
}

.tomorrow-value {
  display: flex;
  align-items: baseline;
  gap: var(--space-inline-gap);
}

.tomorrow-value .value {
  font-size: var(--type-scale-card-value-size);
  font-weight: var(--type-scale-card-value-weight);
}

.range-bar {
  margin: var(--space-inline-gap) 0;
}

.range-track {
  position: relative;
  height: calc(var(--radius-track) * 2);
  border-radius: var(--radius-track);
  background: var(--color-surface-track-neutral);
}

.range-block {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: var(--radius-track);
  background: var(--color-provenance-forecast-fill);
}

.range-ends {
  display: flex;
  justify-content: space-between;
  margin: 0 0 var(--space-marker-gap);
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
  font-variant-numeric: tabular-nums;
}

.tomorrow-caption {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

/* --------------------------------------------------------- forecast only */

.forecast-only-row {
  display: flex;
  align-items: center;
  gap: var(--space-inline-gap);
  width: 100%;
}

.forecast-only-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-marker-gap);
}

.badge {
  align-self: flex-start;
  padding: var(--space-marker-gap) var(--space-inline-gap);
  border-radius: var(--radius-pill);
  background: var(--color-surface-card-alt);
  color: var(--color-text-secondary);
  font-size: var(--type-scale-chip-label-size);
  font-weight: var(--type-scale-chip-label-weight);
  letter-spacing: var(--type-scale-chip-label-tracking);
}

.forecast-only-detail {
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-caption-size);
}

.forecast-only-row .row-chevron {
  margin-left: auto;
}

/* ----------------------------------------------------------------- sheet */

/*
 * The bottom sheet, translated to the web (owner decision C1): the package's
 * 24 px top corners and 22 px side padding, the scrim at its own token color,
 * and only the behaviours a browser makes mandatory. Height follows content up
 * to 88vh, after which the body scrolls inside the sheet rather than the page
 * scrolling behind it.
 */
#sheet-host {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
}

#sheet-host[hidden] {
  display: none;
}

#sheet-scrim {
  position: absolute;
  inset: 0;
  background: var(--color-surface-scrim);
}

#sheet {
  position: relative;
  width: min(402px, 100vw);
  max-height: 88vh;
  overflow-y: auto;
  box-sizing: border-box;
  padding: var(--space-inline-gap) var(--space-sheet-padding-x) var(--space-card-padding-y);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  background: var(--color-surface-sheet);
  animation: sheet-rise 180ms ease-out;
}

@keyframes sheet-rise {
  from {
    transform: translateY(100%);
  }

  to {
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  #sheet {
    animation: none;
  }
}

/*
 * The grabber. tokens.json gives it a color and nothing else, and screens/02
 * names it without dimensioning it, so its geometry comes from the SPACING
 * scale (three stack gaps wide) and the allowlisted 4 px, rather than from a
 * length token that means something else: the header inset and the spine line
 * width both happen to be plausible numbers and neither is about a grabber.
 */
.sheet-grabber {
  width: calc(var(--space-stack-gap) * 3);
  height: 4px;
  margin: var(--space-marker-gap) auto var(--space-stack-gap);
  border-radius: var(--radius-track);
  background: var(--color-surface-grabber);
  cursor: pointer;
}

.sheet-title {
  margin: 0 0 var(--space-inline-gap);
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-caption-strong-size);
  font-weight: var(--type-scale-caption-strong-weight);
}

.sheet-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-stack-gap);
}

.sheet-value {
  margin: 0;
  font-size: var(--type-scale-sheet-value-size);
  font-weight: var(--type-scale-sheet-value-weight);
  letter-spacing: var(--type-scale-sheet-value-tracking);
  font-variant-numeric: tabular-nums;
}

.sheet-value .unit {
  font-size: var(--type-scale-unit-large-size);
  font-weight: var(--type-scale-unit-large-weight);
}

.sheet-provenance {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  margin: 0;
  font-size: var(--type-scale-label-provenance-size);
  font-weight: var(--type-scale-label-provenance-weight);
}

.sheet-lede {
  margin: 0;
  font-size: var(--type-scale-body-size);
  text-wrap: pretty;
}

.sheet-footer {
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

.inner-card {
  padding: var(--space-card-padding-y) var(--space-card-padding-x);
  border: 1px solid var(--color-surface-border);
  border-radius: var(--radius-inner-card);
  background: var(--color-surface-card-alt);
}

/* ------------------------------------------------- sheet: station block */

.station-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-inline-gap);
}

.station-name {
  font-size: var(--type-scale-body-strong-size);
  font-weight: var(--type-scale-body-strong-weight);
}

.station-id {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

.station-id a {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  color: inherit;
}

/*
 * The source chip. screens/02 asks for a chip and gives it no radius, and
 * --radius-swatch is the package's only small-radius token, so it is the
 * nearest thing to a stated intent rather than a number picked for fitting.
 */
.source-chip {
  padding: 0 var(--space-marker-gap);
  border-radius: var(--radius-swatch);
  background: var(--color-surface-track-neutral);
  color: var(--color-text-secondary);
  font-size: var(--type-scale-chip-label-size);
  font-weight: var(--type-scale-chip-label-weight);
  letter-spacing: var(--type-scale-chip-label-tracking);
}

.external-glyph {
  height: var(--type-scale-micro-label-size);
  width: auto;
  flex: none;
}

.station-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-inline-gap) var(--space-card-padding-x);
  margin-top: var(--space-card-padding-y);
}

.grid-cell,
.disclosure-row,
.fact-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-marker-gap);
}

.grid-label {
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-micro-label-size);
}

.grid-value {
  font-size: var(--type-scale-body-size);
}

.grid-value .figure,
.score-value {
  font-variant-numeric: tabular-nums;
}

.score-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-inline-gap);
  margin-top: var(--space-card-padding-y);
  padding-top: var(--space-inline-gap);
  border-top: 1px solid var(--color-surface-divider);
}

.score-value {
  margin-left: auto;
  font-size: var(--type-scale-body-strong-size);
  font-weight: var(--type-scale-body-strong-weight);
}

.score-qualifier,
.score-freshness-detail,
.derivation-at {
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

.score-freshness {
  margin: var(--space-inline-gap) 0 0;
  font-size: var(--type-scale-caption-strong-size);
  font-weight: var(--type-scale-caption-strong-weight);
}

.score-freshness-detail {
  margin: var(--space-marker-gap) 0 0;
}

.derivation {
  margin-top: var(--space-card-padding-y);
  padding-top: var(--space-inline-gap);
  border-top: 1px solid var(--color-surface-divider);
}

.derivation-quantity {
  margin: 0 0 var(--space-marker-gap);
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-micro-label-size);
}

.derivation-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-inline-gap);
  font-variant-numeric: tabular-nums;
}

.derived-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-marker-gap);
}

.disagreement,
.source-line {
  margin: 0;
  color: var(--color-text-secondary);
  font-size: var(--type-scale-body-size);
  text-wrap: pretty;
}

/* --------------------------------------------- sheet: also considered */

.also-considered {
  margin: var(--space-inline-gap) 0 0;
  font-size: var(--type-scale-label-size);
  font-weight: var(--type-scale-label-weight);
}

.also-considered-empty {
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-caption-size);
}

.rejected-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-marker-gap);
}

/*
 * screens/02: "Rejection card border: provenance.rejected at 35% for anomaly."
 * tokens.json carries that exact value once, under the alerts banner's name
 * (oklch(0.50 0.13 40 / 0.35) is provenance.rejected at 35 percent). Named
 * for the banner, correct for this border; noted so the next reader does not
 * have to re-derive that they are the same color.
 */
.rejected-row--anomaly {
  border-color: var(--color-banner-alert-border);
}

.rejected-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-inline-gap);
}

.rejected-value {
  margin-left: auto;
  font-size: var(--type-scale-row-value-size);
  font-weight: var(--type-scale-row-value-weight);
  font-variant-numeric: tabular-nums;
}

.rejected-value--struck {
  text-decoration: line-through;
  color: var(--color-text-tertiary);
}

.rejected-reason {
  margin: 0;
  font-size: var(--type-scale-caption-size);
}

.rejected-row--anomaly .rejected-reason {
  color: var(--color-provenance-rejected);
}

.rejected-detail {
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

.cross-reference {
  color: var(--color-provenance-measured);
  font-size: var(--type-scale-caption-strong-size);
  font-weight: var(--type-scale-caption-strong-weight);
}

/* ------------------------------------------------------ sheet: range */

.range-block {
  display: flex;
  align-items: center;
  justify-content: center;
}

.range-block-label {
  color: var(--color-text-on-dark);
  font-size: var(--type-scale-range-block-label-size);
  font-weight: var(--type-scale-range-block-label-weight);
  white-space: nowrap;
}

/*
 * The sheet's bar is the package's 34 px composite: a 10 px track (the shared
 * .range-track) with a 22 px inner block standing proud of it by 6 px top and
 * bottom, which is --space-marker-gap on each side.
 */
#sheet .range-block {
  top: calc(var(--space-marker-gap) * -1);
  bottom: calc(var(--space-marker-gap) * -1);
  border-radius: var(--radius-range-block);
}

.range-explain,
.snow-explain {
  margin: 0;
  color: var(--color-text-secondary);
  font-size: var(--type-scale-caption-size);
  text-wrap: pretty;
}

.snow-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-inline-gap);
}

.snow-quality {
  margin: 0;
  font-size: var(--type-scale-body-strong-size);
  font-weight: var(--type-scale-body-strong-weight);
}

/*
 * screens/03: "Wet-to-dry gradient scale, 5 px, with a 4x19 px ink marker
 * positioned by ratio." None of those three lengths is a token, so all three
 * are allowlisted literals citing that sentence. The radius is the track's
 * own pill radius, which CSS clamps to half the height on a bar this thin.
 */
.snow-scale {
  position: relative;
  height: 5px;
  border-radius: var(--radius-track);
  background: var(--color-snow-quality-scale);
}

/*
 * The marker is drawn square: screens/03 gives it a size and a position and
 * no radius, and rounding an ink mark it did not ask to be rounded is a
 * design decision this build is not entitled to make.
 */
.snow-scale-marker {
  position: absolute;
  top: calc((19px - 5px) / -2);
  width: 4px;
  height: 19px;
  background: var(--color-text-primary);
  transform: translateX(-50%);
}

.snow-scale-ends {
  display: flex;
  justify-content: space-between;
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-micro-label-size);
}

.model-disclosure {
  display: flex;
  flex-direction: column;
  gap: var(--space-inline-gap);
  font-size: var(--type-scale-caption-size);
}

.model-disclosure summary {
  color: var(--color-text-secondary);
  font-weight: var(--type-scale-caption-strong-weight);
  cursor: pointer;
}

.disclosure-line {
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-meta-size);
}

/* ---------------------------------------------- sheet: forecast only */

.facts-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-card-padding-y);
}

.measurer-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-inline-gap);
}

.measurer-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-marker-gap);
}

.measurer-name {
  display: flex;
  align-items: center;
  gap: var(--space-marker-gap);
  color: var(--color-text-primary);
  font-size: var(--type-scale-body-size);
  font-weight: var(--type-scale-body-emphasis-weight);
}

.measurer-reason {
  margin: 0;
  color: var(--color-text-secondary);
  font-size: var(--type-scale-caption-size);
}

.measurer-secondary {
  margin: 0;
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-caption-size);
}

/* -------------------------------------------------------------- noscript */

.noscript {
  padding: var(--space-screen-padding-x);
  font-size: var(--type-scale-body-size);
}
