/* ============================================================================
   assets/css/sfp-components.css -- the SFP shared component shell (A-28).

   PURPOSE: the hub-and-spoke kit every rebuilt signed-in home and spoke uses,
   per docs/SFP_A28_Tile_IA_Design_Record_v0_1.md TIA-12 (owner-ruled 3 Sep
   2026). Loaded by the SECOND line of the injected header fragment
   (components/header.html), AFTER assets/css/sfp-tokens.css, so every page
   carrying the shared shell inherits it. Colours by token only (B1): this
   sheet mints no colour and carries no literal (B2); the token file is
   untouched. A page that loads this sheet does not load the Tailwind CDN
   (the check.html precedent; Checklist E-1).

   Classes (TIA-12.1):
     .sfp-greeting              the hub's greeting band: who you are signed
                                in as, in the fixed role label of TIA-11.
                                Display facts render via textContent only
                                (D5-7); never a standing claim.
     .sfp-tiles                 the tile grid: 2-up on a phone, 3-up on a desk.
     .sfp-tile                  ONE DOOR PER ROOM (TIA-4): one tile opens one
                                room. The whole tile is the link.
     .sfp-tile-title            the tile's name (the room).
     .sfp-tile-hint             the tile's one-line hint (<= 12 words).
     .sfp-tile-count            a count on a tile is a HINT, never a claim.
     .sfp-tile-neutral / -tint /  the tile faces of the kit look (KL-1, KL-D1; the
                                compact row of KL-1a, KL-D5/D7):
     .sfp-tile-primary          gray-100, blue-50, and blue-50 with the blue edge.
     .sfp-glyph / .sfp-glyph-defs the dashed glyph on its dot grid; the one
                                <pattern> a hub declares (KL-1).
     .sfp-table                 the one table implementation (J8-F9): a
                                sortable header wears aria-sort; the search
                                field wears .sfp-input from the token file.
     .sfp-back                  spoke to hub, one link.
     .sfp-form / .sfp-field /   the editor primitives (A-28 lane 4, L4-D2):
     .sfp-check / .sfp-actions  a bordered form box, a labelled field, a
                                checkbox row, a row of controls. A page
                                mints none of these (TIA-12.3).
     .sfp-check-set             a SET of checks (L4-3a): each .sfp-check inside
                                it is its own row, one per line, the whole row
                                the tap target.
     .sfp-alert-amber           a notice addressed to the operator about the
                                profile itself (D5(v)); never a driver claim.
     .sfp-row-note              a short note beneath a cell's value.
     .sfp-served / .sfp-latch / the mint primitives (A-28 lane 4, L4-D3): the
     .sfp-reveal                served instrument text in a scroll box, the
                                attestation latch (aria-pressed), the one-time
                                reveal card. Colours by token only.
     .sfp-table-stack           an EDITOR table on a phone (L4-D5 part 6): each
                                row a block -- the first cell its title, the
                                rest "Label: value" lines from data-label, the
                                .sfp-cell-actions cell a control row beneath.
                                Desk unchanged; the L3-D8 read tables keep
                                the pin and never take this class.
     .sfp-actions-stack /       the carrier and driver families (A-28 lanes 6+7,
     .sfp-actions-pin           L6-1): a stacked pair of equal doors; a control
                                row pinned to the phone's viewport foot under a
                                list of unbounded length (C4).
     .sfp-proposals /           the Proposed Facts editor rows (L2R-D1).
     .sfp-proposal-row
     .sfp-map-row / .sfp-map-head the import wizard's column-to-target rows.
     .sfp-passport / .sfp-qr /  the passport face (FACE-1 as a room), the
     .sfp-photo / .sfp-photo-room  on-device QR, the photo slots.
     .sfp-check-consent /       a consent box whose label IS the served text
     .sfp-consent-text          (never pre-ticked; textContent only).
     .sfp-todo                  the hub's arrival to-do strip (D-N3R): what is
                                waiting, one door per line, from the boot read.
                                D-D7 (3 Oct 2026): a disclosure box on the amber
                                pair -- a checklist, open on first landing, folded
                                on a revisit; links stay blue-800. Tokens only.
     .sfp-steps / .sfp-step     the import wizard's step strip (D-D10, 3 Oct 2026):
                                one bar and one name per step; the current step
                                bold on the program blue, finished steps on the
                                light blue, those to come grey. Tokens only.
   Touch targets: 44px minimum (tiles, header cells, back link).
   ========================================================================== */

/* ---- Greeting band (KL-1a, KL-D5/KL-D7 28 Sep 2026: the hub fits one screen) --- */
.sfp-greeting {
  padding: .75rem 0 .75rem;
  margin-bottom: .875rem;
  border-bottom: 1px solid var(--sfp-gray-200);
}
.sfp-greeting h1 {
  margin: 0 0 .25rem;
  font-size: 1.75rem;
  line-height: 2.125rem;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--sfp-blue-800);
}
.sfp-greeting p {
  margin: 0;
  color: var(--sfp-gray-600);
  font-size: .9375rem;
  line-height: 1.375rem;
}

