/* ============================================================
   Datahub V1 — app.css
   Layer on top of tokens.css. Adds:
   - Per-artboard dark mode (data-theme="dark" on ANY ancestor)
   - New component classes (dh-*) for screens this brief introduces
   - All values pull from existing tokens (no new colors invented)
   ============================================================ */

/* ------------------------------------------------------------
   1.  Per-artboard dark mode.
   tokens.css scopes dark to :root[data-theme="dark"], which means
   only ONE theme can be active per page. We re-declare the same
   variables on any *[data-theme="dark"] so each artboard on the
   design canvas can render its own theme independently.
   ------------------------------------------------------------ */
[data-theme="dark"] {
  --bg:        oklch(0.16 0.012 250);
  --bg-elev:   oklch(0.20 0.012 250);
  --bg-sunken: oklch(0.14 0.012 250);
  --ink:    oklch(0.96 0.004 85);
  --ink-2:  oklch(0.78 0.008 250);
  --ink-3:  oklch(0.60 0.01 250);
  --line:   oklch(0.28 0.012 250);
  --line-2: oklch(0.34 0.012 250);
  --rail:        oklch(0.10 0.012 250);
  --rail-ink:    oklch(0.96 0.004 85);
  --rail-ink-2:  oklch(0.68 0.01 250);
  --rail-line:   oklch(0.22 0.012 250);
  --accent:      oklch(0.72 0.14 150);
  --accent-ink:  oklch(0.16 0.012 250);
  --accent-soft: oklch(0.30 0.06 150);
  --accent-line: oklch(0.45 0.10 150);
  --warn:   oklch(0.78 0.16 75);
  --danger: oklch(0.72 0.18 28);
}

/* Artboards always need a base bg + ink color so dark cards
   don't bleed the canvas warm-gray through. */
.dh-artboard {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 13px;
  line-height: 1.4;
  height: 100%;
  overflow: hidden; /* artboards are static frames, never scroll */
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
   2.  Foundation cards (palette / type / spacing swatches)
   ------------------------------------------------------------ */
.dh-found {
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.dh-found-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
}
.dh-found-eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.dh-found-title {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.dh-found-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
  line-height: 1.5;
}

.dh-swatch-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.dh-swatch {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg-elev);
}
.dh-swatch-chip {
  width: 28px; height: 28px;
  border-radius: 4px;
  border: 1px solid var(--line-2);
  flex-shrink: 0;
}
.dh-swatch-name {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink);
}
.dh-swatch-meta {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-3);
  margin-top: 2px;
}

.dh-type-row {
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}
.dh-type-row:last-child { border-bottom: none; }
.dh-type-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.dh-spacing-row {
  display: flex; align-items: center; gap: 12px;
  padding: 6px 0;
}
.dh-spacing-bar {
  background: var(--accent);
  height: 12px;
  border-radius: 2px;
}
.dh-spacing-label {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-2);
  min-width: 50px;
}

/* ------------------------------------------------------------
   3.  Primitive components
   ------------------------------------------------------------ */

/* Filter chip ------------------------------------------------
   min-height 32px keeps tap targets comfortable on touch devices
   (Apple HIG / Material baseline). align-items: center keeps the
   visible label/X centered within the taller hit box. */
.dh-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px 3px 9px;
  min-height: 32px;
  box-sizing: border-box;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 120ms, border-color 120ms;
  white-space: nowrap;
}
.dh-chip:hover { background: var(--bg-sunken); border-color: var(--line-2); }
.dh-chip-field { color: var(--ink); font-weight: 500; }
.dh-chip-op {
  color: var(--ink-3);
  font-family: var(--mono);
  padding: 0 2px;
}
.dh-chip-value {
  color: oklch(0.42 0.14 250); /* same blue as identity slug */
  font-weight: 500;
}
[data-theme="dark"] .dh-chip-value { color: oklch(0.72 0.14 250); }
.dh-chip-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  border-radius: 999px;
  color: var(--ink-3);
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 10px;
}
.dh-chip-x:hover { background: var(--bg-sunken); color: var(--danger); }
.dh-chip[data-active] {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--ink);
}
.dh-chip[data-tone="tag"] {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  padding: 2px 8px;
}
.dh-chip[data-tone="tag"] .dh-chip-field { color: var(--ink-2); }

/* Tier badge ------------------------------------------------- */
.dh-tier {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px 2px 8px;
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  border: 1px solid;
  cursor: pointer;
  white-space: nowrap;
}
.dh-tier[data-tier="free"] {
  background: var(--bg-sunken);
  border-color: var(--line);
  color: var(--ink-2);
}
.dh-tier[data-tier="free"]:hover { border-color: var(--line-2); }
.dh-tier[data-tier="pro"] {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: oklch(0.42 0.12 150);
}
[data-theme="dark"] .dh-tier[data-tier="pro"] {
  color: oklch(0.85 0.12 150);
}
.dh-tier-bolt {
  font-size: 11px;
  line-height: 1;
}

/* Status dot ------------------------------------------------- */
.dh-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--ink-3);
  flex-shrink: 0;
}
.dh-dot[data-state="active"] {
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent), transparent 80%);
}
.dh-dot[data-state="stale"] {
  background: transparent;
  border: 1.5px solid var(--ink-3);
  width: 9px; height: 9px;
}
.dh-dot[data-state="paused"] {
  background: var(--warn);
  border-radius: 1px;
  width: 7px; height: 7px;
}
.dh-dot[data-state="archived"] {
  background: var(--bg-sunken);
  border: 1.5px solid var(--line-2);
}

/* Button ----------------------------------------------------- */
.dh-btn {
  appearance: none;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  height: 30px;
  padding: 0 12px;
  background: var(--bg-elev);
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  font-family: var(--ui);
  font-weight: 500;
  font-size: 12.5px;
  transition: background 120ms, border-color 120ms;
  white-space: nowrap;
}
.dh-btn:hover { background: var(--bg-sunken); border-color: var(--ink-3); }
.dh-btn[data-variant="primary"] {
  background: var(--rail);
  color: var(--rail-ink);
  border-color: var(--rail);
}
.dh-btn[data-variant="primary"]:hover { background: color-mix(in oklch, var(--rail), var(--rail-ink) 12%); }
.dh-btn[data-variant="accent"] {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.dh-btn[data-variant="ghost"] {
  background: transparent;
  border-color: transparent;
  color: var(--ink-2);
}
.dh-btn[data-variant="ghost"]:hover { background: var(--bg-sunken); color: var(--ink); }
.dh-btn[data-variant="danger"] {
  background: var(--danger);
  color: oklch(0.98 0.01 28);
  border-color: var(--danger);
}
.dh-btn[data-size="sm"] {
  height: 26px;
  padding: 0 9px;
  font-size: 11.5px;
  gap: 5px;
}
.dh-btn[data-size="lg"] {
  height: 36px;
  padding: 0 16px;
  font-size: 13.5px;
}
.dh-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #15 — bump button height on phones
   so we clear the iOS 32px tap-target floor (default 30 / sm 26 was below). */
@media (max-width: 480px) {
  .dh-btn { min-height: 36px; }
  .dh-btn[data-size="sm"] { min-height: 32px; }
}
.dh-btn .dh-kbd {
  font-family: var(--mono);
  font-size: 10px;
  padding: 0 5px;
  border-radius: 3px;
  background: color-mix(in oklch, currentColor, transparent 86%);
  color: currentColor;
  opacity: 0.7;
}

/* Keyboard hint ---------------------------------------------- */
.dh-kbd {
  display: inline-flex; align-items: center;
  padding: 1px 5px;
  font-family: var(--mono);
  font-size: 10px;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 3px;
  color: var(--ink-2);
  line-height: 1.4;
  min-width: 14px;
  justify-content: center;
}

/* Pill (generic small status label) -------------------------- */
.dh-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  border-radius: 4px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  color: var(--ink-2);
  white-space: nowrap;
}
.dh-pill[data-tone="ok"] {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: oklch(0.42 0.12 150);
}
[data-theme="dark"] .dh-pill[data-tone="ok"] { color: oklch(0.85 0.12 150); }
.dh-pill[data-tone="warn"] {
  background: color-mix(in oklch, var(--warn), white 80%);
  border-color: color-mix(in oklch, var(--warn), white 50%);
  color: oklch(0.45 0.14 70);
}
[data-theme="dark"] .dh-pill[data-tone="warn"] {
  background: color-mix(in oklch, var(--warn), var(--bg) 80%);
  border-color: color-mix(in oklch, var(--warn), var(--bg) 50%);
  color: var(--warn);
}
.dh-pill[data-tone="danger"] {
  background: color-mix(in oklch, var(--danger), white 80%);
  border-color: color-mix(in oklch, var(--danger), white 60%);
  color: var(--danger);
}
[data-theme="dark"] .dh-pill[data-tone="danger"] {
  background: color-mix(in oklch, var(--danger), var(--bg) 80%);
  border-color: color-mix(in oklch, var(--danger), var(--bg) 60%);
  color: var(--danger);
}
.dh-pill[data-tone="info"] {
  background: color-mix(in oklch, oklch(0.55 0.14 250), white 88%);
  border-color: color-mix(in oklch, oklch(0.55 0.14 250), white 60%);
  color: oklch(0.42 0.14 250);
}
[data-theme="dark"] .dh-pill[data-tone="info"] {
  background: color-mix(in oklch, oklch(0.55 0.14 250), var(--bg) 75%);
  border-color: color-mix(in oklch, oklch(0.55 0.14 250), var(--bg) 50%);
  color: oklch(0.78 0.14 250);
}

