/* ============================================================
   Longline — the rotorcraft operator register.

   The world is the aircraft maintenance record: ruled fields, hairline column
   rules, tabular figures, and an attestation on every line. The palette is the
   Longline identity system: Deep Navy, Oxblood, Slate. Colour is not
   decoration here — oxblood appears only on the selected mark;
   serviceable-tag ochre only where a line was stated by the company, and only
   beside the line it describes. A colour anywhere else is a bug.

   The map deliberately carries no attestation colour. Provenance of a record
   field is not a geographic fact, and encoding it as a hue put five colour
   states on a plate whose only questions are where, how big, and which one did
   I pick. On the map: ink is a base, radius is the fleet, red is the selection.
   ============================================================ */

:root {
  --ink: #0E1B2A;          /* Deep Navy */
  --ink-2: #3A444C;
  --ink-3: #586875;        /* Slate */
  --ink-4: #78858E;        /* placeholder: the lightest ink that still clears 4.5:1 */
  --ink-press: #071320;    /* the pressed/hovered state of a solid ink control */
  --paper: #F4F6F7;
  --paper-2: #EAEEF0;
  --plate: #FFFFFF;
  --rule: #D3DBDF;
  --rule-2: #B9C4CA;
  --red: #9E261B;          /* Oxblood */
  --ok: #1F6B3F;           /* accepted / sent — never used for a data state */
  --amber: #6B5200;
  --amber-mark: #8A5F04;   /* mark on land: must clear 3:1 with headroom */
  --amber-tag: #E4B429;    /* the tag itself, on white */
  --land: #E2E7EA;
  --focus: #0B5FFF;
  --measure: 70ch;
  --h: 72px;
  --tabh: 41px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scrollbar-color: var(--rule-2) var(--paper); }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 15px/1.55 "Public Sans", system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

/* Announced, not shown: the visible result list already says it on screen. */
.sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
::selection { background: color-mix(in srgb, var(--amber-tag) 32%, transparent); color: var(--ink); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--rule-2); border: 3px solid var(--paper); border-radius: 6px; }
::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

a { color: var(--ink); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--red); }
h1, h2 { margin: 0; font-weight: 600; letter-spacing: -0.02em; text-wrap: balance; }

/* ───────────────────────────────────────────────── the record header */
.rec {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 20px;
  padding: 0 16px;
  height: var(--h);
  background: var(--plate);
  border-bottom: 1px solid var(--ink);
}
.rec-id { display: flex; align-items: center; gap: 16px; min-width: 0; }
/* The descriptor sits beside the mark rather than under it, so the header keeps
   its single-line height. Divided by a hairline, like every other pairing here.
   It is the first thing to go when the bar gets tight: the mark already says
   the name, and the vitals are the part nobody can infer. */
.rec-id .sub {
  margin: 0; padding-left: 16px; border-left: 1px solid var(--rule);
  font-size: 11px; font-weight: 500; line-height: 1.35;
  letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3);
  white-space: nowrap;
}
@media (max-width: 1400px) { .rec-id .sub { display: none; } }
/* ───────────────────────────────────────────────────── the Longline mark
   One drawn lockup: the reference line, the aircraft on it, and the cable
   dropping through the gap in the word to its load. Nothing here is an image
   file, so it stays sharp at any size and reverses by swapping two tokens. */
.mark { display: block; text-decoration: none; }
.mark-art { display: block; height: 40px; width: auto; overflow: visible; }
.ml-ink { fill: none; stroke: var(--ink); stroke-linecap: round; }
.ml-rule   { stroke-width: 2; }
.ml-body   { fill: var(--ink); stroke: none; }
.ml-boom   { stroke-width: 3.4; }
.ml-rotor  { stroke-width: 1.7; }
.ml-cross  { stroke-width: 1.5; }
.ml-skid   { stroke-width: 1.8; }
.ml-strut  { stroke-width: 1.5; }
.ml-cable path { stroke: var(--red); stroke-width: 1.7; fill: none; }
.ml-cable circle { fill: var(--red); }
.ml-word {
  fill: var(--ink);
  font-family: "Public Sans", system-ui, sans-serif;
  font-weight: 700; font-size: 40px; letter-spacing: .055em;
}
.mark:hover .ml-cable path, .mark:hover .ml-cable circle { stroke: var(--red); fill: var(--red); }
.mark:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; border-radius: 2px; }

.vitals { display: flex; gap: 10px; margin: 0; justify-self: end; margin-right: 18px; }
.vitals div { display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
.vitals dt {
  font-size: 10px; color: var(--ink-3);
  letter-spacing: .085em; text-transform: uppercase;
}
.vitals dd {
  margin: 0; font-size: 15px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: .01em;
}

.rec-act { display: flex; align-items: center; gap: 12px; }
.ghost, .solid {
  font: inherit; font-size: 12px; font-weight: 500;
  padding: 7px 12px; border-radius: 2px; cursor: pointer; white-space: nowrap;
}
/* Only one action in the header reads as a button, which is what the identity
   mockup shows. Methodology and sign-in are real actions but secondary ones, so
   they sit as quiet text and give the bar back the ~110px the vitals needed. */
.ghost {
  background: none; border: 0; color: var(--ink-3);
  padding: 7px 4px; font-size: 12px;
}
.ghost:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 4px; }
.solid {
  background: var(--ink); border: 1px solid var(--ink); color: #fff;
  text-transform: uppercase; letter-spacing: .09em; font-weight: 600;
  font-size: 11.5px; padding: 10px 18px;
}
.solid:hover { background: var(--ink-press); }