/* ---- Tiles (KL-1a, rulings KL-D5, KL-D6, KL-D7 of 28 Sep 2026, on KL-D1..D4) ---
   The hub fits one screen on a laptop and on a phone. A tile is a short row: the
   glyph leads on the left, the title, hint and count follow on the right. On a
   desk the tiles are 3-up; on a phone they are one-up list rows. Faces alternate
   .sfp-tile-neutral (gray-100) and .sfp-tile-tint (blue-50); the primary door
   wears .sfp-tile-primary (blue-50 with the program's blue edge). The glyph is
   inline SVG in the tile markup; its dot grid is the one <pattern> a hub declares
   once (.sfp-glyph-defs). Colours by token only. The skeleton tile (BL-D6) keeps
   its grey face and bars, spans the row without a glyph column, and holds the
   tile's height so nothing moves when the hub paints. ------------------------- */
.sfp-tiles {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .375rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}
.sfp-tiles > li { display: flex; }
@media (min-width: 768px) {
  .sfp-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem; }
}
.sfp-tile {
  display: grid;
  grid-template-columns: 2.25rem minmax(0, 1fr);
  grid-template-rows: auto auto 1fr;
  column-gap: .625rem;
  row-gap: 0;
  align-items: start;
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  padding: .5rem .75rem .5rem .625rem;
  border: 1px solid transparent;
  border-radius: var(--sfp-radius);
  background: var(--sfp-gray-50);
  color: var(--sfp-gray-900);
  text-decoration: none;
  transition: border-color .15s ease;
}
.sfp-tile-neutral { background: var(--sfp-gray-100); }
.sfp-tile-tint    { background: var(--sfp-blue-50); }
.sfp-tile-primary { background: var(--sfp-blue-50); border-color: var(--sfp-blue-800); }
.sfp-tile:focus-visible { border-color: var(--sfp-blue-800); }
/* KL-1b (finding gg): hover only where a pointer can hover -- a tapped tile on a phone keeps no edge. */
@media (hover: hover) { .sfp-tile:hover { border-color: var(--sfp-blue-800); } }
.sfp-tile:focus-visible {
  outline: 2px solid var(--sfp-blue-800);
  outline-offset: 2px;
}
.sfp-tile-title {
  grid-column: 2;
  font-size: 1rem;
  line-height: 1.25rem;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--sfp-blue-800);
}
.sfp-tile-hint {
  grid-column: 2;
  margin: 0;
  font-size: .8125rem;
  line-height: 1.125rem;
  color: var(--sfp-gray-900);
}
.sfp-tile-count {
  display: inline-block;
  margin-top: auto;
  padding: .125rem .5rem;
  border-radius: 9999px;
  background: var(--sfp-gray-100);
  color: var(--sfp-gray-900);
  font-size: .75rem;
  line-height: 1rem;
  font-variant-numeric: tabular-nums;
}
/* The base pill above is unchanged: the rooms' chips (.sfp-chips .sfp-tile-count)
   keep it. Inside a tile the count is a plain foot line (KL-1). */
.sfp-tile .sfp-tile-count {
  grid-column: 2;
  grid-row: 3;
  display: inline-block;
  align-self: end;
  justify-self: start;
  margin-top: .0625rem;
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: var(--sfp-gray-900);
  font-size: .6875rem;
  line-height: .9375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.sfp-glyph-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.sfp-glyph { grid-column: 1; grid-row: 1 / span 3; align-self: start; display: block; width: 2.25rem; margin: .0625rem 0 0; }
.sfp-glyph-dot { fill: var(--sfp-white); }
.sfp-glyph-ink { fill: none; stroke: var(--sfp-blue-800); stroke-width: 5; stroke-linecap: round; }
.sfp-tile.sfp-skel-tile { grid-template-columns: minmax(0, 1fr); min-height: 4.25rem; }  /* KL-1b (finding cc): outranks the desk tile rule so the bars stack */
@media (min-width: 768px) {
  .sfp-tile { grid-template-columns: 4rem minmax(0, 1fr); column-gap: .875rem; row-gap: .125rem; padding: .875rem 1rem .75rem; }
  .sfp-tile-title { font-size: 1.125rem; line-height: 1.5rem; }
  .sfp-tile-hint { margin-bottom: .25rem; font-size: .9375rem; line-height: 1.3125rem; }
  .sfp-tile .sfp-tile-count { margin-top: .25rem; font-size: .8125rem; line-height: 1.25rem; }
  .sfp-glyph { width: 4rem; }
  .sfp-tile.sfp-skel-tile { min-height: 6.5rem; }
}
@media (max-width: 767.98px) {
  /* KL-1b (KL-D9, 29 Sep 2026): the hub fits Safari's usable 390x664 -- six rows in one screen. */
  .sfp-page { padding-top: .25rem; }
  .sfp-greeting { padding: .375rem 0 .5rem; margin-bottom: .5rem; }
  .sfp-greeting h1 { font-size: 1.375rem; line-height: 1.75rem; margin-bottom: .125rem; }
  .sfp-greeting p { font-size: .8125rem; line-height: 1.125rem; }
  .sfp-greeting .sfp-band-switch { margin-top: .375rem; flex-wrap: nowrap; }
  .sfp-greeting .sfp-band-switch label { font-size: .875rem; }
  .sfp-greeting .sfp-band-switch select { flex: 1 1 auto; min-width: 0; max-width: none; }
}
/* KL-1c (KL-D10, 29 Sep 2026; finding hh): on a short phone viewport (an iPhone with
   Safari's bars showing, the SE class) the hub's greeting and rows give up spacing -- never
   type -- so the sixth row's count line sits on the first screen. Taller phones keep the
   comfortable spacing above. */
@media (max-width: 767.98px) and (max-height: 700px) {
  .sfp-greeting { padding: .25rem 0 .375rem; margin-bottom: .375rem; }
  .sfp-tiles { gap: .25rem; }
  .sfp-tile { padding: .375rem .75rem .375rem .625rem; }
}

/* ---- Table ----------------------------------------------------------------- */
.sfp-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .875rem;
  line-height: 1.25rem;
}
.sfp-table th,
.sfp-table td {
  padding: .625rem .75rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--sfp-gray-200);
}
.sfp-table th {
  min-height: 2.75rem;
  background: var(--sfp-gray-50);
  color: var(--sfp-gray-600);
  font-weight: 600;
  font-size: .75rem;
  line-height: 1rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  white-space: nowrap;
}
.sfp-table th.sfp-th-wrap { white-space: normal; }
.sfp-table th[aria-sort] { cursor: pointer; user-select: none; }
/* L3-1b sort affordance (owner-ruled 6 Sep 2026): every sortable header wears a
   faint two-way glyph; the active column wears a solid arrow, bold, full-dark. */
