/* ===================================================================
   Halifax Developments Map — warm-paper design system  (Task B.2)
   Canonical theme locked 2026-05-18 (Spec v4 §2.8 + context/13 +
   design_system_warm_paper.html). Source of truth:
   docs/developments/source-of-truth/03-frontend-design.md §1–§2.

   SELF-CONTAINED: linked only by developments/*.html (never the main
   site). Mirrors the housing-guide/ precedent — no global bleed.
   Class names are load-bearing per the design digest — do not rename.

   Fonts: each developments/*.html <head> must include —
   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
   =================================================================== */

/* VL.P2.P1 — dev.css's competing :root RETIRED. It was the incomplete
   D76.A token-consolidation leftover: it redefined ~37 custom properties
   that ALSO live in _tokens.css and, because dev.css loads AFTER
   _tokens.css (see developments/index.html), it WON the cascade for all
   of them. For 12 tokens its value differed from _tokens.css — the stage
   palette (correct here, stale there) and the radius/type/shadow/surface
   scale (refined there, legacy here). That dual-source shadow was the
   exact bug that bit VL.P1 (a literal --text-muted shadowed the --ink-3
   alias). _tokens.css is now the SOLE source: it was first reconciled to
   these exact live values (provably zero rendered change), then this
   block was deleted. The font-family + status tokens were already
   byte-identical; --staff-bar/--customer-bar moved to _tokens aliases;
   --text-muted already pointed at var(--ink-3) (VL.P1). */

/* ---- Global base (standalone — developments pages only) ---- */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: var(--font-body);
  background: var(--bg-paper);
  color: var(--text);
  line-height: 1.55;
  font-size: var(--text-base);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  color: var(--text);
}
a { color: var(--accent-gold); text-decoration: none; }
a:hover { color: var(--accent-gold-hover); }
/* NAV-FIX (post-cutover walk) — body links inside the About panel are functional prose
   links on a near-white panel; the global gold color is ~2.03:1 (fails WCAG AA). Use legible
   ink with a gold underline (gold-as-ACCENT, not gold-as-text — the VL.P1 rule); gold returns
   on hover. The underline carries the affordance so color isn't load-bearing. */
#dev-about a {
  color: var(--ink-1);
  text-decoration: underline;
  text-decoration-color: var(--gold, #d4a84b);
  text-underline-offset: 2px;
}
#dev-about a:hover, #dev-about a:focus-visible { color: var(--accent-gold-hover); }
.tabular { font-variant-numeric: tabular-nums; }