/* ───────────────────────────────────────────────────────────── tabs */
.tabs {
  display: flex;
  background: var(--plate);
  border-bottom: 1px solid var(--rule);
  padding: 0 24px;
  position: sticky; top: 0; z-index: 30;
  height: var(--tabh);
}
.tab {
  font: inherit; font-size: 13px; font-weight: 500;
  padding: 0 18px; background: none; border: 0;
  border-bottom: 2px solid transparent;
  color: var(--ink-3); cursor: pointer; margin-bottom: -1px;
}
.tab:hover { color: var(--ink); }
.tab.is-on { color: var(--ink); border-bottom-color: var(--ink); }

.panel { display: none; }
.panel.is-on { display: block; }

/* ────────────────────────────────────────────────────────────── map */
#p-map { position: relative; height: calc(100svh - var(--h) - var(--tabh)); overflow: hidden; }
.mapwrap { position: absolute; inset: 0; padding-left: min(34%, 470px); }
#usmap { width: 100%; height: 100%; display: block; }
#usmap:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* The land arrives first and quietly: paper, then ground, then the register
   lands on it. One sequence, ~760ms, once — and gated on .plotting for the
   same reason the marks are. */
#usmap.plotting .region, #usmap.plotting .border-out { animation: ink .26s ease-out backwards; }
#usmap.plotting .inset { animation: ink .26s ease-out .1s backwards; }
@keyframes ink { from { opacity: 0 } to { opacity: 1 } }

.region { fill: var(--land); stroke: var(--paper); stroke-width: 1; }

/* The inset says where it is and that its scale is its own. */
.inset rect { fill: var(--paper); stroke: var(--rule-2); stroke-width: 1; }
.inset text {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 8px; letter-spacing: .08em; fill: var(--ink-3);
}
.border-out { fill: none; stroke: var(--rule-2); stroke-width: 1; }
/* One encoding per channel: the mark is a base, its radius is the fleet,
   airworthiness red is the one you selected. Nothing else is coloured. */
.op {
  fill: var(--ink); fill-opacity: .72; cursor: pointer;
  transform-box: fill-box; transform-origin: center;
}
/* The entrance is opt-in and self-cancelling. The resting rule above is the
   FINISHED map, so the default state of this file is a complete plate; the
   sweep only exists while the svg carries .plotting, which JS adds after
   drawing and a timer removes ~1.1s later no matter what happened in between.
   Putting the invisible state in the resting rule would mean a browser that
   skipped the animation showed no operators at all. */
#usmap.plotting .op {
  animation: land .34s cubic-bezier(.16,1,.3,1) backwards;
  animation-delay: var(--in, 0s);
}
@keyframes land {
  from { transform: scale(.3); fill-opacity: 0; }
  to   { transform: scale(1);  fill-opacity: .72; }
}
.op:hover { fill-opacity: 1; }
.op.on { stroke: var(--red); stroke-width: 2.5; paint-order: stroke; fill-opacity: 1; }
.op.roving { stroke: var(--focus); stroke-width: 2.5; fill-opacity: 1; }

/* ────────────────────────────────────────── the identification plate
   A dot on a map is anonymous. This answers "who is that" in the operator's
   own mark, at the same 34px the register uses everywhere else. */
