/*
 * css/hub.css — Rackulate Hub.
 * -----------------------------------------------------------------------
 * HUB REDESIGN / DE-CLUTTER PASS: the Hub is a fast project launcher and
 * recent-work surface, not a SaaS dashboard. This rewrite keeps the same
 * .app-sidebar/.app-shell-main/.app-topbar shell every workspace page
 * uses, and the same three-column composition inside it (project browser
 * / selected-project preview / info rail), but restyles every zone to:
 *
 *   - use a real, restrained surface ladder (--bg page base -> --bg-
 *     elevated functional panels -> --bg-elevated-2 interactive/nested
 *     controls -> --bg-sunken recessed/quiet zones) instead of nested
 *     cards-on-cards with decorative borders everywhere;
 *   - treat cyan (--accent) as a SIGNAL only — primary action, selection,
 *     focus, active state — not a default border/glow on every box;
 *   - make the project list dense and scannable at 20-50+ rows, with a
 *     real editable status control per row (js/hub.js's
 *     projectRowHtml()/wireProjectRow() — a native <select>, changes the
 *     registry directly, never opens the project);
 *   - demote workflow progress and the module launcher from "monitoring
 *     dashboard" styling to compact, quiet secondary elements.
 *
 * No calculation, no persistence, no new data source — this file only
 * changes how things look and lay out. Every id/class js/hub.js queries
 * matches this file (see that file's own header for what each is fed
 * from). Mobile-first: rules target phone width by default; min-width
 * queries add the tablet/desktop layout. Touch targets stay >=44px on
 * anything actionable outside the deliberately dense project rows
 * (~36-40px there, matching engineering-software row density), editing/
 * navigation/selection stay separate actions (a row click selects — see
 * js/hub.js — only Continue Project or a module tile navigates), and
 * every status signal pairs a text label with colour, never colour alone.
 */

.hub-body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--font-sans); }

.hub-main { padding: var(--space-4); }

/* =======================================================================
   Index read error — a genuinely corrupted saved project index, distinct
   from the "no projects yet" empty state below (see js/hub.js's
   renderIndexErrorBanner()). Danger, not warn: this means real saved
   project data may be unreadable, not just "nothing recorded yet".
   ===================================================================== */
.hub-index-error {
  display: flex; align-items: flex-start; gap: var(--space-3);
  margin-bottom: var(--space-5); padding: var(--space-4);
  background: var(--danger-soft); border: 1px solid var(--danger-line); border-radius: var(--radius-md);
  color: var(--text);
}
.hub-index-error .icon { width: 18px; height: 18px; flex: none; color: var(--danger); margin-top: 1px; }
.hub-index-error p { margin: 0; font-size: 13px; line-height: 1.5; }

/* =======================================================================
   Empty state — a genuinely first-ever visit only (see js/hub.js).
   ===================================================================== */
.hub-empty {
  padding: var(--space-8) 0 var(--space-7);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-7);
}
.hub-empty-inner { display: flex; flex-direction: column; gap: var(--space-7); }
.hub-empty-eyebrow {
  font-family: var(--font-mono); font-size: 0.78em; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent);
  margin: 0 0 var(--space-3);
}
.hub-empty h1 {
  font-family: var(--font-display); font-size: clamp(1.6em, 4vw, 2.3em);
  font-weight: 700; line-height: 1.15; margin: 0 0 var(--space-4); letter-spacing: -0.01em;
}
.hub-empty-lede { color: var(--text-muted); font-size: 0.98em; max-width: 52ch; margin: 0 0 var(--space-6); line-height: 1.65; }
.hub-empty-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.hub-empty-actions .btn { min-height: 46px; }
.hub-empty-chain { list-style: none; margin: 0; padding: var(--space-5) 0 0; display: flex; flex-direction: column; gap: var(--space-3); border-top: 1px solid var(--border); }
.hub-empty-chain li {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-mono); font-size: 0.82em; font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-muted);
}
.hub-empty-chain-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); flex: none; }
@media (min-width: 760px) {
  .hub-empty-inner { flex-direction: row; align-items: flex-start; justify-content: space-between; gap: var(--space-9); }
  .hub-empty-copy { flex: 1 1 auto; max-width: 640px; }
  .hub-empty-chain { flex: none; width: 220px; border-top: none; padding-top: var(--space-2); }
}

/* =======================================================================
   GLOBAL HOME WORKSPACE — GLOBAL HOME / PROJECT HUB SPLIT: a single
   restrained column (Continue Working -> Needs Attention -> Live on Site
   -> Project Navigator), not the old browser/dashboard/rail three-up
   grid — that per-project intelligence all moved to project-hub.html's
   own layout (below). Section spacing is a little more generous than the
   dense project rows inside them, matching the brief's "keep this page
   restrained" instruction.
   ===================================================================== */
.hub-workspace { display: flex; flex-direction: column; gap: var(--space-6); }
.hub-section-title {
  font-family: var(--font-display); font-size: 12.5px; margin: 0 0 var(--space-3);
  color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em;
}

/* ---- Continue Working ----
   The single strongest, most specific call-to-action on Home — one real
   project + module, not a generic "resume" button. Quiet cyan accent
   (this IS the primary interaction on the page), no illustration/photo. */
.hub-continue-card {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: var(--bg-elevated); border: 1px solid var(--accent-line); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  box-shadow: 0 0 0 1px rgba(43, 182, 255, 0.05), var(--shadow-md);
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.hub-continue-card:hover, .hub-continue-card:focus-visible { border-color: var(--accent); background: var(--bg-elevated-2); }
.hub-continue-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hub-continue-id { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.hub-continue-id b { font-family: var(--font-display); font-size: 17px; font-weight: 800; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-continue-id em { font-style: normal; font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--accent); text-transform: uppercase; letter-spacing: 0.03em; }
.hub-continue-meta { display: flex; align-items: center; gap: var(--space-4); flex: none; }
.hub-continue-meta > span:first-child { font-size: 11px; color: var(--text-faint); white-space: nowrap; }
.hub-continue-cta { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; font-size: 13px; color: var(--accent); white-space: nowrap; }
.hub-continue-cta .icon { width: 14px; height: 14px; }

/* ---- Needs Attention (global) ----
   A flat list of Project / Issue rows, each its own click target — never
   a card grid. Severity drives a small left tick only (text still
   carries the real reason), same restrained language as Project Hub's
   own Problems panel and the old per-project attention strip. */
.hub-attention-global-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg-elevated); overflow: hidden; }
.hub-attention-global-item {
  position: relative; display: flex; align-items: center; gap: var(--space-3);
  padding: 11px var(--space-4) 11px 18px; border-top: 1px solid var(--border);
  cursor: pointer; font-size: 12.5px; color: var(--text-muted);
  transition: background var(--duration-fast) var(--ease-out);
}
.hub-attention-global-item:first-child { border-top: none; }
.hub-attention-global-item:hover, .hub-attention-global-item:focus-visible { background: var(--bg-elevated-2); color: var(--text); }
.hub-attention-global-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-attention-global-item::before {
  content: ''; position: absolute; left: 0; top: 4px; bottom: 4px; width: 3px; border-radius: 2px;
  background: var(--warn);
}
.hub-attention-global-item[data-severity="critical"]::before { background: var(--danger, #e5484d); }
.hub-attention-global-project { flex: none; max-width: 34%; font-weight: 700; color: var(--text); font-family: var(--font-display); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-attention-global-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-attention-global-arrow { flex: none; width: 12px; height: 12px; color: var(--text-faint); }
.hub-attention-global-item:hover .hub-attention-global-arrow { color: var(--accent); }

/* ---- Live on Site ----
   Compact rows, one per Active project with real Job Tracker data —
   real figures only (progress/bays/blockers/target), no "on track"
   wording that isn't genuinely calculated anywhere. */
.hub-live-site-list { display: flex; flex-direction: column; gap: var(--space-2); }
.hub-live-site-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.hub-live-site-row:hover, .hub-live-site-row:focus-visible { border-color: var(--accent-line); background: var(--bg-elevated-2); }
.hub-live-site-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-live-site-name { font-family: var(--font-display); font-size: 13px; font-weight: 700; color: var(--text); flex: 1 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-live-site-figures { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.hub-live-site-figure { display: flex; flex-direction: column; gap: 1px; min-width: 56px; }
.hub-live-site-figure em { font-style: normal; font-size: 8.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; }
.hub-live-site-figure b { font-family: var(--font-mono); font-size: 13px; font-weight: 800; color: var(--text); }
.hub-live-site-figure.is-attention b { color: var(--warn); }

/* ---- project browser ----
   One functional panel at --bg-elevated (step 2 of the ladder). Its own
   interactive controls (search, tabs, selects, rows) sit one step up at
   --bg-elevated-2 so the panel itself reads as a single area rather than
   a stack of bordered cards. */
.hub-browser {
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-lg);
  overflow: hidden;
}
.hub-browser-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-3); }

/* HUB PROJECT SEARCH + SCALABLE PROJECT NAVIGATION PASS: this was
   .hub-projects-search, the small search box that used to live inside the
   project browser head. It has moved to a new full-width bar directly
   below the Hub topbar (#hubSearchBar in hub.html) so there is a single,
   wide, global project search field instead of a cramped in-panel one.
   Same visual language (dark input-on-elevated-surface, accent focus
   ring), just renamed and given room to breathe. */
.hub-search-bar {
  display: flex; align-items: stretch; gap: var(--space-2);
  padding: var(--space-4) var(--space-4) 0;
}
.hub-search-field {
  flex: 1; display: flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 14px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  color: var(--text-faint); cursor: text;
  transition: border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out);
}
/* Focus glow only appears while the field is actually in use — never a
   permanent state — matching the brief's "precision instrument, not
   gaming PC case" rule for every cyan treatment on the Hub. */
.hub-search-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft), 0 0 18px -8px var(--accent-glow); }
.hub-search-field .icon { width: 16px; height: 16px; flex: none; }
.hub-search-field input {
  flex: 1; min-width: 0; border: none; background: none; outline: none;
  font: inherit; font-size: 14px; color: var(--text);
}
.hub-search-field input::placeholder { color: var(--text-muted); }
.hub-search-bar .btn { flex: none; }
/* New Project — the Hub's strongest CTA. .btn-accent (css/style.css) is
   shared app-wide, so this is a scoped addition, not an override: a
   crisp resting edge on top of the existing gradient, still compact
   (btn-sm in the markup), full glow reserved for hover as everywhere
   else in the app. */
#hubNewProjectBtnTop { box-shadow: 0 0 0 1px rgba(43, 182, 255, 0.3) inset, var(--shadow-sm); }

/* Compact/Comfortable density toggle — purely visual row-sizing
   preference (js/hub.js's wireDensityToggle()), quiet by default so it
   doesn't compete with New/search for attention. */
.hub-density-toggle {
  flex: none; min-height: 40px; padding: 0 10px; cursor: pointer;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--text-faint); background: none; border: 1px solid var(--border); border-radius: var(--radius-sm);
  white-space: nowrap;
}
.hub-density-toggle:hover { color: var(--text-muted); border-color: var(--border-strong); }
.hub-density-toggle[aria-pressed="true"] { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }

/* GLOBAL HOME / PROJECT HUB SPLIT: the project list is now always
   visible — the old mobile collapse-behind-a-toggle mechanic belonged to
   a header that also had to fit a dashboard preview above it; Home's
   Project Navigator is its own full-width section, so there is no
   competing content to save space from any more. */
.hub-browser-body { overflow: visible; }
.hub-browser-body-inner-pad { padding: 0 var(--space-3) var(--space-3); }
.hub-browser-body-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: 0 var(--space-3); margin-top: var(--space-1); }
.hub-browser-body-head h2 { font-family: var(--font-display); font-size: 13.5px; margin: 0; color: var(--text-muted); }
.hub-browser-body-head .btn { min-height: 32px; padding: 0 10px; font-size: 11.5px; }

/* Compact status tabs — the visible filter control; proxies to the
   hidden #hubProjectFilter select (wired in hub.html's inline script).
   Text labels always, never colour alone. Active tab is the one place
   this row uses accent — everything else stays neutral. */
.hub-browser-tabs { display: flex; flex-wrap: wrap; gap: 4px; padding: var(--space-2) var(--space-3) 0; }
.hub-browser-tab {
  flex: 1 1 auto; min-height: 30px; padding: 0 10px;
  background: none; border: 1px solid transparent; border-radius: var(--radius-sm);
  color: var(--text-muted); font: inherit; font-size: 11px; font-weight: 700; cursor: pointer; white-space: nowrap;
  transition: color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.hub-browser-tab:hover { color: var(--text); background: var(--bg-elevated-2); }
.hub-browser-tab.is-active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }

/* The real filter control js/hub.js reads stays in the DOM (so its value/
   change-event wiring is untouched) but is visually replaced by the tabs
   above. */