/* Lifecycle stacked bar -------------------------------------- */
.dh-lifecycle {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dh-lifecycle-track {
  display: flex;
  height: 8px;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--bg-sunken);
}
.dh-lifecycle-seg {
  height: 100%;
  border-right: 1px solid color-mix(in oklch, var(--bg), transparent 50%);
  /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md primitives.jsx:88-110 LOW — when a
     stage holds a tiny fraction of total count (e.g. 5d grace inside 365d
     hot), its percentage-width segment renders sub-pixel and is invisible
     on the timeline. Floor each rendered segment at 6px so the operator
     still sees a stripe for every populated stage. */
  min-width: 6px;
}
.dh-lifecycle-seg:last-child { border-right: none; }
.dh-lifecycle-seg[data-stage="hot"]      { background: var(--accent); }
.dh-lifecycle-seg[data-stage="warm"]     { background: color-mix(in oklch, var(--accent), var(--warn) 70%); }
.dh-lifecycle-seg[data-stage="cold"]     { background: color-mix(in oklch, var(--ink-2), var(--bg) 30%); }
.dh-lifecycle-seg[data-stage="archive"]  { background: color-mix(in oklch, var(--ink-3), var(--bg) 30%); }
.dh-lifecycle-legend {
  display: flex; flex-wrap: wrap; gap: 12px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
}
.dh-lifecycle-legend > span {
  display: inline-flex; align-items: center; gap: 5px;
}
.dh-lifecycle-legend i {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 2px;
}
.dh-lifecycle-legend strong {
  color: var(--ink-2);
  font-weight: 600;
}

/* Tabs row (Source-detail-style file-folder) ----------------- */
.dh-tabs {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  border-bottom: 1px solid var(--line);
  padding: 0 4px;
  position: relative;
}
.dh-tab {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 14px 11px;
  margin-bottom: -1px;
  background: transparent;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: 7px 7px 0 0;
  font-family: var(--ui);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
  position: relative;
  white-space: nowrap;
}
.dh-tab:hover { color: var(--ink); background: color-mix(in oklch, var(--bg), var(--ink) 3%); }
.dh-tab[data-active] {
  background: var(--bg-elev);
  border-color: var(--line);
  color: var(--ink);
}
.dh-tab[data-active]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--bg-elev);
}
.dh-tab-count {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  padding: 1px 5px;
  background: var(--bg-sunken);
  border-radius: 3px;
}
.dh-tab[data-active] .dh-tab-count {
  background: color-mix(in oklch, var(--accent), var(--bg) 80%);
  color: oklch(0.42 0.12 150);
}
[data-theme="dark"] .dh-tab[data-active] .dh-tab-count { color: oklch(0.85 0.12 150); }
.dh-tab-icon {
  width: 13px; height: 13px;
  display: inline-flex; align-items: center;
  color: var(--ink-3);
}
.dh-tab[data-active] .dh-tab-icon { color: var(--ink-2); }

/* Section card (panel container used in screens) ------------- */
.dh-section {
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
}
.dh-section-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line-2);
  background: var(--bg-elev);
  /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #9 — eyebrow + title + actions stack
     on phones instead of overflowing the row. */
  flex-wrap: wrap;
  row-gap: 6px;
}
.dh-section-head-title {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.dh-section-head-eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.dh-section-head-sub {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
}
.dh-section-head-actions {
  margin-left: auto;
  display: flex; align-items: center; gap: 6px;
}
.dh-section-body {
  padding: 14px 16px;
}
.dh-section-body[data-pad="lg"] { padding: 18px 20px; }
.dh-section-body[data-pad="0"] { padding: 0; }

/* Shape sub-tab empty state — used by sections 01-05 for consistency.
   Single dashed-border bg-sunken block, same padding & monospace voice
   everywhere. Replaces five drifted ad-hoc empty-state styles in
   view-detail.jsx. */
.dh-shape-empty {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  margin: 0;
  background: var(--bg-elev);
  border: 1px dashed var(--line-2);
  border-radius: 8px;
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
}
.dh-shape-empty[data-pad="flush"] {
  border-radius: 0;
  border-left: none;
  border-right: none;
  border-top: none;
}
.dh-shape-empty .dh-shape-empty-glyph {
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-3);
  flex-shrink: 0;
}

/* Inline "+ Add X" affordance shared by all Shape sections. Pill-shaped,
   dashed border, monospace — matches the section-header ghost-Btn voice
   without competing with it. Empty-state CTAs and end-of-list adds both
   render this class so the click target reads the same in every section. */
.dh-shape-add {
  appearance: none;
  background: transparent;
  border: 1px dashed var(--line-2);
  border-radius: 999px;
  height: 28px;
  padding: 0 14px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}
.dh-shape-add:hover {
  border-color: var(--ink-3);
  border-style: solid;
  color: var(--ink);
  background: var(--bg-sunken);
}

/* Annotation chip (post-it-style, attached to design decisions) */
.dh-anno {
  display: inline-flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 12px;
  background: oklch(0.96 0.07 85);
  border: 1px solid oklch(0.78 0.10 85);
  border-radius: 6px;
  color: oklch(0.30 0.05 70);
  font-size: 11.5px;
  line-height: 1.45;
  max-width: 360px;
}
.dh-anno-num {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  background: oklch(0.55 0.16 70);
  color: white;
  border-radius: 999px;
  min-width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 0 5px;
  letter-spacing: 0;
}
.dh-anno-body { flex: 1; }
.dh-anno-title {
  font-weight: 600;
  color: oklch(0.25 0.06 70);
  margin-bottom: 2px;
}
.dh-anno code {
  font-family: var(--mono);
  font-size: 10.5px;
  background: oklch(0.99 0.04 85);
  border: 1px solid oklch(0.85 0.06 85);
  padding: 0 4px;
  border-radius: 3px;
  color: oklch(0.30 0.05 70);
}
/* When in dark mode, soften the annotation paper */
[data-theme="dark"] .dh-anno {
  background: oklch(0.30 0.06 80);
  border-color: oklch(0.45 0.08 75);
  color: oklch(0.92 0.05 85);
}
[data-theme="dark"] .dh-anno-title { color: oklch(0.96 0.06 85); }
[data-theme="dark"] .dh-anno code {
  background: oklch(0.22 0.04 75);
  border-color: oklch(0.40 0.06 75);
  color: oklch(0.92 0.05 85);
}

/* Empty state ------------------------------------------------ */
.dh-empty {
  text-align: center;
  padding: 36px 24px;
}
.dh-empty-glyph {
  width: 40px; height: 40px;
  margin: 0 auto 12px;
  border: 1px dashed var(--line-2);
  border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-3);
}
.dh-empty-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
  letter-spacing: -0.005em;
}
.dh-empty-sub {
  font-size: 12.5px;
  color: var(--ink-2);
  max-width: 38ch;
  margin: 0 auto;
  line-height: 1.5;
}

/* ------------------------------------------------------------
   4.  Source detail screen
   ------------------------------------------------------------ */
.dh-page {
  display: flex; flex-direction: column;
  height: 100%;
}
.dh-topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 24px;
  background: var(--rail);
  color: var(--rail-ink);
  border-bottom: 1px solid var(--rail-line);
  flex-shrink: 0;
}
.dh-topbar-brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-weight: 600; font-size: 13px;
  letter-spacing: -0.01em;
}
.dh-topbar-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  background: var(--rail-ink);
  color: var(--rail);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 11px; font-weight: 700;
}
.dh-topbar-name { color: var(--rail-ink); }
.dh-topbar-name .dot { color: var(--accent); }
.dh-topbar-sep { color: var(--rail-ink-2); font-family: var(--mono); }
.dh-topbar-bread {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--rail-ink-2);
}
.dh-topbar-bread strong { color: var(--rail-ink); font-weight: 500; }
.dh-topbar-right {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--rail-ink-2);
}
.dh-topbar-cmdk {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 4px 10px;
  border: 1px solid var(--rail-line);
  border-radius: 6px;
  color: var(--rail-ink-2);
  cursor: pointer;
}
.dh-topbar-cmdk kbd {
  font-family: var(--mono);
  font-size: 10px;
  padding: 1px 5px;
  background: color-mix(in oklch, var(--rail-ink-2), transparent 80%);
  border-radius: 3px;
  color: var(--rail-ink);
}

/* iter-108 TODO #17 — Share button. Sheets-style accent pill: filled
   primary background, prominent in the top-right so operators see
   the share entry point at a glance. Sits in dh-topbar-right between
   the search box and the env tag. */