.opplate {
  position: absolute; left: 0; top: 0; z-index: 8;
  display: none; width: max-content; max-width: 250px;
  padding: 10px 12px 11px;
  background: var(--plate); border: 1px solid var(--ink); border-radius: 2px;
  box-shadow: 0 6px 18px -8px rgba(14,17,22,.45);
  pointer-events: none;
}
.opplate.on { display: block; animation: plate .13s cubic-bezier(.16,1,.3,1) both; }
@keyframes plate {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.opplate-mark { height: 34px; display: flex; align-items: center; margin-bottom: 8px; }
.opplate-mark img { max-height: 34px; max-width: 150px; object-fit: contain;
  object-position: left center; }
.opplate-mark .ini {
  width: 34px; height: 34px; border-radius: 1px; background: var(--paper-2);
  color: var(--ink-2); font-size: 13px; font-weight: 700;
  display: grid; place-items: center;
}
.opplate b { display: block; font-size: 13.5px; font-weight: 600; line-height: 1.3; }
.opplate-meta {
  display: block; margin-top: 4px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px; color: var(--ink-3);
}

.over {
  position: absolute; top: 0; left: 0;
  width: min(34%, 470px); min-width: 320px; height: 100%;
  padding: 44px 34px 30px 24px;
  background: linear-gradient(90deg, var(--paper) 76%, rgba(244,246,247,0));
  overflow-y: auto; scrollbar-width: none;
}
.over::-webkit-scrollbar { width: 0; }
/* Only when there is genuinely more below: a permanent fade would dim the last
   control on every screen tall enough not to need it. The class is set from
   measurement, on load and on resize. */
.over.has-more { mask-image: linear-gradient(180deg, #000 calc(100% - 46px), transparent); }
h1 { font-size: clamp(30px, 3.3vw, 46px); line-height: 1.04; margin-bottom: 16px; }
.lede { font-size: 14px; line-height: 1.6; color: var(--ink-2); max-width: 38ch; margin: 0 0 24px; }

.find { position: relative; }
.find label, .add-form label {
  display: block; font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
#q, .add-form input, .add-form textarea {
  width: 100%; font: inherit; font-size: 15px; padding: 10px 12px;
  color: var(--ink); background: var(--plate);
  border: 1px solid var(--rule-2); border-radius: 2px; caret-color: var(--red);
}
#q::placeholder, .add-form ::placeholder { color: var(--ink-4); }
#q:focus, .add-form input:focus, .add-form textarea:focus { border-color: var(--ink); outline: none; }

.hits {
  position: absolute; left: 0; right: 0; top: calc(100% + 3px);
  background: var(--plate); border: 1px solid var(--ink);
  max-height: 300px; overflow-y: auto; z-index: 6; display: none;
}
.hits.on { display: block; }
.hits button {
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
  width: 100%; text-align: left; font: inherit; font-size: 13.5px; padding: 8px 12px;
  border: 0; border-bottom: 1px solid var(--rule); background: none;
  color: var(--ink); cursor: pointer;
}
.hits button:last-child { border-bottom: 0; }
.hits button:hover, .hits button:focus-visible { background: var(--paper-2); }
.hits .where { color: var(--ink-3); font-size: 12px; white-space: nowrap; }
.hits .none { padding: 11px 12px; font-size: 13px; color: var(--ink-2); }

/* ──────────────────────────────────────────────────────── map filters */
/* Open from the start. This was a disclosure, on the theory that search should
   own the first viewport — but a fold is a good way to make sure nobody ever
   discovers that the map can be narrowed at all. The controls are the offer;
   they say what the map can do before anyone has to click to find out. */
.mapfilter { margin: 18px 0 0; border-top: 1px solid var(--ink); padding-top: 9px; }
.mf-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 9px; padding: 2px 0;
}
.mf-head #mf-label, .mf-row > label, .mf-row > span {
  font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.mapcount { font-family: "JetBrains Mono", monospace; font-size: 12px;
  color: var(--ink-2); letter-spacing: 0; text-transform: none; font-weight: 500; }
.mf-row { display: grid; gap: 4px; margin-bottom: 8px; }
/* A dropdown does not need a line of its own for its label. The toggle groups
   do: they wrap, and squeezing them into a column pushes them to three rows. */
.mf-row.inline { grid-template-columns: 104px 1fr; align-items: center; gap: 10px; }
.mf-row select {
  font: inherit; font-size: 13.5px; padding: 7px 9px; width: 100%;
  color: var(--ink); background: var(--plate);
  border: 1px solid var(--rule-2); border-radius: 2px; cursor: pointer;
}
.mf-row select:hover { border-color: var(--ink); }
.togs { display: flex; flex-wrap: wrap; gap: 3px; }
.tog {
  font: inherit; font-size: 11.5px; font-weight: 500; padding: 4px 9px;
  background: var(--plate); border: 1px solid var(--rule-2); border-radius: 2px;
  color: var(--ink-2); cursor: pointer; white-space: nowrap;
}
.tog:hover { border-color: var(--ink); color: var(--ink); }
.tog.is-on { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.mf-reset {
  font: inherit; font-size: 11.5px; padding: 0; margin-top: 2px;
  background: none; border: 0; color: var(--ink-3); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.mf-reset:hover { color: var(--red); }
.op.off { display: none; }

.platenote { position: absolute; left: 24px; bottom: 12px; margin: 0; max-width: 44ch;
  font-size: 11px; line-height: 1.5; color: var(--ink-3); }
.notelink {
  font: inherit; font-size: 11px; padding: 0; background: none; border: 0;
  color: var(--ink-2); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.notelink:hover { color: var(--red); }

/* ─────────────────────────────────────────────────── panels & heads */
.panel-head { padding: 38px 24px 20px; max-width: var(--measure); }
/* The Operators head carries a disclosure, so it stops being a measure-wide
   column and becomes two: the introduction, and the note that governs the
   column people came to read. It drops under the intro on narrow screens
   rather than squeezing both into unreadable widths. */
.panel-head.with-note {
  max-width: none; display: grid; gap: 26px 44px;
  grid-template-columns: minmax(0, var(--measure)) minmax(240px, 300px);
  align-items: start; justify-content: space-between;
}
.disclosure {
  border-top: 1px solid var(--ink); padding-top: 9px;
  font-size: 12.5px; line-height: 1.55; color: var(--ink-3);
}
.disclosure p { margin: 0 0 8px; }
.disclosure p:last-child { margin-bottom: 0; }
.disc-h {
  font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-2);
}
.disc-more {
  font: inherit; font-size: 12.5px; padding: 0; background: none; border: 0;
  color: var(--ink-2); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.disc-more:hover { color: var(--red); }
@media (max-width: 900px) {
  .panel-head.with-note { grid-template-columns: 1fr; gap: 20px; }
  .disclosure { max-width: var(--measure); }
}
.panel-head h2 { font-size: clamp(23px, 2.4vw, 32px); margin-bottom: 10px; }
.panel-head p { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.6; }

/* ──────────────────────────────────────────────── the capability grid */
/* ─────────────────────────────────────── the table scroll regions
   A trap worth naming: `overflow-x: auto` forces `overflow-y` to compute to
   `auto` as well. That silently made these wrappers scroll containers, so the
   sticky <thead> stopped resolving `top` against the viewport and started
   resolving it against the wrapper — landing 41px lower than the row it was
   meant to sit above and covering the first line of logos.

   Since they are scroll containers whether we like it or not, they are now
   scroll containers on purpose: a bounded region with the header pinned at
   its own top. The header finally does the job it was claiming to do, and the
   footnote lives outside so it is readable without crossing the table. */
.gridwrap, #opswrap:has(.olist) {
  overflow: auto;
  max-height: calc(100svh - var(--h) - var(--tabh) - 148px);
  min-height: 340px;
  overscroll-behavior-x: contain;
}

.gridwrap { padding: 0 24px 24px; }
.cgrid { border-collapse: collapse; width: 100%; min-width: 860px; }
.cgrid th, .cgrid td { border: 1px solid var(--rule); vertical-align: top; }

.cgrid thead th {
  position: sticky; top: 0; z-index: 6;
  background: var(--plate); padding: 11px 13px 10px; text-align: left;
  border-bottom: 1px solid var(--ink); width: 22%;
}
.cgrid thead th b { display: block; font-size: 12.5px; font-weight: 600; line-height: 1.25; }
.cgrid thead th em { display: block; font-style: normal; font-weight: 400;
  color: var(--ink-3); font-size: 10.5px; margin-top: 3px; line-height: 1.4; }
.cgrid thead th i {
  display: block; font-style: normal; margin-top: 7px;
  font-family: "JetBrains Mono", monospace; font-size: 11px; color: var(--ink-2);
}
.cgrid thead th.corner { width: 190px; font-size: 11.5px; font-weight: 600;
  color: var(--ink-3); letter-spacing: .07em; text-transform: uppercase; }

/* The mission stays put while the eye travels across the classes. */
.cgrid tbody th {
  position: sticky; left: 0; z-index: 4;
  text-align: left; padding: 11px 13px; background: var(--paper-2);
  width: 190px; font-weight: 400;
  box-shadow: 1px 0 0 var(--rule);
}
.cgrid tbody th b { font-size: 13px; font-weight: 600; line-height: 1.3; }

/* The row's weight, read before any name is: how much of the sector works it. */
.meter { display: flex; align-items: center; gap: 7px; margin-top: 6px; height: 9px; }
.meter i { display: block; height: 4px; background: var(--ink); opacity: .5;
  min-width: 2px; flex: 0 0 auto; }
.meter span { font-family: "JetBrains Mono", monospace; font-size: 11px;
  color: var(--ink-3); }

/* The cell ground steps back so the white mark plates read as objects on it. */
.cgrid td { padding: 9px; background: var(--paper); }
.cgrid.dense td { background: var(--paper); }
.cgrid:not(.dense) td { background: var(--plate); }
.cgrid td.empty { background: var(--paper-2); }
.cgrid td .n {
  display: block; margin-bottom: 6px;
  font-family: "JetBrains Mono", monospace; font-size: 11px; color: var(--ink-3);
}
/* --ink-4 is a placeholder tone and lands at 3.26:1 on the empty-cell ground. */
.cgrid td .nil { font-size: 11.5px; color: var(--ink-3); }
.more {
  font: inherit; font-size: 11.5px; margin-top: 6px; padding: 0;
  background: none; border: 0; color: var(--ink-3); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.more:hover { color: var(--red); }
.cell { display: flex; flex-wrap: wrap; gap: 5px; }

/* Marks: the whole distribution visible at once, every operator still a target.
   Sized off the artwork rather than off the table. A logo library is mostly
   horizontal wordmarks, so a square box squeezes the majority of it into its
   short axis — the plate is wider than it is tall for that reason, and it sits
   on white because that is the ground these marks were drawn for. */
.mk {
  display: grid; place-items: center; padding: 4px 7px;
  height: 44px; width: auto; flex: 0 0 auto;
  min-width: 54px; max-width: 128px;
  background: var(--plate); border: 1px solid var(--rule-2); border-radius: 2px;
  cursor: pointer; overflow: hidden;
}
.mk:hover { border-color: var(--ink); box-shadow: 0 1px 3px rgba(14,17,22,.13); }
/* Height is the constant, width follows the artwork. A fixed-width box makes
   width the binding constraint for every wordmark, and a 10.9:1 mark then
   renders four pixels tall — measured, not guessed. */
.mk img { height: 34px; width: auto; max-width: 112px; object-fit: contain; }
.mk .ini {
  background: none; width: auto; height: auto; border-radius: 0;
  color: var(--ink-2); font-size: 13.5px; font-weight: 700; letter-spacing: -.02em;
}
.mk.confirmed { border-color: var(--amber-mark); box-shadow: inset 2px 0 0 var(--amber-mark); }
.mk.confirmed:hover { box-shadow: inset 2px 0 0 var(--amber-mark), 0 1px 3px rgba(14,17,22,.13); }
.mk.verified { border-color: var(--ink); box-shadow: inset 3px 0 0 var(--ink); }
.mk.verified:hover { box-shadow: inset 3px 0 0 var(--ink), 0 1px 3px rgba(14,17,22,.13); }

/* The quiet line under a table that says what the table is not claiming. */
.footnote, .gridnote {
  max-width: var(--measure);
  font-size: 12px; line-height: 1.6; color: var(--ink-3);
}
.footnote { margin: 20px 0 0; }
.gridnote { margin: 16px 24px 64px; }   /* sits outside the scroll region */
.footnote b, .gridnote b { color: var(--ink-2); font-weight: 600; }
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit; font-size: 11.5px; padding: 3px 7px 3px 4px;
  background: var(--paper); border: 1px solid var(--rule); border-radius: 2px;
  cursor: pointer; color: var(--ink); max-width: 190px;
}
.chip:hover { border-color: var(--ink); }
.chip img { width: 15px; height: 15px; object-fit: contain; flex: 0 0 15px; }
.chip .ini {
  width: 15px; height: 15px; flex: 0 0 15px; border-radius: 1px;
  background: var(--rule); color: var(--ink-3);
  font-size: 7.5px; font-weight: 700; display: grid; place-items: center;
}
.chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip.confirmed { border-color: var(--amber-mark); box-shadow: inset 2px 0 0 var(--amber-mark); }
.chip.verified { border-color: var(--ink); box-shadow: inset 3px 0 0 var(--ink); }

/* ──────────────────────────────────────────── the operators explorer
   Every entry on the register, as identification plates or as a ruled list.
   The plates share their rules with their neighbours rather than floating as
   cards, so the sheet reads as one continuous record. Whatever the sort is,
   the value being sorted on is printed on the plate — a sort you cannot see
   the evidence for is just a reshuffle. */
.opsbar {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px 18px;
  padding: 0 24px 18px;
}
.ctl { display: grid; gap: 5px; }
.ctl > label, .ctl > span {
  font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.opsbar select {
  font: inherit; font-size: 13.5px; padding: 7px 10px; min-width: 168px;
  color: var(--ink); background: var(--plate);
  border: 1px solid var(--rule-2); border-radius: 2px; cursor: pointer;
}
.opsbar select:hover { border-color: var(--ink); }

.viewsw { display: flex; border: 1px solid var(--rule-2); border-radius: 2px; }
.vw {
  font: inherit; font-size: 12.5px; font-weight: 500; padding: 7px 14px;
  background: none; border: 0; border-right: 1px solid var(--rule-2);
  color: var(--ink-3); cursor: pointer;
}
.vw:last-child { border-right: 0; }
.vw:hover { color: var(--ink); }
.vw.is-on { background: var(--ink); color: var(--paper); }

.opscount {
  margin: 0 0 3px auto; font-size: 12px; color: var(--ink-3);
  font-family: "JetBrains Mono", monospace;
}
/* The list is seven columns of record and does not compress below about 720px
   without lying about what fits. It scrolls inside its own frame; the page
   itself never scrolls sideways. */
#opswrap { padding: 0 24px 24px; }

.plates {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(214px, 1fr));
  border-top: 1px solid var(--ink); border-left: 1px solid var(--rule);
}
.plate {
  display: grid; align-content: start; gap: 0;
  font: inherit; text-align: left; cursor: pointer;
  padding: 15px 15px 13px; min-height: 128px;
  background: var(--plate); color: var(--ink);
  border: 0; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
}
.plate:hover { background: var(--paper-2); }
.plate.confirmed { box-shadow: inset 2px 0 0 var(--amber-mark); }
.plate.verified { box-shadow: inset 3px 0 0 var(--ink); }
.plate-mark { height: 28px; display: flex; align-items: center; margin-bottom: 12px; }
.plate-mark img { max-height: 28px; max-width: 124px; object-fit: contain;
  object-position: left center; }
.plate-mark .ini {
  width: 28px; height: 28px; border-radius: 1px; background: var(--paper-2);
  color: var(--ink-3); font-size: 11px; font-weight: 700;
  display: grid; place-items: center;
}
.plate b { font-size: 13.5px; font-weight: 600; line-height: 1.3; }
.plate .where { font-size: 11.5px; color: var(--ink-3); margin-top: 3px; }
.plate .key {
  margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--rule);
  font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--ink-2);
}
.plate .key i { font-style: normal; color: var(--ink-3); }

.olist { width: 100%; min-width: 720px; border-collapse: collapse; }
.olist th, .olist td {
  text-align: left; padding: 9px 12px; font-size: 13.5px;
  border-bottom: 1px solid var(--rule);
}
.olist thead th {
  position: sticky; top: 0; z-index: 5; padding: 0;
  background: var(--plate); border-bottom: 1px solid var(--ink);
}
.sortbtn {
  display: flex; align-items: center; gap: 5px; width: 100%;
  font: inherit; font-size: 11.5px; font-weight: 600; letter-spacing: .02em;
  padding: 10px 12px; background: none; border: 0; color: var(--ink-3);
  cursor: pointer; text-align: left;
}
.sortbtn:hover { color: var(--ink); }
.sortbtn svg { width: 9px; height: 9px; flex: 0 0 9px; opacity: 0; }
.sortbtn svg path { fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; }
[aria-sort] .sortbtn { color: var(--ink); }
[aria-sort] .sortbtn svg { opacity: 1; }
[aria-sort="ascending"] .sortbtn svg { transform: rotate(180deg); }
.olist tbody tr { background: var(--plate); }
.olist tbody tr:hover { background: var(--paper-2); }
.olist th[scope="row"] { font-weight: 600; }
.olist .rowname {
  display: flex; align-items: center; gap: 9px; width: 100%;
  font: inherit; font-size: 13.5px; font-weight: 600; text-align: left;
  background: none; border: 0; padding: 0; color: var(--ink); cursor: pointer;
}
.olist .rowname:hover { color: var(--red); }
.olist .rowname img { width: 17px; height: 17px; flex: 0 0 17px; object-fit: contain; }
.olist .rowname .ini {
  width: 17px; height: 17px; flex: 0 0 17px; border-radius: 1px;
  background: var(--rule); color: var(--ink-3);
  font-size: 8px; font-weight: 700; display: grid; place-items: center;
}
.olist .num { font-family: "JetBrains Mono", monospace; text-align: right; }
.olist td.dim { color: var(--ink-3); }
.olist .att { display: inline-block; }

.noresult {
  padding: 26px 0 0; max-width: var(--measure);
  font-size: 14px; line-height: 1.6; color: var(--ink-2);
}
.noresult b { color: var(--ink); }

/* ────────────────────────────────────────────────────────── pulse */
.pulse-vintage {
  margin: 0 0 18px; font-family: "JetBrains Mono", monospace;
  font-size: 12px; color: var(--ink-3);
}
.pulse-cta { margin: 18px 0 8px; min-height: 40px; }
.logrow {
  display: grid; grid-template-columns: 104px 1fr; gap: 20px;
  padding: 13px 0; border-bottom: 1px solid var(--rule); align-items: baseline;
}
.logrow:first-child { border-top: 1px solid var(--ink); }
.logdate { font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--ink-3); }
.logrow b { font-weight: 600; font-size: 14.5px; }
.logrow p { margin: 4px 0 0; font-size: 13px; color: var(--ink-2); line-height: 1.55; }
.logop {
  font: inherit; font-size: 11.5px; margin-left: 8px; padding: 2px 7px;
  background: var(--paper-2); border: 1px solid var(--rule); border-radius: 2px;
  color: var(--ink-2); cursor: pointer;
}
.logop:hover { border-color: var(--ink); color: var(--ink); }
.src-list a { font-size: 13px; }
#pulsewrap { padding: 0 24px 64px; }
.src-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px,1fr));
  gap: 0 22px; max-width: 860px; }