.sfp-table th[aria-sort="none"]::after       { content: " \21C5"; color: var(--sfp-gray-400); }
.sfp-table th[aria-sort="ascending"],
.sfp-table th[aria-sort="descending"]        { color: var(--sfp-gray-900); font-weight: 700; }
.sfp-table th[aria-sort="ascending"]::after  { content: " \25B2"; font-size: .625rem; }
.sfp-table th[aria-sort="descending"]::after { content: " \25BC"; font-size: .625rem; }
.sfp-table th[aria-sort]:hover::after        { color: var(--sfp-blue-800); }
.sfp-table th[aria-sort]:focus-visible       { outline: 2px solid var(--sfp-blue-800); outline-offset: -2px; }
.sfp-table tbody tr:hover { background: var(--sfp-gray-50); }
/* L3-1d (walk finding, 6 Sep 2026): cells do not wrap -- a wide table scrolls
   sideways (.sfp-table-pin), so rows stay one line tall; prose cells opt in. */
.sfp-table td { white-space: nowrap; }
.sfp-table td.sfp-wrap, .sfp-table tr.sfp-disclose td { white-space: normal; }
.sfp-table td.sfp-wrap { min-width: 16rem; }
.sfp-table td.sfp-ident { white-space: nowrap; }

/* ---- Back link (spoke to hub) --------------------------------------------- */
.sfp-back {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  min-height: 2.75rem;
  color: var(--sfp-blue-800);
  font-size: .875rem;
  line-height: 1.25rem;
  text-decoration: none;
}
.sfp-back::before { content: "\2190"; }
.sfp-back:hover { text-decoration: underline; }

/* ============================================================================
   A-28 lane 3 (L3-1, owner-ruled 5 Sep 2026): the room shell -- the classes the
   Site Operator review rooms (and every later spoke) share. Colours by token
   only (B1); no literal (B2). Status is icon + label, never colour alone.
   ========================================================================== */

/* The hidden attribute wins over every display rule in this sheet (L3-1a,
   walk finding: an author display beat the browser's [hidden] rule). */
[hidden] { display: none !important; }

/* ---- Page frame (a page that loads this sheet loads no Tailwind) ---------- */
.sfp-page { max-width: 896px; margin: 0 auto; padding: .5rem 1rem 2.5rem; }
.sfp-page-narrow { max-width: 28rem; }
/* L3-D10 (owner-ruled 6 Sep 2026): a room that carries a table takes the wide
   frame; hubs, panels and every other page keep the 896px column. */
.sfp-page-wide { max-width: 1440px; }

/* ---- Room band: title, context line, the site switch (a context control,
        never a door; the server validates the site on every read).
        KL-1b (KL-D8, 29 Sep 2026): on a desk the band is one row -- the room name
        and context on the left, the site control on the right -- so the room's
        work starts on the first screen; on a phone the label and select share a
        line. The back link is a step smaller on a desk. ----------------------- */
