/* ============================================================================
   FSA Normal Grazing Periods · css/app.css
   APP LAYOUT ONLY. The kit (theme/sfsa-theme.css) owns every component — the
   navbar, buttons, range, drawer, card, combobox, modal, toast, tooltip. What
   lives here is the page skeleton and the placement decisions the kit
   deliberately leaves to the app ("positioning is the app's job — the kit does
   not know how many panes the map row has").

   Loaded AFTER the theme, so anything here that touches a kit selector wins
   without !important. There are exactly three such places, each tagged
   `kit-override:` with its reason (the drawer's stacked segmented groups in §3,
   the map attribution's dock clearance in §5, and the data-table modal's width
   in §10). Everything else is either an app-owned id (#map, #map-frame,
   #county-card), an app-owned class (.control-note) or a control the kit ships
   no component for (a <select>).

   Contents:
     1. Page shell            5. County card (docked)
     2. Map + status pill     6. Footer
     3. Drawer controls       7. Compact
     4. Legend (in the drawer)
   ========================================================================== */

/* ── 1. Page shell ────────────────────────────────────────────────────────
   A three-row grid: navbar (auto) · map row (1fr) · footer (auto).

   100dvh, never 100vh: on iOS Safari 100vh is the URL-bar-HIDDEN height, so
   the bottom of the map — where the bottom sheet and the corner controls live
   — would sit under the browser chrome (HOUSE-STYLE §3). */
html { height: 100%; }

body {
  height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* The map row fills itself and the sheet/drawer surfaces are positioned
     inside it; nothing on this page is meant to scroll. */
  overflow: hidden;
}

/* The map row is a flex ROW: [ #drawer | #map-frame ]. That is the whole point
   of the kit's .sfsa-drawer on desktop — it is a real column that TAKES width
   from the map instead of floating over it, so collapsing it gives the canvas
   the space back (app.js resizes the map once the slide has finished).
   `position: relative` also makes it the containing block for the two
   absolutely-positioned drawer pieces, .sfsa-drawer-tab and
   .sfsa-drawer-scrim — the scrim therefore dims the map row and never the
   navbar.

   min-height: 0 lets the 1fr row actually shrink — without it a grid item's
   automatic minimum size keeps the map from ever being smaller than its
   content, and the footer gets pushed off a short viewport. */
main {
  position: relative;
  display: flex;
  align-items: stretch;
  min-height: 0;
  /* clip, not hidden: hidden leaves the box programmatically scrollable, and
     a focus() on a child mid slide-in (the card's dock-right enter animation
     overhangs the row) makes the browser scroll-to-reveal it — permanently
     shifting the whole map row sideways. clip forbids all scrolling. */
  overflow: clip;
}

/* Everything that is "the map" — canvas, status pill, docked card. min-width: 0
   is what lets it give way to the drawer instead of overflowing <main>: a flex
   item's automatic minimum size is its content, and a MapLibre canvas reports
   whatever it was last sized to. */
#map-frame {
  flex: 1 1 auto;
  min-width: 0;
  position: relative;
}

/* ── 2. Map + status pill ────────────────────────────────────────────────── */

#map {
  position: absolute;
  inset: 0;
}

/* The docked card is normally an OVERLAY. When the selected county would sit
   under it, app.js (revealSelectedCounty) stamps .card-pushes and the card
   pushes instead: the canvas gives up the dock's width — the width mirrors
   the kit's .sfsa-card.dock-right, keep them in lockstep — and map.resize()
   reflows it. No transition: the canvas can only reflow at the resize call,
   so animating the box would just show 200ms of letterboxing. */
#map-frame.card-pushes #map {
  right: min(360px, 34vw);
}

/* Boot progress, vintage swaps, and fetch failures. Centred at the top of the
   map, above the panels (--z-map-progress) but below the navbar. */
#app-note {
  position: absolute;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-map-progress);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  max-width: min(calc(100% - 1.5rem), 34rem);
  padding: 0.4rem 0.5rem 0.4rem 0.85rem;
  border: 1px solid var(--ctrl-border);
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: var(--shadow);
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--text-primary);
}

/* A failure is a different KIND of message, not just a redder one: it also
   carries the Retry button, so the border change is redundant with content
   rather than the only signal (WCAG 1.4.1). */
#app-note[data-tone="error"] { border-color: var(--accent-line); }

/* No text label to pad around when the pill is only a sentence. */
#app-note:not(:has(button)) { padding-right: 0.85rem; }