.src-list div { padding: 9px 0; border-bottom: 1px solid var(--rule); font-size: 13px; }
.src-list em { font-style: normal; color: var(--ink-3); font-size: 11.5px; display: block; }
.pending {
  margin: 22px 0 30px; padding: 14px 16px; max-width: var(--measure);
  background: var(--plate); border: 1px solid var(--rule);
  border-left: 2px solid var(--red);
  font-size: 13.5px; line-height: 1.6; color: var(--ink-2);
}
.pending b { color: var(--ink); }

/* ──────────────────────────────────────────────────── the entry sheet */
.scrim { position: fixed; inset: 0; background: rgba(14,17,22,.4); display: none; z-index: 50; }
.scrim.on { display: block; animation: fade .2s ease-out both; }
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }

.sheet {
  position: fixed; top: 0; right: 0; height: 100svh; width: min(470px, 100vw);
  background: var(--paper); border-left: 1px solid var(--ink);
  transform: translateX(100%);
  transition: transform .3s cubic-bezier(.22,.9,.28,1);
  z-index: 60; overflow-y: auto; overscroll-behavior: contain;
}
.sheet.on { transform: none; }
.sheet[inert] { pointer-events: none; }
#sheet-in { padding: 20px 24px 60px; }

.x { float: right; background: none; border: 0; cursor: pointer;
  padding: 2px 0 8px 10px; line-height: 0; color: var(--ink-3); }