.dh-topbar-share {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border: 1px solid var(--accent, oklch(0.42 0.14 250));
  border-radius: 6px;
  background: var(--accent, oklch(0.42 0.14 250));
  color: var(--accent-ink, #fff);
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  transition: filter 120ms;
}
.dh-topbar-share:hover { filter: brightness(1.08); }
.dh-topbar-share:focus-visible {
  outline: 2px solid var(--accent, oklch(0.42 0.14 250));
  outline-offset: 2px;
}

/* VW-A4 (UPGRADE_UX_TODO.md, 2026-05-19) — at narrow viewports the
   brand + workspace + breadcrumb + Search + PROD pill all crowd onto
   one row and overlap badly around 600–720px (common split-screen
   widths). Hide the breadcrumb path entirely below 760px — the brand
   mark still links home and the workspace switcher carries context.
   Also tighten the right cluster gap and drop the topbar padding so
   the PROD pill (operator's screen-share guard) stays visible. */
@media (max-width: 760px) {
  .dh-topbar { padding: 10px 14px; }
  .dh-topbar-sep,
  .dh-topbar-bread { display: none; }
  .dh-topbar-right { gap: 8px; }
}

.dh-page-body {
  flex: 1; min-height: 0;
  overflow: hidden;
  padding: 22px 32px 0;
  display: flex; flex-direction: column;
  gap: 18px;
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #1 — phones get ~40px more content
   width by trimming page-body padding (was 22/32/0/32 → 14/12/0/12).
   wave-2 — also tighten section-to-section vertical gap from 18 → 12 so
   3-4 sections fit on a single viewport scroll rather than 2. */
@media (max-width: 480px) {
  .dh-page-body { padding: 14px 12px 0; gap: 12px; }
}

/* iter-127 U#1 — source-detail header tightened. Was column-flex with
   10px gap so a typical source took ~80px above the tab bar (title row
   + stats row + tags row + lifecycle bar). Now gap is 4px and tags
   inline alongside stats (see source-detail.jsx restructure) so the
   header lands at 2 visible rows + a 2px sparkline-stripe — ~54px
   total. Matches the iter-127 UX-criteria #1 ("primary work surface
   starts within 120px of the top edge"). */
.dh-source-head {
  display: flex; flex-direction: column; gap: 4px;
}

/* iter-105 TODO #16 — one-liner header. The compact variant lays the
   back arrow + name + status on a SINGLE flex row at ~28px height
   (previous stacked layout was ~60px). Tags row below stays on its
   own line — they're often empty and don't need to share the slot. */
.dh-source-head-compact {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  min-height: 28px;
}
.dh-source-title-compact {
  flex: 1;
  min-width: 0;
  gap: 8px;
}

/* AUDIT_V5_ITER41_LIVE_WALK_2026-05-19.md MED-4 — on phones (≤480px) the
   workspaces page title row (h2 + super-admin checkbox + "+ New workspace"
   Btn) wrapped messily because flexWrap left the primary action below the
   checkbox on its own short line. Stack the whole header column-wise on
   narrow viewports so each control gets a full row. Targets the page-body
   header on /workspaces (uses .dh-source-head + .dh-view-title-row). */
@media (max-width: 480px) {
  .dh-source-head .dh-view-title-row {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
}

.dh-source-back {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
  cursor: pointer;
}
.dh-source-back:hover { color: var(--ink-2); }
.dh-source-title {
  display: flex; align-items: center; gap: 12px;
}
.dh-source-title h1 {
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink);
  /* VW-B3: long names like "Demo — Acme Salesforce" used to wrap to 3
     lines at 800px and eat the first viewport. Cap width + ellipsis,
     full name on hover via title="" on the <h1>. */
  max-width: 600px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dh-source-id {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 7px;
  font-family: var(--mono);
  font-size: 11px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--ink-2);
  cursor: pointer;
}
.dh-source-id:hover { background: var(--bg-elev); border-color: var(--line-2); }
.dh-source-tags {
  display: flex; gap: 6px; flex-wrap: wrap;
}

/* iter-106 TODO #10 — slim inline stats strip. Replaces the 5-card
   grid (~110px) with a single horizontal meta-strip (~28px). Each
   value is the dominant typographic element; label sits to its right
   in ink-3 mono. Bullets separate cells. Cost still gets the warn
   tint to flag it. */
.dh-stats-inline {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-elev);
  font-family: var(--mono);
  font-size: 11.5px;
  flex-wrap: wrap;
  min-height: 28px;
}
.dh-stat-inline {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  color: var(--ink-3);
}
.dh-stat-inline strong {
  font-weight: 600;
  color: var(--ink);
  font-size: 13px;
}
.dh-stat-inline-label { font-size: 11px; }
.dh-stat-inline-sep { color: var(--ink-3); opacity: 0.5; }
.dh-stat-inline[data-cost] strong { color: color-mix(in oklch, var(--warn), var(--ink) 60%); }

/* Stats strip — 5 cells, dense info-chrome */
.dh-stats {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-elev);
}
.dh-stat {
  padding: 14px 16px;
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
}
.dh-stat:last-child { border-right: none; }
.dh-stat[data-cost] { background: color-mix(in oklch, var(--warn), var(--bg-elev) 92%); }
[data-theme="dark"] .dh-stat[data-cost] { background: color-mix(in oklch, var(--warn), var(--bg-elev) 85%); }
.dh-stat-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.dh-stat-value {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.dh-stat-value small {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  margin-left: 4px;
  letter-spacing: 0;
}
.dh-stat-sub {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
}
.dh-stat-sub strong { color: var(--ink-2); font-weight: 500; }
.dh-stat-mini-bars {
  display: flex; align-items: flex-end; gap: 2px;
  height: 22px;
  margin-top: 2px;
}
.dh-stat-mini-bars > i {
  width: 4px;
  background: var(--accent);
  border-radius: 1px 1px 0 0;
  opacity: 0.85;
}

/* Live feed (mini preview block used in some screens) -------- */
.dh-feed {
  flex: 1; min-height: 0;
  overflow: auto;
  font-family: var(--mono);
  font-size: 11.5px;
}
.dh-feed-row {
  display: grid;
  grid-template-columns: 80px 70px 130px 1fr;
  gap: 12px;
  padding: 7px 14px;
  border-bottom: 1px dashed var(--line);
  align-items: baseline;
  cursor: pointer;
}
.dh-feed-row:hover { background: var(--bg-sunken); }
/* iter-106 TODO #9 — test-event gutter accent. Standard log-viewer
   pattern (Stackdriver / Datadog / Sentry): a 3px peach left-edge
   strip flags synthetic test events without painting the whole row.
   Implemented as inset box-shadow so it doesn't disturb the grid
   columns or padding. Pairs with the lowercase `test` label inline
   next to the method chip (see source-detail.jsx). */
.dh-feed-row[data-test-event="true"] {
  box-shadow: inset 3px 0 0 oklch(0.78 0.13 70);
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md Vis-2 — at 390px viewport the fixed
   columns (80+70+130+gaps ≈ 316px) crushed the JSON body to nothing and
   the "WEBHOOK" label clipped to "WEBHOO". Shrink fixed cells + use the
   shortened 3-char method label rendered in source-detail.jsx. */
@media (max-width: 480px) {
  .dh-feed-row {
    grid-template-columns: 56px 36px 90px 1fr;
    gap: 8px;
    padding: 7px 10px;
  }
}
.dh-feed-time { color: var(--ink-3); }
.dh-feed-method {
  font-weight: 600;
  color: oklch(0.42 0.12 150);
}
[data-theme="dark"] .dh-feed-method { color: oklch(0.85 0.12 150); }
.dh-feed-id { color: var(--ink-3); }
.dh-feed-body { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dh-feed-body .k { color: oklch(0.45 0.14 250); }
[data-theme="dark"] .dh-feed-body .k { color: oklch(0.78 0.14 250); }
.dh-feed-body .s { color: oklch(0.42 0.12 150); }
[data-theme="dark"] .dh-feed-body .s { color: oklch(0.78 0.12 150); }
.dh-feed-body .n { color: oklch(0.50 0.16 30); }
[data-theme="dark"] .dh-feed-body .n { color: oklch(0.78 0.16 30); }

/* ------------------------------------------------------------
   5.  View detail (★ Shape sub-tab)
   ------------------------------------------------------------ */
.dh-view-head {
  display: flex; flex-direction: column; gap: 8px;
}
.dh-view-title-row {
  display: flex; align-items: center; gap: 12px;
  /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #2 — wrap lets star + meta + actions
     drop below the h2 instead of horizontally overflowing on phones. */
  flex-wrap: wrap;
}
.dh-view-title-row h2 {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--ink);
}
.dh-view-title-star {
  font-size: 18px;
  color: var(--warn);
}
.dh-view-meta {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
}
.dh-view-meta strong { color: var(--ink-2); font-weight: 500; }
.dh-view-actions {
  margin-left: auto;
  display: flex; gap: 8px;
}

.dh-subtabs {
  display: flex; align-items: center; gap: 0;
  border-bottom: 1px solid var(--line);
  margin-top: 2px;
}
.dh-subtab {
  padding: 7px 14px;
  font-family: var(--ui);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  background: transparent;
  border-top: none; border-left: none; border-right: none;
  display: inline-flex; align-items: center; gap: 6px;
}
.dh-subtab:hover { color: var(--ink-2); }
.dh-subtab[data-active] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.dh-subtab-badge {
  font-family: var(--mono);
  font-size: 9.5px;
  padding: 1px 5px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}

/* WHERE clause row (filter row) ------------------------------- */
.dh-where {
  display: grid;
  grid-template-columns: 72px 1fr 36px;
  gap: 10px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px dashed var(--line);
}
.dh-where:last-child { border-bottom: none; }
.dh-where-kw {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.dh-where-kw[data-kw="and"] { color: oklch(0.42 0.12 150); }
.dh-where-kw[data-kw="or"]  { color: oklch(0.45 0.14 250); }
[data-theme="dark"] .dh-where-kw[data-kw="and"] { color: oklch(0.78 0.12 150); }
[data-theme="dark"] .dh-where-kw[data-kw="or"]  { color: oklch(0.78 0.14 250); }
.dh-where-expr {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
}
.dh-where-actions {
  display: flex; gap: 4px; justify-self: end;
}
.dh-where-add {
  appearance: none;
  background: transparent;
  border: 1px dashed var(--line-2);
  border-radius: 999px;
  width: 24px; height: 24px;
  color: var(--ink-3);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.dh-where-add:hover { border-color: var(--ink-3); color: var(--ink); border-style: solid; }

/* Column rows */
.dh-cols {
  display: flex; flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
.dh-col {
  display: grid;
  grid-template-columns: 24px 1fr 28px 1fr 130px 28px;
  gap: 10px;
  align-items: center;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-elev);
}
.dh-col:last-child { border-bottom: none; }
.dh-col:hover { background: var(--bg-sunken); }
/* iter-97 REC-4 — column-row pencil glyph. Visible at rest so the
   "click to rename" affordance doesn't require hover-discovery (touch
   devices, dense screens); amplified on row hover so the operator's
   eye lands on the target before clicking. */
.dh-col-edit-hint { opacity: 0.45; transition: opacity 120ms; }
.dh-col:hover .dh-col-edit-hint { opacity: 0.85; }
.dh-col-grip {
  color: var(--ink-3);
  cursor: grab;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: -2px;
}
.dh-col-src {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dh-col-arrow {
  color: var(--ink-3);
  font-family: var(--mono);
  text-align: center;
}
.dh-col-name {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
  font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dh-col-name[data-renamed] {
  color: oklch(0.42 0.14 250);
}
[data-theme="dark"] .dh-col-name[data-renamed] { color: oklch(0.78 0.14 250); }
.dh-col-xform {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 10.5px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--ink-2);
  white-space: nowrap;
  cursor: pointer;
}
.dh-col-xform:hover { border-color: var(--ink-3); }
.dh-col-xform[data-empty] { color: var(--ink-3); border-style: dashed; }
.dh-col-del {
  appearance: none;
  background: transparent;
  border: none;
  color: var(--ink-3);
  cursor: pointer;
  padding: 2px;
  border-radius: 3px;
  display: inline-flex; align-items: center; justify-content: center;
}
.dh-col-del:hover { color: var(--danger); background: color-mix(in oklch, var(--danger), transparent 90%); }
.dh-col-add {
  padding: 9px 12px;
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
  background: var(--bg-elev);
  border: none;
  cursor: pointer;
  width: 100%;
  text-align: left;
}
.dh-col-add:hover { background: var(--bg-sunken); color: var(--ink); }

/* If-then row */
.dh-ifthen {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
  padding: 8px 0;
  border-bottom: 1px dashed var(--line);
  font-family: var(--mono);
  font-size: 11.5px;
}
.dh-ifthen:last-child { border-bottom: none; }
.dh-ifthen-kw {
  color: oklch(0.45 0.14 250);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 10.5px;
}
[data-theme="dark"] .dh-ifthen-kw { color: oklch(0.78 0.14 250); }

/* Enrichment row */
.dh-enrich {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 0;
  border-bottom: 1px dashed var(--line);
  font-size: 12px;
}
.dh-enrich:last-child { border-bottom: none; }
.dh-enrich-target {
  font-family: var(--mono);
  font-weight: 600;
  color: var(--ink);
}
.dh-enrich-src {
  font-family: var(--mono);
  color: var(--ink-2);
}
.dh-enrich-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  margin-left: auto;
}

/* Preview table */
.dh-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 11.5px;
}
.dh-table thead th {
  text-align: left;
  padding: 7px 10px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--bg-sunken);
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  white-space: nowrap;
  /* Sticky on scroll — Section 05 preview is the last section and the
     operator usually scrolls down to it; once they do, the column
     headers should stay visible while they scan rows. */
  position: sticky;
  top: 0;
  z-index: 1;
}
.dh-table tbody td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}
.dh-table tbody tr:hover td { background: var(--bg-sunken); }

/* iter-95 — header rename affordance. The pencil glyph stays hidden
   until the operator hovers the header cell, then fades in so the
   click-to-rename target reads as interactive without making the table
   chrome noisier. */
.dh-table thead th:hover .dh-col-rename-hint { opacity: 0.6 !important; }

/* iter-112 REC-8 — filter-dot indicator on preview headers. Tiny 4px
   accent-colored circle that fires when at least one filter clause
   targets this column's path. Quiet at rest (70% opacity), pops to
   100% on header hover. Click scrolls to FiltersSection. Render as a
   button (not span) so it gets a native focus ring + click hit-target
   without poisoning the surrounding header's rename-on-click. */
.dh-col-filter-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 6px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--accent, var(--ink));
  opacity: 0.7;
  cursor: pointer;
  vertical-align: middle;
  transition: opacity 120ms, transform 120ms;
}
.dh-table thead th:hover .dh-col-filter-dot { opacity: 1; }
.dh-col-filter-dot:hover { opacity: 1; transform: scale(1.15); }
.dh-col-filter-dot:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* iter-97 REC-1 — title rename affordance. Faint pencil at rest,
   visible on hover. Subtle background tint on hover so the click
   target reads as interactive without an outline that screams. */