/* ── 3. Drawer controls ───────────────────────────────────────────────────
   The kit ships no <select> component, so the pasture-type menu is styled
   here to match the kit's search input: same height, border, radius, and
   type scale. Not an override — there is nothing to override.

   Everything else the drawer holds — the range, the segmented buttons, the
   combobox — is sized by the kit's own `.sfsa-drawer <control>` full-width
   rules (theme §5). The app used to cap the range and the search field to fit
   them into the navbar; in a 272px column full width is the right answer and
   those caps are gone. */

#type-select,
#elig-type-select,
#elig-source {
  min-height: 34px;
  max-width: 15rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--ctrl-border);
  border-radius: var(--radius-md);
  background: var(--input-bg);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 0.8rem;
  cursor: pointer;
  transition: var(--transition);
}
#type-select:hover,
#elig-type-select:hover,
#elig-source:hover { border-color: var(--accent-line); }
#type-select[disabled],
#elig-type-select[disabled],
#elig-source[disabled] { opacity: 0.45; cursor: not-allowed; }

/* The menu is the full width of the drawer column. Scoped to #drawer rather
   than written into the rule above so the box above stays reusable if the
   select ever appears anywhere else. */
#drawer #type-select,
#drawer #elig-type-select,
#drawer #elig-source {
  width: 100%;
  max-width: none;
}

/* The aggregation picker is a control INSIDE the dataset section — it belongs
   to one of that section's three buttons — so it needs the separation from the
   note above it that a section boundary would otherwise have given it. Its
   label is visible (unlike the type select's, whose section title says the same
   word), because "Aggregation" is not a word the eyebrow above it repeats. */
#elig-source-wrap {
  margin-top: 0.6rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}
#elig-source-wrap > .control-label {
  display: block;
  margin-bottom: 0.25rem;
}

/* A caption under a control: what the switcher does not offer yet, and why the
   year slider is disabled on a climatology. Same muted small type as
   #legend-key (§4) — a note about a control, not a second label for it, so it
   never carries the control's accessible name. */
.control-note {
  margin: 0.35rem 0 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--text-muted);
}

/* kit-override: `.seg-btns` is a horizontal fused group and `.nav-btn` is
   `white-space: nowrap`, both sized for the short navbar labels the kit was
   drawn for ("Start · End · Duration"). The SCOPING groups — which data family,
   and which dataset within it — are named in words a reader can act on
   ("NAP-190 Derived (nClimGrid)", "FSA LFP boundaries"), and two or three of
   those cannot share a 248px drawer row without spilling out of their own
   borders. So these groups stack instead, with the fused radii and the shared
   border rotated a quarter turn; every other .seg-btns in the app keeps the kit's
   geometry. min-height is deliberately NOT set here, so the kit's own 40px
   touch target (theme §6) still wins on a pointerless device.

   The eligibility interface's COLOR-BY group is in this list too, and it is the
   one that is not a scoping group: its two labels ("Payment months",
   "Qualifying date") are the quantities themselves, and nothing shorter says
   which of them is the payable one. The grazing periods' three-word group keeps
   the kit's row.

   The disaster designations have no group at all: that view is one slice of one
   archive and the shared year is the whole of its state (js/interfaces/
   disasters.js § ONE SLICE). */
#view-seg .seg-btns,
#ngp-dataset-seg .seg-btns,
#usdm-dataset-seg .seg-btns,
#elig-dataset-seg .seg-btns,
#elig-variable-seg .seg-btns { flex-direction: column; }
#view-seg .seg-btn,
#ngp-dataset-seg .seg-btn,
#usdm-dataset-seg .seg-btn,
#elig-dataset-seg .seg-btn,
#elig-variable-seg .seg-btn {
  height: auto;
  padding: 6px 10px;
  border-right-width: 1px;
  border-bottom-width: 0;
  white-space: normal;
  line-height: 1.3;
}
#view-seg .seg-btn:first-child,
#ngp-dataset-seg .seg-btn:first-child,
#usdm-dataset-seg .seg-btn:first-child,
#elig-dataset-seg .seg-btn:first-child,
#elig-variable-seg .seg-btn:first-child {
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
#view-seg .seg-btn:last-child,
#ngp-dataset-seg .seg-btn:last-child,
#usdm-dataset-seg .seg-btn:last-child,
#elig-dataset-seg .seg-btn:last-child,
#elig-variable-seg .seg-btn:last-child {
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  border-bottom-width: 1px;
}