.x svg { width: 15px; height: 15px; display: block; }
.x svg path { stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; fill: none; }
.x:hover { color: var(--red); }

.entry-logo { height: 30px; max-width: 140px; object-fit: contain; display: block; margin-bottom: 12px; }
#sheet-in h2 { font-size: 23px; line-height: 1.15; }
.entry-legal { font-size: 12.5px; color: var(--ink-3); margin: 3px 0 16px;
  font-family: "JetBrains Mono", monospace; }

.lines { border-top: 1px solid var(--ink); margin: 0; }
.line {
  display: grid; grid-template-columns: 112px 1fr auto; gap: 12px; align-items: baseline;
  padding: 9px 0; border-bottom: 1px solid var(--rule); font-size: 13.5px;
}
.line dt { color: var(--ink-3); font-size: 11.5px; }
.line dd { margin: 0; overflow-wrap: anywhere; }
/* Three stamps, and the weight is the argument: solid outranks tinted outranks
   flat, so a page of them sorts itself before anyone reads a word. */
.att { font-size: 9.5px; font-weight: 600; letter-spacing: .05em;
  padding: 2px 6px; border-radius: 2px; white-space: nowrap; }
.att.verified { background: var(--ink); color: var(--paper); }
.att.company { background: rgba(228,180,41,.28); color: var(--amber); }
.att.sourced { background: var(--paper-2); color: var(--ink-3); }