/* =================== 2.1 Buttons =================== */
.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  padding: 9px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: all var(--duration-fast) var(--ease-out);
}
.btn-primary { background: var(--accent-gold); color: #111; }
.btn-primary:hover { background: var(--accent-gold-hover); color: #111; }

/* D76.D2 — Header "Contact" link demoted from .btn-primary gold pill.
 * Quiet secondary text link per HIG §1.3 (Helio attribution allowed,
 * never leading) + §2.1 ("CTAs in a data product are quiet"). */
.dev-topbar-contact {
  font: var(--weight-medium) var(--text-sm)/1 var(--font-body);
  color: var(--text-muted); text-decoration: none;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out);
}
.dev-topbar-contact:hover { color: var(--text); background: var(--bg-subtle); }
.btn-secondary {
  background: var(--bg-paper); color: var(--text);
  border-color: var(--border-strong);
}
.btn-secondary:hover { background: var(--bg-subtle); }
.btn-ghost { background: transparent; color: var(--text-muted); padding: 9px 0; }
.btn-ghost:hover { color: var(--text); }

/* =================== 2.2 Stage pills =================== */
.pill {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #fff;
}
.pill-proposed     { background: var(--stage-proposed); }
.pill-approved     { background: var(--stage-approved); }
.pill-construction { background: var(--stage-construction); color: #111; }
.pill-completed    { background: var(--stage-completed); }
.pill-inactive     { background: var(--stage-inactive); color: #374151; }

/* =================== 2.3 Confidence pills =================== */
.conf-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--text-xs); font-weight: 500;
  padding: 4px 10px; border-radius: 12px;
  border: 1px solid transparent;
}
.conf-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.conf-verified { background: rgba(22,163,74,0.10); color: var(--positive); border-color: rgba(22,163,74,0.25); }
.conf-single   { background: rgba(217,119,6,0.10); color: #b45309; border-color: rgba(217,119,6,0.25); }
.conf-unknown  { background: var(--bg-subtle); color: var(--text-muted); border-color: var(--border); }

/* =================== 2.4 Stat tile =================== */
.stat {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-md); padding: 14px 16px;
}
.stat .label {
  font-size: var(--text-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 6px;
}
/* v0.9.5 — terminal numerics: mono + tabular (Bloomberg) */
.stat .value {
  font-family: var(--font-mono); font-weight: 600;
  font-size: var(--text-2xl); line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.stat .sub { font-size: var(--text-xs); color: var(--text-muted); margin-top: 6px; }
.stat-row { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; }

/* =================== 2.5 Project card =================== */
.project-card {
  background: var(--bg-paper); border: 1px solid var(--border);
  border-radius: var(--radius-md); overflow: hidden;
  /* v0.9.5 — border, not shadow (Ive: hierarchy by line on calm paper) */
  transition: border-color var(--duration-fast) var(--ease-out);
}
.project-card:hover { border-color: var(--accent-gold); }
.project-card .photo {
  height: 140px; position: relative;
  background: linear-gradient(135deg,#c8c2bb,#e7e5e4);
}
.project-card .photo .pill { position: absolute; top: 12px; left: 12px; }
.project-card .body { padding: 16px; }
.project-card .name { font-size: var(--text-base); font-weight: 600; }
.project-card .addr { font-size: var(--text-xs); color: var(--text-muted); margin-top: 3px; }
.project-card .stats {
  display: flex; gap: 10px; font-size: var(--text-xs);
  color: var(--text-muted); margin-top: 10px;
}
.project-card .role-tag {
  font-size: 10px; color: var(--accent-gold); margin-top: 8px;
  text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600;
}

/* =================== 2.6 Accordion / right-rail panel =================== */
.panel {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-md); overflow: hidden;
  display: flex; flex-direction: column; height: 100%;
}
.panel-head {
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: baseline;
}
/* D77.C4 — Panel-title hierarchy lift per D77-VISUAL-AUDIT §5.2 / ship #6.
   Previously both nav-tier and project-tier panels rendered at text-lg
   (18px), flattening the hierarchy. Bump nav-tier to 22px so the
   project-panel title (text-display = 26px) reads as a clear step above
   it instead of one notch up. Reserves visual weight for the project,
   not the surface. */
.panel-title { font-family: var(--font-display); font-weight: 600; font-size: 22px; letter-spacing: -0.01em; }
.panel-close { color: var(--text-muted); cursor: pointer; }
.panel-close:hover { color: var(--text); }
.panel-meta {
  font-size: var(--text-xs); color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.05em; font-weight: 600; margin-top: 4px;
  display: flex; align-items: center; gap: 6px;
}
.panel-meta .pulse {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-gold); animation: dev-pulse 1.5s ease-in-out infinite;
}
.panel-section { padding: 12px 18px; border-bottom: 1px solid var(--border); cursor: pointer; }
.panel-section:last-child { border-bottom: none; }
.panel-section-head { display: flex; justify-content: space-between; align-items: center; }
/* D77.C4 — Section heads were 11px uppercase 600 everywhere, stacking
   six identical small-caps headers and flattening the rhythm
   (D77-VISUAL-AUDIT §5.1). Bump to 12.5px sentence-case 600 — uppercase
   is now reserved for true caption-tier metadata (ticker labels,
   stat-tile labels, .panel-meta). */
.panel-section-title {
  font-size: var(--text-sm); font-weight: 600;
  letter-spacing: 0.01em; color: var(--text);
}
.panel-section-count {
  font-size: var(--text-xs); color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
@keyframes dev-pulse { 0%,100% { opacity: .4; } 50% { opacity: 1; } }

/* D76.I — Quiet-week section + body. Larger paragraph treatment than
 * .dev-evt-empty (which is per-section); reads as editorial rather
 * than absence. Per HIG §5.4 + §9.3. */
.panel-section--quiet { padding: 14px 18px 18px; cursor: default; }
.dev-evt-quiet {
  margin-top: 6px;
  font: 400 var(--text-base)/1.55 var(--font-body);
  color: var(--text-secondary);
}

/* =================== 2.7 Map chrome =================== */
.map-overlay {
  position: absolute; padding: 10px 12px;
  background: rgba(250,250,249,0.96); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-sm);
  font-size: var(--text-xs);
}
.map-overlay-tl { top: 12px; left: 12px; }
.map-overlay-bl { bottom: 12px; left: 12px; }
.map-overlay .label {
  font-size: 9px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted);
  margin-bottom: 4px; display: block;
}
.legend-row { display: flex; align-items: center; gap: 6px; font-size: 10px; }
.legend-swatch { width: 10px; height: 10px; border-radius: 2px; }

/* =================== 2.8 Horizontal bar chart =================== */
.bar-chart {
  background: var(--bg-paper); border: 1px solid var(--border);
  border-radius: var(--radius-md); padding: 20px;
}
.bar-row {
  display: grid; grid-template-columns: 120px 1fr 80px; gap: 14px;
  align-items: center; padding: 10px 0; border-bottom: 1px solid var(--border);
}
.bar-row:last-child { border-bottom: none; }
.bar-track {
  background: var(--bg-sunken); height: 24px;   /* VL.P2.FU — track stays a recessed well after the --bg-subtle lift */
  border-radius: var(--radius-sm); overflow: hidden; position: relative;
}
.bar-fill { height: 100%; border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.bar-fill.staff    { background: var(--staff-bar); }
.bar-fill.customer { background: var(--customer-bar); }
.bar-value {
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--text-base); font-variant-numeric: tabular-nums;
  text-align: right;
}

/* =================== 2.9 CTA block =================== */
.cta-block {
  background: var(--bg-card); border: 1px solid var(--accent-gold);
  border-radius: var(--radius-md); padding: 20px 24px;
}
.cta-text { font-size: var(--text-base); margin-bottom: 12px; }
.cta-sub  { font-size: var(--text-xs); color: var(--text-muted); margin-top: 8px; }

/* =================== 2.10 Illustration slot (placeholder) =================== */
.illo-slot {
  background: linear-gradient(135deg,var(--bg-card),var(--bg-sunken));   /* VL.P2.FU — keep gradient depth after the lift */
  border: 1px dashed var(--border-strong); border-radius: var(--radius-md);
  padding: 40px; text-align: center;
}
.illo-slot .icon { font-family: var(--font-display); font-size: 32px; color: var(--text-muted); }
.illo-slot .label {
  font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-muted); margin-top: 8px;
}
.illo-slot .note { font-size: 11px; color: var(--text-faint); font-style: italic; margin-top: 6px; }

/* =================== 3. App chrome (B.3 header/rail) =================== */
/* v0.9.5 — Apple × Bloomberg × Ive: the map is the product; the
   chrome is a quiet, exact instrument. Greyscale, recedes; the one
   gold is the single call to action. Numbers are a Bloomberg status
   line (mono, tabular). */
.dev-topbar {
  height: 56px; display: flex; align-items: center; justify-content: space-between;
  padding: 0 20px; background: var(--bg-paper); border-bottom: 1px solid var(--border);
  position: relative; /* anchor for .dev-search-bar-dropdown */
}

