/* ============================================================================
   room-stewards-compass.css — the interior of the Dashboard Room.

   furnishing-vessel-interiors S5 (DT authoring). Presentation only.
   Spec: docs/room-specs/10-dashboard.md — committed before this file.
   Pattern: the S2-accepted pair (room-librarians-desk / room-lineage-dial),
   as re-applied at S3 (room-discovery-lens / room-practice-board).

   ── THE SEAM ───────────────────────────────────────────────────────────────
   buildWindow() stamps `.ffrw-shell.ffrw-vessel.ffrw-dashboard`; the view-room
   factory reparents `#view-family-dashboard` into `.ffrw-body` with
   `.ffrw-hosted`. Everything below rides

       .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted

   so the flat App-Panel view and mobile are untouched by construction, and
   the single-step revert is this file plus its one <link>.

   ⛔ THE SEAM IS ALSO THE FIREWALL AGAINST ADMIN. `.admin-header`,
   `.admin-card*` and `.admin-badge` are SHARED with `#view-admin`. Every rule
   here is confined to the Dashboard shell. Admin remains un-admitted and its
   six inline #374151 sites are S9/S10's, untouched here.

   ── NO CHROME CUSTODY (unlike Stories/Training) ────────────────────────────
   ffa-launcher-design-manifest.json carries `chrome: null` for `dashboard`,
   so `.ffvl-chromed-header` never applies and no --ffvc-header-* value
   exists. This is the FN/Explore case: the Room CSS takes the header band
   whole — which is also why the indigo gradient survived to baseline.

   ── WHAT THIS FILE MAY NOT DO ──────────────────────────────────────────────
   No handler, no label, no route, no truthful string, no bang-important, no
   second scroll owner (#view-family-dashboard is the one, and this Room has
   no nested scroller at all). Progress-fill WIDTHS are renderer custody —
   truthful computed percentages — and are untouched. No figure is added,
   moved or reformatted.

   WITHHELD (spec §6): the Fergi aperture, and every census behavioral
   finding (BR-04/77/78/79/80/81/82/83/84/85/86) — code and backend defects,
   not dress. Zero markup and zero handlers change here.

   ⚠️ This Room has ZERO interactive controls in every state. Nothing below
   may make a card look pressable; the cards are dials, not actions, which is
   why they take elevation on hover but never translate (D1 §3.7 reserves
   translateY(-1px) for interactive cards).
   ============================================================================ */