#sheet-in h3 { font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3); margin: 24px 0 9px; }
.tags { display: flex; flex-wrap: wrap; gap: 5px; }
.tag { font-size: 11.5px; padding: 3px 8px; border: 1px solid var(--rule);
  border-radius: 2px; background: var(--plate); color: var(--ink-2); }
.tag.inferred { border-style: dashed; }
.tag.card { border-color: var(--ink); color: var(--ink); }

.fleetline { display: flex; justify-content: space-between; gap: 12px;
  padding: 6px 0; border-bottom: 1px solid var(--rule); font-size: 13.5px; }
.fleetline span { font-family: "JetBrains Mono", monospace; color: var(--ink-3); }

.sign { display: block; width: 100%; margin-top: 24px; padding: 12px; text-align: center;
  font: inherit; font-size: 14px; font-weight: 500; background: var(--ink);
  color: var(--paper); border: 0; border-radius: 2px; cursor: pointer; }
.sign:hover { background: var(--ink-press); }
.entry-note { font-size: 11.5px; color: var(--ink-3); margin: 14px 0 0; line-height: 1.55; }

.add-form { display: grid; gap: 14px; margin-top: 6px; }
.add-form .two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.add-form textarea { resize: vertical; line-height: 1.5; }
.hint { margin: 0; font-size: 11.5px; color: var(--ink-3); }
.formnote { margin: 0; font-size: 13px; min-height: 1.2em; }
.formnote.ok { color: var(--ok); }
.formnote.bad { color: var(--red); }

/* ───────────────────────────────────────────────────────── footer */
.foot { border-top: 1px solid var(--rule); background: var(--plate); padding: 34px 24px 46px; }
.foot-in { max-width: var(--measure); }
.foot-lead { font-size: 16px; font-weight: 700; letter-spacing: -.03em; margin: 0 0 8px; }
.foot p { margin: 0 0 10px; font-size: 12px; line-height: 1.6; color: var(--ink-3); }
.advisor { color: var(--ink-2); }

/* Red Mountain's peak. Takes its colour from the link, so it turns with the
   text on hover instead of sitting there as a separate object. */