.sfp-band { padding: .75rem 0 1rem; margin-bottom: 1rem; border-bottom: 1px solid var(--sfp-gray-200); }
.sfp-band h1 { margin: 0 0 .25rem; font-size: 1.5rem; line-height: 1.875rem; font-weight: 700; letter-spacing: -.01em; color: var(--sfp-blue-800); }
.sfp-band-context { margin: 0; color: var(--sfp-gray-600); font-size: .875rem; line-height: 1.25rem; }
.sfp-band-switch { display: flex; align-items: center; gap: .5rem; margin-top: .5rem; flex-wrap: nowrap; }
.sfp-band-switch label { font-size: .875rem; font-weight: 600; color: var(--sfp-gray-900); }
.sfp-band-switch select { min-height: 2.75rem; flex: 1 1 auto; min-width: 0; max-width: none; }
@media (min-width: 768px) {
  .sfp-page { padding-top: .25rem; }
  .sfp-back { min-height: 2rem; font-size: .8125rem; }
  .sfp-band { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto; column-gap: 1.5rem; row-gap: 0; align-items: center; padding: .25rem 0 .625rem; margin-bottom: .75rem; }
  .sfp-band h1 { grid-column: 1; grid-row: 1; margin: 0; }
  .sfp-band-context { grid-column: 1 / -1; grid-row: 2; margin-top: .125rem; }  /* KL-1c (KL-D10, finding ii): the context runs the full band width, under the name and the control */
  .sfp-band-switch { grid-column: 2; grid-row: 1; margin-top: 0; }
  .sfp-band-switch label { font-size: 1rem; }
  .sfp-band-switch select { flex: none; width: 22rem; max-width: 22rem; min-height: 2.5rem; }
}

/* ---- Panels: loading, logged out, no access, notice, error ----------------- */
.sfp-panel { background: var(--sfp-gray-50); border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); box-shadow: var(--sfp-shadow); padding: 1.5rem; margin: 1rem auto; text-align: center; }
.sfp-panel h1 { margin: 0 0 .5rem; font-size: 1.5rem; line-height: 2rem; font-weight: 600; color: var(--sfp-blue-800); }
.sfp-panel p { margin: 0 0 .75rem; color: var(--sfp-gray-600); font-size: .875rem; line-height: 1.25rem; }
.sfp-panel-left { text-align: left; }
.sfp-doors { display: flex; flex-direction: column; gap: .5rem; margin: 0 0 .75rem; }
.sfp-doors a, .sfp-link { color: var(--sfp-blue-800); font-size: .875rem; text-decoration: underline; min-height: 2.75rem; display: inline-flex; align-items: center; }

/* ---- Skeleton (the boot-latency lane, BL-3; ruling BL-D6): the loading state of
        a hub, shaped like the band and the tiles it is about to paint. Paints no
        claim: no words on glass (the one word, for the screen reader, is visually
        hidden); the blocks are the tile frame and grey bars where text will be.
        Static -- no motion. Surface greys by token only; never the standing grey
        (doctrine B3). A hub carries only the tiles every tier sees; tier-only
        tiles appear when the boot answers. ---------------------------------- */
.sfp-skeleton { }
.sfp-skel { display: block; background: var(--sfp-gray-200); border-radius: .375rem; }
.sfp-skel-h1 { height: 2rem; width: 40%; margin: 0 0 .25rem; }
.sfp-skel-line { height: 1.25rem; width: 72%; }
.sfp-skel-label { height: 1.25rem; width: 2.25rem; }
.sfp-skel-select { height: 2.75rem; flex: 1 1 100%; }
.sfp-skel-tile { pointer-events: none; }
.sfp-skel-title { height: 1.5rem; width: 62%; }
.sfp-skel-hint { height: 1.25rem; width: 88%; }
.sfp-skel-photo { width: 100%; aspect-ratio: 1 / 1; margin: 0 0 .5rem; }  /* RD-12: holds the photo's place in My photo while it is fetched */
.sfp-visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

/* ---- Toolbar: range control, chips, search ------------------------------- */
.sfp-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; margin: 0 0 .75rem; }
.sfp-toolbar .sfp-input { flex: 1 1 14rem; min-height: 2.75rem; }
.sfp-seg { display: inline-flex; border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); overflow: hidden; background: var(--sfp-gray-50); }
.sfp-seg button { min-height: 2.75rem; padding: 0 .875rem; border: 0; background: transparent; color: var(--sfp-gray-600); font: inherit; font-size: .875rem; font-weight: 600; cursor: pointer; }
.sfp-seg button + button { border-left: 1px solid var(--sfp-gray-200); }
.sfp-seg button[aria-pressed="true"] { background: var(--sfp-blue-800); color: var(--sfp-gray-50); }
.sfp-seg button:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: -2px; }
.sfp-dates { display: inline-flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.sfp-dates input { min-height: 2.75rem; }
.sfp-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 .75rem; padding: 0; list-style: none; }
.sfp-chips button { display: inline-flex; align-items: center; gap: .375rem; min-height: 2.75rem; padding: 0 .875rem; border: 1px solid var(--sfp-gray-200); border-radius: 9999px; background: var(--sfp-gray-50); color: var(--sfp-gray-900); font: inherit; font-size: .875rem; font-weight: 600; cursor: pointer; }
.sfp-chips button[aria-pressed="true"] { border-color: var(--sfp-blue-800); background: var(--sfp-blue-800); color: var(--sfp-gray-50); }
.sfp-chips button:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: 2px; }
.sfp-chips .sfp-tile-count { margin: 0; }
/* KL-1b (KL-D8): density follows the pointer -- 44px stays wherever a finger is the
   pointer; a mouse gets 36px controls on a desk. */