.hub-projects-select-proxied { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

.hub-browser-filters { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-2) var(--space-3) 0; }
.hub-projects-select {
  flex: 1 1 100px; min-height: 34px; padding: 0 8px;
  background: var(--bg-elevated-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--text); font: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer;
}
.hub-pinned-toggle {
  display: flex; align-items: center; gap: 6px; min-height: 30px; padding: var(--space-2) var(--space-3) 0;
  font-size: 11.5px; font-weight: 600; color: var(--text-muted); cursor: pointer; user-select: none;
}
.hub-pinned-toggle .icon { width: 12px; height: 12px; }
.hub-pinned-toggle input { accent-color: var(--accent); }

/* ---- project list rows ----
   Dense, scannable, one line per project at default (compact) density.
   Each row is the click target for "select" (js/hub.js) — the status
   select and icon actions stop propagation so they never also trigger a
   selection change. No per-row card border/shadow noise: rows are
   separated by a hairline and distinguished on hover/selection by a
   quiet background shift plus, for selection only, a left accent bar —
   the one place a project row uses accent as more than text. */
.hub-project-list { display: flex; flex-direction: column; padding: var(--space-2) var(--space-3) 0; }
/* STRUCTURAL/VISUAL REDESIGN PASS §8: subtle alternating row backgrounds
   so adjacent jobs are easier to tell apart at a glance — deliberately a
   very low-contrast tint (--bg-sunken, already the app's own "recessed"
   surface, not a new colour), so it reads as structure, not stripes.
   Selection/open state (below) still uses a stronger, distinct treatment
   (accent background/left-bar) so alternating shading never doubles as a
   selection signal by itself. */
.hub-project-list > .hub-row:nth-child(even) { background: var(--bg-sunken); }
.hub-project-list > .hub-row.is-selected:nth-child(even) { background: var(--accent-soft); }
.hub-project-list-empty { font-size: 12px; color: var(--text-faint); padding: var(--space-3) var(--space-3) 0; text-align: center; }
.hub-browser-foot { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-3); border-top: 1px solid var(--border); }
.hub-browser-foot .btn { flex: 1 1 auto; min-height: 34px; font-size: 11.5px; }

/* HUB PROJECT SEARCH + SCALABLE PROJECT NAVIGATION PASS: rows moved from
   one packed horizontal line to a 3-line vertical stack (see
   js/hub.js's projectRowHtml()) — this is what actually removes the
   horizontal scrollbar: nothing in a row needs fixed horizontal width
   any more, so the whole thing reflows cleanly at any navigator column
   width, narrow or wide, without hiding any identity field. */
.hub-row {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px 10px; cursor: pointer;
  border-bottom: 1px solid var(--border);
  border-left: 2px solid transparent;
  transition: background var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.hub-project-list > .hub-row:last-child { border-bottom: none; }
.hub-row-lines { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }

/* ---- Job identity colour (HUB DENSE OPERATIONAL LIST PASS) ----
   A per-project identity marker — SEPARATE from status colour (the
   .hub-status-select next to it keeps its own amber/accent/neutral
   language untouched). Deterministic from the project's own permanent id
   (js/hub.js's jobColorIndex()), so it never changes across a reload,
   and always carries the project's initial letter, never colour alone.
   Palette is css/tokens.css's --job-color-1..10, deliberately a
   different hue band from --accent/--warn/--ok/--danger. */
.hub-row-swatch {
  flex: none; width: 26px; height: 26px; margin-top: 1px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  font-family: var(--font-display); font-size: 11px; font-weight: 800;
  color: #fff; text-shadow: 0 1px 1px rgba(0,0,0,0.25);
}
.hub-row-swatch[data-job-color="1"] { background: var(--job-color-1); }
.hub-row-swatch[data-job-color="2"] { background: var(--job-color-2); }
.hub-row-swatch[data-job-color="3"] { background: var(--job-color-3); }
.hub-row-swatch[data-job-color="4"] { background: var(--job-color-4); }
.hub-row-swatch[data-job-color="5"] { background: var(--job-color-5); }
.hub-row-swatch[data-job-color="6"] { background: var(--job-color-6); }
.hub-row-swatch[data-job-color="7"] { background: var(--job-color-7); }
.hub-row-swatch[data-job-color="8"] { background: var(--job-color-8); }
.hub-row-swatch[data-job-color="9"] { background: var(--job-color-9); }
.hub-row-swatch[data-job-color="10"] { background: var(--job-color-10); }

/* Tiny inline version used in Needs Attention / Live on Site so the same
   project reads as "the same job" wherever it's referenced across the
   Hub, without the full lettered chip's weight in an already-compact
   list row. Same data-job-color values, same palette. */
.hub-job-dot { flex: none; width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.hub-job-dot[data-job-color="1"] { background: var(--job-color-1); }
.hub-job-dot[data-job-color="2"] { background: var(--job-color-2); }
.hub-job-dot[data-job-color="3"] { background: var(--job-color-3); }
.hub-job-dot[data-job-color="4"] { background: var(--job-color-4); }
.hub-job-dot[data-job-color="5"] { background: var(--job-color-5); }
.hub-job-dot[data-job-color="6"] { background: var(--job-color-6); }
.hub-job-dot[data-job-color="7"] { background: var(--job-color-7); }
.hub-job-dot[data-job-color="8"] { background: var(--job-color-8); }
.hub-job-dot[data-job-color="9"] { background: var(--job-color-9); }
.hub-job-dot[data-job-color="10"] { background: var(--job-color-10); }

/* ---- Per-row signal badge (HUB DENSE OPERATIONAL LIST PASS) ----
   The same top-priority computeAttentionItems() result Needs Attention
   shows for this project (js/hub.js's rowSignalHtml()) — amber/red never
   alone, always icon + the real reason text. Falls back to a quiet
   informational "Issued Rev N" badge when there's nothing wrong and a
   design has genuinely been issued; shows nothing at all otherwise
   (never an invented "all good" state). */
.hub-row-signal {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  font-size: 10.5px; font-weight: 700; padding: 2px 7px; border-radius: var(--radius-pill);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--warn); background: var(--warn-soft); border: 1px solid var(--warn-line);
}
.hub-row-signal .icon { width: 10px; height: 10px; flex: none; }
.hub-row-signal[data-severity="critical"] { color: var(--danger); background: var(--danger-soft); border-color: var(--danger-line); }
.hub-row-signal.hub-row-signal-issued { color: var(--accent); background: var(--accent-soft); border-color: var(--accent-line); }
.hub-row:hover { background: var(--bg-elevated-2); }
.hub-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Selected row — a restrained cyan outline treatment (edge + faint inset
   ring), noticeably stronger than the plain background-shift hover gets,
   so "which project is selected" is never ambiguous while scanning. */
.hub-row.is-selected {
  background: var(--accent-soft); border-left-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
.hub-row.is-open:not(.is-selected) { border-left-color: var(--accent); }

/* Line 1 — name (strongest text) + status, right-aligned and compact. */
.hub-row-line1 { display: flex; align-items: center; gap: var(--space-2); }
.hub-row-name { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1 1 auto; font-family: var(--font-display); font-size: 12.5px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-row.is-selected .hub-row-name { color: var(--text); font-weight: 800; }
.hub-row-pin { width: 12px; height: 12px; flex: none; color: var(--accent); }
.hub-row-openflag {
  font-family: var(--font-mono); font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--accent); border: 1px solid var(--accent-line); border-radius: var(--radius-pill); padding: 1px 6px; flex: none;
}
.hub-row-archivedflag {
  font-family: var(--font-mono); font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-faint); border: 1px solid var(--border-strong); border-radius: var(--radius-pill); padding: 1px 6px; flex: none;
}

/* Line 2 — customer / site / reference, quiet, wraps rather than clips
   when the navigator column is narrow (brief: no horizontal overflow,
   no clipped text where avoidable) — plus the optional signal badge
   (HUB DENSE OPERATIONAL LIST PASS), which sits after it on the same
   line when there's room and wraps below it otherwise. */
.hub-row-line2 { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.hub-row-sub { flex: 1 1 auto; min-width: 0; font-size: 10.5px; color: var(--text-faint); overflow-wrap: break-word; }

/* Editable status control — a real <select>, quick and obvious but not
   visually loud: no colour fill by default, just a thin border and the
   text value; colour only appears for Active (accent, the one status
   that IS the signal worth highlighting) and On Hold (warn, a real
   semantic flag). Draft/Completed stay neutral text. Compact and
   right-aligned on line 1 — a control, not the visual focus of the row. */
.hub-status-select {
  flex: none; max-width: 92px; min-height: 24px; padding: 0 5px;
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em;
  background: var(--bg-elevated-2); color: var(--text-muted); border: 1px solid var(--border); border-radius: var(--radius-sm);
  cursor: pointer;
}
.hub-status-select:hover { border-color: var(--border-strong); }
.hub-status-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.hub-status-select[data-status="Active"] { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.hub-status-select[data-status="On Hold"] { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }

/* Line 3 — quiet metadata (last opened/modified) + pin + overflow menu. */
.hub-row-line3 { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.hub-row-when { min-width: 0; font-size: 10px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* CORE HARDENING PASS §4: transient "Copying attachments..." hint while
   a just-duplicated project's RAMS blobs are still being written to
   IndexedDB — same faint/quiet treatment as the timestamp it follows,
   just accent-coloured so it reads as active/in-progress rather than
   idle metadata. */
.hub-row-syncing { color: var(--accent); font-weight: 600; }

.hub-row-actions { flex: none; display: flex; align-items: center; gap: 2px; position: relative; }
/* SUPER-PROMPT §3: explicit, discoverable Open action — the touch/
   accessible equivalent of "second tap on a selected row" or a desktop
   double-click. Quiet by default; only surfaces on hover/focus of the
   row (desktop affordance) or once the row is actually selected (so a
   first tap on touch always reveals it, satisfying "second tap opens"
   without relying on double-tap gesture detection). */
.hub-row-open-btn {
  display: none; align-items: center; justify-content: center;
  height: 22px; padding: 0 8px; flex: none;
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--accent); background: var(--accent-soft); border: 1px solid var(--accent-line); border-radius: var(--radius-sm);
  cursor: pointer;
}
.hub-row-open-btn:hover { background: var(--accent-line); }
.hub-row:hover .hub-row-open-btn,
.hub-row:focus-within .hub-row-open-btn,
.hub-row-open-btn.is-visible {
  display: inline-flex;
}
.hub-row-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; flex: none;
  background: none; border: none; color: var(--text-faint); border-radius: var(--radius-sm);
  cursor: pointer; transition: color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.hub-row-icon-btn .icon { width: 12px; height: 12px; }
.hub-row-icon-btn:hover { color: var(--text); background: var(--bg-elevated); }
.hub-row-icon-btn[data-pinned="true"] { color: var(--accent); }

/* Overflow ("more actions") menu — Duplicate/Export/Archive/Delete live
   here instead of as four more icon buttons on the row (brief: "stop
   fitting every action across the row"). A floating popover, not a
   modal — consistent with the app's "avoid modal pop-ups, prefer
   floating inspectors/contextual controls" convention. Menu-open state
   is tracked in js/hub.js (openRowMenuId) so it survives the list's
   full re-render. */
.hub-row-menu { position: relative; flex: none; }
.hub-row-menu-popover {
  display: none;
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
  min-width: 158px; padding: 4px;
  background: var(--bg-elevated-2); border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg, 0 8px 24px rgba(0,0,0,0.35));
}
.hub-row-menu-popover.is-open { display: flex; flex-direction: column; gap: 1px; }
.hub-row-menu-item {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 7px 8px; border-radius: var(--radius-sm);
  background: none; border: none; color: var(--text); font: inherit; font-size: 11.5px; font-weight: 600; text-align: left;
  cursor: pointer; white-space: nowrap;
}
.hub-row-menu-item .icon { width: 13px; height: 13px; flex: none; color: var(--text-faint); }
.hub-row-menu-item:hover { background: var(--bg-elevated); }
.hub-row-menu-item.is-destructive { color: var(--danger); }
.hub-row-menu-item.is-destructive .icon { color: var(--danger); }
.hub-row-menu-item.is-destructive:hover { background: var(--danger-soft, rgba(220,38,38,0.12)); }

/* Comfortable density — a taller row for anyone who wants more breathing
   room; still no card borders, just larger padding/type. */
#hubWorkspace[data-density="comfortable"] .hub-row { padding: 12px 12px; }
#hubWorkspace[data-density="comfortable"] .hub-row-lines { gap: 5px; }
#hubWorkspace[data-density="comfortable"] .hub-row-swatch { width: 30px; height: 30px; font-size: 12px; }
#hubWorkspace[data-density="comfortable"] .hub-row-name { font-size: 13.5px; }
#hubWorkspace[data-density="comfortable"] .hub-row-sub { font-size: 11.5px; }
#hubWorkspace[data-density="comfortable"] .hub-status-select { min-height: 28px; max-width: 104px; font-size: 10px; }
#hubWorkspace[data-density="comfortable"] .hub-row-when { font-size: 10.5px; }
#hubWorkspace[data-density="comfortable"] .hub-row-icon-btn { width: 28px; height: 28px; }

/* =======================================================================
   SELECTED-PROJECT PREVIEW — one functional panel (--bg-elevated). Kept
   deliberately quiet: selecting a project in the browser only ever
   updates this panel in place (js/hub.js's computeDashboard()); it never
   navigates. Continue Project or a module tile is the only way in.
   ===================================================================== */
.hub-dashboard {
  position: relative;
  display: flex; flex-direction: column; gap: var(--space-4);
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  /* PREMIUM VISUAL POLISH PASS: this is the Hub's command centre — the one
     panel that should always read as "the important one". A restrained
     cyan top+left edge (via ::before, not a full glowing border) plus a
     faint outer glow give it just enough presence to anchor the layout
     without the whole panel turning cyan. */
  box-shadow: 0 0 0 1px rgba(43, 182, 255, 0.05), var(--shadow-md);
  overflow: hidden;
}
.hub-dashboard::before {
  content: ''; position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;
  width: 100%; height: 2px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-soft) 38%, transparent 78%);
  opacity: 0.85;
}
.hub-dashboard::after {
  content: ''; position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;
  width: 2px; height: 100%;
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-soft) 30%, transparent 65%);
  opacity: 0.7;
}