.chev {
  width: 11px; height: 9px; display: inline-block;
  vertical-align: baseline; margin-right: 5px;
}
.chev path {
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ─────────────────────────────────────────────────────── responsive */
@media (max-width: 1080px) {
  .rec { grid-template-columns: 1fr auto; height: auto; padding: 12px 18px; gap: 12px; }
  .vitals { display: none; }
  .rec-id { flex-direction: column; gap: 1px; align-items: flex-start; }
}
@media (max-width: 860px) {
  /* Below this width the pointer is a thumb, so every control grows to the
     44px target rather than shrinking to fit more of them on the bar. */
  :root { --tabh: 44px; }
  #p-map { height: auto; overflow: visible; }
  /* relative, not static: the identification plate positions against this box */
  .mapwrap { position: relative; padding: 0; height: 52svh; }
  .over { position: static; width: auto; height: auto; min-width: 0;
    background: none; padding: 26px 18px 20px; overflow: visible; }
  .platenote { position: static; margin: 10px 18px 22px; max-width: none; }
  .tabs { padding: 0 8px; height: 44px; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { padding: 0 14px; min-height: 44px; flex: 0 0 auto; }
  .gridwrap, #pulsewrap, .panel-head, .opsbar, #opswrap {
    padding-left: 18px; padding-right: 18px; }
  .gridnote { margin-left: 18px; margin-right: 18px; }
  /* No nested vertical scroller on a thumb. A 560px region inside a 812px
     screen means every downward swipe over the table scrolls the table and
     the page underneath never moves. The tables scroll sideways only; the
     page carries the vertical, and the header simply does not pin. */
  .gridwrap, #opswrap:has(.olist) {
    max-height: none; min-height: 0; overflow-y: hidden;
  }
  .tog, .mf-reset { min-height: 44px; }
  /* The head is a label now, not a control, so it no longer needs a thumb's
     worth of height — and on a phone that space is better spent on the map. */
  .mf-head { align-items: center; margin-bottom: 9px; }
  .mapfilter { margin-top: 20px; }
  .mf-row { margin-bottom: 9px; }
  .logop { min-height: 44px; padding: 6px 12px; margin: 6px 0 0 0; display: inline-block; }
  .tog { padding: 5px 14px; }
  .mf-row select { min-height: 44px; }
  .rec-act { flex-wrap: wrap; gap: 10px; }
  .ghost, .solid { min-height: 44px; }
  .solid { padding: 10px 16px; }
  .ghost { padding: 7px 8px; }
  .mark { min-height: 44px; }
  .x { padding: 15px 0 15px 16px; }
  .vw { min-height: 44px; }
  .opsbar select { min-height: 44px; }
}
@media (max-width: 520px) {
  .add-form .two { grid-template-columns: 1fr; }
  .line { grid-template-columns: 100px 1fr; }
  .line .att { grid-column: 2; justify-self: start; }
  .rec-act { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
  .ghost, .solid { padding: 7px 10px; }
  .opsbar { grid-template-columns: 1fr 1fr; }
  .opsbar .ctl:first-child { grid-column: 1 / -1; }
}
/* Reduced motion means less travel, not less feedback. The entry panel still
   announces that it arrived — it cross-fades in place instead of sliding, and
   the transform snaps behind the fade so nothing crosses the screen. Killing
   the transition outright would make the panel teleport, which is the one
   outcome worse than the slide. */
@media (prefers-reduced-motion: reduce) {
  .sheet {
    opacity: 0;
    transition: opacity .15s linear, transform 0s linear .15s;
  }
  .sheet.on {
    opacity: 1;
    transition: opacity .15s linear, transform 0s linear;
  }
  .scrim.on { animation-duration: .15s; }

  /* The survey sweep is the part that moves, so the sweep is what goes. The
     bases still arrive rather than blinking into being — they fade together,
     in place, and nobody waits out a 760ms stagger to read a map. */
  #usmap.plotting .op {
    animation: fadein .2s ease-out backwards;
    animation-delay: 0s;
  }
  #usmap.plotting .region, #usmap.plotting .border-out,
  #usmap.plotting .inset { animation: fadein .2s ease-out backwards; }
  @keyframes fadein { from { opacity: 0 } to { opacity: 1 } }

  /* The plate still announces itself; it just stops travelling to do it. */
  .opplate.on { animation: fadein .12s ease-out both; }
}

/* The sponsor's own mark, on the entry that it backs. */
.sponsor {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 12px; background: var(--plate);
  border: 1px solid var(--rule); border-radius: 2px;
}
.sponsor img { max-height: 30px; max-width: 104px; object-fit: contain; flex: 0 0 auto; }
.sponsor b { display: block; font-size: 13.5px; font-weight: 600; line-height: 1.3; }
.sponsor span { display: block; margin-top: 2px; font-size: 11.5px; color: var(--ink-3); }

/* A mark drawn in white on a transparent ground is invisible on the white
   plate the register uses everywhere else. The build measures which marks
   those are; here they get the ink backing they were designed for. */
.onink {
  background: var(--ink);
  padding: 3px 5px;
  border-radius: 2px;
  box-sizing: content-box;
}
.mk .onink { padding: 2px 4px; }

/* ============================================================
   Fluid-interface pass. Four things, in the order they matter.
   ============================================================ */

/* 1 ── RESPONSE. The site had 28 hover states and no press states, so every
   control waited for the click before admitting anything had happened. Feedback
   belongs on pointer-down: the press is the moment the user commits, and a
   control that only reacts on release reads as dead under the finger.
   Objects with physical presence take a scale; text actions take a tone. */
.solid, .sign, .tab, .vw, .tog, .mf-reset, .ghost, .more, .notelink,
.logop, .sortbtn, .plate, .chip, .mk, .rowname, .x, .foot-method, .hits button {
  transition: transform 100ms ease-out, background-color 100ms ease-out,
              border-color 100ms ease-out, color 100ms ease-out;
  -webkit-tap-highlight-color: transparent;   /* we draw our own */
}
.plate:active, .chip:active, .mk:active { transform: scale(.972); }
.solid:active, .sign:active, .vw:active, .tog:active { transform: scale(.982); }
.hits button:active, .rowname:active { transform: scale(.99); }
.tab:active, .ghost:active, .mf-reset:active, .more:active,
.notelink:active, .logop:active, .sortbtn:active, .x:active,
.foot-method:active { color: var(--red); }
.op { transition: fill-opacity 100ms ease-out; }
.op:active { fill-opacity: 1; }