@media (min-width: 768px) and (pointer: fine) {
  .sfp-seg button, .sfp-chips button, .sfp-toolbar .sfp-input { min-height: 2.25rem; }
  .sfp-chips button { padding: 0 .75rem; }
  .sfp-toolbar { margin-bottom: .625rem; }
  .sfp-chips { margin-bottom: .625rem; }
}
/* KL-1b (KL-D8): on a phone a room's toolbar and chips fold behind one Filters
   button (doctrine C4, progressive disclosure); a desk shows them always. The
   open state is data-open on the wrapper, set by the room's script. */
.sfp-filters-row { display: none; }
@media (max-width: 767.98px) {
  .sfp-filters-row { display: flex; align-items: center; margin: 0 0 .5rem; }
  .sfp-filters-toggle { min-height: 2.75rem; }
  .sfp-filters { display: none; }
  .sfp-filters[data-open="true"] { display: block; padding: .75rem .75rem 0; margin: 0 0 .75rem; border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); background: var(--sfp-gray-50); }
}

/* ---- Status chips: icon + label (the shipped shield vocabulary) ------------ */
.sfp-chip { display: inline-flex; align-items: center; gap: .375rem; padding: .125rem .625rem; border-radius: 9999px; font-size: .75rem; line-height: 1.25rem; font-weight: 600; white-space: nowrap; background: var(--sfp-gray-100); color: var(--sfp-gray-900); }
.sfp-chip-green { background: var(--sfp-green-bg); color: var(--sfp-green-fg); }
.sfp-chip-amber { background: var(--sfp-amber-bg); color: var(--sfp-amber-fg); }
.sfp-chip-red   { background: var(--sfp-red-bg);   color: var(--sfp-red-fg); }
.sfp-chip-grey  { background: var(--sfp-gray-100); color: var(--sfp-gray-900); }
.sfp-chip-icon { font-weight: 700; }

/* ---- Table extras: day headers, the in-place disclosure, entries ----------- */
/* L3-D8 (owner-ruled 6 Sep 2026): a wide table scrolls sideways inside
   .sfp-table-pin with its first column pinned, so the row's key stays in view. */
.sfp-table-pin { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.sfp-table-pin .sfp-table th:first-child,
.sfp-table-pin .sfp-table td:first-child { position: sticky; left: 0; z-index: 1; background: var(--sfp-gray-50); box-shadow: 1px 0 0 var(--sfp-gray-200); }
.sfp-table-pin .sfp-table tr[data-open="true"] td:first-child,
.sfp-table-pin .sfp-table tr.sfp-disclose td:first-child { background: var(--sfp-gray-50); }
.sfp-table tr[data-open] { cursor: pointer; }
.sfp-table tr[data-open="true"] td { background: var(--sfp-gray-50); border-bottom-color: transparent; }
.sfp-table tr.sfp-disclose td { background: var(--sfp-gray-50); padding-top: 0; }
.sfp-disclose-body { font-size: .875rem; color: var(--sfp-gray-900); }
.sfp-disclose-body p { margin: 0 0 .375rem; }
.sfp-disclose-body ul { margin: 0; padding-left: 1.125rem; }
.sfp-entry { color: var(--sfp-blue-800); text-decoration: underline; }
.sfp-mono { font-family: var(--sfp-font-mono); }
.sfp-muted-cell { color: var(--sfp-gray-600); white-space: nowrap; }
.sfp-empty { margin: 1rem 0; color: var(--sfp-gray-600); font-size: .875rem; }
.sfp-more { display: flex; justify-content: center; margin: 1rem 0; }

/* ---- Observations (B-17 R1/R5/R9): fixed label, state, actor, date --------- */
.sfp-obs { display: flex; flex-direction: column; gap: .375rem; }
.sfp-obs-item { display: flex; flex-wrap: wrap; align-items: center; gap: .375rem; font-size: .8125rem; line-height: 1.25rem; }
.sfp-obs-meta { color: var(--sfp-gray-600); }
.sfp-btn-link { min-height: 2.75rem; padding: 0 .5rem; border: 0; background: transparent; color: var(--sfp-blue-800); font: inherit; font-size: .8125rem; font-weight: 600; text-decoration: underline; cursor: pointer; }
.sfp-btn-link:disabled { color: var(--sfp-gray-400); text-decoration: none; cursor: default; }
.sfp-btn-link:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: 2px; }