/* F6.4.F.UI (2026-05-27) — center wrapper holds the new search bar +
 * the existing ticker, side by side, between brand and contact. */
.dev-topbar-center {
  display: flex; align-items: center; gap: 18px;
  flex: 1; justify-content: center;
  min-width: 0; /* allow children to shrink */
  margin: 0 24px;
}

/* ── F6.4.F.UI: identity-aware search bar ─────────────────────────
 * The input is the F5 §11 entry point. The glyph + help-text are
 * subtle; the dropdown appears below the topbar (position: absolute
 * relative to .dev-topbar so it can overflow into the map area). */
.dev-search-bar {
  position: relative; flex: 0 1 320px; min-width: 200px; max-width: 380px;
}
.dev-search-bar-glyph {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  color: var(--text-muted); font-size: 14px; pointer-events: none;
  line-height: 1;
}
.dev-search-bar-input {
  width: 100%; height: 34px; box-sizing: border-box;
  padding: 0 12px 0 30px;
  background: var(--bg-subtle, #f7f7f7); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm, 4px);
  font-family: var(--font-body, inherit); font-size: 13px; line-height: 1.4;
  transition: border-color var(--duration-fast, 150ms) var(--ease-out, ease-out),
              background-color var(--duration-fast, 150ms) var(--ease-out, ease-out);
}
.dev-search-bar-input::placeholder { color: var(--text-muted); }
.dev-search-bar-input:hover { background: var(--bg-paper); }
.dev-search-bar-input:focus {
  outline: none; background: var(--bg-paper);
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(212, 168, 75, 0.18);
}
.dev-search-bar-help {
  /* Visually hidden but exposed to screen readers via aria-describedby. */
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap;
}

/* Dropdown anchored to the input. position: absolute relative to
 * .dev-search-bar (which is position: relative). Bumps above ticker
 * via z-index. Width matches the input + small flare. */
.dev-search-bar-dropdown {
  position: absolute; top: calc(100% + 6px); left: -8px; right: -8px;
  background: var(--bg-paper); border: 1px solid var(--border);
  border-radius: var(--radius-md, 8px);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16), 0 2px 6px rgba(0, 0, 0, 0.08);
  max-height: 480px; overflow-y: auto;
  z-index: 200;
}
.dev-search-bar-dropdown[hidden] { display: none; }