/* top summary — identity + status + last-opened + Continue, one row. No
   decorative thumbnail (removed — nothing real to show there). */
.hub-dash-summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); }
.hub-dash-summary-id { min-width: 0; flex: 1 1 220px; }
.hub-dash-summary-id h2 { font-family: var(--font-display); font-size: 21px; font-weight: 800; letter-spacing: -0.01em; margin: 0 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-dash-summary-id p { margin: 0; font-size: 11.5px; color: var(--text-faint); font-family: var(--font-mono); letter-spacing: 0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-dash-summary-state { display: flex; align-items: center; gap: var(--space-4); flex: none; }
.hub-dash-status-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; padding: 5px 12px 5px 10px; }
.hub-dash-status-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.hub-dash-last-opened { display: flex; flex-direction: column; gap: 2px; font-size: 11px; white-space: nowrap; }
.hub-dash-last-opened span { color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; font-size: 9.5px; }
.hub-dash-last-opened b { color: var(--text); font-weight: 700; font-size: 12.5px; }
.hub-dash-continue { flex: none; min-height: 44px; display: inline-flex; align-items: center; gap: 8px; }

/* JOB TRACKER / PROJECT LIFECYCLE PASS — one quiet line, Active projects
   only (js/hub.js's renderJobLine()). Text only, no card/border/colour
   fill — the brief is explicit the Hub must not become a monitoring
   dashboard, so this reads as a single muted status line, not a widget. */
.hub-dash-jobline { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--text-faint); }
.hub-dash-jobline .icon { width: 13px; height: 13px; color: var(--accent); flex: none; }

/* Status pill — text + colour, quiet by default. Draft/Completed stay
   neutral; Active is the accent signal; On Hold is the real warn signal. */
.hub-project-status-pill {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 2px 8px; border-radius: var(--radius-pill);
  background: var(--bg-elevated-2); color: var(--text-muted); border: 1px solid var(--border);
  white-space: nowrap;
}
.hub-project-status-pill[data-status="Active"] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.hub-project-status-pill[data-status="Completed"] { background: var(--ok-soft); color: var(--ok); border-color: var(--ok-line); }
.hub-project-status-pill[data-status="On Hold"] { background: var(--warn-soft); color: var(--warn); border-color: var(--warn-line); }

/* =======================================================================
   PROJECT HUB — NEXT ACTION (brief §14): the strongest visual element on
   the whole page, together with the milestone strip above it. One big
   cyan-edged, full-width button — not competing equally with any other
   panel below it.
   ===================================================================== */
.hub-next-action {
  display: flex; align-items: center; gap: var(--space-4);
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: var(--accent-soft); border: 1px solid var(--accent); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  box-shadow: 0 0 24px -10px var(--accent-glow);
  transition: background var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.hub-next-action:hover, .hub-next-action:focus-visible { background: var(--accent-soft); border-color: var(--accent); filter: brightness(1.08); }
.hub-next-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hub-next-action-label {
  flex: none; font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--accent); background: var(--bg-elevated); border: 1px solid var(--accent-line); border-radius: var(--radius-pill); padding: 3px 10px;
}
.hub-next-action-text { flex: 1 1 auto; min-width: 0; font-size: 14.5px; font-weight: 700; color: var(--text); }
.hub-next-action-arrow { flex: none; width: 16px; height: 16px; color: var(--accent); }
.hub-next-action-done {
  cursor: default; background: var(--bg-sunken); border-color: var(--border); box-shadow: none;
  color: var(--text-muted); font-size: 13px;
}
.hub-next-action-done .icon { width: 16px; height: 16px; color: var(--accent); flex: none; }

/* ---- PASS 2 §1/§5: Adaptive Main Block frame. The container itself
   never moves — only which child is visible changes (project-hub.js's
   renderMainBlock()). ---- */
.hub-main-block { display: flex; flex-direction: column; gap: var(--space-5); }

/* Setup-phase instructional panel (Pass 2 §5 Phase 1 / §27) — quiet,
   single card, no dead empty Live Plan/Evidence panels underneath it. */
.hub-setup-panel {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-elevated); cursor: pointer;
}
.hub-setup-panel:hover { border-color: var(--border-strong); }
.hub-setup-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-setup-panel > .icon { width: 20px; height: 20px; flex: none; color: var(--text-faint); margin-top: 2px; }
.hub-setup-panel h3 { margin: 0 0 4px; font-size: 13px; font-weight: 700; color: var(--text); }
.hub-setup-panel p { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.5; }

/* Live Project Plan + Evidence two-column pair (Pass 2 §1/§6-12). Desktop
   default: plan wider than the evidence column, matching the ASCII
   target's proportions; stacks to one column at 1024px (§26). */
.hub-main-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
@media (max-width: 1024px) { .hub-main-grid { grid-template-columns: 1fr; } }

/* ---- Live Project Plan (Pass 2 §6-11) — read-only "project at a
   glance", neutral/light drawing surface inside the dark chrome, same
   restrained cyan-for-selection-only rule as everywhere else. ---- */
.hub-plan { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-elevated); padding: var(--space-4); }
.hub-plan-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-2); }
.hub-plan-scale-note { font-size: 10px; color: var(--text-faint); font-family: var(--font-mono); }
.hub-plan-svg { display: block; width: 100%; height: auto; aspect-ratio: 400 / 220; background: #f4f5f7; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); cursor: pointer; }
.hub-plan-boundary { fill: none; stroke: #b8bcc2; stroke-width: 1; }
.hub-plan-obstacle { fill: #d8dbe0; stroke: #b8bcc2; stroke-width: 0.75; }
.hub-plan-run { fill: #eceef1; stroke: #9aa0a6; stroke-width: 0.75; }
.hub-plan-run-notbuilt { fill: #eceef1; stroke: #9aa0a6; }
.hub-plan-run-partial { fill: rgba(226, 160, 63, 0.35); stroke: #e2a03f; }
.hub-plan-run-built { fill: rgba(34, 160, 107, 0.35); stroke: #22a06b; }
.hub-plan-empty { margin: var(--space-3) 0 0; font-size: 12px; color: var(--text-faint); text-align: center; }
.hub-plan-legend { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-2); font-size: 10px; color: var(--text-faint); }
.hub-plan-legend span { display: inline-flex; align-items: center; gap: 5px; }

/* ---- Design divergence indicator (Pass 3 §13) — restrained: a single
   factual banner line plus a dashed amber outline on affected runs/bays
   only. Never colours the whole plan red; state colours above are
   untouched. ---- */
.hub-plan-divergence { display: flex; align-items: center; gap: 6px; margin-bottom: var(--space-2); padding: 6px 10px; font-size: 11px; color: #b5791f; background: rgba(226, 160, 63, 0.12); border: 1px solid rgba(226, 160, 63, 0.5); border-radius: var(--radius-sm); }
.hub-plan-run-divergent { stroke: var(--warn); stroke-width: 1.5; stroke-dasharray: 3 2; }

/* ---- Closeout Sequence (Pass 2 §14) — one engineered process line, same
   visual family as the milestone strip, not a second unrelated widget. ---- */
.hub-closeout { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-elevated); padding: var(--space-4); }
.hub-closeout-steps { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-4); }
.hub-closeout-step { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-faint); }
.hub-closeout-step-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--bg-sunken); border: 1.5px solid var(--border-strong); }
.hub-closeout-step[data-state="complete"] { color: var(--text-muted); }
.hub-closeout-step[data-state="complete"] .hub-closeout-step-dot { background: var(--ok); border-color: var(--ok); }
.hub-closeout-step[data-state="current"] { color: var(--text); font-weight: 700; }
.hub-closeout-step[data-state="current"] .hub-closeout-step-dot { background: var(--accent); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* PRODUCT HARDENING PASS §12/§13: reopen-for-revision affordance — quiet,
   only ever visible once the project is actually Completed. */
.hub-closeout-reopen { margin-top: var(--space-4); padding-top: var(--space-3); border-top: 1px solid var(--border); display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); justify-content: space-between; }
.hub-closeout-reopen-note { margin: 0; font-size: 12px; color: var(--text-muted); max-width: 46ch; }

/* ---- Recent Activity — collapsed by default (Pass 2 §16), a plain
   <details>/<summary> wrapping the existing hub-intel block untouched. ---- */
.hub-intel-details { margin-top: var(--space-2); }
.hub-intel-details-summary {
  cursor: pointer; list-style: none; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-faint); padding: var(--space-2) 0;
}
.hub-intel-details-summary::-webkit-details-marker { display: none; }
.hub-intel-details-summary:hover { color: var(--text-muted); }
.hub-intel-details[open] .hub-intel-details-summary { color: var(--text); }
.hub-intel-details > .hub-intel { margin-top: var(--space-2); }

/* ---- Evidence summary (brief §15) — same panel treatment as the Live
   Plan beside it, so the two-column pair reads as one deliberate layout. ---- */
.hub-evidence { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-elevated); padding: var(--space-4); }
.hub-evidence-grid { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); padding: var(--space-1) 0; }
.hub-evidence-item { display: flex; flex-direction: column; gap: 2px; min-width: 110px; }
.hub-evidence-item em { font-style: normal; font-size: 9px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; }
.hub-evidence-item b { font-family: var(--font-mono); font-size: 14px; font-weight: 800; letter-spacing: -0.005em; color: var(--text); }

/* BACKUP / EXPORT UX PASS §2 — one more compact secondary-info line inside
   the same Evidence panel, not a card or a dashboard of its own. */
.hub-backup-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border); flex-wrap: wrap; }
.hub-backup-row-text { display: flex; flex-direction: column; gap: 2px; }
.hub-backup-row-label { font-size: 9px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; }
.hub-backup-row-value { font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--text); }
.hub-backup-row-note { display: block; font-size: 11px; color: var(--warn); font-weight: 600; }
.hub-backup-state-never .hub-backup-row-value,
.hub-backup-state-outofdate .hub-backup-row-value { color: var(--warn); }
.hub-backup-state-error { color: var(--danger); }
.hub-backup-explainer { margin: var(--space-2) 0 0; font-size: 11px; color: var(--text-faint); }

/* ---- Problems / blockers (brief §16) — same semantic-colour language
   as Global Home's cross-project Needs Attention list. ---- */