/* The week scrubber's readout. It sits BELOW its slider rather than beside it
   (index.html says why), so it is a block of its own and not the kit's
   `.sfsa-range > output` — same monospaced, tabular treatment, because "week 30
   of 52" is a number that should not jump as the thumb moves. */
.week-out {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

/* The two step buttons need NO rule of their own: they sit inside the kit's
   `.sfsa-range` flex row, where the range is `flex: 1 1 0` (theme §5) and gives
   way first, and `.nav-btn.icon-only` is already a 34px square that grows to
   40px under `@media (hover: none)` (theme §6). This comment exists so the next
   reader does not add a kit-override that the kit was already handling. */

/* ── 4. Legend (in the drawer) ────────────────────────────────────────────
   The legend used to be a collapsible floating .sfsa-panel in the bottom-right
   corner, lifted clear of the compact bottom sheet with --sheet-h. It is now
   the last section of the drawer: always visible, scrolling with the rest of
   the column, and out of the map's way at every size — so there is no
   positioning, no collapse, and no sheet clearance left to write here. What
   remains is the interior of the two legend bodies. */

/* The month wheel (N-W4) draws into a square; the placeholder holds the same
   box so the drawer does not reflow when the real legend arrives. */
#legend-wheel {
  width: 100%;
  max-width: 200px;
  margin: 0 auto;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
#legend-wheel > svg { width: 100%; height: auto; display: block; }

.legend-placeholder {
  font-size: 0.72rem;
  font-style: italic;
  color: var(--text-dim);
  text-align: center;
}

/* The kit's colorbar sizes its own SVG; this is just breathing room. */
#legend-bar { margin-top: 0.15rem; }

#legend-key {
  margin-top: 0.5rem;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--text-secondary);
}

/* ── 5. County card (docked) ──────────────────────────────────────────────
   The card no longer floats inset in a corner: on desktop it carries the kit's
   `dock-right` variant and fills the right edge of #map-frame at full height,
   and under compact it is the kit's unchanged bottom sheet. Both geometries are
   the kit's, so THIS app has no card positioning left — the old top-right inset
   (and the max-height kit-override it needed to clear its own container,
   defect NGP-1) is gone with it.

   What the dock does need is room for the map's own attribution, which
   MapLibre pins to the bottom-right of the canvas — i.e. underneath the card.

   The MQ below is the complement of the kit's compact query
   ((max-width: 640px), (max-height: 560px)) and a hand-authored copy of its
   numbers: KEEP THE FOUR NUMBERS IN LOCKSTEP with theme §6 and with the kit's
   own `.sfsa-card.dock-right` complement MQ. Under compact the card is a sheet
   at the bottom of the screen, the attribution is above it already, and this
   rule must not fire. */
@media (min-width: 641px) and (min-height: 561px) {
  /* kit-override: the kit pads the two bottom control corners by
     env(safe-area-inset-*) and knows nothing about what an app docks on top of
     them. min(360px, 34vw) is the dock's own width from the kit's dock-right
     rule — mirrored here, and additive so the safe-area inset survives. :has()
     keeps it to the open state; the closed card gets its corner back.
     :not(.card-pushes): when the card pushes instead of overlaying, the
     canvas already ends at the card's edge and the attribution needs no
     shove — padding it again would double-shift it. */
  #map-frame:has(#county-card:not([hidden])):not(.card-pushes) .maplibregl-ctrl-bottom-right {
    padding-right: calc(min(360px, 34vw) + env(safe-area-inset-right));
  }
}

#card-rows {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.2rem 0.75rem;
  margin: 0 0 0.25rem;
}
#card-rows dt {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  align-self: baseline;
}
#card-rows dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-primary);
}
/* Prose rows — "No data for …", "no polygon in this vintage" — are sentences,
   not values: they get the UI font and the muted color so they do not read as
   a measurement. */
#card-rows dd.card-note {
  font-family: var(--font-ui);
  font-size: 0.78rem;
  color: var(--text-muted);
}

/* ── 6. Footer ───────────────────────────────────────────────────────────── */

.app-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1rem;
  padding:
    0.35rem
    max(0.75rem, env(safe-area-inset-right))
    calc(0.35rem + env(safe-area-inset-bottom))
    max(0.75rem, env(safe-area-inset-left));
  background: var(--bg-surface);
  border-top: 1px solid var(--border);
  font-size: 0.7rem;
  line-height: 1.4;
  color: var(--text-muted);
}