.dh-title-display:hover { background: var(--bg-sunken); }
.dh-title-display:hover .dh-title-pencil { opacity: 0.85 !important; }
.dh-title-display:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* iter-97 REC-2 — preview cell hover op buttons. Hidden at rest so the
   table stays quiet; fade in when the operator hovers anywhere on the
   row, giving them a one-click path to `!=` / `>` / `contains` without
   scrolling back to the Filter section. */
.dh-cell-ops { opacity: 0; transition: opacity 120ms; pointer-events: none; }
.dh-table tbody tr:hover .dh-cell-ops { opacity: 0.85; pointer-events: auto; }
.dh-cell-op-btn {
  appearance: none;
  min-width: 22px;
  height: 20px;
  padding: 0 5px;
  border: 1px solid var(--line-2);
  border-radius: 4px;
  background: var(--bg-elev);
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 11px;
  cursor: pointer;
  line-height: 1;
}
.dh-cell-op-btn:hover {
  background: var(--accent);
  color: var(--accent-ink, #fff);
  border-color: var(--accent);
}
/* iter-127 audit fix — touch targets bump to the Apple HIG 44×44
   minimum on coarse pointers. Desktop hover stays compact (20px)
   so the cell-op cluster doesn't dominate the row; coarse-pointer
   (touch) bumps to 32px min with surrounding padding to widen the
   hit area to ~44px without changing the visible button size. Same
   treatment on the per-row "view event detail" leading-column
   button (28×28 → 44×44 on touch). */
@media (pointer: coarse) {
  .dh-cell-op-btn {
    min-width: 36px;
    height: 32px;
    padding: 0 10px;
    font-size: 13px;
  }
  .dh-cell-eventdetail-btn {
    min-height: 44px !important;
    min-width: 44px !important;
  }
}
.dh-table tbody td:first-child { color: var(--ink-3); }
.dh-table tbody td.is-num { color: var(--danger); text-align: right; }
/* Click-to-filter affordance — td with cursor:pointer (set inline) gets
   a dotted underline on hover so it reads as actionable, not just
   hoverable. Matches the implicit promise of the title="Click to add
   filter" tooltip. */
.dh-table tbody td[style*="cursor: pointer"]:hover {
  text-decoration: underline dotted var(--ink-3);
  text-underline-offset: 3px;
  color: var(--ink);
}
.dh-table-foot {
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  background: var(--bg-sunken);
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center;
}

/* Footer: save/discard/upgrade */
.dh-view-foot {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 20px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.dh-view-foot .upgrade {
  margin-left: auto;
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md wave-2 — Discard + Save + Upgrade
   button row gets ~40px of horizontal padding on phones; cap to 10px so
   the right-aligned Save button stays inside the viewport. */
@media (max-width: 480px) {
  .dh-view-foot { padding: 12px 10px; gap: 6px; flex-wrap: wrap; }
}

/* ------------------------------------------------------------
   6.  Subscription rows / Shares rows
   ------------------------------------------------------------ */
.dh-row-list {
  display: flex; flex-direction: column;
}
.dh-row {
  display: grid;
  grid-template-columns: 24px 1fr 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.dh-row:last-child { border-bottom: none; }
.dh-row:hover { background: var(--bg-sunken); }
/* iter-79 P6 — mobile collapse for view-shares + view-subs share rows.
   At wide layout the 24/1fr/1fr/auto grid overflows a 480px viewport
   (action cluster on the right pushes past the gutter). Stack icon +
   main + stats; let the action cluster wrap to a second row below.
   AUDIT_V5_ITER78_CHECKPOINT_2026-05-20.md P6. */
@media (max-width: 480px) {
  .dh-row {
    grid-template-columns: 24px 1fr;
    row-gap: 6px;
  }
  .dh-row-stats { grid-column: 1 / -1; }
  .dh-row-actions {
    grid-column: 1 / -1;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
}
.dh-row-icon {
  width: 24px; height: 24px;
  border-radius: 6px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.dh-row-icon[data-tone="stream"] { color: oklch(0.42 0.12 150); }
.dh-row-icon[data-tone="batch"]  { color: oklch(0.45 0.14 250); }
[data-theme="dark"] .dh-row-icon[data-tone="stream"] { color: oklch(0.78 0.12 150); }
[data-theme="dark"] .dh-row-icon[data-tone="batch"]  { color: oklch(0.78 0.14 250); }
.dh-row-main {
  min-width: 0;
}
.dh-row-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
}
.dh-row-sub {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 3px;
}
.dh-row-stats {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-2);
}
.dh-row-stats strong { color: var(--ink); font-weight: 500; }
.dh-row-actions {
  display: flex; gap: 6px;
}

/* iter-34 N1: keyboard-driven focus indicator on the Sources list.
   ArrowUp/Down moves the highlight; Enter opens the focused source.
   The native :focus-visible ring still applies when the operator
   tabs into a row — this class is for the orthogonal "row navigated
   by arrow keys but not actually DOM-focused" affordance. */
.v5-sources-row[data-kbd-focused] {
  background: var(--accent-soft);
  outline: 2px solid var(--accent-line);
  outline-offset: -2px;
}

/* iter-31: Triggers-audit row needs a 5-col grid (icon · main · stats ·
   time · actions). Inline-styling that grid leaked it into every viewport
   width — the @media(max-width:480px) override below couldn't reach an
   inline rule, so rows overflowed the viewport on mobile. The class lets
   the wide layout opt in above the breakpoint while inheriting the
   .dh-row 3-col collapse below it. */
.dh-row-triggers-audit {
  grid-template-columns: 24px 1fr 1fr 90px auto;
}
@media (max-width: 480px) {
  .dh-row-triggers-audit {
    grid-template-columns: 24px 1fr auto;
  }
}

/* iter-33 N11: Audit-log row — when · action · resource · actor · IP.
   Wide-layout total ~730px overflows a 480px viewport when bolted on as
   an inline style. Same shape as the iter-31 triggers-audit fix above:
   class-based grid that the mobile @media can override. Mobile collapse
   stacks every cell into a single column so the row reads top-to-bottom
   on phones without horizontal scroll. */
.dh-row-audit {
  grid-template-columns: 170px 220px 1fr 220px 120px;
}
@media (max-width: 480px) {
  .dh-row-audit {
    grid-template-columns: 1fr;
    row-gap: 2px;
  }
}

/* iter-33 N6: Schema fields table — path · type · sample · rename · count.
   Wide-layout ~530px overflows 480px viewport. Mobile collapse to single
   column so each field renders as a stacked card-ish block; preserves the
   inline rename input which keeps its own max-width:170px.
   iter-61 HIGH-1 (AUDIT_V5_DEEP_SUBTABS_2026-05-20.md) — strengthen mobile
   rule: each cell gets a top divider + left-align "count" cell so the
   stack reads as a card per field instead of a confusing run of plain
   text. The header row collapses to a single sticky "Field" label since
   the column headers are nonsensical when every cell is full-width. */
/* iter-125 — 5 → 4 cols (Rename-to dropped; see source-detail-schema.jsx). */
.dh-row-schema {
  display: grid;
  grid-template-columns: 2fr 100px 1.5fr 60px;
}
@media (max-width: 480px) {
  .dh-row-schema {
    grid-template-columns: 1fr;
    row-gap: 0;
  }
  /* Headers (4 cells) disappear on mobile — column labels don't
     describe stacked cells. The cell content carries enough context
     (path is mono-spaced, type is a Pill). */
  .dh-row-schema > div:nth-child(-n+4) {
    display: none;
  }
  /* Live cells: first cell of each row (the path) gets a card-top
     divider; align "count" left so it doesn't dangle right alone. */
  .dh-row-schema > div:nth-child(4n+5) {
    border-top: 2px solid var(--line);
    padding-top: 10px;
  }
  .dh-row-schema > div:nth-child(4n+8) {
    text-align: left !important;
  }
}

/* iter-33 N9: Workspace members table — user · role · status · actions.
   Wide-layout ~430px overflows on narrow iPad / phone viewports.
   Companion class .dh-row-ws-keys covers the API-keys table on the same
   page which has slightly different column widths. */
.dh-row-ws-members {
  display: grid;
  grid-template-columns: 1fr 100px 130px 100px;
}
.dh-row-ws-keys {
  display: grid;
  grid-template-columns: 1fr 110px 110px 100px;
}
@media (max-width: 480px) {
  .dh-row-ws-members,
  .dh-row-ws-keys {
    grid-template-columns: 1fr;
    row-gap: 2px;
  }
}

/* ------------------------------------------------------------
   7.  Modal
   ------------------------------------------------------------ */
.dh-modal-frame {
  position: relative;
  height: 100%;
  background: color-mix(in oklch, var(--bg), black 20%);
  display: flex; align-items: center; justify-content: center;
  padding: 40px;
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md app.css:1354 HIGH — 40px of horizontal
   backdrop padding on a 390px viewport leaves 310px for the modal; the
   560px max-width modal then forces a horizontal scrollbar inside the
   showcase frame. Cap padding at 16 on phones so the modal can claim its
   full effective width. Live modals use ModalShell which has its own
   backdrop, but any runtime fallback to .dh-modal-frame inherits this. */
@media (max-width: 480px) {
  .dh-modal-frame { padding: 16px; }
}
.dh-modal {
  width: 100%;
  max-width: 560px;
  background: var(--bg-elev);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  box-shadow:
    0 1px 0 rgba(255,255,255,0.5) inset,
    0 24px 60px -12px rgba(12,14,20,0.45),
    0 8px 24px -8px rgba(12,14,20,0.3);
}
.dh-modal-head {
  padding: 20px 22px 14px;
  border-bottom: 1px solid var(--line-2);
}
.dh-modal-title {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin-bottom: 4px;
}
.dh-modal-sub {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.dh-modal-body {
  padding: 18px 22px;
  display: flex; flex-direction: column;
  gap: 14px;
}
.dh-modal-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 22px;
  background: var(--bg-sunken);
  border-top: 1px solid var(--line-2);
}
.dh-modal-foot-actions {
  display: flex; gap: 8px;
  margin-left: auto;
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md app.css:1390-1399 LOW — at 326px
   content width minus 44 horizontal padding leaves ~282px for 3 buttons
   (Cancel / Test connection / Save). Wrap the foot row and shrink padding
   so the right-aligned Save button doesn't get clipped. */
@media (max-width: 480px) {
  .dh-modal-foot { padding: 12px 14px; flex-wrap: wrap; row-gap: 8px; }
  .dh-modal-foot-actions { flex-wrap: wrap; }
}

/* Form bits used inside modals */
.dh-field-label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.dh-field-input,
.dh-field-select {
  width: 100%;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12.5px;
}
.dh-field-input:focus,
.dh-field-select:focus {
  outline: none;
  border-color: var(--accent-line);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent), transparent 80%);
}
.dh-radio-list {
  display: flex; flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--bg);
}
.dh-radio {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
.dh-radio:last-child { border-bottom: none; }
.dh-radio:hover { background: var(--bg-sunken); }
.dh-radio[data-checked] { background: color-mix(in oklch, var(--accent), var(--bg) 92%); }
[data-theme="dark"] .dh-radio[data-checked] { background: color-mix(in oklch, var(--accent), var(--bg) 88%); }
.dh-radio-dot {
  width: 16px; height: 16px;
  border-radius: 999px;
  border: 1.5px solid var(--line-2);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  margin-top: 1px;
}
.dh-radio[data-checked] .dh-radio-dot {
  border-color: var(--accent);
}
.dh-radio[data-checked] .dh-radio-dot::after {
  content: "";
  width: 8px; height: 8px;
  background: var(--accent);
  border-radius: 999px;
}
.dh-radio-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
}
.dh-radio-desc {
  font-size: 11.5px;
  color: var(--ink-2);
  font-family: var(--mono);
  margin-top: 3px;
  line-height: 1.4;
}
.dh-radio-disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.dh-radio-disabled .dh-radio-desc { color: var(--danger); }

/* Warning bar used in modal (e.g. streaming block) */
.dh-alert {
  display: flex; gap: 10px;
  padding: 11px 13px;
  background: color-mix(in oklch, var(--warn), white 82%);
  border: 1px solid color-mix(in oklch, var(--warn), white 55%);
  border-radius: 7px;
  color: oklch(0.35 0.08 70);
  font-size: 12px;
  line-height: 1.5;
}
[data-theme="dark"] .dh-alert {
  background: color-mix(in oklch, var(--warn), var(--bg) 80%);
  border-color: color-mix(in oklch, var(--warn), var(--bg) 55%);
  color: color-mix(in oklch, var(--warn), white 30%);
}
.dh-alert-icon {
  flex-shrink: 0;
  color: var(--warn);
  margin-top: 2px;
}
.dh-alert strong { font-weight: 600; }

/* ------------------------------------------------------------
   8.  Lineage drawer (right-anchored overlay artboard)
   ------------------------------------------------------------ */
.dh-drawer-frame {
  position: relative;
  height: 100%;
  background: color-mix(in oklch, var(--bg), black 18%);
  display: flex;
  justify-content: flex-end;
}
.dh-drawer-frame::before {
  /* faded background page hint */
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(transparent 0%, transparent 100%);
  pointer-events: none;
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #14 — date-pair grids collapse to a
   single column on phones so native date pickers don't truncate at 142px
   wide. Used by replay-range and view-subs-shares date pickers. */
.dh-date-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 480px) {
  .dh-date-pair { grid-template-columns: 1fr; }
}

.dh-drawer {
  /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #10 — clamp to viewport so the
     event-detail drawer doesn't horizontally overflow on 390-wide phones. */
  width: min(380px, 100vw);
  background: var(--bg-elev);
  color: var(--ink);
  border-left: 1px solid var(--line);
  display: flex; flex-direction: column;
  box-shadow: -20px 0 60px -20px rgba(12,14,20,0.35);
}
.dh-drawer-head {
  padding: 16px 18px 12px;
  border-bottom: 1px solid var(--line-2);
  display: flex; align-items: flex-start; gap: 10px;
}
.dh-drawer-head-title {
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 2px;
}
.dh-drawer-head-id {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
}
.dh-drawer-close {
  margin-left: auto;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-2);
  border-radius: 5px;
  width: 24px; height: 24px;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.dh-drawer-body {
  flex: 1; min-height: 0; overflow: auto;
  padding: 14px 18px;
}
/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md wave-2 — drawer body shrinks its
   horizontal padding on phones; a 380px-wide drawer with 36px of inline
   padding leaves 344px for content, scaled metadata reads cramped. */
@media (max-width: 480px) {
  .dh-drawer-body { padding: 14px 12px; }
}
.dh-lineage-node {
  position: relative;
  padding: 10px 12px 12px 30px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  margin-bottom: 14px;
}
.dh-lineage-node[data-this] {
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.dh-lineage-node::before {
  content: "";
  position: absolute;
  left: 14px; top: -14px;
  width: 1px; height: 14px;
  background: var(--line-2);
}
.dh-lineage-node:first-child::before { display: none; }
.dh-lineage-node-dot {
  position: absolute;
  left: 10px; top: 14px;
  width: 9px; height: 9px;
  border-radius: 999px;
  background: var(--bg-elev);
  border: 1.5px solid var(--ink-3);
}
.dh-lineage-node[data-this] .dh-lineage-node-dot {
  background: var(--accent);
  border-color: var(--accent);
}
.dh-lineage-eyebrow {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 3px;
}
.dh-lineage-id {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink);
  font-weight: 500;
  margin-bottom: 4px;
}
.dh-lineage-from {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-2);
  line-height: 1.5;
}
.dh-lineage-from a {
  color: oklch(0.42 0.14 250);
  text-decoration: underline;
  text-underline-offset: 2px;
}
[data-theme="dark"] .dh-lineage-from a { color: oklch(0.78 0.14 250); }
.dh-lineage-foot {
  padding: 12px 18px;
  border-top: 1px solid var(--line-2);
  background: var(--bg-sunken);
  display: flex; gap: 8px;
}

/* AUDIT_V5_UX_CLICKCOUNT_2026-05-19.md B-8 — runtime side-drawer.
   The static .dh-drawer-frame above paints a gray "page behind" hint
   used by the design showcase; in the live overlay we want the actual
   source-detail page to show through a true dim backdrop. */
.dh-lineage-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(12, 14, 20, 0.45);
  pointer-events: auto;
  display: flex;
  justify-content: flex-end;
  animation: dh-lineage-fade-in 160ms ease-out;
}
.dh-lineage-frame {
  /* Override the showcase .dh-drawer-frame's gray fill — inside the
     overlay it must be transparent so the backdrop shows through. */
  background: transparent !important;
  height: 100%;
  width: min(440px, 100vw);
}
.dh-lineage-frame .dh-drawer {
  width: 100%;
  animation: dh-lineage-slide-in 200ms ease-out;
}
@keyframes dh-lineage-fade-in {
  from { background: rgba(12, 14, 20, 0); }
  to   { background: rgba(12, 14, 20, 0.45); }
}
@keyframes dh-lineage-slide-in {
  from { transform: translateX(24px); opacity: 0.6; }
  to   { transform: translateX(0); opacity: 1; }
}

/* ------------------------------------------------------------
   9.  Cmd+K palette overlay
   ------------------------------------------------------------ */
.dh-cmdk-frame {
  position: relative;
  height: 100%;
  background: color-mix(in oklch, var(--bg), black 35%);
  display: flex; justify-content: center;
  padding-top: 80px;
}
.dh-cmdk {
  /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md #3 — clamp to viewport on phones so
     the Cmd+K palette never overflows horizontally on 390-wide screens. */
  width: min(560px, calc(100vw - 24px));
  max-height: 480px;
  background: var(--bg-elev);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 12px;
  display: flex; flex-direction: column;
  overflow: hidden;
  box-shadow:
    0 24px 60px -12px rgba(12,14,20,0.5),
    0 8px 24px -8px rgba(12,14,20,0.3);
}
.dh-cmdk-input {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
}
.dh-cmdk-input span {
  font-family: var(--mono);
  color: var(--ink-3);
  font-size: 13px;
}
.dh-cmdk-input input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--ui);
  font-size: 14px;
  color: var(--ink);
}
.dh-cmdk-section {
  padding: 6px 0;
  border-bottom: 1px solid var(--line);
}
.dh-cmdk-section:last-child { border-bottom: none; }
.dh-cmdk-section-head {
  padding: 6px 16px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.dh-cmdk-item {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 7px 16px;
  cursor: pointer;
  font-size: 13px;
}
.dh-cmdk-item:hover, .dh-cmdk-item[data-active] {
  background: var(--accent-soft);
}
.dh-cmdk-item-icon {
  color: var(--ink-3);
  display: inline-flex; align-items: center; justify-content: center;
}
.dh-cmdk-item-kind {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
}
.dh-cmdk-foot {
  padding: 8px 14px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  background: var(--bg-sunken);
  border-top: 1px solid var(--line);
  display: flex; gap: 16px;
}
.dh-cmdk-foot kbd {
  font-family: var(--mono);
  font-size: 10px;
  padding: 1px 5px;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 3px;
  color: var(--ink-2);
  margin-right: 4px;
}

/* ------------------------------------------------------------
   10. Lifecycle policy form
   ------------------------------------------------------------ */
.dh-life-form {
  display: flex; flex-direction: column;
  gap: 12px;
}
.dh-life-row {
  display: grid;
  grid-template-columns: 90px 1fr 88px;
  gap: 14px;
  align-items: center;
}
.dh-life-stage {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.dh-life-stage i {
  width: 10px; height: 10px;
  border-radius: 2px;
}
.dh-life-stage[data-stage="hot"] i     { background: var(--accent); }
.dh-life-stage[data-stage="warm"] i    { background: color-mix(in oklch, var(--accent), var(--warn) 70%); }
.dh-life-stage[data-stage="cold"] i    { background: color-mix(in oklch, var(--ink-2), var(--bg) 30%); }
.dh-life-stage[data-stage="archive"] i { background: color-mix(in oklch, var(--ink-3), var(--bg) 30%); }
.dh-life-stage[data-stage="grace"] i   { background: var(--danger); }
.dh-life-input-row {
  display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  padding: 0 8px;
  height: 34px;
}
.dh-life-input {
  flex: 1;
  width: 100%;
  border: none; outline: none;
  background: transparent;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink);
  text-align: right;
}
.dh-life-input-unit {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
}
.dh-life-step {
  display: flex; flex-direction: column;
  border-left: 1px solid var(--line);
  margin-left: 6px;
  padding-left: 4px;
}
.dh-life-step button {
  background: transparent;
  border: none;
  color: var(--ink-3);
  cursor: pointer;
  padding: 0 2px;
  font-size: 9px;
  line-height: 1;
}
.dh-life-step button:hover { color: var(--ink); }
.dh-life-pct {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  text-align: right;
}

/* Preset list */
.dh-preset-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.dh-preset {
  appearance: none;
  text-align: left;
  border: 1px solid var(--line);
  background: var(--bg);
  padding: 11px 13px;
  border-radius: 7px;
  cursor: pointer;
  display: flex; flex-direction: column; gap: 4px;
}
.dh-preset:hover { border-color: var(--ink-3); }
.dh-preset[data-active] {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.dh-preset-name {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
}
.dh-preset-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
}

/* Cost projection row */
.dh-cost-line {
  display: flex; align-items: baseline; gap: 8px;
  padding: 12px 14px;
  background: color-mix(in oklch, var(--warn), var(--bg) 92%);
  border: 1px solid color-mix(in oklch, var(--warn), var(--bg) 70%);
  border-radius: 8px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
}
.dh-cost-line strong {
  color: oklch(0.40 0.14 75);
  font-weight: 600;
  font-size: 14px;
}
[data-theme="dark"] .dh-cost-line strong { color: var(--warn); }

/* ============================================================
   Accessibility — focus rings (DESIGN_BRIEF §9)
   ============================================================
   Global :focus-visible policy. Keyboard focus draws a 2px outset
   ring in --accent; mouse/touch focus stays unringed (Chrome /
   Safari / Firefox all honour :focus-visible heuristics).
   The `!important` is load-bearing: it wins over the inline
   `outline: 'none'` React style attributes set on several inputs
   (view-detail.jsx inlineInput, sources-list.jsx search, onboarding
   tag fields, lifecycle.dh-life-input) and over the explicit
   `outline: none` declarations on .dh-field-input:focus and
   .dh-life-input above. Those rules suppress the default browser
   ring but never re-introduce one — the global rule below does.
   LIGHT MODE ONLY (the dark token resolves to a lighter accent,
   but V5 ships light-only anyway).
   ============================================================ */
:focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px;
  border-radius: inherit;
}