.hub-problems-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--warn-line); border-radius: var(--radius-lg); background: var(--warn-soft); overflow: hidden; }
.hub-problems-item {
  position: relative; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: 10px var(--space-4) 10px 18px; border-top: 1px solid var(--border);
  cursor: pointer; font-size: 12.5px; color: var(--text);
}
.hub-problems-item:first-child { border-top: none; }
.hub-problems-item:hover, .hub-problems-item:focus-visible { background: rgba(0,0,0,0.06); }
.hub-problems-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-problems-item::before { content: ''; position: absolute; left: 0; top: 4px; bottom: 4px; width: 3px; border-radius: 2px; background: var(--warn); }
.hub-problems-item[data-severity="critical"]::before { background: var(--danger, #e5484d); }
.hub-problems-item .icon { width: 12px; height: 12px; flex: none; color: var(--text-faint); }

/* ---- Module Entry, compact (brief §17) — smaller than Global Home has
   no module tiles at all; Project Hub's own tiles are already the
   quieter existing .hub-module-tile treatment, just packed tighter and
   icon+label only (no descriptive subtitle) so they read as secondary to
   Next Action above. ---- */
.hub-module-tiles-compact { grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); }
.hub-module-tiles-compact .hub-module-tile { padding: var(--space-2) var(--space-3); }
.hub-module-tiles-compact .hub-module-tile-body { flex-direction: row; align-items: center; gap: 8px; }
.hub-module-tiles-compact .hub-module-tile-body .icon { width: 15px; height: 15px; }
.hub-module-tiles-compact .hub-module-tile-body b { font-size: 12px; }

/* progress rail — demoted: small, quiet, no per-stage colour flood. Only
   the stage that is actually complete or needs attention gets a colour;
   everything else (not-started/in-progress) stays a neutral outline with
   a text label underneath, exactly like every other status signal in
   this app. */
.hub-dash-progress {
  list-style: none; margin: 0; padding: var(--space-3) 0;
  display: flex; align-items: flex-start; gap: 0; overflow-x: auto;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  position: relative;
}
.hub-dash-prog-step { display: flex; flex-direction: column; align-items: center; gap: 5px; flex: 1 1 0; min-width: 62px; position: relative; }
.hub-dash-prog-step:not(:last-child)::after {
  content: ''; position: absolute; top: 13px; left: calc(50% + 15px); right: calc(-50% + 15px);
  height: 1px; background: var(--border); z-index: 0;
}
.hub-dash-prog-step[data-status="complete"]:not(:last-child)::after { background: var(--accent-line); }
.hub-prog-circle {
  position: relative; z-index: 1; width: 30px; height: 30px; flex: none; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center; border-radius: 50%;
  background: var(--bg-elevated); border: 1.5px solid var(--border-strong); color: var(--text-faint);
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.hub-prog-circle .icon { width: 16px; height: 16px; }
.hub-prog-badge { display: none; } /* demoted rail relies on circle colour + text label, not a second corner badge */
.hub-prog-text { display: flex; flex-direction: column; align-items: center; gap: 0; font-size: 10px; font-weight: 700; color: var(--text-faint); text-align: center; }
.hub-prog-state { font-style: normal; font-family: var(--font-mono); font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em; color: inherit; opacity: 0.8; }

/* Current stage — the single strongest signal on the whole Hub. Only one
   stage is ever "inprogress" at a time (js/hub.js's stageStatus() only
   marks the first not-done stage whose predecessor IS done), so this is
   genuinely "where the project is right now", not a generic in-progress
   flag — it earns the brightest treatment on the rail: bright cyan
   outline, a restrained outer glow (precision-instrument, not gaming-rig)
   and an elevated circle surface so it reads ahead of "complete". */
.hub-dash-prog-step[data-status="inprogress"] .hub-prog-circle {
  background: var(--bg-elevated-2); border-color: var(--accent); color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 12px -2px var(--accent-glow);
}
.hub-dash-prog-step[data-status="inprogress"] .hub-prog-text { color: var(--text); }
.hub-dash-prog-step[data-status="inprogress"] .hub-prog-state { color: var(--accent); opacity: 1; }

/* Complete — deliberately calmer than "current": a small, quiet cyan
   confirmation mark rather than a full glowing ring, so the eye is not
   pulled to finished stages ahead of the one that actually needs
   attention right now. */
.hub-dash-prog-step[data-status="complete"] .hub-prog-circle { position: relative; background: var(--bg-elevated); border-color: var(--border-strong); color: var(--accent); }
.hub-dash-prog-step[data-status="complete"] .hub-prog-circle::after {
  content: ''; position: absolute; bottom: -1px; right: -1px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--bg-elevated);
}
.hub-dash-prog-step[data-status="complete"] .hub-prog-text { color: var(--text-muted); }

.hub-dash-prog-step[data-status="attention"] .hub-prog-circle { border-color: var(--warn-line); color: var(--warn); background: var(--warn-soft); }
.hub-dash-prog-step[data-status="attention"] .hub-prog-text { color: var(--warn); }

.hub-prog-future { opacity: 0.55; }
.hub-prog-future .hub-prog-circle { border-style: dashed; }

/* key figures — one quiet strip of label:value pairs, all seven at equal
   weight, no boxed "KPI card" treatment. */
.hub-dash-figures { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); padding: var(--space-1) 0; }
.hub-dash-figure { display: flex; flex-direction: column; gap: 2px; min-width: 84px; }
.hub-dash-figure em { font-style: normal; font-size: 9px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; }
.hub-dash-figure b { font-family: var(--font-mono); font-size: 17px; font-weight: 800; letter-spacing: -0.01em; color: var(--text); overflow-wrap: break-word; }

/* needs attention — one quiet strip, amber accents only when non-empty. */
.hub-dash-attention { border: 1px solid var(--border); background: var(--bg-sunken); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); }
.hub-dash-attention[data-empty="false"] { border-color: var(--warn-line); }
.hub-dash-attention-head { display: flex; align-items: center; gap: 8px; }
.hub-dash-attention-head .icon { width: 16px; height: 16px; color: var(--text-faint); flex: none; }
.hub-dash-attention[data-empty="false"] .hub-dash-attention-head .icon { color: var(--warn); }
.hub-dash-attention-head span:nth-of-type(1) { font-size: 12.5px; font-weight: 700; color: var(--text); }
.hub-dash-attention-count {
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  background: var(--bg-elevated-2); color: var(--text-faint); border-radius: var(--radius-pill); padding: 1px 8px;
}
.hub-dash-attention[data-empty="false"] .hub-dash-attention-count { background: var(--warn); color: #1a1200; }
.hub-dash-attention-toggle {
  margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
  background: none; border: none; color: var(--warn); font: inherit; font-size: 11.5px; font-weight: 700;
  cursor: pointer; min-height: 32px; padding: 0 4px;
}
.hub-dash-attention[data-empty="true"] .hub-dash-attention-toggle { color: var(--text-muted); }
.hub-dash-attention-toggle .icon { width: 12px; height: 12px; transform: rotate(90deg); transition: transform var(--duration-fast) var(--ease-out); }
.hub-dash-attention.is-expanded .hub-dash-attention-toggle .icon { transform: rotate(-90deg); }
.hub-dash-attention-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; font-size: 12px; line-height: 1.6; max-height: 0; overflow: hidden; }
.hub-dash-attention.is-expanded .hub-dash-attention-list { max-height: 400px; }
.hub-dash-attention-list li { padding: 6px 0; border-top: 1px dashed var(--border); color: var(--text-muted); }
.hub-dash-attention-list li:first-child { border-top: none; }

/* open a module — flat, quiet launcher tiles: no gradient-photo texture,
   just an icon + name + subtitle on a --bg-elevated-2 surface (one step
   up from the dashboard panel, per the surface ladder). Small lift +
   accent border on hover/focus is the only cyan here. */
.hub-dash-modules h3 { font-family: var(--font-display); font-size: 12.5px; margin: 0 0 var(--space-3); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.hub-module-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--space-2); }
.hub-module-tile {
  position: relative; display: block; border-radius: var(--radius-md);
  border: 1px solid var(--border); background: var(--bg-elevated-2);
  color: var(--text); text-decoration: none; font: inherit; text-align: left; cursor: pointer;
  padding: var(--space-3);
  transition: border-color var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.hub-module-tile-body { display: flex; flex-direction: column; gap: 6px; }
.hub-module-tile-body .icon { width: 22px; height: 22px; color: var(--accent); flex: none; }
.hub-module-tile-body b { font-family: var(--font-display); font-size: 13px; font-weight: 700; }
.hub-module-tile-body em { font-style: normal; font-size: 10.5px; color: var(--text-faint); }
button.hub-module-tile:hover { border-color: var(--accent-line); background: var(--bg-elevated); transform: translateY(-1px); }
button.hub-module-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-module-tile-soon { cursor: default; }
.hub-module-tile-soon .hub-module-tile-body b { color: var(--text-muted); }
.hub-module-tile-soon-flag {
  display: inline-block; margin-left: 6px; font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-faint); border: 1px solid var(--border-strong); border-radius: var(--radius-pill); padding: 1px 6px; background: var(--bg-sunken);
}

/* Current/recommended module — js/hub.js's renderModuleTileStates() sets
   data-tile-status from the same stageStatus() the progress rail uses.
   Normal tiles stay quiet; only the tile matching where the project
   actually is right now gets the signal, exactly like the progress rail. */
.hub-module-tile[data-tile-status="inprogress"] {
  border-color: var(--accent); background: var(--bg-elevated);
  box-shadow: 0 0 0 1px var(--accent-line);
}
.hub-module-tile[data-tile-status="inprogress"] .hub-module-tile-body b { color: var(--text); }
.hub-module-tile[data-tile-status="attention"] { border-color: var(--warn-line); background: var(--warn-soft); }
.hub-module-tile[data-tile-status="attention"] .hub-module-tile-body .icon { color: var(--warn); }
/* Completed — a small, quiet corner mark, same restrained language as the
   progress rail's own "complete" confirmation dot; the tile itself stays
   neutral so it doesn't compete with the current stage. */
.hub-module-tile[data-tile-status="complete"]::after {
  content: ''; position: absolute; top: 9px; right: 9px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--accent); opacity: 0.75;
}
.hub-module-tile[data-tile-status="attention"]::after {
  content: ''; position: absolute; top: 9px; right: 9px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--warn);
}

/* =======================================================================
   MAXIMISE THE HUB WITH USEFUL PROJECT INTELLIGENCE PASS — real
   selected-project intelligence filling the space below the module
   tiles (js/hub-intel.js). Same surface ladder as the rest of the
   dashboard panel: quiet strips (--bg-sunken, same step as "Needs
   attention" above) not boxed cards, hairline separators, cyan reserved
   for the active/interactive signal (the clickable job/preview panels,
   Next Actions links, timeline "done"/"in progress" dots — mirroring
   the existing progress rail's own accent-for-complete convention
   above), semantic colour only where it's a real status (bay Built/
   Changed overlay). No decorative gradients, glows or extra rounding.
   ===================================================================== */
.hub-intel { border-top: 1px solid var(--border); padding-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-4); }
.hub-intel-row { display: grid; gap: var(--space-3); align-items: start; }
.hub-intel-row-job { grid-template-columns: 1.4fr 1fr; }
.hub-intel-row-2col { grid-template-columns: 1fr 1fr; }
.hub-intel-row-3col { grid-template-columns: repeat(3, 1fr); }

.hub-intel-panel {
  background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
}
/* As-Built / Handover / Inspection — even quieter one-liners, no fill. */
.hub-intel-panel-quiet { background: none; border: none; border-top: 1px dashed var(--border); border-radius: 0; padding: var(--space-3) 0 0; }

.hub-intel-panel-head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); }
.hub-intel-panel-head h3 { font-family: var(--font-display); font-size: 11.5px; margin: 0; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.05em; }
.hub-intel-panel-link {
  margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700; color: var(--accent);
}
.hub-intel-panel-link .icon { width: 11px; height: 11px; }

/* Live job summary — the one clickable, cyan-bordered-on-hover panel,
   same interaction language as .hub-module-tile. */
button.hub-intel-job, button.hub-intel-preview {
  display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out);
}
button.hub-intel-job:hover, button.hub-intel-preview:hover { border-color: var(--accent-line); }
button.hub-intel-job:focus-visible, button.hub-intel-preview:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-intel-job-line { margin: 0 0 var(--space-3); font-family: var(--font-mono); font-size: 14px; font-weight: 800; letter-spacing: -0.005em; color: var(--text); }

/* Shared dense stat grid — Live Job's crew/supervisor/etc + Project
   Snapshot both use this, same label:value quiet-strip language as the
   existing .hub-dash-figure row above. */