/* ── The well ─────────────────────────────────────────────────────────────
   #view-family-dashboard is the scroll owner. Gutters + scroll padding so the
   first and last cards are reachable, not merely painted (D1 §1.3, §8.2). */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted {
  --sc-gutter: 20px;
  --sc-ink: var(--ffvr-ink, #F2FCF9);
  --sc-ink-muted: var(--ffvr-ink-muted, #C0C9C7);
  --sc-rule: color-mix(in srgb, var(--ffvr-rule, #4AA598) 32%, transparent);
  --sc-rule-strong: color-mix(in srgb, var(--ffvr-rule, #4AA598) 58%, transparent);
  --sc-plane: var(--ffvr-surface-raised, #27302F);
  --sc-accent: var(--ffvr-accent, #DA9C37);

  padding: 0 var(--sc-gutter) 24px;
  scroll-padding-block-start: 16px;
  scroll-padding-block-end: 24px;
  color: var(--sc-ink);
}

/* ── One hierarchy: the chassis title is the title ─────────────────────────
   The vessel header already says `Dashboard / STEWARD'S COMPASS`. The hosted
   view repeats it verbatim as `<h2>Dashboard</h2>`. VISUALLY RETIRED, NOT
   REMOVED (D1 §2.2 outcome 2): heading node, order and outline survive for
   AT; only the pixels go. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-header-content h2 {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── The rail (D1 §1.3 rule 4, §2.3) ──────────────────────────────────────
   `.admin-header` is the Room's one loud foreigner: a 135deg #667eea→#764ba2
   gradient with white ink and a 12px radius — a separate product's masthead
   floating inside the vessel. With no chrome custody this file owns the band
   outright: the gradient dissolves to the ground, the radius goes, the band
   bleeds to the ground's left and right edges, and one 1px verdigris rule
   carries the separation. No border, no shadow, no second identity. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-header {
  display: flex;
  align-items: center;
  min-height: 52px;
  margin: 0 calc(-1 * var(--sc-gutter)) 24px;
  padding: 8px var(--sc-gutter);
  background: transparent;
  background-image: none;
  color: var(--sc-ink);
  border-radius: 0;
  border-bottom: 1px solid var(--sc-rule);
  box-shadow: none;
}

/* The truthful subtitle becomes the context slot in the eyebrow register — it
   says what the compass reads without repeating the Room name. Copy is the
   renderer's; only the register is ours. Opacity 0.9 is replaced by an opaque
   muted ink: D1 §3.4 forbids an opacity that lowers a text role's contrast. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-header-content p {
  margin: 0;
  font-size: 11px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sc-ink-muted);
  opacity: 1;
}

/* ── The instrument face (D1 §4.2 standard density) ───────────────────────
   `.admin-grid` has NO CSS anywhere in the app tree, so the four cards stack
   as adjacent block boxes with no gap — and the two inline
   `grid-column: 1 / -1` declarations in the markup have never rendered.
   Supplying the grid makes an existing AUTHORED intent real; it invents
   nothing. DOM order and focus order are unchanged: a two-column grid flows
   left-to-right, row by row, which is DOM order. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
  align-items: start;
}

/* At the Room's 640px supported minimum the two columns would crush the stat
   grid; one column is the D1 §8.3 step-3 reflow (multi-column reduces
   columns) and nothing hides. */
@media (max-width: 820px) {
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-grid {
    grid-template-columns: 1fr;
  }
}

/* ── The dials (D1 §5.4, §6.1) ────────────────────────────────────────────
   Already raised + rule-bordered + radius 12 by token; they join the plate
   grammar with the inset highlight, and their existing hover shadow becomes
   the Room's elevation-1. They do NOT translate — see the header note. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-card {
  background: var(--sc-plane);
  border: 1px solid var(--sc-rule);
  border-radius: 12px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .045);
  transition: border-color 150ms, box-shadow 150ms;
}

.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-card:hover {
  border-color: var(--sc-rule-strong);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .045), 0 6px 18px rgba(0, 0, 0, .24);
}

/* The card cap carried `background: var(--ffvr-surface)` — the GROUND colour
   inside a raised card, which reads as an unexplained recessed strip. D1 §1.4
   forbids a perimeter around "a header plus all content below it": the
   separation is a rule, not a filled band. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-card-header {
  background: transparent;
  border-bottom: 1px solid var(--sc-rule);
}

.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-card-header h3 {
  font-family: var(--font-heading, "Playfair Display", Georgia, serif);
  font-size: 18px;
  line-height: 24px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--sc-ink);
}

/* ── Badges: existing truthful labels, presented (D1 §3.5 pill) ───────────
   `.admin-badge` has NO CSS anywhere in the app tree, so "Read-Only" and
   "Current" render as undifferentiated inline words. This presents two
   labels that already exist; it adds neither. The renderer's inline
   font-size on the "Current" badge outranks this file — harmless, left be. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-badge {
  display: inline-block;
  padding: 2px 10px;
  border: 1px solid var(--sc-rule);
  border-radius: 999px;
  font-size: 11px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sc-ink-muted);
  white-space: nowrap;
}

/* ── The cells (D1 §6.1: structural divisions are 1px --ffvi-divider) ─────
   Stat tiles already sit on the ground colour inside a raised card, so they
   are recessed by construction. The 1px rule makes them read as etched
   instrument cells rather than floating gray blocks. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-stat,
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-enrichment-stat {
  border: 1px solid var(--sc-rule);
}

/* A reading on an instrument is a figure, and figures align. Tabular numerals
   only — the value itself is renderer truth (D1 §4.3 explicitly does not
   authorize adding a metric, and none is added). */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-stat-value {
  font-variant-numeric: tabular-nums;
}

.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-progress-pct {
  font-variant-numeric: tabular-nums;
}

/* Brass is reserved for the one thing in this Room that actually moves. The
   track and fill are already token-driven; only the rhythm is ours, and the
   WIDTH is never touched. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-progress-label {
  color: var(--sc-ink);
}

/* ── Docket rows (D1 §1.5 default separation) ─────────────────────────────
   Already divider-ruled; the rule becomes the Room's verdigris. Heights are
   deliberately NOT raised to D1 §4.4's 52px minimum — ten activity rows plus
   five session rows would add ~400px and push the Room into overflow at its
   640×480 supported minimum, trading a spacing rule for a reachability
   regression. Deviation declared in spec §6.4, not applied silently. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-session-row,
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-activity-row {
  border-bottom-color: var(--sc-rule);
}

.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-activity-action {
  color: var(--sc-ink);
}

/* ── Loading, empty and error (D1 §7.1, §7.2) ─────────────────────────────
   `.loading-state` and `.text-muted` have NO CSS anywhere in the app tree, so
   every one of these blocks renders in plain ink today. Muted is the truthful
   register. ALL COPY UNTOUCHED — including the three "Unable to load …"
   strings, which are deliberately NOT given danger paint: census BR-81
   records them as terminal text with no retry, and painting a dead end as an
   alert would dress a defect as a feature. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .loading-state {
  padding: 16px 0;
  text-align: center;
  color: var(--sc-ink-muted);
}

.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .text-muted {
  color: var(--sc-ink-muted);
}

/* The spinner's track joins the Room so it stops being a stranger's blue.
   Geometry and animation are the chassis's; only the colour is ours. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .loading-spinner {
  border-color: var(--sc-rule);
  border-top-color: var(--sc-accent);
}

/* ── Focus is the universal treatment (D1 §3.6) ───────────────────────────
   ⚠️ This Room has ZERO focusable controls in every state today — it is
   read-only, truthfully so. The rule is authored anyway so it engages the
   moment census BR-86 (stat figures become links) or any other control
   lands, rather than shipping a Room whose first control has no focus ring. */
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted a:focus-visible,
.ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted button:focus-visible {
  outline: 3px solid #FFFFFF;
  outline-offset: 2px;
  box-shadow: 0 0 0 1px #000000;
}

/* ── Reduced motion (the floor plus the list — pilot pattern) ─────────────*/
@media (prefers-reduced-motion: reduce) {
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted,
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted * {
    transition: none;
  }

  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-card,
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-progress-fill {
    transition: none;
  }

  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .loading-spinner {
    animation: none;
  }
}

/* ── Forced colours ───────────────────────────────────────────────────────
   Restore system borders so the dials, cells and badges keep their shapes;
   the progress fill keeps a visible mark rather than dissolving into the
   track; essential text never sits under an opacity (the pilots' masthead
   trap). */
@media (forced-colors: active) {
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-card,
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-stat,
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-enrichment-stat,
  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-badge {
    border: 1px solid ButtonBorder;
  }

  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-progress-bar {
    border: 1px solid ButtonBorder;
  }

  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .dashboard-progress-fill {
    background: Highlight;
  }

  .ffrw-dashboard .ffrw-body > #view-family-dashboard.ffrw-hosted .admin-header-content p {
    opacity: 1;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE V14 CHASSIS DRESS — porting-perimeter-souls S5 (designed at S4)

   Everything below this line is reached ONLY through `html.ffv-modal-fleet-v14`.
   With the flag off not one selector here matches, and the room renders exactly
   as the lines above render it. The SHELL half needs the flag class because
   `.ffvc-rim-glow`, `.ffvc-body` and `.ffvc-lip` are drawn by room-windows.css
   in BOTH states; an unconditioned override would break the byte-identity that
   makes this flag a rollback path.

   ── WHAT THE PORT TOUCHES, AND WHAT IT DOES NOT ─────────────────────────
   Nothing below reaches the Dashboard's cards, stats, progress bars, badges or
   counts, and nothing below crosses THE SEAM'S FIREWALL AGAINST ADMIN — no
   selector here names `.admin-header`, `.admin-card*` or `.admin-badge`, which
   this room shares with `#view-admin`. Every rule is scoped
   `html.ffv-modal-fleet-v14 .ffrw-dashboard`, which cannot reach the flat App
   Panel, mobile, or another room's chassis.

   The port's only geometry is VERTICAL, through the theme's own DERIVED
   keep-outs (140 / 101, from 85 / 63) — and every unit of that raise is the
   SHELL: the lip alone asks 140 / 101 before any furniture is placed, and after
   all three aperture directives the derived numbers are unchanged. The
   decoration costs the workspace nothing. No horizontal inset moves; the
   overview keeps its width.

   Widths are the lab's times the geometric mean sqrt(0.625 * 0.7) = 0.6614.
   ═══════════════════════════════════════════════════════════════════════════ */

html.ffv-modal-fleet-v14 .ffrw-dashboard {
  --v14-sky:   #55b8ff;   /* the lab's --room-a     */
  --v14-jade:  #4fd1a1;   /* the lab's --room-b     */
  --v14-amber: #f2b84b;   /* the lab's --room-c     */
  --v14-metal: #ef3fa5;   /* the lab's --room-metal */
}

html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-rim-glow { stroke-width: 6.61; opacity: .24; }   /* lab 10  x 0.6614 */
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-body     { stroke-width: 2.65; }                 /* lab 4   x 0.6614 */
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-lip      { stroke: rgba(220, 246, 255, .45); stroke-width: .99; opacity: 1; }  /* lab 1.5 x 0.6614 */

html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-steward path,
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-tablework path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* the head: the two quadrant swags that clear the overview entirely */
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-quadrant {
  stroke: color-mix(in srgb, var(--v14-sky) 58%, transparent);
  stroke-width: 1.46;                                                                           /* lab 2.2 x 0.6614 */
}

/* the compass rose, seated on the north lancet (sunk 7.2 — see the theme) */
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-hero-ring { fill: rgba(4, 15, 26, .96); stroke-width: 1.46; }  /* lab 2.2 x 0.6614 */
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-hero-fill {
  stroke: color-mix(in srgb, var(--v14-metal) 65%, #ffffff 10%);
  stroke-width: .66;                                                                            /* lab 1   x 0.6614 */
}
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-node {
  fill: #06131e;
  stroke: var(--v14-metal);
  stroke-width: 1.32;                                                                           /* lab 2   x 0.6614 */
}

/* the foot: the table's cross-banding, its one carried inlay, and the bearing
   medallion the card is measured from */
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-inlay,
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-table-band {
  stroke: var(--v14-metal);
  stroke-width: 1.98;                                                                           /* lab 3   x 0.6614 */
}
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-bearing-medallion {
  fill: #0a191b;
  stroke-width: 1.98;                                                                           /* lab 3   x 0.6614 */
}
html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-bearing-needle {
  fill: var(--v14-metal);
  stroke: var(--v14-jade);
  stroke-width: .99;                                                                            /* lab 1.5 x 0.6614 */
}

/* ── motion: PAINT CARRIES, GEOMETRY DOES NOT (HELPER_CONTRACT §6b) ────────
   The lab gives this room a COMPOUND keyframe, and it is SPLIT — the second
   instance in this train after Browse Media's `scan-breathe`, and the reason
   §6b exists. `compass-settle` is

       from { transform: rotate(-18deg); opacity: .45; } to { transform: rotate(0); opacity: 1; }

   The opacity half is paint and is carried verbatim. The ROTATE half is
   refused: a transform moves rendered ink while leaving the geometry both
   capture gates measure untouched, so a turning crest would sweep the head
   band and BOTH gates would report the room clean, at every geometry, forever.
   The lab's own transform-origin (800px 82px) is its viewBox centre-of-crest;
   under an 18-degree turn the ring's outboard edge travels roughly eleven units
   here, which is more than this crown's 3.5-unit clearance can absorb — so the
   refusal is not merely procedural, the swept ink would leave the shell.

   `node-breathe` cycles the pin's OPACITY and is carried. Nothing else in this
   room moves: `.quadrant`, `.inlay`, `.table-band`, `.bearing-medallion` and
   `.bearing-needle` appear nowhere in the lab's
   `prefers-reduced-motion: no-preference` block, and a steward's marks holding
   still is the room's own reading — which is also why its motes pulse in place
   rather than drift.
   ───────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-hero {
    animation: ffvc-v14-compass-settle 2.2s ease-out both;
  }
  html.ffv-modal-fleet-v14 .ffrw-dashboard .ffvc-v14-node {
    animation: ffvc-v14-compass-pin-breathe 5.4s ease-in-out infinite;
  }
}
@keyframes ffvc-v14-compass-settle { from { opacity: .45; } to { opacity: 1; } }
/* The lab's `node-breathe`, carried under a room-owned name. Training already
   ships a `ffvc-v14-node-breathe` with the identical body, and reusing that
   name would make this room's motion depend on ANOTHER room's stylesheet being
   present — true in the vault, false in capture-gates.cjs, which loads exactly
   one interior sheet. A gate that cannot see an animation cannot rule on it. */
@keyframes ffvc-v14-compass-pin-breathe { 0%, 100% { opacity: .4; } 50% { opacity: 1; } }