/* Per-component overrides — slightly tighter offset on chips /
   tabs / sub-tabs / tier so the ring hugs the pill geometry.
   ITER28 F3: .dh-audit-chip joins the chip family so the audit-log
   filter buttons get the same tight focus ring (and aria-pressed is
   advertised via the JSX side). */
.dh-chip:focus-visible,
.dh-chip-x:focus-visible,
.dh-tab:focus-visible,
.dh-subtab:focus-visible,
.dh-tier:focus-visible,
.dh-dot:focus-visible,
.dh-audit-chip:focus-visible {
  outline-offset: 1px;
}

/* Form fields get a soft ring + accent border, matching the
   existing dh-field-input :focus rule (which we keep — it adds
   the box-shadow halo even on mouse focus). */
.dh-field-input:focus-visible,
.dh-field-select:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline-offset: 0;
}

/* Menu items inside .dh-cmdk and overflow menus. */
[role="menuitem"]:focus-visible {
  outline-offset: -2px;
}

/* Anchor focus — keep the ring tight against the text box. */
a[href]:focus-visible {
  outline-offset: 2px;
}

/* ------------------------------------------------------------
   Mobile responsive (≤480px) — VW-B16/17/18 fixes
   ------------------------------------------------------------
   VW-B16: dh-stats 5-col grid is unreadable on 375px phones →
           collapse to 2-col at ≤480px, single col at ≤360px.
   VW-B17: dh-source-id pill overflows viewport — let the mono id
           wrap and cap width so it never extends past the page.
   VW-B18: dh-row 4-col grid (icon · main · main · actions) makes
           the right-side metadata overlap the source name on
           narrow widths — stack the stats column under the main
           column and let the right column wrap.
   ------------------------------------------------------------ */