.hub-intel-stat-grid { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
.hub-intel-stat { display: flex; flex-direction: column; gap: 2px; min-width: 76px; }
.hub-intel-stat em { font-style: normal; font-size: 9px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; }
.hub-intel-stat b { font-family: var(--font-mono); font-size: 13.5px; font-weight: 800; letter-spacing: -0.005em; color: var(--text); overflow-wrap: break-word; }

/* Mini installation layout preview — read-only, no pointer affordances
   drawn on the drawing itself (the whole panel is the click target). */
.hub-intel-preview-svg { display: block; width: 100%; height: auto; aspect-ratio: 400 / 220; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.hub-intel-bay { stroke-width: 0.75; }
.hub-intel-bay-notbuilt { fill: var(--bg-elevated-2); stroke: var(--border-strong); }
.hub-intel-bay-built { fill: var(--ok-soft); stroke: var(--ok); }
.hub-intel-bay-changed { fill: var(--warn-soft); stroke: var(--warn); }
.hub-intel-preview-legend { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-2); font-size: 10px; color: var(--text-faint); }
.hub-intel-preview-legend span { display: inline-flex; align-items: center; gap: 5px; }
.hub-intel-legend-dot { width: 9px; height: 9px; border-radius: 2px; display: inline-block; border: 1.5px solid; }
.hub-intel-legend-dot.hub-intel-bay-notbuilt { border-color: var(--border-strong); }
.hub-intel-legend-dot.hub-intel-bay-built { border-color: var(--ok); }
.hub-intel-legend-dot.hub-intel-bay-changed { border-color: var(--warn); }

/* Next Actions / Project Activity — dense list, dashed hairline between
   rows (same pattern as .hub-dash-attention-list li). */
.hub-intel-list { list-style: none; margin: 0; padding: 0; font-size: 12px; }
.hub-intel-list li { border-top: 1px dashed var(--border); }
.hub-intel-list li:first-child { border-top: none; }
.hub-intel-action {
  display: block; width: 100%; text-align: left; padding: 7px 0;
  background: none; border: none; font: inherit; font-size: 12px; color: var(--text-muted); cursor: pointer;
}
.hub-intel-action:hover, .hub-intel-action:focus-visible { color: var(--accent); }

/* Next Actions — the primary (first) action is the most important
   operational signal on the Hub after project identity itself, so it
   gets its own quiet cyan-edged surface and an arrow affordance; every
   action after it stays plain list text, same as before. Pure CSS: the
   list already renders the primary action first (js/hub-intel.js's
   nextActions()), so :first-child is a reliable, non-invasive hook. */
.hub-intel-actions-list li:first-child { border-top: none; margin-bottom: 2px; }
.hub-intel-actions-list li:first-child .hub-intel-action {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: 10px 12px; border-radius: var(--radius-md);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  color: var(--text); font-weight: 700; font-size: 12.5px;
  box-shadow: 0 0 16px -8px var(--accent-glow);
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.hub-intel-actions-list li:first-child .hub-intel-action::after {
  content: '\2192'; flex: none; color: var(--accent); font-weight: 700;
}
.hub-intel-actions-list li:first-child .hub-intel-action:hover,
.hub-intel-actions-list li:first-child .hub-intel-action:focus-visible {
  color: var(--text); border-color: var(--accent);
}
.hub-intel-actions-list li + li .hub-intel-action { color: var(--text-faint); font-size: 11.5px; }
.hub-intel-actions-list li + li .hub-intel-action:hover,
.hub-intel-actions-list li + li .hub-intel-action:focus-visible { color: var(--accent); }
/* Tiny cyan markers on every event — the quiet, restrained default this
   brief asks for. There's no per-event "kind" data to key semantic
   colour off here (unlike the right rail's activity feed, which does
   have one), so a single consistent marker is the honest choice rather
   than inventing categorisation. */
.hub-intel-activity-list li { position: relative; display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); padding: 8px 0 8px 13px; }
.hub-intel-activity-list li::before {
  content: ''; position: absolute; left: 0; top: 50%; margin-top: -2.5px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent); opacity: 0.65;
}
.hub-intel-activity-label { color: var(--text-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-intel-activity-time { flex: none; font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faint); }

/* Project Timeline — compact vertical chain, accent = done (same
   "complete = accent" convention the progress rail above already uses),
   muted = in progress, dashed/faint = pending with no real data yet. */
.hub-intel-timeline { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.hub-intel-timeline-step { display: flex; align-items: center; gap: var(--space-2); font-size: 12px; }
.hub-intel-timeline-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; border: 1.5px solid var(--border-strong); background: var(--bg-elevated); }
.hub-intel-timeline-step[data-state="done"] .hub-intel-timeline-dot { background: var(--accent); border-color: var(--accent); width: 6px; height: 6px; }
/* Current stage — the strongest marker on the timeline, same "current
   beats complete" hierarchy the progress rail above already establishes. */
.hub-intel-timeline-step[data-state="active"] .hub-intel-timeline-dot {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 10px -2px var(--accent-glow);
}
.hub-intel-timeline-step[data-state="pending"] .hub-intel-timeline-dot { border-style: dashed; opacity: 0.6; }
.hub-intel-timeline-body { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; }
.hub-intel-timeline-step[data-state="done"] .hub-intel-timeline-body b { color: var(--text-muted); }
.hub-intel-timeline-step[data-state="active"] .hub-intel-timeline-body b { color: var(--text); }
.hub-intel-timeline-step[data-state="active"] .hub-intel-timeline-date { color: var(--accent); }
.hub-intel-timeline-step[data-state="pending"] .hub-intel-timeline-body { opacity: 0.55; }
.hub-intel-timeline-body b { font-weight: 700; color: var(--text-muted); }
.hub-intel-timeline-date { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* As-Built / Handover Readiness / Inspection — one plain line each.
   Ready/attention/not-ready are exposed via data-state on the quiet
   panel wrapper (js/hub-intel.js's renderAsBuilt()/renderHandoverReadiness())
   for a compact engineering-status treatment: a coloured left tick plus
   the line's own text brightening slightly — never a big card, the text
   itself still carries the actual reason. */
.hub-intel-line { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.5; }
.hub-intel-panel-quiet { position: relative; padding-left: var(--space-3); }
.hub-intel-panel-quiet::before {
  content: ''; position: absolute; left: 0; top: var(--space-3); bottom: 2px; width: 2px; border-radius: 2px;
  background: var(--border-strong);
}
.hub-intel-panel-quiet[data-state="ready"]::before { background: var(--accent); }
.hub-intel-panel-quiet[data-state="ready"] .hub-intel-line { color: var(--text); }
.hub-intel-panel-quiet[data-state="attention"]::before { background: var(--warn); }
.hub-intel-panel-quiet[data-state="attention"] .hub-intel-line { color: var(--warn); }
.hub-intel-panel-quiet[data-state="notready"]::before { background: var(--border-strong); }

@media (max-width: 900px) {
  .hub-intel-row-job, .hub-intel-row-2col, .hub-intel-row-3col { grid-template-columns: 1fr; }
}

/* =======================================================================
   RIGHT INFORMATION RAIL — one functional panel per section
   (--bg-elevated), quiet, no per-item card borders.
   ===================================================================== */
.hub-info-rail { display: flex; flex-direction: column; gap: var(--space-4); }
/* On wide screens the rail stretches to the project list's height so the
   Project Health block can centre in the space under Recent Activity. */
@media (min-width: 1024px) { .hub-info-rail { align-self: stretch; } }

/* ---- Project Health: three concentric lifecycle rings (outer Design,
   middle Deliver, inner Operate) + a compact state breakdown. Thin strokes,
   existing status colours, no card chrome, no glow/gradient. ---- */
.hub-health { flex: 1 1 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3); padding: var(--space-4) var(--space-2); min-height: 220px; }
.hub-health-title { margin: 0; font-family: var(--font-display); font-size: 12.5px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.hub-health-svg { width: clamp(112px, 12vw, 132px); height: auto; aspect-ratio: 1; transform: rotate(-90deg); flex: none; }
.hub-hring-track { fill: none; stroke: var(--border); stroke-width: 6; transition: opacity 120ms var(--ease-out); }
.hub-hring-value { fill: none; stroke: var(--accent); stroke-width: 6; stroke-linecap: round; transition: stroke-dashoffset 320ms var(--ease-out), opacity 120ms var(--ease-out); }
.hub-hring[data-state="complete"] .hub-hring-value { stroke: var(--ok); }
.hub-hring[data-state="attention"] .hub-hring-value { stroke: var(--warn); }
.hub-hring[data-state="notstarted"] .hub-hring-value { stroke: transparent; }
/* hover/focus on a row dims the other rings */
.hub-health[data-hl] .hub-hring { opacity: 0.35; transition: opacity 120ms var(--ease-out); }
.hub-health[data-hl="design"] .hub-hring[data-ring="design"],
.hub-health[data-hl="deliver"] .hub-hring[data-ring="deliver"],
.hub-health[data-hl="operate"] .hub-hring[data-ring="operate"] { opacity: 1; }
.hub-health-list { list-style: none; margin: 0; padding: 0; width: 100%; max-width: 240px; display: flex; flex-direction: column; gap: 2px; }
.hub-health-row-btn {
  width: 100%; display: grid; grid-template-columns: 10px 1fr auto; align-items: center; gap: var(--space-2);
  background: none; border: 0; border-radius: var(--radius-sm); padding: 6px 4px; cursor: pointer; text-align: left; color: var(--text); font: inherit;
}
.hub-health-row-btn:hover { background: var(--bg-elevated-2); }
.hub-health-row-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.hub-health-swatch { width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--accent); box-sizing: border-box; }
.hub-health-row[data-state="complete"] .hub-health-swatch { background: var(--ok); border-color: var(--ok); }
.hub-health-row[data-state="attention"] .hub-health-swatch { border-color: var(--warn); background: var(--warn); }
.hub-health-row[data-state="notstarted"] .hub-health-swatch { border-color: var(--text-faint); }
.hub-health-name { font-size: 12px; font-weight: 700; }
.hub-health-state { font-size: 11px; color: var(--text-muted); }
.hub-health-row[data-state="attention"] .hub-health-state { color: var(--warn); }
.hub-health-modules { list-style: none; margin: 0 0 4px 22px; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.hub-health-modules[hidden] { display: none; }
.hub-health-modules li { display: flex; justify-content: space-between; gap: var(--space-2); font-size: 11px; color: var(--text-muted); }
.hub-health-modules li em { font-style: normal; color: var(--text-faint); }
.hub-health-modules li[data-state="complete"] em { color: var(--ok); }
.hub-health-modules li[data-state="attention"] em { color: var(--warn); }
@media (max-width: 1023px) { .hub-health { min-height: 0; padding-top: var(--space-5); } }
@media (prefers-reduced-motion: reduce) { .hub-hring-value { transition: none; } }
.hub-rail-section {
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-4);
}
.hub-rail-section h3 { font-family: var(--font-display); font-size: 12.5px; margin: 0 0 var(--space-3); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

.hub-rail-files { list-style: none; margin: 0; padding: 0; }
.hub-rail-file { display: flex; align-items: center; gap: var(--space-3); padding: 6px 0; }
.hub-rail-file-icon { width: 20px; height: 20px; flex: none; color: var(--accent); background: var(--accent-soft); border-radius: var(--radius-sm); padding: 4px; box-sizing: border-box; }
.hub-rail-file-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.hub-rail-file-id b { font-size: 12px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-rail-file-id span { font-size: 10px; color: var(--text-faint); }
.hub-rail-file-btn {
  flex: none; min-height: 30px; padding: 0 10px; font-size: 11px; font-weight: 700;
  background: none; border: 1px solid var(--border); color: var(--text-muted); border-radius: var(--radius-sm); cursor: pointer;
}
.hub-rail-file-btn:hover { color: var(--text); border-color: var(--accent-line); }

.hub-rail-activity { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.hub-rail-activity li { display: flex; align-items: flex-start; gap: 10px; }
.hub-rail-activity-dot { width: 6px; height: 6px; border-radius: 50%; margin-top: 5px; flex: none; background: var(--accent); }
.hub-rail-activity-dot[data-kind="created"] { background: var(--ok); }
.hub-rail-activity-dot[data-kind="modified"] { background: var(--accent); }
.hub-rail-activity-dot[data-kind="opened"] { background: var(--warn); }
.hub-rail-activity li div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.hub-rail-activity li b { font-size: 12px; font-weight: 700; color: var(--text); }
.hub-rail-activity li span { font-size: 10.5px; color: var(--text-faint); }
.hub-rail-empty { color: var(--text-faint) !important; font-size: 12px; }

/* Project Details — plain label:value pairs, same quiet-strip language as
   the rest of the rail; a real "Edit" link only appears where a field
   genuinely has a source page to edit it on. */
.hub-details-grid { margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.hub-details-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); padding: 4px 0; border-top: 1px dashed var(--border); }
.hub-details-row:first-child { border-top: none; }
.hub-details-row dt { font-size: 10.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; flex: none; }
.hub-details-row dd { margin: 0; font-size: 12px; font-weight: 600; color: var(--text); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.hub-rail-section-head { display: flex; align-items: center; gap: var(--space-2); }
.hub-rail-section-head h3 { margin: 0; }
.hub-rail-edit-link { margin-left: auto; font-size: 10.5px; font-weight: 700; color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; }
}

/* =======================================================================
   RESPONSIVE — desktop-primary, readable on tablet (brief §32). GLOBAL
   HOME / PROJECT HUB SPLIT: a single restrained column at every width —
   there is no second column competing for space any more (that was the
   old browser+dashboard+rail grid), so Home just gets a wider max
   reading width as the viewport grows, same as the empty state already
   did above.
   ===================================================================== */
@media (min-width: 760px) {
  .hub-continue-meta { gap: var(--space-6); }
  .hub-live-site-figures { gap: var(--space-6); }
}

@media (min-width: 1180px) {
  .hub-main { padding: var(--space-5) var(--space-6); }
  .hub-search-bar { padding: var(--space-5) var(--space-6) 0; }
  /* HUB DENSE OPERATIONAL LIST PASS: was 920px — on a real desktop monitor
     that left roughly half the viewport as bare background either side of
     a single narrow column, which is exactly the "wasted margins" this
     pass exists to fix. The Project Navigator is the one section that
     genuinely benefits from real width (see .hub-row's desktop grid
     below); Continue Working/Needs Attention/Live on Site stay readable
     at this width too — none of them need to be artificially narrow to
     look intentional. */
  .hub-workspace { max-width: none; }
}

@media (min-width: 1440px) {
  .hub-workspace { max-width: none; }
}

/* =======================================================================
   DENSE DESKTOP PROJECT ROW (HUB DENSE OPERATIONAL LIST PASS) — once the
   navigator column is genuinely wide (matches the 1180px point .hub-
   workspace itself widens at, above), a project row becomes ONE real
   line — identity swatch, name, customer/site, signal, status, last-
   opened, actions — instead of the narrow/tablet 3-line stack. This is
   what "use the available desktop space" and "easy to scan without
   excessive scrolling" actually mean for a list that can run to dozens
   of rows: more rows visible per screen, each fully scannable left to
   right, no wasted vertical padding repeating the same three line-breaks
   for every project.

   Mechanism: .hub-row-line1/2/3 (the narrow-width stacking wrappers just
   above) become `display:contents` — they stop being boxes and their
   children are promoted to direct grid items of .hub-row, which becomes
   the actual grid. Below 1180px, none of this applies and the proven
   narrow/tablet 3-line flex layout above is completely untouched.
   ===================================================================== */
@media (min-width: 1180px) {
  .hub-row {
    display: grid;
    grid-template-columns: 26px minmax(160px, 1.3fr) minmax(140px, 1fr) minmax(150px, 1fr) 104px 130px auto;
    column-gap: var(--space-3); row-gap: 0;
    align-items: center;
    padding: 7px 12px;
  }
  .hub-row-swatch { margin-top: 0; grid-row: 1; }
  .hub-row-lines { display: contents; }
  .hub-row-line1, .hub-row-line2, .hub-row-line3 { display: contents; }
  .hub-row-name { grid-column: 2; }
  .hub-row-sub { grid-column: 3; font-size: 11px; }
  .hub-row-signal { grid-column: 4; justify-self: start; }
  .hub-status-select { grid-column: 5; justify-self: start; max-width: 100%; }
  .hub-row-when { grid-column: 6; }
  .hub-row-actions { grid-column: 7; justify-self: end; }
  /* The signal/status/when/actions columns are always present as grid
     tracks even when a row has no signal badge (rowSignalHtml() returns
     an empty string for that row) — an empty grid cell there is correct,
     it just means every OTHER row's status/when/actions still land in
     the same visual column, which is the entire point of a dense table-
     like list: columns line up. */
}

/* =========================================================================
   UNIFIED HUB PASS — reference-image visual match.
   project-hub.html is now the single Hub screen: module sidebar + a top
   bar (search + attention bell) + the active project's own command
   header/workflow/metrics/attention/modules + the Recent Projects browser
   (styled above, untouched) + a right context rail. Everything in this
   block is new presentation only — no calculation, no new data source;
   every figure it displays is fed by real project-hub.js render functions
   reading the same RMHubShared.computeDashboard() ctx every other panel on
   this page already reads.
   ========================================================================= */

/* ---- Top bar: global project search + attention bell ---- */
.hub-topbar { display: flex; align-items: center; gap: var(--space-3); }
.hub-topbar-search { flex: 1 1 auto; max-width: 480px; min-height: 38px; }
.hub-topbar-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.hub-topbar-bell { position: relative; }
.hub-topbar-bell-count {
  position: absolute; top: 2px; right: 2px; min-width: 15px; height: 15px; padding: 0 3px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 9px; font-weight: 800; line-height: 1;
  color: #1a1200; background: var(--warn); border-radius: var(--radius-pill);
  box-shadow: 0 0 0 2px var(--bg-elevated);
}

/* ---- Bell popover (REVIEW PASS) — the cross-project "Needs Attention —
   All Projects" list, consolidated here instead of a third permanently-
   rendered attention section in the main column. Reuses the existing
   .hub-row-menu / .hub-row-menu-popover floating-popover pattern (same
   component already used for row overflow menus and the Active Project
   Header menu), just wider and anchored under the bell. ---- */
.hub-notify-menu { position: relative; }
.hub-notify-popover {
  /* REVIEW PASS mobile check: a fixed 320px min-width popover anchored
     right:0 under the bell risked pushing past the viewport edge (and
     forcing horizontal scroll) on narrow phones (~390px and below) —
     width now caps to the viewport instead of a fixed pixel floor. */
  right: 0; left: auto; width: min(320px, calc(100vw - 32px)); max-width: 380px; max-height: 380px;
  overflow-y: auto; padding: var(--space-2);
}
.hub-notify-popover-head {
  font-family: var(--font-display); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-faint); padding: 4px 6px var(--space-2);
}
.hub-notify-popover .hub-attention-global-list { border: none; border-radius: 0; background: none; }
.hub-notify-popover-empty { margin: 0; padding: var(--space-3) 6px; font-size: 12px; color: var(--text-faint); text-align: center; }

/* ---- Page layout: main column + right context rail ----
   REVIEW PASS: the two-column split now starts at 1024px, not 1280px —
   at 1280px+ a tablet-width device (~1024px, e.g. iPad landscape) was
   falling into the single-column stack, which buried Project Details
   (client/site/pallet locations/handover date) below the entire main
   column, including the collapsible "More Detail" section. Keeping the
   rail beside the main column at genuine tablet widths means Project
   Details stays visually adjacent to the Active Project Header, exactly
   where the review asked for it, with no markup change needed. The rail
   narrows slightly (280px vs 320px) to leave the main column workable
   room at 1024px; module/metric cards already reflow via auto-fit/
   auto-fill, so a narrower main column just means fewer columns per row,
   not overflow. Below 1024px (genuine phone widths) the rail still
   stacks fully below the main column — Files/Activity landing low there
   is an accepted trade-off (see the accompanying report), not something
   this pass restructures further. */
.hub-layout { display: grid; grid-template-columns: 1fr; gap: var(--space-5); align-items: start; }
.hub-layout-main { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }
@media (min-width: 1024px) {
  .hub-layout { grid-template-columns: minmax(0, 1fr) 300px; }
}

/* ---- No project genuinely open yet, but projects exist (UNIFIED HUB
   PASS) — a quiet prompt, not an error; Recent Projects below is always
   there to act on. ---- */
.hub-pick-project {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-4); margin-bottom: var(--space-5);
  background: var(--bg-elevated); border: 1px dashed var(--border-strong); border-radius: var(--radius-lg);
  color: var(--text-muted); font-size: 13px;
}
.hub-pick-project .icon { width: 18px; height: 18px; flex: none; color: var(--text-faint); }
.hub-pick-project p { margin: 0; }

/* ---- Active Project Header — reuses the existing .hub-dashboard command-
   centre treatment (cyan top/left edge) via the same class, plus a small
   identity block. No fake thumbnail photo: the same job-colour swatch
   system the Recent Projects rows already use stands in for one
   (honest — there is no per-project image anywhere in this app). ---- */
.hub-active-panel {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4);
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  box-shadow: 0 0 0 1px rgba(43, 182, 255, 0.05), var(--shadow-md);
  overflow: hidden;
  transition: border-color 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
}
/* HUB PROJECT-SWITCHING STABILITY PASS: the one visual confirmation that
   the active project changed — a brief accent pulse on the identity
   header itself (the anchor the user reads to know which job they're in),
   toggled for ~200ms by js/project-hub.js's flashActiveIdentity(). Reuses
   the existing accent/accent-line/accent-soft tokens and the same
   restrained ring treatment .hub-search-field:focus-within already uses
   elsewhere on this page — no new colour, no glow-heavy effect, no
   page-level motion. */
.hub-active-panel.hub-active-flash {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(43, 182, 255, 0.05), var(--shadow-md), 0 0 0 3px var(--accent-soft);
}
.hub-active-panel::before {
  content: ''; position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;
  width: 100%; height: 2px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-soft) 38%, transparent 78%);
  opacity: 0.85;
}
.hub-active-visual {
  flex: none; width: 52px; height: 52px; border-radius: var(--radius-md);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  display: flex; align-items: center; justify-content: center;
}
.hub-active-id { flex: 1 1 220px; min-width: 0; }
.hub-active-eyebrow {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 3px;
}
.hub-active-id h1 { font-family: var(--font-display); font-size: 20px; font-weight: 800; letter-spacing: -0.01em; margin: 0 0 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-active-facts { display: flex; flex-wrap: wrap; gap: var(--space-3); font-size: 11.5px; color: var(--text-faint); font-family: var(--font-mono); }
.hub-active-state { display: flex; align-items: center; gap: var(--space-4); flex: none; flex-wrap: wrap; }
.hub-active-continue { min-height: 42px; display: inline-flex; align-items: center; gap: 8px; }
.hub-active-continue-done { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-muted); }
.hub-active-continue-done .icon { width: 15px; height: 15px; color: var(--accent); }
.hub-active-menu .hub-row-menu-popover { right: 0; left: auto; }