/* ---- Directory: carrier rows and their opened drivers and vehicles --------- */
.sfp-section-title { margin: 1.5rem 0 .5rem; font-size: 1rem; line-height: 1.5rem; font-weight: 600; color: var(--sfp-blue-800); }
.sfp-carrier { border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); background: var(--sfp-gray-50); margin: 0 0 .5rem; }
.sfp-carrier > button { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: .75rem; min-height: 3.25rem; padding: .625rem 1rem; border: 0; background: transparent; font: inherit; text-align: left; cursor: pointer; color: var(--sfp-gray-900); }
.sfp-carrier > button:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: -2px; }
.sfp-carrier-name { font-weight: 600; color: var(--sfp-blue-800); }
.sfp-carrier[data-entry] .sfp-carrier-name { text-decoration: underline; }
.sfp-carrier-meta { display: block; color: var(--sfp-gray-600); font-size: .8125rem; line-height: 1.25rem; }
.sfp-carrier .sfp-tile-count { white-space: nowrap; }  /* KL-1c (KL-D10, finding jj): "1 in 30 days" stays one line on a phone */
.sfp-carrier-body { padding: 0 1rem .75rem; }
.sfp-carrier-body .sfp-table { margin-top: .5rem; }

/* ---- Inline notice (result of an action, or a refusal in plain words) ------ */
.sfp-alert { margin: .75rem 0; padding: .5rem .75rem; border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); font-size: .875rem; color: var(--sfp-gray-900); background: var(--sfp-gray-50); }
.sfp-alert-red { border-color: var(--sfp-red-fg); color: var(--sfp-red-fg); background: var(--sfp-red-bg); }
.sfp-alert-amber { border-color: var(--sfp-amber-fg); color: var(--sfp-amber-fg); background: var(--sfp-amber-bg); }
.sfp-table .sfp-alert { margin: 0; }

/* ---- Editor primitives (A-28 lane 4, L4-D2: the Sites room; shared by the
   Carriers and Staff rooms). Colours by token only; touch targets 44px. ---- */
.sfp-form { margin: .75rem 0 0; padding: 1rem; border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); background: var(--sfp-gray-50); }
.sfp-field { margin: 0 0 .75rem; }
.sfp-field .sfp-label { display: block; margin-bottom: .25rem; }
.sfp-check { display: inline-flex; align-items: center; gap: .5rem; min-height: 2.75rem; margin: 0; font-size: .875rem; line-height: 1.25rem; color: var(--sfp-gray-900); cursor: pointer; }
.sfp-check input { width: 1.125rem; height: 1.125rem; margin: 0; flex: none; accent-color: var(--sfp-blue-800); }
.sfp-check input:disabled { cursor: default; }
/* L4-3a (walk finding (vv), 11 Sep 2026): .sfp-check is inline-flex for a
   table cell, so a SET of checks ran inline and each label butted against
   the next box; inside .sfp-check-set each check is its own full-width row
   (the old page stacked them one per line). */
.sfp-check-set > .sfp-check { display: flex; }
.sfp-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; margin-top: .75rem; }
.sfp-table .sfp-actions { margin-top: 0; flex-wrap: nowrap; }
.sfp-row-note { margin: .25rem 0 0; font-size: .8125rem; line-height: 1.125rem; }
.sfp-row-note-red { color: var(--sfp-red-fg); }
/* L4-1b (walk finding (uu), 8 Sep 2026): an editor row's two wrap cells asked
   16rem each (the L3-1d read-table rule) and the frame paid in a scrollbar;
   an editor table's wrap cells ask 9rem, and its actions cell may wrap so an
   armed label ("Confirm removal") is never clipped at the frame's edge. */
.sfp-table-stack td.sfp-wrap { min-width: 9rem; }
.sfp-table-stack td.sfp-cell-actions { white-space: normal; }

/* ---- Mint primitives (A-28 lane 4, L4-D3: the Carriers room; the Staff room
   next). The served text is read, never edited; the latch is a pressed
   toggle, disabled until there is text to warrant; the reveal is the token's
   only home. ---- */
.sfp-served { max-height: 14rem; overflow-y: auto; margin: .25rem 0 0; padding: .5rem .75rem; border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); background: var(--sfp-gray-50); font-size: .75rem; line-height: 1.125rem; white-space: pre-wrap; color: var(--sfp-gray-900); }
.sfp-latch { display: block; width: 100%; min-height: 2.75rem; margin: 0 0 .75rem; padding: .625rem .75rem; border: 2px solid var(--sfp-blue-800); border-radius: var(--sfp-radius); background: var(--sfp-gray-50); color: var(--sfp-blue-800); font: inherit; font-size: .875rem; font-weight: 600; text-align: left; cursor: pointer; }
.sfp-latch:disabled { cursor: default; }
.sfp-latch[aria-pressed="true"] { background: var(--sfp-blue-800); color: var(--sfp-gray-50); }
.sfp-latch[aria-pressed="false"]:disabled { border-color: var(--sfp-gray-200); color: var(--sfp-gray-400); }
.sfp-latch:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: 2px; }
.sfp-reveal { margin: .75rem 0 0; padding: 1rem; border: 1px solid var(--sfp-blue-800); border-radius: var(--sfp-radius); background: var(--sfp-gray-50); }
.sfp-reveal h3 { margin: 0 0 .25rem; font-size: 1rem; line-height: 1.5rem; color: var(--sfp-blue-800); }
.sfp-reveal p { margin: 0 0 .5rem; font-size: .875rem; line-height: 1.25rem; }
.sfp-reveal-link { font-family: var(--sfp-font-mono, ui-monospace, monospace); font-size: .8125rem; word-break: break-all; user-select: all; }