@media (max-width: 480px) {
  /* VW-B16: hero metric grid → 2 cols */
  .dh-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .dh-stat {
    border-right: none;
    border-bottom: 1px solid var(--line);
    padding: 12px 14px;
  }
  /* Avoid a dangling 5th cell with a bottom border. */
  .dh-stat:nth-last-child(-n+2):nth-child(odd):last-child,
  .dh-stat:last-child { border-bottom: none; }
  .dh-stat-value { font-size: 19px; }

  /* VW-B17: source-id pill — allow wrap, cap width */
  .dh-source-id {
    max-width: 100%;
    word-break: break-all;
    overflow-wrap: anywhere;
  }
  .dh-source-title {
    flex-wrap: wrap;
    gap: 8px;
  }
  .dh-source-title h1 {
    font-size: 22px;
    /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md wave-2 — desktop's 600px max-width
       still applies on phones, ellipsizing names like "Demo · Acme SF Prod
       Webhook" at the same desktop point. Drop the cap so the natural
       width: 100% from the flex parent applies and the full name fits
       wrapped within the 326px content column. */
    max-width: 100%;
  }

  /* VW-B18: sources list row — stack right-side metrics under
     the main column so they no longer overlap the title. */
  .dh-row {
    grid-template-columns: 24px 1fr auto;
    gap: 10px;
    row-gap: 4px;
  }
  .dh-row-stats {
    grid-column: 2 / -1;
    font-size: 10.5px;
    white-space: normal;
  }
  .dh-row-actions {
    grid-column: 3 / 4;
    grid-row: 1;
  }
  /* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md Vis-1 — collapse the sources-list
     row to a 2-line summary on phones. The right-stats metrics row uses
     whiteSpace:nowrap inline and the inner row container had no flexWrap,
     so the 3 stat pills (events24h / views / lastEvent) overflowed the
     row horizontally. Allow wrap + truncate source_id so each row is
     name+tags on line 1, src_id+stats on line 2. */
  .v5-sources-metrics {
    flex-wrap: wrap !important;
    white-space: normal !important;
    row-gap: 2px !important;
  }
  .dh-row-title { gap: 6px; flex-wrap: wrap; row-gap: 2px; }
  .dh-row-title > span:nth-child(3) {
    /* the src_<hex> mono badge inside the title */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    max-width: 140px;
  }
  /* Hide the trailing forward-chevron at the row end — the whole row is
     an <a> already, the chevron just steals 36px of horizontal space and
     visually disconnects after the stats wrap to row 2. */
  .v5-sources-row > .dh-btn[aria-label="Open"] { display: none; }
}