.dev-search-bar-result {
  display: block; padding: 10px 14px; text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--border-faint, var(--border));
  transition: background-color var(--duration-fast, 150ms) var(--ease-out, ease-out);
}
.dev-search-bar-result:last-child { border-bottom: none; }
.dev-search-bar-result:hover,
.dev-search-bar-result.is-active {
  background: var(--bg-subtle, #f7f7f7);
}
.dev-search-bar-result:focus-visible {
  outline: 2px solid var(--gold); outline-offset: -2px;
}

.dev-search-bar-result-line1 {
  display: flex; align-items: center; gap: 8px; min-width: 0;
}
.dev-search-bar-result-name {
  font-size: 13.5px; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto;
}
.dev-search-bar-result-line2 {
  margin-top: 3px; font-size: 11.5px; color: var(--text-muted); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Stage badge inside results — mirrors the panel-v5 / today stage
 * vocabulary (5 colors). The data-stage attribute carries the value. */
.dev-search-bar-stage {
  flex-shrink: 0;
  display: inline-block; padding: 2px 7px;
  font-size: 10px; font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase;
  border-radius: 3px;
  background: var(--bg-subtle, #f0f0f0); color: var(--text-muted);
}
/* VL.P2.P5 — realigned to the canonical stage palette. These were SCRAMBLED:
   construction rendered green (#2d6b3d) and completed rendered blue (#1e4ea8),
   contradicting the rest of the product (construction=gold, completed=green),
   and proposed was an exact duplicate of approved (both purple). Now each
   stage's tinted badge matches its system colour, with AA-darkened text
   (construction/completed reuse the evt-stage AA values #806012/#246b3f). */
.dev-search-bar-stage[data-stage="construction"]   { background: rgba(212, 168, 75, 0.18); color: #806012; }
.dev-search-bar-stage[data-stage="completed"]      { background: rgba(22, 163, 74, 0.14);  color: #246b3f; }
.dev-search-bar-stage[data-stage="approved"]       { background: rgba(37, 99, 235, 0.12);  color: #1e4ea8; }
.dev-search-bar-stage[data-stage="proposed"]       { background: rgba(124, 108, 174, 0.16); color: #5b3aa8; }
.dev-search-bar-stage[data-stage="announced"]      { background: rgba(229, 162, 59, 0.18); color: #8a5a13; }
.dev-search-bar-stage[data-stage="inactive"]       { background: rgba(148, 163, 184, 0.18); color: #475569; }

.dev-search-bar-empty {
  padding: 16px 14px; font-size: 12.5px; color: var(--text-muted); line-height: 1.5;
}

/* Mobile: hide search on narrow screens; the rail icon for Explore
 * still serves as a catalog finder there. */
@media (max-width: 720px) {
  .dev-search-bar { display: none; }
  .dev-topbar-center { justify-content: flex-end; }
}
/* D85.1 (S5) — Brand became an anchor in header.js. Keep visual identical
 * to the pre-D85 span (no link-color, no underline) but expose subtle
 * hover affordance + match the topbar-contact treatment. */
.dev-brand { display: flex; align-items: center; gap: 12px;
  text-decoration: none; color: inherit;
  padding: var(--space-1, 4px) var(--space-2, 8px); margin: 0 calc(-1 * var(--space-2, 8px));
  border-radius: var(--radius-sm);
  transition: background-color var(--duration-fast) var(--ease-out);
}
.dev-brand:hover { background: var(--bg-subtle); }
.dev-brand:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* D77.C1 -> #1138 — Brand mark. D77.C1 fixed the pre-D77 bare 26x26 "H"
   (a stretched favicon) into a 32x32 charcoal text-tile. #1138 (2026-06-06)
   replaces the typeset "H" with a designed inline-SVG monogram-as-architecture
   ("Massing / gold grade-line", owner-approved over alt D): two off-white stems
   of unequal height (built vs unbuilt headroom) on a single gold grade-line —
   the datum every height is measured from. The SVG paints its own charcoal rx6
   tile + glyph, so this rule is now just a 32x32 rounded, depth-shadowed,
   overflow-clipped frame (the old bg/color/Outfit text-tile props are gone). */
.dev-brand-mark {
  width: 32px; height: 32px; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.18);
  flex-shrink: 0;
}
.dev-brand-mark svg { display: block; width: 100%; height: 100%; }
.dev-brand-text {
  display: flex; flex-direction: column; line-height: 1.15;
  gap: 1px;
}
.dev-brand-text small {
  font-size: 11px; font-weight: 500; color: var(--text-muted);
  letter-spacing: 0.06em; text-transform: uppercase;
}
.dev-brand-text strong {
  font-size: 14px; font-weight: 600;
  letter-spacing: -0.005em; color: var(--text);
  font-family: var(--font-display);
}

/* D77.C2 — Ticker typography per D77-VISUAL-AUDIT §5.2 / ship #3.
   Pre-D77: 11px uppercase mono with negative tracking — read as
   Bloomberg terminal output, which sets the wrong frame ("look at the
   numbers!") for a data-craft product where the map is the headline.
   Now: 12.5px sentence-case mono with positive tracking; values still
   bold-tabular, labels still faint. Adds :hover affordance + cursor
   pointer (the chips look drillable — they should respond to clicks
   once the filter-apply binding lands). */
.dev-ticker {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 12.5px; letter-spacing: 0.005em;
  color: var(--text-muted);
}
.dev-tick {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 2px 4px; margin: -2px -4px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.dev-tick:hover {
  background: var(--bg-subtle);
  color: var(--text);
}
.dev-tick strong {
  color: var(--text); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* D77.C2.b — Ticker separator was border-strong (#d1d5db), reading as
   a table-cell divider. Drop to ink-4 (#9ca3af) so the dots stop
   structuring the line into cells. */
.dev-tick-sep { color: var(--ink-4); margin: 0 2px; }
/* D77.A1 — Mobile ticker overflow. At 375px viewport the ticker wraps
   into 5–6 rows, blowing the topbar from 56px to 212px and pushing
   content under it (D77-VISUAL-AUDIT §1.2). Hide the full ticker below
   the small-tablet breakpoint; the active-projects count is already
   surfaced in the panel meta and the map itself is the headline.
   When designing a condensed mobile alternative, lift this rule first.
   D85.1 (F6) — Contact link was 29px tall on mobile (sub-WCAG-44px
   touch target). Bump to a 44px min-height in mobile context. */
@media (max-width: 540px) {
  .dev-ticker { display: none; }
  .dev-topbar-contact {
    min-height: 44px; display: inline-flex; align-items: center;
    padding-left: var(--space-3, 12px); padding-right: var(--space-3, 12px);
  }
  .dev-brand { min-height: 44px; }
}
/* v0.13.1 (D45) — Apple-leaning hybrid rail. Consumer product, not a
   Bloomberg instrument: chrome that's quiet at rest, soft when engaged.
   One coordinated transition (.12s ease-out) on the two properties
   that actually change. No box-shadow easing (active edge is binary).
   No translate on the label (Apple doesn't bounce things on hover).
   Hidden labels at rest, gentle .16s fade on engage. */
.dev-rail {
  width: 60px; background: var(--bg-paper);
  border-left: 1px solid var(--border);
  display: flex; flex-direction: column; align-items: center;
  padding: 12px 0; gap: 2px;
}
/* D77.C3 — Rail icon hit area + active state per D77-VISUAL-AUDIT
   ship #4 + #5 + #10. Pre-D77:
   - 48×52 (off-grid, rounded-to-edge)
   - 8.5px uppercase labels (below the HIG 11px legibility floor)
   - active state was layered (bg + 2px shadow + color shift)
   Now:
   - 48×48 square on the 8px grid with radius-md corners (discrete hit
     area, consistent with the rest of the system)
   - native `title` tooltip carries the label name on desktop hover
     (`title` is already set in header.js render); the 8.5px text is
     dropped at desktop, kept at mobile where tooltips don't fire
   - active state is one signal cleanly executed: surface-2 bg + 3px
     gold inset shadow */
.dev-rail-icon {
  width: 48px; height: 48px; border: none; background: transparent; cursor: pointer;
  border-radius: var(--radius-md);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  color: var(--text-faint);
  transition: color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out);
  position: relative;
}
.dev-rail-icon:hover { background: var(--bg-subtle); color: var(--text); }
.dev-rail-icon.active {
  background: var(--surface-2); color: var(--text);
  box-shadow: inset 3px 0 0 var(--gold);
}
/* P1 (IA v2) — group separator between rail scope-tiers (discover · yours · ops).
   Inserted by nav-registry.js only when the IA-v2 flag is on; absent otherwise. A
   thin centred divider on the 60px vertical rail. */
.dev-rail-sep {
  width: 24px; height: 1px; margin: 6px 0;
  background: var(--border);
  flex: 0 0 auto;
}
/* P1.2 (IA v2) — recency scope caption under a panel head. Rendered only when the
   IA-v2 flag is on (today.js / movement-brief.js); muted, on the shared type scale. */
.panel-caption {
  margin: 6px 0 0; padding: 0;
  font-size: var(--text-sm); line-height: 1.4; color: var(--ink-3, var(--text-faint));
}
.panel-caption__jump {
  display: inline; margin-left: 6px; padding: 0;
  background: none; border: none; cursor: pointer;
  font: inherit; color: var(--ink-2, var(--text)); text-decoration: underline;
  text-underline-offset: 2px;
}
.panel-caption__jump:hover { color: var(--text); }
.dev-rail-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px;
}
.dev-rail-glyph svg { display: block; width: 20px; height: 20px; }
.dev-rail-label {
  /* Hidden at desktop — native title attribute handles the hint on hover.
     Mobile keeps the label visible (touch surfaces have no tooltip), but
     at 11px sentence-case, not 8.5px uppercase. */
  display: none;
}
@media (max-width: 540px) {
  .dev-rail-label {
    display: block;
    font-size: 11px;
    letter-spacing: 0.02em;
    text-transform: none;
    opacity: 0.85;
  }
}

/* =================== 3.1 Today event cards (B.5) =================== */
.dev-evt-list { padding: 4px 8px 8px; }
.dev-evt {
  display: grid; grid-template-columns: 48px 1fr; gap: 10px; align-items: center;
  padding: 8px 10px; border-radius: var(--radius-sm); cursor: pointer;
}
.dev-evt:hover { background: var(--bg-subtle); }
.dev-evt-thumb {
  width: 48px; height: 48px; border-radius: var(--radius-sm);
  background: linear-gradient(135deg, #d6d3d1, #e7e5e4); background-size: cover;
  display: flex; align-items: center; justify-content: center;
}
/* D65.D — Initials placeholder: charcoal pill with gold initials so each
   no-photo event still has a sense of identity. Replaces the generic
   `▥` unicode square that gave every empty card the same washed-out
   look. JetBrains Mono matches the rail-icon typographic style. */
.dev-evt-thumb.no-photo {
  /* VL.P1 — was a dark charcoal tile + gold initials (a dark-theme remnant).
     Inside the light faces --charcoal-700 remaps to --surface-2, leaving gold
     initials on a near-white tile (2.03:1). The product is warm-paper now, so
     make the placeholder a light tile with muted-ink initials + a hairline —
     legible (ink-3 = 4.6:1) and consistent everywhere. */
  background: var(--surface-2, #f5f5f4);
  border: 1px solid var(--line, #e7e5e4);
  color: var(--ink-3, #67707c);
  font: 600 13px/1 var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  letter-spacing: 0.02em;
}

/* D65.E — Explore catalog panel additions */
.dev-explore-body {
  padding: 12px 14px 14px;
  display: flex; flex-direction: column; gap: 10px;
}
.dev-explore-toggle {
  display: flex; align-items: center; gap: 8px;
  font: 500 12px/1.3 var(--font-body);
  color: var(--text-muted); cursor: pointer;
  padding: 4px 0;
}
.dev-explore-toggle input { cursor: pointer; }
.dev-explore-count {
  font: 500 11px/1.2 var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  color: var(--text-muted); padding: 0 14px;
}
.dev-explore-more {
  display: block; width: 100%;
  margin: 12px 0 4px;
  padding: 10px 12px;
  background: var(--bg-paper); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: 500 12px/1.3 var(--font-body); color: var(--text);
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.dev-explore-more:hover { border-color: var(--text-muted); background: var(--bg-subtle); }
/* Track-2 unified Explore — "Show all tracked projects (N)" collapses the dormant tail. */
.dev-explore-showall {
  display: block; width: 100%; margin: 14px 0 4px; padding: 10px 12px;
  background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-sm);
  font: 600 12px/1.3 var(--font-body); color: var(--text-muted); cursor: pointer; text-align: center;
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.dev-explore-showall:hover { border-color: var(--text-muted); color: var(--text); }
.dev-explore-dormant-head {
  margin: 14px 0 6px; padding-top: 10px; border-top: 1px solid var(--border);
  font: 600 10px/1.3 var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted);
}
/* D77.C5 — Stage chip per D77-VISUAL-AUDIT ship #8. Pre-D77 was 9.5px
   uppercase mono — read as a debug label, not a status. Now: 11px
   sentence-case Inter with a coloured dot prefix (drawn via the
   :before below) so the eye reads the colour before the word. Matches
   the HIG §4 chip system and the rest of the project-panel chips. */
.dev-evt-stage {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 8px;
  padding: 2px 8px;
  font: 500 11px/1.3 var(--font-body);
  letter-spacing: 0;
  color: var(--text);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  vertical-align: 1px;
}
.dev-evt-stage::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
/* VL.P1 — darkened the event-feed stage-pill text to clear AA on the
   #ebeae8 pill (completed 4.38→5.37, construction/amber 3.29→4.85,
   proposed 4.43→5.56). approved #2d6da3 already passed. The ::before dot
   uses currentColor so it darkens in step. */
.dev-evt-stage[data-stage="completed"] { color: #246b3f; border-color: rgba(36,107,63,0.32); }
.dev-evt-stage[data-stage="construction"] { color: #806012; border-color: rgba(128,96,18,0.32); }
.dev-evt-stage[data-stage="approved"] { color: #2d6da3; border-color: rgba(45,109,163,0.3); }
.dev-evt-stage[data-stage="proposed"] { color: #5c5c5c; }
/* VL.P2.P5 — `inactive` is EMITTED (panels.js STAGE_BADGE) but had no rule, so
   it fell through to base color:var(--text) (near-black) — read as an active
   stage. Give it a dormant grey (AA ~5.7 on the #ebeae8 pill; rises if the bg
   lifts in P6). dot uses currentColor so it tracks. */
.dev-evt-stage[data-stage="inactive"] { color: #595959; border-color: rgba(89,89,89,0.26); }

/* D65.G — Photos strip inside This Week. Horizontal scrollable row of
   small cards (photo + project + relative date). Click on a card opens
   the project panel on its Photos lens. No animation (Skeptic
   resolution: data is the point, not motion). */
.panel-section--photos { padding-bottom: 4px; }
.dev-photo-strip {
  /* D-GALLERY (2026-06-02) — was a single horizontal scroll line: only ~2 cards
     visible at the 373px rail width, so the newest blog tiles (index 17+ behind a
     Facebook burst) were never seen. Now a compact 3-row, horizontally-scrollable gallery — a prominent
     2-3+ row gallery of the newest photos across BOTH feeds (FB + blog), each tile
     clickable through to its project. Pure global-newest order (per-project is
     intentionally NOT deduped). */
  display: grid;
  grid-template-rows: repeat(3, auto); grid-auto-flow: column; grid-auto-columns: 122px; overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: thin;
  gap: 8px;
  padding: 4px 14px 10px;
}
.dev-photo-card {
  /* D-GALLERY — the grid sizes the card now (was flex:0 0 auto; width:132px;
     scroll-snap-align:start for the old horizontal strip). */
  width: auto;
  text-decoration: none;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--bg-paper);
  border: 1px solid var(--border);
  display: flex; flex-direction: column;
  transition: border-color var(--duration-fast) var(--ease-out);
}
.dev-photo-card:hover { border-color: var(--text-muted); }
.dev-photo-card-img {
  /* D75.K — was background-image div; now native <img>. The
     aspect-ratio + object-fit keep visual parity with the old
     background-size: cover behavior. background-color stays as
     the loading placeholder. */
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: center;
  background-color: var(--bg-subtle);
  border: none;
}
.dev-photo-card-caption {
  padding: 6px 8px 8px;
  display: flex; flex-direction: column;
  font-size: 11px; line-height: 1.3;
}
.dev-photo-card-project {
  font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dev-photo-card-date {
  color: var(--text-muted); font-size: 10px;
}
/* #2 (2026-06-02) — source-attribution pill overlaid on the card so a viewer
   can tell FB-archive vs blog photos at a glance. The card is overflow:hidden;
   the badge sits inside its bounds (top/left 6px) so it isn't clipped. */
.dev-photo-card { position: relative; }
.dev-photo-card-source {
  position: absolute; top: 6px; left: 6px; z-index: 1;
  padding: 2px 6px; border-radius: var(--radius-pill, 999px);
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.02em; line-height: 1.25;
  color: #fff; background: rgba(20, 22, 28, 0.72);
  pointer-events: none;
}
.dev-photo-card-source--fb { background: rgba(24, 60, 120, 0.84); }
.dev-photo-card-source--blog { background: rgba(45, 45, 45, 0.82); }
.dev-evt-line { font-size: 12.5px; }
.dev-evt-verb { font-weight: 600; }
.dev-evt-name { font-weight: 600; }
.dev-evt-meta { font-size: 10.5px; color: var(--text-muted); margin-top: 2px; }
.dev-evt-dev { color: var(--ink-2); font-weight: 600; }  /* VL.P1 — was gold (2.03:1 on the light feed); ink-2 (9.45) + weight for the applicant name. */
.dev-evt-empty { font-size: var(--text-xs); color: var(--text-faint); padding: 6px 4px; }

/* =========== 3.1b Brief — YOUR-HALIFAX Development-Updates (S1.2) ===========
   The Explore "Brief" view: a daily-return feed of Development-Update cards
   (material event + the HELIO ANALYSIS it triggered + anonymous Follow).
   Reuses .dev-evt-thumb + .dev-evt-stage; light-panel tokens throughout. */

/* Brief / Catalog mode toggle (segmented control). */
.dev-brief-mode {
  display: inline-flex; gap: 2px;
  background: var(--bg-subtle); border: 1px solid var(--border);
  border-radius: var(--radius-pill); padding: 2px;
  align-self: flex-start;
}
.dev-brief-mode__btn {
  border: 0; background: transparent; cursor: pointer;
  padding: 5px 16px; border-radius: var(--radius-pill);
  font: 600 12px/1.2 var(--font-body); color: var(--text-muted);
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.dev-brief-mode__btn:hover { color: var(--text); }
.dev-brief-mode__btn.is-active {
  background: var(--bg-paper); color: var(--text);
  box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.08));
}

.dev-brief { display: flex; flex-direction: column; gap: 10px; }
.dev-brief__intro { display: flex; flex-direction: column; gap: 1px; padding: 2px 2px 0; }
.dev-brief__intro-lead {
  font: 600 14px/1.2 var(--font-display); color: var(--text); letter-spacing: -0.01em;
}
.dev-brief__intro-meta {
  font: 500 11px/1.3 var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  color: var(--text-muted);
}

/* Inert "saved on this device" nudge — revealed after the first Follow. */
.dev-brief-nudge {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 9px 11px;
  background: rgba(212,168,75,0.08);
  border: 1px solid rgba(212,168,75,0.35);
  border-radius: var(--radius-md);
}
.dev-brief-nudge[hidden] { display: none; }
.dev-brief-nudge__icon { color: var(--accent-gold); font-size: 14px; line-height: 1.4; }
.dev-brief-nudge__text { font: 400 11.5px/1.45 var(--font-body); color: var(--text); display: flex; flex-direction: column; gap: 4px; }
.dev-brief-nudge__text strong { font-weight: 600; }
.dev-brief-nudge__msg { color: var(--text); }
.dev-brief-nudge__cta {
  align-self: flex-start; margin-top: 2px;
  font: 600 11.5px/1 var(--font-body); color: var(--charcoal-900, #141414);
  background: var(--accent-gold); border: 0; border-radius: var(--radius-sm, 6px);
  padding: 6px 10px; cursor: pointer;
}
.dev-brief-nudge__cta:hover { filter: brightness(1.06); }
.dev-brief-nudge__cta[hidden] { display: none; }

.dev-update-list { display: flex; flex-direction: column; gap: 6px; }

/* The Development-Update card. */
.dev-update {
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-paper);
  overflow: hidden;
  transition: border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out);
}
.dev-update:hover { border-color: var(--text-muted); box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.06)); }
.dev-update__main {
  display: grid; grid-template-columns: 48px 1fr; gap: 11px; align-items: start;
  padding: 11px 12px 9px; cursor: pointer;
}
.dev-update__main .dev-evt-thumb { width: 48px; height: 48px; }
.dev-update__body { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.dev-update__head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.dev-update__name {
  font: 600 13.5px/1.25 var(--font-display); color: var(--text);
  letter-spacing: -0.01em;
}
.dev-update__change { font: 400 12px/1.4 var(--font-body); color: var(--text-2, #3a3a3a); }
.dev-update__verb { font-weight: 600; color: var(--text); }

/* HELIO ANALYSIS badge — only when a current+approved narrative joined. */
.dev-update__analysis {
  margin-top: 3px; padding: 8px 10px;
  background: var(--bg-subtle); border-left: 2px solid var(--accent-gold);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.dev-update__analysis-tag {
  display: inline-block; margin-bottom: 3px;
  font: 700 9px/1 var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-gold);
}
.dev-update__thesis { display: block; font: 600 11.5px/1.35 var(--font-body); color: var(--text); }
.dev-update__snippet { margin: 2px 0 0; font: 400 11px/1.45 var(--font-body); color: var(--text-muted); }

.dev-update__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 12px 8px 71px; /* 71 = 48 thumb + 11 gap + 12 pad, aligns with body */
  border-top: 1px solid var(--border-faint, rgba(0,0,0,0.05));
}
.dev-update__when {
  font: 500 10.5px/1.3 var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
  color: var(--text-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dev-update__src { color: var(--text-muted); }
/* Track-2 unified Explore — the "Moved · <when>" stamp dot + gold "recent" affordance
   (≤30 days), and the honest undated state. Reuses --accent-gold / --text-muted. */
.dev-update__dot {
  display: inline-block; margin-right: 5px; font-size: 9px; line-height: 1;
  color: var(--text-muted); vertical-align: baseline;
}
.dev-update__dot.is-recent { color: var(--accent-gold, #d4a84b); }
.dev-update__undated { color: var(--text-muted); font-style: italic; }
.dev-follow-btn {
  flex: 0 0 auto;
  border: 1px solid var(--border-strong, #ccc); background: var(--bg-paper);
  color: var(--text); cursor: pointer;
  padding: 4px 12px; border-radius: var(--radius-pill);
  font: 600 11px/1.2 var(--font-body);
  transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.dev-follow-btn:hover { border-color: var(--accent-gold); color: var(--accent-gold); }
.dev-follow-btn.is-following {
  background: var(--accent-gold); border-color: var(--accent-gold); color: #1f1f1f;
}

/* =================== 3.2 Project Lens (B.7) =================== */
.dev-lens-hero {
  height: 160px; position: relative; display: flex; align-items: flex-end;
  padding: 12px; background: linear-gradient(135deg, #c8c2bb, #e7e5e4);
}
.dev-lens-hero.stage-construction { background: linear-gradient(135deg, #e6c98a, #d8a035); }
.dev-lens-hero.stage-completed { background: linear-gradient(135deg, #9fd6b0, #16a34a); }
.dev-lens-hero.stage-approved { background: linear-gradient(135deg, #9dbcf2, #2563eb); }
.dev-lens-body { padding: 4px 18px 12px; font-size: var(--text-sm); }
.dev-attr-row, .dev-pl-row {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 5px 0; border-bottom: 1px solid var(--border); font-size: var(--text-sm);
}
.dev-attr-row:last-child, .dev-pl-row:last-child { border-bottom: none; }

/* =================== 3.3 Search / Filter / Photos / About (B.8) ========= */
.dev-search-input {
  width: 100%; padding: 9px 12px; font: inherit; font-size: var(--text-sm);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--bg-paper); color: var(--text);
}
.dev-search-results { margin-top: 10px; }
.dev-search-row {
  display: flex; flex-direction: column; gap: 2px; padding: 8px 10px;
  border-radius: var(--radius-sm); cursor: pointer;
}
.dev-search-row:hover { background: var(--bg-subtle); }
.dev-search-row span { font-size: var(--text-xs); color: var(--text-muted); }
/* D53.4 — richer search rows: stage badge + showcase star + units */
.dev-search-row-head {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--text-sm);
}
.dev-search-row-head strong { flex: 1; font-weight: 500; color: var(--text); }
.dev-search-row-meta {
  display: flex; align-items: baseline; gap: 8px;
  font-size: var(--text-xs); color: var(--text-muted);
}
.dev-search-showcase {
  color: var(--accent-gold, #c89938); font-size: 11px; line-height: 1;
}
.dev-search-stage {
  font-size: 10px; padding: 2px 6px; border-radius: 8px;
  background: var(--bg-subtle); color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.dev-search-stage[data-stage="construction"] {
  background: rgba(224,163,46,0.15); color: #8b6914;
}
.dev-search-stage[data-stage="approved"] {
  background: rgba(37,99,235,0.12); color: #1a4daa;
}
.dev-search-stage[data-stage="proposed"] {
  background: rgba(124,108,174,0.15); color: #4d3f7d;
}
.dev-search-stage[data-stage="completed"] {
  background: rgba(22,163,74,0.12); color: #0f6535;
}
/* D77.C5 — Filter chip system per D77-VISUAL-AUDIT ship #7. Pre-D77:
   active chip was saturated gold fill — louder than the panel title,
   reading as a CTA when it's actually just a filter state. Now: quiet
   gold-faint background + gold border (the HIG §4 chip-active pattern
   that was specced but never applied here). Radius bumped from off-
   scale 16px to canonical --radius-pill (999) so all pill controls
   live on the same scale. Hover deepens the border alone. */
.dev-filter-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.map-filter-chip {
  font: 500 var(--text-sm)/1.3 var(--font-body);
  padding: 5px 12px; border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong); background: var(--bg-paper);
  color: var(--text); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}
.map-filter-chip:hover { border-color: var(--text-muted); }
.map-filter-chip.active {
  background: var(--gold-faint);
  color: var(--gold-dark);
  border-color: var(--gold);
  font-weight: 600;
}
.dev-filter-field { display: flex; flex-direction: column; gap: 4px; font-size: var(--text-xs); color: var(--text-muted); }
.dev-filter-field select {
  font: inherit; font-size: var(--text-sm); padding: 7px 10px; color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--bg-paper);
}
.dev-photo-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; padding: 14px 18px; }
.dev-photo { margin: 0; }
.dev-photo-img {
  aspect-ratio: 4/3; border-radius: var(--radius-sm);
  background: linear-gradient(135deg, #d6d3d1, #e7e5e4) center/cover;
}
.dev-photo figcaption { font-size: 10px; color: var(--text-muted); margin-top: 4px; }
.dev-quote {
  margin: 14px 0; padding: 10px 14px; font-style: italic;
  border-left: 3px solid var(--accent-gold); color: var(--text-secondary);
}

/* META-C (mobile/iPad arc) — 16px floor on focusable inputs for coarse pointers
   so iOS Safari does not auto-zoom on focus (CLAUDE.md ground-rule 4). Desktop
   info-density (13 / 12.5px) is unchanged; the --text-sm token is left alone. */
@media (pointer: coarse) {
  .dev-search-bar-input,
  .dev-search-input,
  .admin-gate-input { font-size: 16px; touch-action: manipulation; }
}

/* =================== 3.4 App shell layout =================== */
.dev-shell { display: grid; grid-template-rows: 56px 1fr; height: 100vh; height: 100dvh; } /* META-B: dvh (100vh fallback) */
/* D65.B — panel column now flexes between 420px (min) and 540px (max).
   Previously hard-coded at 380px, which forced tab-bar overflow and
   cramped lens content even on 1920px viewports. minmax keeps the
   map prominent at narrow widths while letting the panel breathe on
   wide monitors. */
.dev-main { display: grid; grid-template-columns: 1fr minmax(420px, 540px) 56px; min-height: 0; }
.dev-map-canvas {
  background: var(--bg-subtle); display: flex; align-items: center;
  justify-content: center; color: var(--text-faint); font-size: var(--text-sm);
}
.dev-panel-slot { overflow-y: auto; border-left: 1px solid var(--border); }
@media (max-width: 900px) {
  .dev-main { grid-template-columns: 1fr; grid-auto-rows: min-content; }
}

/* =================== 3.5 Map chrome (B.4) =================== */
.dev-map-filterbar {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  display: flex; gap: 6px; background: rgba(250,250,249,0.96);
  border: 1px solid var(--border); border-radius: 18px; padding: 4px 6px;
  box-shadow: var(--shadow-sm);
}
.dev-map-stat { font-family: var(--font-display); font-weight: 600; font-size: var(--text-xl); display: block; }
.dev-map-controls {
  position: absolute; bottom: 12px; right: 12px; display: flex; flex-direction: column; gap: 4px;
}
.dev-map-controls button {
  width: 32px; height: 32px; border: 1px solid var(--border);
  background: rgba(250,250,249,0.96); border-radius: var(--radius-sm);
  cursor: pointer; font-size: 16px; color: var(--text);
}
.dev-map-controls button:hover { background: var(--accent-gold); color: #111; }
.dev-map-attr {
  position: absolute; bottom: 6px; right: 52px; font-size: 9px;
  color: var(--text-muted); background: rgba(250,250,249,0.8); padding: 2px 6px; border-radius: 3px;
}

/* =================== 2.11 Section rule =================== */
hr.rule { border: none; border-top: 1px solid var(--border); margin: 0 0 40px 0; }

/* ---- Reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  *, ::before, ::after { animation: none !important; transition: none !important; }
}

/* P4.6 — Per-section freshness chip (rendered above each section
   header from meta.freshness in build-panel-sections). Subtle inline
   caption per F-freshness-ux.md "freshness as posture not chrome". */
.panel-section__freshness {
  display: inline-flex;
  align-items: baseline;
  gap: 0;
  font-size: 11px;
  line-height: 1.4;
  /* VFU.E.contrast — was #6b7280 → 4.43 contrast on #f5f5f4 surface,
     axe-core flagged as failing 4.5 WCAG AA minimum. #525860 raises
     ratio to ~5.5 while preserving the "muted caption" feel. */
  color: var(--ink-3, #525860);
  margin: 2px 0 8px;
  letter-spacing: 0.02em;
}
.panel-section__freshness-when {
  font-variant-numeric: tabular-nums;
  cursor: help;  /* surfaces title="<iso>" on hover */
}
.panel-section__freshness-source {
  font-style: italic;
  /* VFU.E.contrast — opacity 0.85 against #525860 cuts effective
     contrast back below WCAG AA. Drop the italic-fade to ~0.92
     (~5.1 effective ratio) so source label stays readable. */
  opacity: 0.92;
}
.panel-section__freshness-sep {
  opacity: 0.5;
}
