/* ==========================================================================
   TEMassist — THE SURFACE CONTROL
   --------------------------------------------------------------------------
   THE NORTH STAR, MADE INTO A CONTROL.

     data → engine → data → endpoint → user

   All information is available at the endpoint.  What is SURFACED is the
   user's choice: Critical · High · Medium · All.  Every place upstream that
   picks for the reader is, by this definition, a defect.

   Three properties this control must have, and they are honesty rules, not
   interaction niceties:

     1. NOTHING IS DESTROYED.  Filtering hides; it never removes.  Every row
        stays in the document, addressable, and one click away.
     2. IT ALWAYS SAYS WHAT IT IS HIDING.  A count of what is held back is
        rendered beside the control, always — never a silent narrowing.  This
        is the same rule as "not shown on map": an absence is stated.
     3. WITHOUT JS IT SHOWS EVERYTHING.  The honest default is ALL.  A reader
        with no script gets the complete brief, not an empty one.

   The gap marker is NOT a rank and is never filtered by severity — it is the
   honest-degradation signal, and hiding it would be the one thing this
   product must never do.  It is filtered only by its own explicit control.
   ========================================================================== */

/* ⛔ HIDDEN UNTIL SCRIPTING IS CONFIRMED, and that is an honesty rule, not progressive
   enhancement for its own sake. Rendered unconditionally, this control put four sticky,
   focusable, clickable buttons and a checked box in front of a no-JS reader, none of which
   did anything — the definition of the "fake interactivity" the blueprint's Act II guardrail
   forbids. The complete brief is still below it either way; what changes is that we no longer
   offer a control we cannot honour.
   `.has-js`, NOT `.js-on`: a reader with reduced motion has scripting and must keep the
   filter. */
.surface { display: none; }

.has-js .surface {
  position: sticky;
  top: 4.25rem;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  padding-block: var(--sp-4);
  margin-bottom: var(--sp-5);
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--hairline);
}

.surface__label { flex: 0 0 auto; }

.surface__set {
  display: flex;
  border: 1px solid var(--line);
}

.surface__btn {
  appearance: none;
  background: transparent;
  border: 0;
  border-right: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  transition: color var(--t-hover) var(--ease),
              background var(--t-hover) var(--ease);
}
.surface__btn:last-child { border-right: 0; }
.surface__btn:hover { color: var(--ink); }

/* The selected state carries its own rank colour, so the control speaks the
   same severity language as the rows it governs. */
.surface__btn[aria-pressed="true"] {
  color: var(--paper);
  background: var(--ink);
}
/* ⚠ THE PRESSED STATE READS AS ITS RANK WITHOUT PAINTING WHITE ON IT.
   The first version filled the button with the rank colour and set `color:#fff`. Measured:
   white on night `--high` is 2.49:1 — below even the 3:1 floor for a UI mark, on the
   showcase theme — and white on day `--high` is 4.11:1, under AA for a 12px label. It also
   introduced the only three raw hex values in the build, against CD §16's rule that the
   tokens are the single source of truth.
   So the rank is carried by a FILLED BAR and the label stays on the page's own ink, which
   is AA on both grounds by construction. Colour still means what it means; it just stops
   being the thing the text has to survive. */
.surface__btn[aria-pressed="true"] {
  color: var(--ink);
  background: transparent;
  box-shadow: inset 0 -3px 0 0 var(--ink);
}
.surface__btn[data-floor="critical"][aria-pressed="true"] { box-shadow: inset 0 -3px 0 0 var(--critical); }
.surface__btn[data-floor="high"][aria-pressed="true"]     { box-shadow: inset 0 -3px 0 0 var(--high); }
.surface__btn[data-floor="medium"][aria-pressed="true"]   { box-shadow: inset 0 -3px 0 0 var(--medium); }

/* THE HELD-BACK COUNT.  Always rendered.  Reads as a calm statement of fact,
   in the mono data voice — never a warning, never an error tint. */
.surface__count {
  margin-left: auto;
  font-family: var(--mono);
  font-size: var(--fs-label);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  letter-spacing: .04em;
}
.surface__count strong { color: var(--ink); font-weight: 500; }

/* The gap toggle — separate, because a gap is not a rank. */
.surface__gap {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--mono);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--accent);
  cursor: pointer;
  user-select: none;
}
.surface__gap input { accent-color: var(--accent); margin: 0; }

@media (max-width: 44rem) {
  .surface { top: 3.5rem; gap: var(--sp-3); }
  .surface__count { margin-left: 0; width: 100%; }
}

/* --------------------------------------------------------------------------
   THE HIDDEN STATE
   `hidden` is used, not display:none in a class, so the DOM stays honest and
   assistive tech agrees with the visual state.  The rule below only exists
   because the base reset sets [hidden] and a grid child can override it.
   -------------------------------------------------------------------------- */

[hidden] { display: none !important; }

/* A row being surfaced animates only its own opacity — never a layout shift
   (blueprint §Budget: zero layout-shift from motion). */
.js-on .row, .js-on .aptcard { transition: opacity var(--t-micro) var(--ease); }

/* --------------------------------------------------------------------------
   THE ATTRIBUTE STRIP
   Every row carries the attributes the filter selects on, rendered as small
   mono chips.  This is deliberately visible rather than hidden in data-*:
   it is the argument the site is making — that the endpoint receives
   ATTRIBUTED facts, not a pre-made page.
   -------------------------------------------------------------------------- */

.attrs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

/* 11px and --muted, not 10px and --faint. These chips are the site's actual argument —
   "every row arrived attributed" — and they were set in the least legible value on the
   page (--faint measures ~2.3:1) at a size below the build's own smallest type step. */
.attr {
  font-family: var(--mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--muted);
  border: 1px solid var(--line);
  padding: 2px 6px;
  /* ⛔ `white-space: nowrap` PUT A 208px CHIP IN A 153px COLUMN. `.attrs` already wraps, so the
     chips flow — but wrapping moves a chip to its own line and never makes one NARROWER, and a
     flex item still refuses to go below its min-content width. `ROLE · ENROUTE ALTERNATE`, mono,
     uppercase, +0.1em, is 208px of unbreakable text, and at 390px it took the whole page sideways
     with it (400px of document, measured 2026-09-11). The chip may take two lines on a phone; the
     page may not take two screens. Same doctrine as the brief's NOTAM raw text, which "wraps
     inside its frame at any length" with a 1,795-character stand closure as the stress case. */
  white-space: normal;
  overflow-wrap: anywhere;
}
.attr--transient { color: var(--medium); border-color: color-mix(in srgb, var(--medium) 40%, transparent); }
.attr--assessed  { color: var(--low);    border-color: color-mix(in srgb, var(--low) 40%, transparent); }