/* ---- Stacked editor table on a phone (A-28 lane 4, L4-D5 part 6). Below the
   kit's desk breakpoint each row reads top to bottom and is acted on with a
   thumb; the pin's sideways scroll and sticky first cell are off here. ---- */
@media (max-width: 767.98px) {
  .sfp-table-stack, .sfp-table-stack tbody, .sfp-table-stack tr, .sfp-table-stack td { display: block; width: 100%; }
  .sfp-table-stack thead { display: none; }
  .sfp-table-stack tr { padding: .75rem 0; border-bottom: 1px solid var(--sfp-gray-200); }
  .sfp-table-stack td { padding: .125rem 0; border-bottom: 0; white-space: normal; }
  .sfp-table-stack td:first-child { font-weight: 600; padding-bottom: .375rem; }
  .sfp-table-stack td[data-label]:not(:first-child)::before { content: attr(data-label) ": "; color: var(--sfp-gray-600); font-weight: 400; }
  .sfp-table-stack td.sfp-cell-actions::before { content: none; }
  .sfp-table-stack td.sfp-cell-actions { padding-top: .5rem; }
  .sfp-table-pin .sfp-table-stack td:first-child { position: static; box-shadow: none; background: transparent; }
  .sfp-table-stack .sfp-actions { flex-wrap: wrap; margin-top: 0; }
  .sfp-table-stack tr:hover { background: transparent; }
}

/* ---- The carrier and driver families (A-28 lanes 6 and 7, pass L6-1, 1 Oct
   2026; record v0.9 Sections 16-18). Tokens only; this block mints no colour
   and carries no literal. The phone's served-text box shortens so the act
   beneath it stays in the first viewport (C4; the import wizard's notice and
   warranty steps). ---- */
.sfp-actions-stack { flex-direction: column; align-items: stretch; }
.sfp-actions-stack .sfp-btn-primary, .sfp-actions-stack .sfp-btn-secondary { width: 100%; }
.sfp-proposals { margin: 0 0 .5rem; }
.sfp-proposal-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 .75rem; padding: .75rem 0 .25rem; border-top: 1px solid var(--sfp-gray-200); }
.sfp-proposal-row .sfp-field { margin-bottom: .5rem; }
.sfp-proposal-row .sfp-btn-link { grid-column: 1 / -1; justify-self: start; }
.sfp-map-row { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr); gap: .5rem .75rem; align-items: center; padding: .5rem 0; border-top: 1px solid var(--sfp-gray-200); }
.sfp-map-row:first-child { border-top: 0; }
.sfp-map-head { display: flex; flex-direction: column; min-width: 0; }
.sfp-map-head strong, .sfp-map-head .sfp-band-context { margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sfp-map-row .sfp-input { min-height: 2.75rem; }
.sfp-passport { max-width: 24rem; margin: .75rem auto 0; padding: 1rem; border: 1px solid var(--sfp-gray-200); border-radius: var(--sfp-radius); background: var(--sfp-white); text-align: center; }
.sfp-passport-label { margin: 0 0 .75rem; font-size: .75rem; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: var(--sfp-gray-600); }
.sfp-passport-code { margin: .75rem 0 0; font-size: 1.75rem; line-height: 2.25rem; font-weight: 700; color: var(--sfp-blue-800); word-break: break-all; }
.sfp-passport-name { margin: 0 0 .5rem; color: var(--sfp-gray-900); }
.sfp-passport .sfp-actions { justify-content: center; }
.sfp-passport .sfp-reveal { text-align: left; }
.sfp-qr { max-width: 16rem; margin: 0 auto; color: var(--sfp-gray-900); }
.sfp-qr svg { display: block; width: 100%; height: auto; }
.sfp-photo { max-width: 16rem; margin: 0 auto .75rem; }
.sfp-photo img { display: block; width: 100%; border-radius: var(--sfp-radius); margin: 0 0 .5rem; }
.sfp-photo .sfp-btn-secondary { width: 100%; }
.sfp-photo-room { max-width: 28rem; }
.sfp-photo-room > .sfp-btn-primary { margin-top: .75rem; }
.sfp-check-consent { display: flex; align-items: flex-start; min-height: 0; margin: .5rem 0; }
.sfp-check-consent input { margin-top: .125rem; }
.sfp-consent-text { white-space: pre-wrap; line-height: 1.25rem; }
.sfp-carrier > .sfp-carrier-body:first-child { padding-top: .75rem; }
.sfp-carrier > .sfp-carrier-body:first-child > p { margin: 0 0 .25rem; }
.sfp-carrier-name .sfp-chip { margin-left: .25rem; vertical-align: middle; }
.sfp-todo { margin: 0 0 .5rem; padding: 0 .75rem; border: 1px solid var(--sfp-amber); border-left-width: 4px; border-radius: var(--sfp-radius); background: var(--sfp-amber-bg); }
.sfp-todo-title { display: flex; align-items: center; gap: .5rem; min-height: 2.5rem; margin: 0; font-size: .75rem; line-height: 1rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--sfp-amber-fg); cursor: pointer; list-style: none; }
.sfp-todo-title::-webkit-details-marker { display: none; }
.sfp-todo-title::before { content: ""; flex: 0 0 auto; width: .5rem; height: .5rem; margin: 0 .25rem 0 .125rem; border: solid var(--sfp-amber-fg); border-width: 0 2px 2px 0; transform: rotate(-45deg); }
.sfp-todo[open] > .sfp-todo-title::before { transform: rotate(45deg); margin-top: -.25rem; }
.sfp-todo-title:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: 2px; }
.sfp-todo-count { font-variant-numeric: tabular-nums; }
.sfp-todo ul { list-style: none; margin: 0 0 .375rem; padding: 0; }
.sfp-todo li a { display: flex; align-items: center; min-height: 2.25rem; color: var(--sfp-blue-800); font-size: .875rem; line-height: 1.25rem; font-weight: 600; text-decoration: underline; }
.sfp-todo li a:focus-visible { outline: 2px solid var(--sfp-blue-800); outline-offset: 2px; }
@media (min-width: 768px) {
  .sfp-todo-title { min-height: 2rem; }
  .sfp-todo ul { display: flex; flex-wrap: wrap; gap: 0 1.5rem; margin-bottom: .25rem; }
  .sfp-todo li a { min-height: 2rem; }
}
@media (max-width: 767.98px) {
  .sfp-served { max-height: 9rem; }
  .sfp-proposal-row, .sfp-map-row { grid-template-columns: minmax(0, 1fr); }
  .sfp-map-row { gap: .375rem; }
  .sfp-actions-pin { position: sticky; bottom: 0; z-index: 1; margin-top: .75rem; padding: .75rem 0; background: var(--sfp-white); border-top: 1px solid var(--sfp-gray-200); }
  .sfp-passport { padding: .75rem; }
}