/* ---- Metrics — four real, derived figures. Honest "—" fallback (never a
   fake number) uses the same neutral text colour as every other empty
   value in this app; no invented trend/comparison figures. ---- */
.hub-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-3); }
.hub-metric-card {
  position: relative;
  display: flex; flex-direction: column; gap: 4px;
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
}
.hub-metric-card .icon { width: 16px; height: 16px; color: var(--accent); margin-bottom: 2px; }
.hub-metric-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-faint); }
.hub-metric-value { font-family: var(--font-mono); font-size: 22px; font-weight: 800; letter-spacing: -0.01em; color: var(--text); }
.hub-metric-sub { font-size: 10.5px; color: var(--text-faint); min-height: 1em; }

/* ---- "Why this number?" info affordance (Phase 1 item 3) — reuses the
   existing .hub-row-menu/.hub-row-menu-popover floating-popover mechanics
   (position/z-index/background/border/shadow/.is-open toggle) verbatim;
   only a small size/readability override for a short paragraph of static
   explanation text instead of a list of menu actions. Display-only. ---- */
.hub-metric-info { position: absolute; top: 8px; right: 8px; }
.hub-metric-info-btn { width: 20px; height: 20px; }
.hub-metric-info-btn .icon { width: 12px; height: 12px; }
.hub-metric-info-popover { left: auto; right: 0; width: 220px; padding: 10px 12px; }
.hub-metric-info-popover p { margin: 0; font-size: 11px; line-height: 1.45; font-weight: 500; color: var(--text-muted); white-space: normal; }

/* ---- Attention bar — a full-width restrained restyle of the Problems
   panel: one line (count + top item) plus a disclosure for the rest,
   rather than a list shown open by default. Same amber/red semantics as
   every other attention surface in this app (js/hub-shared.js). ---- */