.footer-line { margin: 0; }

/* Links in a text block are underlined, not color-only (WCAG 1.4.1). */
.app-footer a {
  color: var(--accent-line);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.app-footer a:hover { text-decoration-thickness: 2px; }

.footer-logo {
  display: flex;
  align-items: center;
  text-decoration: none;
}
/* 432×159 intrinsic; 28px tall renders 76px wide. */
.footer-logo img {
  height: 28px;
  width: auto;
  display: block;
}

.footer-code { margin-left: auto; }

/* ── 7. Compact ───────────────────────────────────────────────────────────
   The string matches the kit's compact query character for character
   (theme §6 / core's viewport.COMPACT_MQ).

   Almost nothing is left here: the drawer's off-canvas geometry, the scrim, the
   navbar hamburger and the card's bottom-sheet dock are all the kit's, inside
   the kit's own copy of this query. The app's compact-only concern is the
   footer. */
@media (max-width: 640px), (max-height: 560px) {
  /* Keep the footer to one line on a phone: the funder acknowledgement is
     CLIPPED, not removed, so it stays in the accessibility tree and in the
     page's text — the same discipline the kit applies to shed button labels. */
  .app-footer > span.footer-line {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* WCAG 2.5.5 — match the kit's touch sizing on the one control it does not
   ship. */
@media (hover: none) {
  #type-select,
  #elig-type-select,
  #elig-source { min-height: 40px; }
}

/* ============================================================================
   ===== N-W4 feature styles ==================================================
   The four feature modules' chrome: the month wheel's box, the card's span
   chart and its table twin, and the on-demand data table in #table-modal.

   TOKENS ONLY. Every color below is a var(--…); the only literal colors these
   features draw are DATA colors (the two ramps, the no-data fill), and those
   are set in JS from assets/colors*.json and the --no-data token, never here.

   One of the three kit-overrides this file's header counts lives down here: the
   #table-modal width in §10, tagged the same way and for the same kind of
   reason as the attribution clearance in §5.

   Contents:
     8. Month wheel      9. Card body (chart, table twin, designation list)
    10. Data table modal
   ========================================================================== */

/* ── 8. Month wheel ───────────────────────────────────────────────────────
   §4 already sizes #legend-wheel and its child <svg>; what is left is the one
   thing the SVG cannot say for itself. The wheel's month labels are authored
   at 11.5 user units in a 220-unit viewBox, so they scale WITH the wheel —
   which is the point (the ring and its labels are one drawing) but means they
   shrink in a narrow column. #legend-wheel is capped at 200px, so the labels
   land at ~10.5px: small, and deliberately not the reading channel.
   #legend-key is.
   No rule needed here; this comment exists so the next reader does not "fix"
   it with a fixed font-size that would break the ring's proportions. */

/* ── 9. Card body: span chart, table twin, designation list ──────────────── */

.span-figure,
.usdm-figure,
.elig-figure {
  margin: 0.35rem 0 0;
}
.span-figure svg,
.usdm-figure svg,
.elig-figure svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The cross-archive sentence under the eligibility chart: what ANOTHER archive
   says about the same county, year and type. Prose, not a value — so it gets
   the UI font and the muted color, exactly like a `.card-note` row in the
   readout above it (§5), and it is only ever drawn when a second payload is
   already in hand. */
.card-compare {
  margin: 0.4rem 0 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--text-muted);
}

/* The <details> twin. Closed by default: the chart is the fast read, and a
   19-row table under a floating card would push the map's own content off a
   short window. The summary is a real control, so it gets a control's target. */
#card-table-details {
  margin-top: 0.4rem;
  border-top: 1px solid var(--border);
  padding-top: 0.35rem;
}
#card-table-details > summary {
  cursor: pointer;
  padding: 0.2rem 0;
  font-size: 0.72rem;
  color: var(--accent-line);
  /* list-item keeps the native disclosure triangle — it is the affordance that
     says "this opens", and a custom marker would have to re-earn that. */
  display: list-item;
  list-style-position: inside;
}
#card-table-details > summary:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.card-table {
  width: 100%;
  margin-top: 0.35rem;
  border-collapse: collapse;
  font-size: 0.7rem;
  /* Tabular figures so the date column reads as a column and not as ragged
     text — the same reason #card-rows dd is monospaced. */
  font-variant-numeric: tabular-nums;
}
.card-table th,
.card-table td {
  padding: 0.15rem 0.35rem 0.15rem 0;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.card-table thead th {
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--ctrl-border);
}
.card-table tbody th {
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.card-table td {
  color: var(--text-secondary);
}
.card-table .card-table-empty {
  color: var(--text-dim);
  font-style: italic;
}

/* The disaster designations' card body is a LIST rather than a picture, so it
   has no figure and no <details> twin: what the archive holds for one county in
   one year is text — a declaration number, an uncleaned disaster type, a
   description somebody typed, and three dates two of which are often missing —
   and semantic markup is already the accessible form of that
   (js/interfaces/disasters.js § The card's second half).

   TOKENS ONLY here, as everywhere in this file. The one colour these rules do
   NOT set is the swatch's fill: that is the map's own Primary/Contiguous data
   colour and js/interfaces/disasters.js sets it, like every other data colour in
   this app. */
.decl-caption {
  margin: 0.4rem 0 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--text-muted);
}
/* A tab stop, because on compact the card body scrolls and this list is the
   only thing in it a keyboard could land on (js/interfaces/disasters.js says
   why). The kit's global :focus-visible ring is the whole visible treatment;
   the rule below only keeps the ring off the text. */