@media (max-width: 360px) {
  /* Extra-narrow phones — collapse hero stats to single col. */
  .dh-stats {
    grid-template-columns: 1fr;
  }
  .dh-stat { border-bottom: 1px solid var(--line); }
  .dh-stat:last-child { border-bottom: none; }
}

/* iter-38 M3 — under 720px hide the "+ new view" label, icon-only chip. */
@media (max-width: 720px) {
  .dh-tab-newview-label { display: none; }
}

/* AUDIT_MOBILE_V5_SWEEP_2026-05-19.md wave-2 — at ≤480 the inputs strip
   collapses to a single column (auto-fill minmax(280, 1fr)). Each cell
   still renders borderRight which becomes a vertical line on the only
   column, looking like a broken edge. Strip it on phones. */
@media (max-width: 480px) {
  .v5-inputs-cell { border-right: none !important; }
  /* ModalShell backdrop padding shrink — see primitives.jsx ModalShell. */
  .dh-modal-backdrop { padding: 20px 12px !important; }
  /* Audit-log resource <select> font-size bump to dodge iOS auto-zoom. */
  .v5-audit-resource-select { font-size: 16px !important; padding: 6px 8px !important; }
}

/* iter-38 M5 — keyboard-Tab focus ring on dropdown menu items
   (More ▾, +more views ▾). Inline hover styles were already in place but
   :focus-visible had no affordance — keyboard-only users landed blind. */
.dh-tab-menuitem:focus-visible {
  outline: 2px solid var(--accent-line);
  outline-offset: -2px;
}

/* iter-45 a11y-2 — Skip-to-main-content link.
   AUDIT_V5_ITER44_A11Y_2026-05-19.md finding #2: V5 shipped with zero
   landmark elements and no keyboard-bypass affordance, so screen-reader
   users had to Tab through the entire TopBar on every screen.

   Pattern: visible only when focused. We translate it off-screen by
   default (so sighted users never see it) and snap it back on :focus
   so the first Tab press from page load surfaces it. Activation jumps
   focus into <main id="dh-main"> (tabIndex=-1) which announces as the
   "main" landmark. Token-based colors so it inherits theme correctly. */
.dh-skip-link {
  position: absolute;
  left: 8px;
  top: 8px;
  padding: 8px 12px;
  background: var(--bg-elev);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: var(--ui);
  font-size: 13px;
  text-decoration: none;
  transform: translateY(calc(-100% - 16px));
  transition: transform 0.15s ease;
  z-index: 1000;
}
.dh-skip-link:focus,
.dh-skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid var(--accent-line);
  outline-offset: 2px;
}

/* The <main id="dh-main"> wrapper around the route body is programmatically
   focusable (tabIndex=-1) but must not show a focus ring during normal
   mouse / route navigation — only when the skip link explicitly targeted
   it. :focus-visible suppresses the ring for non-keyboard focus moves. */
#dh-main:focus { outline: none; }
#dh-main:focus-visible { outline: 2px solid var(--accent-line); outline-offset: -2px; }