.hub-attention-bar {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  background: var(--warn-soft); border: 1px solid var(--warn-line); border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
}
.hub-attention-bar > .icon { width: 18px; height: 18px; color: var(--warn); flex: none; }
.hub-attention-bar-body { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.hub-attention-bar-body b { font-size: 12.5px; font-weight: 800; color: var(--text); }
.hub-attention-bar-body p { margin: 0; font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-attention-bar-toggle {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  background: none; border: none; color: var(--warn); font: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  min-height: 32px; padding: 0 4px;
}
.hub-attention-bar-toggle .icon { width: 12px; height: 12px; }
.hub-attention-bar .hub-problems-list { flex-basis: 100%; margin-top: var(--space-1); background: var(--bg-elevated); }

/* ---- Module cards — reuses .hub-module-tile's existing surface/hover
   language; the reference's larger image-header treatment becomes an
   icon-led visual block instead (there are no per-module photos in this
   app), with a short real description and a trailing arrow. ---- */
.hub-module-tiles-cards { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.hub-module-tiles-cards .hub-module-tile { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4); }
.hub-module-tile-visual {
  flex: none; width: 38px; height: 38px; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); border: 1px solid var(--accent-line);
}
.hub-module-tile-visual .icon { width: 24px; height: 24px; color: var(--accent); }
.hub-module-tiles-cards .hub-module-tile-body { flex: 1 1 auto; min-width: 0; gap: 3px; }
.hub-module-tiles-cards .hub-module-tile-body em { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-module-tile-arrow { flex: none; width: 14px; height: 14px; color: var(--text-faint); }
.hub-module-tiles-cards .hub-module-tile:hover .hub-module-tile-arrow { color: var(--accent); }

/* ---- Continue Working / cross-project sections, demoted below the
   primary reference hierarchy (see project-hub.html) — same spacing
   rhythm as everything else in the main column. ---- */
.hub-continue, .hub-attention-global, .hub-live-site { margin-top: 0; }

@media (min-width: 1180px) {
  .hub-metrics { grid-template-columns: repeat(4, 1fr); }
}

/* =========================================================================
   STRUCTURAL/VISUAL REDESIGN PASS — new component styling
   (§3 top metrics, §4 health rings, §6 identity plan thumbnail,
   §10 Quick View drawer, §12 activity show-more). Every rule below reuses
   the existing token set (--bg-elevated/--bg-sunken, --accent*, --warn*,
   --ok*, --danger*, --border*, --text*, --space-*, --radius-*, --shadow-*)
   — no new colours, no glow, no gradients. ========================== */

/* ---- §3 Top operational metrics strip — a compact single row above the
   main grid, one honest figure per cell, no card chrome (this is a
   summary strip, not four more dashboard cards). ---- */
.hub-top-metrics {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px;
  background: var(--border); border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  overflow: hidden;
}
.hub-top-metric {
  background: var(--bg-elevated); padding: var(--space-3) var(--space-4);
  display: flex; flex-direction: column; gap: 2px;
}
.hub-top-metric-value { font-family: var(--font-mono); font-size: 24px; font-weight: 800; letter-spacing: -0.01em; color: var(--text); line-height: 1.1; }
.hub-top-metric-label { font-size: 11px; font-weight: 600; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.03em; }
/* VALIDATION + CORRECTION PASS: overdue is reported separately from "due
   this week" (js/hub.js's renderTopMetrics()) so a missed deadline is
   never silently counted as "due soon" — shown only when there is at
   least one, in the warn colour (a missed date needs action, but isn't
   by itself the "blocked/critical" red the app reserves for handover
   blockers and clashes). */
.hub-top-metric-sub { display: block; margin-top: 2px; font-size: 10.5px; font-weight: 700; color: var(--warn); }
/* Attention count only gets weight when it is genuinely non-zero — a
   plain "0" reads the same neutral colour as every other metric. */
.hub-top-metric[data-metric="attention"] .hub-top-metric-value[data-nonzero="true"] { color: var(--warn); }
.hub-top-metric[data-metric="due"] .hub-top-metric-value[data-nonzero="true"] { color: var(--accent); }
@media (min-width: 640px) {
  .hub-top-metrics { grid-template-columns: repeat(4, 1fr); }
}
/* KPI tiles filter Recent Projects (js/hub.js wireKpiTiles()). Only an
   affordance + a quiet selected state — no layout/colour change otherwise. */
.hub-top-metric[role="button"] { cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; }
.hub-top-metric[role="button"]:hover { background: color-mix(in srgb, var(--accent) 6%, var(--bg-elevated)); }
.hub-top-metric[role="button"]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.hub-top-metric.is-selected { background: color-mix(in srgb, var(--accent) 12%, var(--bg-elevated)); box-shadow: inset 0 -2px 0 var(--accent); }

/* ---- §4 Health rings — two small radial indicators inside the identity
   header. stroke-dasharray/offset are set inline by js/project-hub.js
   (setRing()); CSS only supplies track/value colour per semantic state
   and the compact label layout. Circumference math: r=20 → 2πr≈125.7,
   matching RING_CIRCUMFERENCE in project-hub.js. ---- */
/* (The old identity-header ring styles were removed — the health visual now
   lives in the right rail; see "Project Health" below.) */

/* ---- §6 Identity header plan thumbnail — reuses .hub-active-visual's
   existing 52px swatch box; once real run geometry exists the letter
   avatar is replaced with a tiny top-down plan (js/hub-intel.js
   renderIdentityThumb()), so the box gets a touch more room and a
   crisper inset so the rectangles read cleanly at this size. ---- */
.hub-active-visual[data-has-plan="true"] { width: 64px; height: 64px; padding: 0; background: var(--bg-sunken); }
.hub-identity-plan-svg { width: 100%; height: 100%; display: block; }
.hub-identity-plan-bg { fill: var(--bg-elevated-2); stroke: var(--border-strong); stroke-width: 0.5; }
.hub-identity-plan-run { fill: var(--accent); opacity: 0.85; }

/* ---- §10 Project Quick View — a right-side drawer, not a centred modal.
   Backdrop dims the page; the panel itself slides in from the edge.
   ~38% of desktop width per the brief, generous min/max so it never
   gets absurdly wide on ultra-wide monitors or unusably narrow on a
   laptop. ---- */
.hub-quickview-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(6, 7, 10, 0.55);
  opacity: 0; pointer-events: none;
  transition: opacity 180ms var(--ease-out);
}
.hub-quickview-backdrop.is-open { opacity: 1; pointer-events: auto; }
.hub-quickview {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 61;
  width: 38%; min-width: 340px; max-width: 480px;
  background: var(--bg-elevated); border-left: 1px solid var(--border-strong);
  box-shadow: var(--shadow-xl);
  display: flex; flex-direction: column;
  transform: translateX(100%);
  transition: transform 220ms var(--ease-out);
}
.hub-quickview.is-open { transform: translateX(0); }
.hub-quickview-head {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--border);
}
.hub-quickview-id { display: flex; align-items: center; gap: var(--space-3); flex: 1 1 auto; min-width: 0; }
.hub-quickview-swatch {
  flex: none; width: 40px; height: 40px; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 800; font-size: 15px; color: var(--accent);
  background: var(--accent-soft); border: 1px solid var(--accent-line);
}
.hub-quickview-id-text { min-width: 0; }
.hub-quickview-id-text h2 { margin: 0 0 2px; font-family: var(--font-display); font-size: 16px; font-weight: 800; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-quickview-id-text p { margin: 0; font-size: 12px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-quickview-body { flex: 1 1 auto; overflow-y: auto; padding: var(--space-4) var(--space-5); }
.hub-qv-grid { margin: 0; display: flex; flex-direction: column; }
.hub-qv-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); padding: 9px 0; border-top: 1px dashed var(--border); }
.hub-qv-row:first-child { border-top: none; }
.hub-qv-row dt { margin: 0; font-size: 12px; color: var(--text-faint); flex: none; }
.hub-qv-row dd { margin: 0; font-size: 12.5px; font-weight: 700; color: var(--text); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-quickview-foot { flex: none; padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border); }
.hub-quickview-open { width: 100%; justify-content: center; display: inline-flex; align-items: center; gap: 8px; min-height: 42px; }
@media (max-width: 719px) {
  /* Small screens: the drawer becomes a full-height sheet rather than a
     partial-width panel (§17) — same slide/backdrop mechanics, just full
     width so nothing is cramped against the edge of a phone screen. */
  .hub-quickview { width: 100%; min-width: 0; max-width: none; }
}

/* ---- §12 Recent Activity show-more — a plain text-button matching the
   existing .hub-rail-edit-link treatment, appended below the (now
   collapsed-by-default) activity list. ---- */
.hub-rail-showmore {
  display: block; width: 100%; margin-top: var(--space-2); padding: 6px 0;
  background: none; border: none; border-top: 1px dashed var(--border);
  font: inherit; font-size: 11px; font-weight: 700; color: var(--accent); cursor: pointer;
  text-align: center;
}
.hub-rail-showmore:hover { color: var(--text); }

/* =======================================================================
   WORKSPACE CLEAN-UP PASS — CAD / construction-management look.
   Appended last so it wins at equal specificity; only presentation changes
   (surface contrast, borders, padding, headings, list rows). No markup,
   JS or behaviour touched; every existing section/control is still shown.
   One system:  page = recessed (--bg-sunken)   panel = raised (--bg-elevated)
                panel header band = --bg-elevated-2 with a divider
                radius 6px   gap between panels 16px   panel padding 16px
   ===================================================================== */
.hub-body { background: var(--bg-sunken); }
.hub-main { padding: var(--space-5) var(--space-5) var(--space-7); }
.hub-layout, .hub-layout-main, .hub-workspace, .hub-main-block { gap: 16px; }
.hub-layout-main { display: flex; flex-direction: column; }
.hub-info-rail { gap: 16px; }

/* --- panels: same surface, border, radius everywhere ---------------- */
.hub-browser, .hub-dashboard, .hub-active-panel, .hub-setup-panel, .hub-rail-section,
.hub-continue, .hub-live-site, .hub-health, .hub-top-metrics, .hub-metric-card, .hub-intel-panel:not(.hub-intel-panel-quiet) {
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-shadow: none;
}
.hub-dashboard, .hub-rail-section, .hub-intel-panel:not(.hub-intel-panel-quiet), .hub-setup-panel { padding: 16px; }
/* the command-centre keeps one calm accent: a thin left bar, no glow/gradient */
.hub-dashboard::before { display: none; }
.hub-dashboard::after { width: 3px; background: var(--accent); opacity: 1; }
.hub-dashboard { padding-left: 20px; }

/* --- panel headings: small caps label on a divider band --------------- */
.hub-intel-panel-head, .hub-rail-section-head {
  margin: -16px -16px 12px; padding: 9px 16px;
  background: var(--bg-elevated-2); border-bottom: 1px solid var(--border-strong);
  border-radius: 6px 6px 0 0;
}
.hub-intel-panel-head h3, .hub-rail-section h3, .hub-health-title, .hub-section-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted);
}
.hub-rail-section > h3 { margin: -16px -16px 12px; padding: 9px 16px; background: var(--bg-elevated-2); border-bottom: 1px solid var(--border-strong); border-radius: 6px 6px 0 0; }
.hub-intel-panel-quiet { border-top: 1px solid var(--border-strong); padding-top: 10px; }

/* --- top metrics strip: one ruled instrument bar ---------------------- */
.hub-top-metrics { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 0; padding: 0; overflow: hidden; }
.hub-top-metric { padding: 12px 16px; border-left: 1px solid var(--border-strong); }
.hub-top-metric:first-child { border-left: 0; }
.hub-top-metric-value { font-family: var(--font-mono); font-weight: 800; font-variant-numeric: tabular-nums; }
.hub-top-metric-label { font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }
.hub-metrics { gap: 16px; }
.hub-metric-card { padding: 12px 14px; }

/* --- project list: ruled table-like rows ------------------------------- */
.hub-browser-head { padding: 12px 16px; background: var(--bg-elevated-2); border-bottom: 1px solid var(--border-strong); }
.hub-browser-tabs { padding: 10px 16px 0; border-bottom: 1px solid var(--border); }
.hub-browser-filters { padding: 10px 16px 0; }
.hub-project-list { padding: 8px 0 0; }
.hub-row { border-bottom: 1px solid var(--border); border-radius: 0; padding-left: 16px; padding-right: 16px; }
.hub-row:last-child { border-bottom: 0; }
.hub-row:nth-child(even) { background: color-mix(in srgb, var(--bg-elevated-2) 45%, transparent); }
.hub-row:hover { background: var(--bg-elevated-2); }
.hub-browser-foot { padding: 12px 16px; background: var(--bg-elevated-2); border-top: 1px solid var(--border-strong); }

/* --- intel stat grids and lists: aligned key/value rows ---------------- */
.hub-intel-stat-grid { gap: 0; }
.hub-intel-stat-grid > * { border-bottom: 1px solid var(--border); padding-top: 6px; padding-bottom: 6px; }
.hub-intel-stat-grid > *:last-child { border-bottom: 0; }
.hub-attention-global-list, .hub-live-site-list { border-radius: 6px; border-color: var(--border-strong); }
.hub-live-site-row { border-radius: 0; border-bottom: 1px solid var(--border); }