/* ---- L6-1a (the lanes 6+7 walk rider, 2 Oct 2026): the fixed SFPD- prefix
   beside a six-digit field. Tokens only. ---- */
.sfp-code-field { display: flex; align-items: stretch; }
.sfp-code-prefix { display: inline-flex; align-items: center; padding: 0 .625rem; border: 1px solid var(--sfp-gray-200); border-right: 0; border-radius: .375rem 0 0 .375rem; background: var(--sfp-gray-100); color: var(--sfp-gray-600); font-family: var(--sfp-font-mono); font-size: .9375rem; white-space: nowrap; }
.sfp-code-field .sfp-input { border-radius: 0 .375rem .375rem 0; flex: 1 1 auto; min-width: 0; }

/* ---- L6-D2 (A-28 lane D, 2 Oct 2026): the send ceremony's per-driver rows, the
   checkbox column of the Invitations table, the results list. Tokens only. ---- */
.sfp-send-rows { display: grid; gap: .5rem; margin: 0 0 .75rem; }
.sfp-send-row { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 1rem; padding: .625rem .75rem; border: 1px solid var(--sfp-gray-200); border-radius: .375rem; background: var(--sfp-gray-50); }
.sfp-send-head { flex: 1 1 100%; display: flex; flex-wrap: wrap; align-items: baseline; gap: .25rem .5rem; }
.sfp-send-code { color: var(--sfp-gray-600); font-size: .875rem; }
.sfp-check-inline { min-height: 2.25rem; }
.sfp-cell-check { width: 2.5rem; }
.sfp-cell-check input { width: 1.125rem; height: 1.125rem; margin: 0; accent-color: var(--sfp-blue-800); }
.sfp-send-results { margin: .5rem 0 0; padding-left: 1.25rem; }
.sfp-send-results li { margin: .25rem 0; }
@media (min-width: 768px) {
  .sfp-send-head { flex: 1 1 24rem; }
}

/* ---- D-D10 (A-28 lane D, 3 Oct 2026): the import wizard's step strip. One bar
   and one name per step; names are content-sized so six fit a 360px phone.
   Tokens only. ---- */
.sfp-steps { display: flex; justify-content: space-between; gap: .5rem; margin: 0 0 .75rem; padding: 0; list-style: none; }
.sfp-step { flex: 0 1 auto; min-width: 0; padding-top: .375rem; border-top: 4px solid var(--sfp-gray-200); color: var(--sfp-gray-600); font-size: .75rem; line-height: 1rem; }
.sfp-step-done { border-top-color: var(--sfp-blue-300); }
.sfp-step-now { border-top-color: var(--sfp-blue-800); color: var(--sfp-gray-900); font-weight: 700; }