.decl-list {
  margin: 0.3rem 0 0;
  padding: 0;
  list-style: none;
}
.decl-list:focus-visible {
  outline-offset: 3px;
}
.decl-item {
  margin-top: 0.35rem;
  padding-top: 0.35rem;
  border-top: 1px solid var(--border);
  font-size: 0.72rem;
  line-height: 1.45;
}
.decl-item > p {
  margin: 0;
}
.decl-head {
  color: var(--text-primary);
  font-weight: 600;
}
.decl-head code {
  font-family: var(--font-mono);
  font-weight: 700;
}
/* The word and the colour together, never the colour alone (WCAG 1.4.1): the
   swatch is a second channel for the label beside it, which is why it is
   aria-hidden and why nothing here depends on its fill being legible. */
.decl-role {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  white-space: nowrap;
}
.decl-swatch {
  display: inline-block;
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  border: 1px solid var(--ctrl-border);
  border-radius: var(--radius-sm);
}
.decl-desc {
  color: var(--text-secondary);
}
.decl-dates {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ── 10. Data table modal ─────────────────────────────────────────────────
   kit-override: .info-modal-box is authored at min(540px, …) for a column of
   prose — the help modal. This one holds a six-column table of three thousand
   rows, and 540px would wrap every county name. Widened for THIS dialog only;
   the help modal keeps the kit's measure. */
#table-modal .info-modal-box {
  width: min(960px, calc(100vw - 2rem));
}

/* The table scrolls inside the box rather than the box growing past the
   viewport: the modal header (with the live caption) stays put, and the sticky
   header row keeps the column meanings on screen through three thousand rows. */
#table-modal-body {
  max-height: min(60dvh, 520px);
  overflow: auto;
  /* A scrollable region needs to be reachable and announced as one: table-view
     .js gives it tabindex and a label. The border makes the edge visible. */
  border: 1px solid var(--border);
  border-radius: 6px;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}
.data-table caption {
  text-align: left;
}
.data-table th,
.data-table td {
  padding: 0.3rem 0.6rem;
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
}
.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  /* Opaque, not --glass: rows scroll UNDER this row, and a translucent header
     over arbitrary text is unreadable at any contrast ratio. */
  background: var(--bg-surface);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  box-shadow: inset 0 -1px 0 0 var(--ctrl-border);
}
.data-table tbody th {
  font-weight: 600;
  color: var(--text-primary);
}
.data-table td {
  color: var(--text-secondary);
}
.data-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.data-table tbody tr:hover th,
.data-table tbody tr:hover td {
  background: var(--bg-raised);
}
.data-table code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--text-primary);
}

/* Compact: the table modal is nearly the whole screen on a phone, and the
   type has to shrink or the six columns become a horizontal scroll bar with
   two columns visible. It still scrolls sideways if it must — a table is
   allowed to be wide, it is not allowed to be truncated. */
@media (max-width: 640px), (max-height: 560px) {
  #table-modal .info-modal-box {
    width: calc(100vw - 2rem);
    padding: 1rem;
  }
  #table-modal-body { max-height: 62dvh; }
  .data-table { font-size: 0.72rem; }
  .data-table th,
  .data-table td { padding: 0.25rem 0.4rem; }
}