/* ------------------------------------------------------------
   iter-111 / TODO #17b — View Tabs Footer (Sheets-style)
   Fixed strip at the bottom of the viewport listing every saved
   view as a tab. Active tab gets accent underline + filled bg.
   ------------------------------------------------------------ */
/* iter-127 U#8 — Sheets-style view-tabs footer scaled up to match
   Google Sheets' physical size. Was 36px tall / 12.5px text — read
   as a subordinate widget. Now 44px tall / 13.5px text with tabs
   that hit 38px so the click target is comfortable for both desktop
   and touch (44px min advised; we're close once the page-body
   padding adds up). Active-tab accent bar bumped from 3px to 4px
   for parity with the Sheets active indicator. */
.dh-vtf-strip {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 30;
  display: flex;
  align-items: stretch;
  height: 44px;
  background: var(--bg-elev);
  border-top: 1px solid var(--line);
  box-shadow: 0 -2px 12px rgba(12,14,20,0.06);
  font-family: var(--ui);
  font-size: 13.5px;
  padding: 0 6px;
  gap: 3px;
}
.dh-vtf-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 38px;
  padding: 0 10px;
  background: transparent;
  border: none;
  color: var(--ink-2);
  cursor: pointer;
  font-family: var(--ui);
  font-size: 15px;
  border-radius: 4px;
  flex-shrink: 0;
}
.dh-vtf-btn:hover { background: var(--bg-sunken); color: var(--ink); }
.dh-vtf-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.dh-vtf-all { font-size: 17px; }
.dh-vtf-plus { font-size: 22px; font-weight: 500; line-height: 1; }

.dh-vtf-scroller {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none; /* Firefox */
  padding-top: 4px;
}
.dh-vtf-scroller::-webkit-scrollbar { display: none; }

.dh-vtf-tab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  padding: 6px 14px 8px;
  max-width: 200px;
  height: 38px;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  position: relative;
  white-space: nowrap;
  font-family: var(--ui);
  font-size: 13.5px;
  user-select: none;
  transition: background 100ms ease, color 100ms ease;
}
.dh-vtf-tab:hover { background: var(--bg-sunken); color: var(--ink-2); }
.dh-vtf-tab[data-active] {
  background: var(--bg);
  border-color: var(--line);
  color: var(--ink);
  font-weight: 500;
}
.dh-vtf-tab[data-active]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 4px;
  background: var(--accent);
  border-radius: 8px 8px 0 0;
}
.dh-vtf-tab-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 160px;
}
.dh-vtf-tab-pro { color: var(--accent); font-size: 13px; }
.dh-vtf-tab-default { color: var(--accent); font-size: 13px; }
.dh-vtf-tab-input {
  font: inherit;
  padding: 2px 5px;
  min-width: 90px;
  max-width: 140px;
  border: 1px solid var(--line-2);
  border-radius: 3px;
  background: var(--bg-elev);
  color: var(--ink);
  outline: none;
}
.dh-vtf-tab-caret {
  background: none;
  border: none;
  padding: 0 3px;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
}
.dh-vtf-tab-caret:hover { color: var(--ink); }

.dh-vtf-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  background: transparent;
  border: none;
  border-radius: 4px;
  color: var(--ink-2);
  cursor: pointer;
  font-size: 18px;
  font-weight: 600;
  flex-shrink: 0;
}
.dh-vtf-arrow:hover { background: var(--bg-sunken); color: var(--ink); }

.dh-vtf-allmenu-wrap { position: relative; display: inline-flex; }
.dh-vtf-allmenu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  min-width: 220px;
  max-width: calc(100vw - 24px);
  max-height: 360px;
  overflow-y: auto;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.05);
  padding: 4px;
  z-index: 35;
}
.dh-vtf-allmenu-item {
  display: flex; align-items: center; gap: 6px;
  width: 100%;
  padding: 7px 10px;
  background: transparent;
  border: none;
  border-radius: 6px;
  font-family: var(--ui);
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
  text-align: left;
}
.dh-vtf-allmenu-item:hover { background: var(--bg-sunken); color: var(--ink); }
.dh-vtf-allmenu-item[data-active],
.dh-vtf-allmenu-row[data-active] .dh-vtf-allmenu-item {
  background: var(--bg-sunken);
  color: var(--ink);
  font-weight: 500;
}
.dh-vtf-allmenu-row {
  display: flex; align-items: center; gap: 4px;
}
.dh-vtf-allmenu-row .dh-vtf-allmenu-item-name { flex: 1 1 auto; }
.dh-vtf-allmenu-unhide {
  font-size: 11px;
  padding: 3px 6px;
  border: 1px solid var(--line);
  background: transparent;
  border-radius: 4px;
  color: var(--ink-2);
  cursor: pointer;
  margin-right: 4px;
}
.dh-vtf-allmenu-unhide:hover { background: var(--bg-sunken); color: var(--ink); }
.dh-vtf-allmenu-hidden-tag {
  font-size: 10px;
  color: var(--ink-3);
  font-style: italic;
  margin-left: 4px;
}
.dh-vtf-allmenu-empty {
  padding: 8px 10px;
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
}

.dh-vtf-ctxmenu {
  position: fixed;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.06);
  padding: 4px;
  z-index: 120;
}
.dh-vtf-ctxmenu-item {
  display: block;
  width: 100%;
  padding: 7px 10px;
  background: transparent;
  border: none;
  border-radius: 5px;
  font-family: var(--ui);
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
  text-align: left;
}
.dh-vtf-ctxmenu-item:hover:not(:disabled) { background: var(--bg-sunken); color: var(--ink); }
.dh-vtf-ctxmenu-item:disabled { opacity: 0.4; cursor: not-allowed; }
.dh-vtf-ctxmenu-danger { color: var(--danger, #c0413e); }
.dh-vtf-ctxmenu-danger:hover:not(:disabled) {
  background: color-mix(in oklch, var(--danger, #c0413e), var(--bg-elev) 88%);
  color: var(--danger, #c0413e);
}
.dh-vtf-ctxmenu-sep {
  height: 1px;
  margin: 4px 2px;
  background: var(--line);
}

/* iter-127 U#8 — footer bumped from 36 to 44px; lift the cmdK FAB +
   page-body bottom-padding to match so nothing sits under the strip. */
.v5-cmdk-fab { bottom: 64px !important; }
.v5-root .dh-page-body { padding-bottom: 56px; }

/* Mobile — at <=480px the strip stays visible but compresses: smaller font,
   tighter tabs, the ☰ all-views menu becomes the primary affordance.
   iter-127 U#8 — slightly larger after the desktop bump so touch targets
   still hit the 36-40px Apple HIG floor. */
@media (max-width: 480px) {
  .dh-vtf-strip { height: 40px; padding: 0 3px; gap: 2px; }
  .dh-vtf-tab { max-width: 130px; padding: 5px 10px 7px; font-size: 12.5px; height: 34px; }
  .dh-vtf-tab-label { max-width: 100px; }
  .dh-vtf-btn { min-width: 34px; padding: 0 8px; font-size: 14px; }
  .dh-vtf-plus { font-size: 20px; }
  .dh-vtf-arrow { width: 24px; font-size: 16px; }
  .dh-vtf-allmenu { min-width: 220px; }
  .v5-root .dh-page-body { padding-bottom: 52px; }
  .v5-cmdk-fab { bottom: 56px !important; }
}

/* iter-133 — kill iOS Safari focus-zoom on form fields. Mobile webkit
   auto-zooms the viewport when the operator focuses an <input> /
   <textarea> / <select> with computed font-size < 16px. The layout
   ends up scaled in by ~10-15%, the operator manually pinch-zooms
   back out, the next focus zooms in again — broken. Floor every
   form-field font-size to 16px on coarse-pointer or narrow-viewport
   devices. Desktop visual stays at the per-input 11-13px the design
   system uses. The viewport <meta> stays `initial-scale=1` (no
   maximum-scale lock) so user-initiated pinch-zoom still works. */
@media (max-width: 480px), (pointer: coarse) {
  .v5-root input,
  .v5-root input[type="text"],
  .v5-root input[type="search"],
  .v5-root input[type="email"],
  .v5-root input[type="number"],
  .v5-root input[type="url"],
  .v5-root input[type="password"],
  .v5-root input[type="tel"],
  .v5-root input[type="date"],
  .v5-root input[type="datetime-local"],
  .v5-root input[type="time"],
  .v5-root input:not([type]),
  .v5-root textarea,
  .v5-root select {
    font-size: 16px !important;
  }
}

/* iter-74 A1 — prefers-reduced-motion sweep. Vestibular-disorder users
   opt out of motion at the OS level; without this block V5 still runs
   11 infinite animations (livepulse 1.8s, name-hint-pulse 1.6s,
   skel-shimmer, skel-pulse, design-mode hint pulse, slug pulse 1.6s,
   first-event-flash 4s, eventSlide 400ms per feed row, …) plus every
   transition. Single blanket rule disables them all without touching
   individual @keyframes. See AUDIT_V5_ITER73_CHECKPOINT_2026-05-20.md A1. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