/* 12 ── MATERIAL. The tab bar is sticky, so content passes beneath it. An
   opaque strip pretends that isn't happening; a translucent one admits it and
   keeps the page continuous. Restrained on purpose — this world is printed
   paper, not glass. */
.tabs {
  background: color-mix(in srgb, var(--plate) 78%, transparent);
  backdrop-filter: blur(14px) saturate(115%);
  -webkit-backdrop-filter: blur(14px) saturate(115%);
}
/* The playbook prefers a scroll-edge fade to a permanent divider. Not taken:
   the hairline rule is this design's own grammar — every pairing on the page is
   divided by one — so a line that comes and goes would be the odd element, not
   the refined one. The translucency already does the separating. */

/* 14 ── PREFERENCES. Reduced motion was handled; the other two were not.
   Translucency and contrast are separate requests and each needs its own
   answer, not a shared one. */
@media (prefers-reduced-transparency: reduce) {
  .tabs {
    background: var(--plate);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
}
@media (prefers-contrast: more) {
  .tabs { background: var(--plate); backdrop-filter: none; border-bottom-color: var(--ink); }
  .ghost, .tog, .vw { border: 1px solid var(--ink); }
  .att.sourced { border: 1px solid var(--ink-3); }
  .att.company { border: 1px solid var(--amber); }
  .region { stroke: var(--ink-3); }
}

/* 15 ── LEADING TRACKS SIZE INVERSELY. h2 was inheriting the body's 1.55 at
   31px, which reads as loose paragraph setting rather than a heading. */
.panel-head h2 { line-height: 1.12; }
#sheet-in h2 { line-height: 1.15; }


/* ═══════════════════════════════════════════════════ the operator portal
   Same world as the atlas: ruled fields, hairline separators, one accent. The
   confidential block is set apart deliberately — an operator handing over a
   direct line deserves to see, without reading a word, that it is being kept
   somewhere different from the rest. */
.portal { max-width: 760px; margin: 0 auto; padding: 40px 24px 80px; }
.portal h1 { font-size: clamp(26px, 3vw, 36px); line-height: 1.08; margin-bottom: 12px; }
.portal .panel-head { padding: 0 0 26px; }

.portal-gate { max-width: var(--measure); }
.portal-gate .sign { display: inline-block; width: auto; padding: 12px 22px;
  text-decoration: none; margin-top: 8px; }
.gate-problem { color: var(--red); }

.portal-form { display: block; }
.portal-block {
  border-top: 1px solid var(--ink); padding: 22px 0 26px;
  display: grid; gap: 16px;
}
.portal-block h2 { font-size: 15px; font-weight: 600; letter-spacing: 0; }
.portal-block .two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

/* Not a warning, a boundary: this material is held to a different rule. */
.portal-block.confidential {
  background: var(--paper-2);
  border: 1px solid var(--rule-2); border-radius: 2px;
  /* the same inset the company-stated chips carry, not a coloured border */
  box-shadow: inset 2px 0 0 var(--amber-mark);
  padding: 20px 20px 24px; margin-top: 26px;
}
.portal-block.confidential h2 { color: var(--amber); }
.contact-row { border-top: 1px solid var(--rule); padding-top: 14px; display: grid; gap: 12px; }
.contact-row:first-child { border-top: 0; padding-top: 0; }
.contact-n {
  margin: 0; font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.portal-done { border-top: 1px solid var(--ink); padding-top: 24px; }
.portal-form input[type=file] { font-size: 13px; padding: 8px 0; }

/* The spam trap has to be reachable by a bot and invisible to a person. */
.hidden-field {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

@media (max-width: 620px) {
  .portal-block .two { grid-template-columns: 1fr; }
  .portal { padding: 26px 18px 64px; }
}

/* ────────────────────────────────────────────────────────── the gate
   A closed register, said plainly. Set on the same ruled paper as everything
   else rather than as a modal over a blurred page: there is nothing behind
   this to tease, because the payload was never sent. */
.gate {
  max-width: 430px; margin: max(9vh, 64px) auto; padding: 0 22px 64px;
}
.gate h2 { font-size: clamp(23px, 3vw, 29px); line-height: 1.15; letter-spacing: -.022em; }
.gate-lede {
  margin: 12px 0 26px; color: var(--ink-2); font-size: 14.5px; line-height: 1.6;
  max-width: 42ch;
}
.gate-form { border-top: 1px solid var(--ink); padding-top: 20px; }
.gate-form .gf { display: grid; gap: 5px; margin-bottom: 15px; }
.gate-form label {
  font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.gate-form input {
  font: inherit; font-size: 14.5px; padding: 10px 11px; width: 100%;
  color: var(--ink); background: var(--plate);
  border: 1px solid var(--rule-2); border-radius: 2px;
}
.gate-form input:hover { border-color: var(--ink-3); }
.gate-form input:focus { border-color: var(--ink); outline: 2px solid var(--focus); outline-offset: 1px; }
.gate-form .solid { width: 100%; margin-top: 6px; padding: 12px 18px; }
.gate-form .solid[disabled] { opacity: .55; cursor: default; }
.gate-note { min-height: 20px; margin: 11px 0 0; font-size: 13px; color: var(--ink-3); }
.gate-note.bad { color: var(--red); }
/* The header keeps the mark and the descriptor and loses everything else, so a
   shut door still says whose door it is. */
body.is-gated .rec { grid-template-columns: auto 1fr; }
@media (max-width: 1400px) { body.is-gated .rec-id .sub { display: block; } }
@media (max-width: 620px) { body.is-gated .rec-id .sub { display: none; } }