/* --- hierarchy of text inside the command centre ---------------------- */
.hub-dash-summary { padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.hub-next-action { border-radius: 6px; }

html[data-theme="light"] .hub-body { background: var(--bg-sunken); }
html[data-theme="light"] .hub-browser, html[data-theme="light"] .hub-dashboard, html[data-theme="light"] .hub-rail-section,
html[data-theme="light"] .hub-health, html[data-theme="light"] .hub-top-metrics { box-shadow: 0 1px 0 rgba(15, 30, 40, 0.04); }

@media (max-width: 760px) {
  .hub-main { padding: 12px 12px 24px; }
  .hub-top-metrics { grid-auto-flow: row; grid-template-columns: 1fr 1fr; }
  .hub-top-metric:nth-child(odd) { border-left: 0; }
  .hub-top-metric { border-top: 1px solid var(--border-strong); }
  .hub-top-metric:nth-child(-n+2) { border-top: 0; }
}

/* Filter tabs: counts + clearer empty state */
.hub-tab-count { margin-left: 4px; font-family: var(--font-mono); font-size: 10px; font-weight: 700; opacity: 0.75; font-variant-numeric: tabular-nums; }
.hub-browser-tab.is-active .hub-tab-count { opacity: 1; }
.hub-project-list-empty { margin: 12px 16px; padding: 18px 12px; border: 1px dashed var(--border-strong); border-radius: 6px; font-size: 13px; color: var(--text-muted); text-align: center; }

/* Project Health — operational detail (status / layout / installation / readiness) */
.hub-health { justify-content: flex-start; }
.hub-hd { width: 100%; display: flex; flex-direction: column; gap: 12px; margin-top: 4px; text-align: left; }
.hub-hd-sec { border-top: 1px solid var(--border-strong); padding-top: 8px; }
.hub-hd-sec h4 { margin: 0 0 4px; font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); }
.hub-hd-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 4px 0; border-bottom: 1px solid var(--border); font-size: 12px; color: var(--text); text-decoration: none; }
.hub-hd-row:last-child { border-bottom: 0; }
a.hub-hd-row:hover { background: var(--bg-elevated-2); }
a.hub-hd-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.hub-hd-key { color: var(--text-muted); flex: none; }
.hub-hd-val { text-align: right; font-variant-numeric: tabular-nums; min-width: 0; overflow-wrap: anywhere; }
.hub-hd-val.is-ok { color: var(--ok); }
.hub-hd-val.is-warn { color: var(--warn); }
.hub-hd-val.is-crit { color: var(--danger); font-weight: 700; }

/* Touch-friendly tab height (single row of six on desktop; wraps on narrow screens). */
.hub-browser-tab { min-height: 36px; touch-action: manipulation; }

/* Fixed app frame — header and sidebar stay put, only .hub-main scrolls.
   Scoped to the Hub (.hub-body) so no other module's shell changes. The
   existing shell classes are reused: .app-shell-body already clips and
   .app-sidebar-nav already scrolls independently when taller than the
   viewport; the body just needs a viewport-sized height so the document
   itself no longer scrolls. Collapsed/mobile sidebar behaviour untouched. */
.hub-body { height: 100vh; height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }
.hub-body > .app-shell-body { flex: 1 1 auto; min-height: 0; }
.hub-body .app-shell-main > .hub-main {
  flex: 1 1 auto; min-height: 0; min-width: 0;
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* =========================================================================
   HUB UI IMPROVEMENTS (five targeted changes)
   ========================================================================= */

/* 1. Left sidebar scrollbar — thin, minimal, no track/arrows. */
.hub-body .app-sidebar-nav,
.hub-body .app-sidebar {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--text-faint) 45%, transparent) transparent;
}
.hub-body .app-sidebar-nav::-webkit-scrollbar { width: 4px; height: 4px; }
.hub-body .app-sidebar-nav::-webkit-scrollbar-track { background: transparent; }
.hub-body .app-sidebar-nav::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.hub-body .app-sidebar-nav::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--text-faint) 40%, transparent); border-radius: 2px; }
.hub-body .app-sidebar-nav:hover::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--text-faint) 80%, transparent); }
.hub-body .app-sidebar-nav:hover { scrollbar-color: color-mix(in srgb, var(--text-faint) 80%, transparent) transparent; }

/* 2. Separation between the four top statistics and the project section. */
.hub-top-metrics { margin-bottom: var(--space-5); }

/* 3. Needs Attention — compact engineering-style status notice: neutral
   surface, thin warning edge, small icon; no large orange block. */
.hub-attention-bar {
  background: var(--bg-elevated); border: 1px solid var(--border); border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm); padding: 6px var(--space-3); gap: var(--space-2);
}
.hub-attention-bar > .icon { width: 14px; height: 14px; }
.hub-attention-bar-body { flex-direction: row; align-items: baseline; gap: var(--space-2); flex: 1 1 200px; }
.hub-attention-bar-body b { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--warn); flex: none; }
.hub-attention-bar-body p { font-size: 12px; min-width: 0; }
.hub-attention-bar-toggle { min-height: 28px; font-size: 11.5px; color: var(--text-muted); }
.hub-attention-bar-toggle:hover { color: var(--text); }

/* 4. Project Health — plain status rows (no rings / dots). */
.hub-health { min-height: 0; align-items: stretch; }
.hub-health-title { text-align: left; }
.hub-health-list { max-width: none; gap: 0; }
.hub-health-row-btn { grid-template-columns: 1fr auto; padding: 7px 4px; border-bottom: 1px solid var(--border); border-radius: 0; }
.hub-health-name { font-size: 12.5px; }
.hub-health-state {
  font-size: 11px; font-weight: 600; padding: 1px 7px; border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); color: var(--text-muted); white-space: nowrap;
}
.hub-health-row[data-state="complete"] .hub-health-state { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.hub-health-row[data-state="attention"] .hub-health-state { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 50%, transparent); }
.hub-health-row[data-state="notstarted"] .hub-health-state { color: var(--text-faint); }
.hub-health-modules { margin-left: 4px; padding: 4px 0 6px; }

/* 5. Project preview — compact floating panel instead of a slide-out
   drawer. No dimming backdrop: the page stays live so clicking another
   project simply updates the preview. */
.hub-quickview-backdrop { display: none; }
.hub-quickview {
  top: 50%; left: calc(50% + 104px); right: auto; bottom: auto;
  width: min(400px, calc(100vw - 32px)); min-width: 0; max-width: none;
  max-height: min(560px, calc(100dvh - 48px));
  border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  transform: translate(-50%, -48%); opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity 120ms var(--ease-out), transform 120ms var(--ease-out), visibility 0s linear 120ms;
}
.hub-quickview.is-open { transform: translate(-50%, -50%); opacity: 1; pointer-events: auto; visibility: visible; transition-delay: 0s; }
.hub-quickview-head { padding: var(--space-3) var(--space-4); }
.hub-quickview-swatch { width: 32px; height: 32px; font-size: 13px; }
.hub-quickview-body { padding: var(--space-2) var(--space-4); }
.hub-qv-row { padding: 6px 0; }
.hub-quickview-foot { padding: var(--space-3) var(--space-4); }
.hub-quickview-open { min-height: 36px; }
@media (max-width: 900px) {
  .hub-quickview { left: 50%; }
}
@media (prefers-reduced-motion: reduce) { .hub-quickview { transition: none; } }

/* Project Health — slim progress bar under each Design/Deliver/Operate row.
   Width comes from the same fill value the health state already uses. */
.hub-health-row-btn { row-gap: 6px; }
.hub-health-bar { grid-column: 1 / -1; display: block; height: 5px; border-radius: 3px; background: var(--border); overflow: hidden; }
.hub-health-bar-fill { display: block; height: 100%; border-radius: 3px; background: var(--accent); transition: width 240ms var(--ease-out); }
.hub-health-row[data-state="complete"] .hub-health-bar-fill { background: var(--ok); }
.hub-health-row[data-state="attention"] .hub-health-bar-fill { background: var(--warn); }
.hub-health-row[data-state="notstarted"] .hub-health-bar-fill { width: 0 !important; }
@media (prefers-reduced-motion: reduce) { .hub-health-bar-fill { transition: none; } }

/* ---------------------------------------------------------------------
   Recent Projects — visual definition (targeted pass). Scoped to the
   Project Hub's embedded browser (#hubWorkspace); markup, ids and every
   action are unchanged. Flat, hairline-bordered, navy header band.
--------------------------------------------------------------------- */
#hubWorkspace { margin-top: var(--space-4); }
#hubWorkspace .hub-browser {
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  /* no overflow:hidden — the per-row menu popover must not be clipped */
}
#hubWorkspace .hub-browser-body-head {
  margin: 0; padding: 8px var(--space-4);
  background: transparent;
  border-bottom: 1px solid var(--border-strong);
}
#hubWorkspace .hub-browser-body-head h2 {
  font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; font-weight: 800; color: var(--text);
}
#hubWorkspace .hub-browser-count {
  margin-right: auto; padding: 1px 8px; border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  font-size: 11px; font-weight: 700; color: var(--text-muted); background: var(--bg-elevated);
}
#hubWorkspace .hub-browser-tabs { padding: var(--space-3) var(--space-4) 0; }
#hubWorkspace .hub-browser-filters, #hubWorkspace .hub-pinned-toggle { padding-left: var(--space-4); padding-right: var(--space-4); }
#hubWorkspace .hub-project-list { padding: var(--space-3) 0 0; border-top: 1px solid var(--border); margin-top: var(--space-3); }
#hubWorkspace .hub-row { padding: 10px var(--space-4); border-bottom: 1px solid var(--border-strong); border-left-width: 3px; }
#hubWorkspace .hub-row-name { font-size: 13.5px; }
#hubWorkspace .hub-row-sub { font-size: 11.5px; color: var(--text-muted); }
#hubWorkspace .hub-row-when { font-size: 11px; color: var(--text-muted); }
#hubWorkspace .hub-project-list > .hub-row:nth-child(even) { background: var(--bg-sunken); }
#hubWorkspace .hub-project-list > .hub-row.is-selected { background: var(--accent-soft); border-left-color: var(--accent); }
#hubWorkspace .hub-browser-foot { padding: var(--space-3) var(--space-4); background: var(--bg-sunken); }

/* ---- Jobs Hub pass: header New Project, currently-open emphasis ---- */
.hub-topbar-new { white-space: nowrap; min-height: 38px; }
@media (max-width: 520px) { .hub-topbar-new { padding: 0 10px; font-size: 12px; } }
.hub-active-panel { border-left: 3px solid var(--accent); }
.hub-active-eyebrow { font-size: 10.5px; }
.hub-active-id h1 { font-size: 24px; }
.hub-row.is-open .hub-row-openflag { background: var(--accent-soft); font-weight: 800; }

/* ---- Hub V3: Next Action bar, available state, switcher, KPI row ---- */
.hub-next-bar {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding: 10px var(--space-4); border: 1px solid var(--accent-line); border-left: 3px solid var(--accent);
  border-radius: var(--radius-md); background: var(--bg-elevated);
}
.hub-next-bar[data-done="true"] { border-color: var(--border-strong); border-left-color: var(--ok); }
.hub-next-bar-label { font-family: var(--font-mono); font-size: 10.5px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); flex: none; }
.hub-next-bar-text { flex: 1 1 260px; min-width: 0; font-size: 13.5px; font-weight: 600; color: var(--text); }
.hub-next-bar-btn { flex: none; min-height: 34px; display: inline-flex; align-items: center; gap: 6px; }
.hub-dash-prog-step[data-status="available"] .hub-prog-circle { border-color: var(--border-strong); color: var(--text-muted); }
.hub-dash-prog-step[data-status="available"] .hub-prog-state { opacity: 0.8; }
.hub-dash-prog-step[role="link"]:hover .hub-prog-circle { border-color: var(--accent); }
.hub-dash-prog-step[role="link"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--radius-sm); }
.hub-project-switch { max-width: 220px; min-height: 38px; }
@media (max-width: 640px) { .hub-project-switch { max-width: 130px; } }
.hub-metrics { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }

/* Backup reminder — compact strip, no animation. */
.hub-backup-reminder { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin: 0 0 var(--space-3); padding: var(--space-2) var(--space-3); background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md, 8px); }
.hub-backup-reminder .icon { width: 16px; height: 16px; flex: none; color: var(--accent); }
.hub-backup-reminder-text { margin: 0; flex: 1 1 260px; min-width: 0; font-size: 12px; line-height: 1.5; color: var(--text-muted, var(--text)); }
.hub-backup-reminder-text strong { color: var(--text); }
.hub-backup-reminder-actions { display: flex; gap: var(--space-2); flex: none; }

/* UI polish overhaul — Hub: readable minimum label sizes (loaded after app-canvas.css, so restated here). */
.hub-dash-progress .hub-prog-text { font-size: 12px; white-space: normal; overflow-wrap: anywhere; }
.hub-dash-progress .hub-prog-state { font-size: 11px; }
.hub-metric-card .hub-metric-label { font-size: 12px; }
.hub-metric-card .hub-metric-sub { font-size: 12px; }
.hub-metric-value { font-variant-numeric: tabular-nums; }
.hub-dash-status-pill { font-size: 12px; }
.hub-next-bar-btn { min-height: 40px; }
@media (max-width: 900px) {
  .hub-topbar { flex-wrap: nowrap; gap: var(--space-2); }
  .hub-main { padding: var(--space-3); }
}

/* Final pre-deployment fix: Export/Import Project must stay reachable at tablet widths (wrap, never clip). */
@media (max-width: 1100px) {
  .hub-topbar { flex-wrap: wrap; row-gap: var(--space-2); }
  .hub-topbar-actions { flex-wrap: wrap; justify-content: flex-end; }
}
@media (max-width: 900px) {
  .hub-topbar { flex-wrap: wrap; }
}
