/* ============================================================
 * PHNTM // AZUL — global shell surfaces
 * ============================================================
 * Imported by theme.css, so these styles are present on every page
 * with no flash-of-unstyled-content. They style the operator-grade
 * surfaces injected at runtime by static/js/phntm-shell.js:
 *   toasts · status bar · command palette · shortcut overlay ·
 *   hover quick-cards · text-selection menu · feedback settings.
 * Canonical values per docs/STYLE-GUIDE.md (the guide wins on conflict).
 * Reduced-motion is handled globally in motion-tokens.css.
 * ARKHM | Premium Polish — grows one surface per milestone.
 * ----------------------------------------------------------- */

/* ── Toasts (guide §7.4 / spec §5b.3) ───────────────────────────
   Desktop: stack top-left, max 4, slide in from translateX(-12px).
   Mobile : centered, single, drops from translateY(-20px). Glass. */
#phntm-toasts {
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 4000;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
  max-width: min(360px, calc(100vw - 28px));
}
.phntm-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  background: rgba(20, 24, 31, 0.92);
  backdrop-filter: blur(24px) saturate(150%);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  border: 0.5px solid rgba(255, 255, 255, 0.10);
  border-radius: 10px;
  box-shadow: var(--lift-modal);
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1.4;
  animation: phntm-toast-in var(--motion-slow) var(--ease-refined);
  will-change: transform, opacity;
}
.phntm-toast.leaving {
  animation: phntm-toast-out var(--motion-fast) var(--ease-refined) forwards;
}
.phntm-toast .pt-icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  font-size: 12px;
  margin-top: 1px;
  font-family: var(--font-chrome);
}
.phntm-toast.ok .pt-icon,
.phntm-toast.create .pt-icon { color: var(--azul-pure); }
.phntm-toast.warn .pt-icon   { color: var(--warn); }
.phntm-toast.danger .pt-icon { color: var(--danger); }
.phntm-toast.info .pt-icon   { color: var(--info); }
.phntm-toast .pt-body { flex: 1; min-width: 0; }
.phntm-toast .pt-title { color: var(--text-primary); font-weight: 500; }
.phntm-toast .pt-msg { color: var(--text-muted); font-size: 12.5px; }
.phntm-toast .pt-x {
  flex-shrink: 0;
  cursor: pointer;
  color: var(--text-faint);
  background: none;
  border: none;
  font-size: 13px;
  line-height: 1;
  padding: 2px 4px;
  font-family: var(--font-chrome);
  transition: color var(--motion-fast) var(--ease-refined);
}
.phntm-toast .pt-x:hover { color: var(--text-secondary); }

@keyframes phntm-toast-in  { from { opacity: 0; transform: translateX(-12px); } to { opacity: 1; transform: none; } }
@keyframes phntm-toast-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateX(-12px); } }

@media (max-width: 1199px) {
  #phntm-toasts {
    top: 10px;
    left: 50%;
    transform: translateX(-50%);
    align-items: center;
    max-width: calc(100vw - 20px);
  }
  .phntm-toast { animation-name: phntm-toast-in-m; }
}
@keyframes phntm-toast-in-m { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: none; } }

/* ── Bottom status bar (guide §7.8 / spec §5b.2) ────────────────
   Slim glass strip pinned to the bottom of every authenticated page.
   pointer-events:none so it informs without ever blocking content;
   body padding (added only when the bar is present) keeps content clear. */
body.has-phntm-statusbar { padding-bottom: var(--statusbar-height); }
#phntm-statusbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: var(--statusbar-height);
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 14px;
  background: var(--statusbar-bg);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  /* The hairline is drawn rather than laid out. As a border it consumed
     layout height (0.5px resolves to a whole pixel at DPR 1), leaving a 47px
     content box that a 48dp target overhangs by half a pixel, and the amount
     it consumed varied with device pixel ratio. As an inset shadow it is
     identical to look at and costs no height at any DPR. */
  box-shadow: inset 0 0.5px 0 var(--border-divider);
  font-family: var(--font-mono);
  font-size: max(11px, var(--fs-floor));
  letter-spacing: 0.02em;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  user-select: none;
}
#phntm-statusbar .sb-left,
#phntm-statusbar .sb-right { display: flex; align-items: center; gap: 14px; min-width: 0; }
#phntm-statusbar .sb-item { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
/* P48.7: this author rule overrides the UA's [hidden] { display: none }, so
   every status item rendered even while hidden. The wa field therefore showed
   its en-dash placeholder as a 7px stub before /whatsapp/status answered,
   which is the 6.8 x 48 the operator measured against the 126.8 x 48 measured
   here after the poll populated it. Same guard shell.css already carries for
   cmdk, shortcuts, hovercard and selmenu, which .sb-item was simply missing. */
#phntm-statusbar .sb-item[hidden] { display: none; }
#phntm-statusbar .sb-k { color: var(--text-faint); }
/* P47.4: "wa pending Meta" is a blocker the operator is waiting on, not a
   readout, so it is the one item in the strip that can be acted on. The strip
   is pointer-events: none by design; this opts back in for that field only. */
#phntm-statusbar a.sb-wa-v {
  pointer-events: auto; text-decoration: underline; text-underline-offset: 2px;
  text-decoration-thickness: from-font;
  /* Fills the strip's height rather than overhanging it. An earlier attempt
     kept the strip at 32px and grew the target upward with a negative margin;
     it measured 48px and hit-tested correctly, but the 16px that stuck out
     sat over page content and swallowed clicks meant for it. The layout audit
     caught that as a 22px gap between this anchor and the sort select on
     /archive at 885x800. A target this size has to be space the strip owns,
     not space it borrows. */
  display: inline-flex; align-items: center; box-sizing: border-box;
  min-height: var(--target-min);
}
#phntm-statusbar .sb-v { color: var(--text-secondary); }
#phntm-statusbar .sb-online-label { color: var(--text-secondary); }
#phntm-statusbar .sb-model { max-width: 30vw; overflow: hidden; }
#phntm-statusbar .sb-model .sb-v { overflow: hidden; text-overflow: ellipsis; }
#phntm-statusbar .sb-ver { color: var(--text-faint); }
#phntm-statusbar .sb-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--azul-pure);
  animation: sb-pulse 3s ease-in-out infinite;
}
#phntm-statusbar .sb-online.off .sb-dot { background: var(--danger); animation: none; }
#phntm-statusbar .sb-spin {
  color: var(--azul-pure);
  display: inline-block;
  animation: sb-spin 1.4s linear infinite;
}
/* P15.5: live "processing" marker. A spinner reads as a hung request; a
   gentle pulsing dot reads as "data is live", which is what this is. */
#phntm-statusbar .sb-proc-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--azul-pure); display: inline-block;
  margin-right: 5px; vertical-align: middle;
  animation: sb-pulse 1.6s ease-in-out infinite;
}
@keyframes sb-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@keyframes sb-spin { to { transform: rotate(360deg); } }
@media (max-width: 1199px) {
  #phntm-statusbar { font-size: max(10.5px, var(--fs-floor)); padding: 0 10px; }
  #phntm-statusbar .sb-gpu,
  #phntm-statusbar .sb-model,
  #phntm-statusbar .sb-sync { display: none !important; }
}

/* ── Inline kbd (guide §8) — shared by palette + shortcut overlay ── */
.phntm-kbd,
#phntm-cmdk kbd,
#phntm-shortcuts kbd {
  display: inline-block;
  background: rgba(255, 255, 255, 0.06);
  border: 0.5px solid rgba(255, 255, 255, 0.1);
  padding: 1px 6px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: max(11px, var(--fs-floor));
  line-height: 1.5;
  color: var(--text-secondary);
}

/* ── Command palette (spec §5b.1) ──────────────────────────────── */
#phntm-cmdk { position: fixed; inset: 0; z-index: 4500; }
#phntm-cmdk[hidden] { display: none; }
.cmdk-backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation: cmdk-fade var(--motion-fast) var(--ease-refined);
}
.cmdk-panel {
  position: relative;
  width: min(560px, calc(100vw - 32px));
  margin: 14vh auto 0;
  background: var(--bg-glass);
  backdrop-filter: blur(28px) saturate(160%);
  -webkit-backdrop-filter: blur(28px) saturate(160%);
  border: 0.5px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  box-shadow: var(--lift-modal);
  overflow: hidden;
  font-family: var(--font-sans);
  animation: cmdk-rise var(--motion-base) var(--ease-refined);
}
.cmdk-input-wrap { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 0.5px solid var(--border-divider); }
.cmdk-prompt { color: var(--azul-pure); font-family: var(--font-chrome); font-size: 14px; }
.cmdk-input { flex: 1; background: none; border: none; outline: none; color: var(--text-primary); font-family: var(--font-sans); font-size: 15px; min-width: 0; }
.cmdk-input::placeholder { color: var(--text-faint); }
.cmdk-list { max-height: 52vh; overflow-y: auto; padding: 6px; }
.cmdk-group { font-size: max(10px, var(--fs-floor)); font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-faint); padding: 8px 10px 4px; }
.cmdk-row { display: flex; align-items: center; gap: 10px; height: 28px; padding: 0 10px; border-radius: 7px; cursor: pointer; }
.cmdk-row.sel { background: var(--azul-tint); }
.cmdk-glyph { width: 16px; text-align: center; color: var(--text-muted); font-family: var(--font-chrome); font-size: 12px; flex-shrink: 0; }
.cmdk-row.sel .cmdk-glyph,
.cmdk-glyph.cmdk-action,
.cmdk-glyph.cmdk-search { color: var(--azul-pure); }
.cmdk-label { color: var(--text-secondary); font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmdk-row.sel .cmdk-label { color: var(--text-primary); }
.cmdk-sub { margin-left: auto; color: var(--text-faint); font-size: max(11.5px, var(--fs-floor)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 45%; padding-left: 10px; }
.cmdk-empty { padding: 24px; text-align: center; color: var(--text-faint); font-size: 13px; }
.cmdk-foot { display: flex; gap: 14px; align-items: center; padding: 8px 14px; border-top: 0.5px solid var(--border-divider); font-size: max(11px, var(--fs-floor)); color: var(--text-faint); }
.cmdk-foot kbd { margin-right: 2px; }
.cmdk-esc { margin-left: auto; }
@keyframes cmdk-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes cmdk-rise { from { opacity: 0; transform: translateY(-8px) scale(0.98); } to { opacity: 1; transform: none; } }
@media (max-width: 1199px) {
  .cmdk-panel { margin-top: 8vh; }
  .cmdk-sub { display: none; }
}

/* ── Keyboard shortcut overlay (spec §5b.5) — reuses cmdk keyframes ── */
#phntm-shortcuts { position: fixed; inset: 0; z-index: 4500; }
#phntm-shortcuts[hidden] { display: none; }
.sc-backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation: cmdk-fade var(--motion-fast) var(--ease-refined);
}
.sc-panel {
  position: relative;
  width: min(560px, calc(100vw - 32px));
  margin: 16vh auto 0;
  background: var(--bg-glass);
  backdrop-filter: blur(28px) saturate(160%);
  -webkit-backdrop-filter: blur(28px) saturate(160%);
  border: 0.5px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  box-shadow: var(--lift-modal);
  overflow: hidden;
  font-family: var(--font-sans);
  animation: cmdk-rise var(--motion-base) var(--ease-refined);
}
.sc-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 0.5px solid var(--border-divider);
  color: var(--text-primary); font-size: 14px; font-weight: 500;
}
.sc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 18px; padding: 12px 16px 16px; }
.sc-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.sc-keys { display: inline-flex; align-items: center; gap: 3px; flex-shrink: 0; min-width: 96px; }
.sc-plus { color: var(--text-faint); font-size: max(10px, var(--fs-floor)); }
.sc-desc { color: var(--text-secondary); font-size: 12.5px; }
@media (max-width: 1199px) {
  .sc-grid { grid-template-columns: 1fr; }
  .sc-panel { margin-top: 10vh; }
}

/* ── Empty states (guide §7.6 / spec §5b.4) ─────────────────────
   Drone wireframe glyph + calm sentence-case copy + one primary CTA.
   Never emoji. The drone SVG carries its own reduced-motion guard. */
.phntm-empty {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 0.4rem; padding: 3rem 1.5rem;
}
.phntm-empty .phntm-drone { width: 120px; height: 100px; opacity: 0.9; margin-bottom: 0.4rem; }
.phntm-empty .pe-title { color: var(--text-secondary); font-family: var(--font-sans); font-size: 15px; font-weight: 500; }
.phntm-empty .pe-msg { color: var(--text-muted); font-family: var(--font-sans); font-size: 13px; max-width: 340px; line-height: 1.55; }
.phntm-empty .pe-cta {
  margin-top: 0.7rem;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0.5rem 0.95rem; border-radius: 7px;
  background: var(--azul-tint);
  border: 0.5px solid var(--border-hover);
  color: var(--azul-bright);
  font-family: var(--font-sans); font-size: 13px;
  text-decoration: none; cursor: pointer;
  transition: transform var(--motion-fast) var(--ease-refined),
              background var(--motion-fast) var(--ease-refined);
}
.phntm-empty .pe-cta:hover { transform: translateY(-1px); background: var(--azul-glow); }
.phntm-empty .pe-cta:active { transform: scale(0.98); }

/* ── Hover quick cards (spec §5b.6) ─────────────────────────────── */
[data-person-card] { cursor: help; }
#phntm-hovercard {
  position: fixed; z-index: 4200; width: 240px;
  background: var(--bg-glass);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 0.5px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  box-shadow: var(--lift-modal);
  padding: 12px;
  cursor: pointer;
  font-family: var(--font-sans);
  animation: hc-rise 200ms var(--ease-refined);
}
#phntm-hovercard[hidden] { display: none; }
.hc-top { display: flex; align-items: center; gap: 10px; }
.hc-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--on-accent); font-weight: 600; font-size: 12.5px;
  flex-shrink: 0; font-family: var(--font-sans);
}
.hc-id { min-width: 0; }
.hc-name { color: var(--text-primary); font-size: 14px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hc-role { color: var(--text-muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hc-stats { margin-top: 9px; color: var(--text-secondary); font-size: 12px; font-variant-numeric: tabular-nums; }
.hc-foot { margin-top: 9px; padding-top: 8px; border-top: 0.5px solid var(--border-divider); color: var(--azul-bright); font-size: max(11.5px, var(--fs-floor)); }
@keyframes hc-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ── Inline text-selection menu (spec §5b.7) ────────────────────── */
#phntm-selmenu {
  position: fixed; z-index: 4300;
  display: flex; gap: 2px; padding: 4px;
  background: var(--bg-glass);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 0.5px solid rgba(255, 255, 255, 0.1);
  border-radius: 9px;
  box-shadow: var(--lift-modal);
  animation: sm-rise 160ms var(--ease-refined);
}
#phntm-selmenu[hidden] { display: none; }
#phntm-selmenu button {
  background: none; border: none; cursor: pointer;
  color: var(--text-secondary);
  font-family: var(--font-sans); font-size: 12.5px;
  padding: 6px 10px; border-radius: 6px; white-space: nowrap;
  transition: background var(--motion-fast) var(--ease-refined),
              color var(--motion-fast) var(--ease-refined);
}
#phntm-selmenu button:hover { background: var(--azul-tint); color: var(--azul-bright); }
@keyframes sm-rise { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (max-width: 1199px) { #phntm-selmenu button { padding: 8px 9px; font-size: 12px; } }

/* ── Reduced motion (guide §4 / spec §8 / §13) ──────────────────
   The global guard in motion-tokens.css already neutralizes every
   animation + transition + View Transition app-wide. This is an explicit,
   self-documenting belt-and-suspenders for the runtime-injected surfaces:
   they appear instantly with no entrance, pulse, or spin. Opacity fades
   collapse to instant per the global rule; nothing here overshoots. */
@media (prefers-reduced-motion: reduce) {
  .phntm-toast,
  #phntm-cmdk .cmdk-panel, #phntm-cmdk .cmdk-backdrop,
  #phntm-shortcuts .sc-panel, #phntm-shortcuts .sc-backdrop,
  #phntm-hovercard,
  #phntm-selmenu,
  #phntm-statusbar .sb-dot,
  #phntm-statusbar .sb-proc-dot,
  #phntm-statusbar .sb-spin { animation: none !important; }
}

/* ── Universal typography baseline (guide §3) ───────────────────
   Inter sans is the default everywhere. `html body` (specificity 0,0,2)
   beats each template's inline `body { font-family: var(--font-chrome) }` (0,0,1)
   regardless of source order, so every page flips to sans in one place —
   while elements that set var(--font-chrome)/var(--font-chrome) explicitly (IDs,
   timestamps, codes, wordmarks, transcripts) keep mono. Madrasah loads its
   own stylesheet (not theme.css) and is unaffected. */
html body,
html body button, html body input, html body textarea, html body select {
  font-family: var(--font-sans);
  font-feature-settings: 'cv11', 'ss01', 'ss03';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
html body code, html body pre, html body .mono,
html body .timestamp, html body .duration, html body .stat-value, html body .file-meta {
  font-family: var(--font-mono);
}

/* =====================================================================
 * PHNTM // AZUL — system-wide visual layer (canonical, centralized)
 * =====================================================================
 * Defined once here and applied to every page via theme.css, using
 * `html body …` specificity (0,0,2 base) so these win over each
 * template's inline <style>. This is what guarantees no surface gets
 * "missed" and that hover states are unmistakably different from rest.
 *
 * --accent-rgb is the active module's accent (RGB triplet for rgba()),
 * set per page by a body.module-* class (default = azul). Card
 * hovers use it, so Dispatch hovers amber, Spectre purple, etc.
 * ===================================================================== */

/* ── C. Module accent (RGB triplet). Default azul; per STYLE-GUIDE §1. ── */
/* Azul, the decomposed form of --azul #2e9bff, since CSS cannot take a
   hex apart for rgba(). It sits on body, which outranks the :root value
   in tokens.css, so this one line kept every hover glow, focus ring and
   button tint viridian long after the rest of the app turned blue.
   The per-module accents below are deliberate and stay as they are. */
body { --accent-rgb: 46, 155, 255; }
/* Per-module accent hues (amber Dispatch/Arsenal, sky Cortex/Vitals, purple Spectre,
   red Command, grey Cipher, gold Dossier) retired 2026-09-09: one app, one accent.
   Every module inherits the azul --accent-rgb from tokens.css. */
*/
/* capture · herald · hub stay azul (default) */

/* ── A1/A2. Page background gradient + ambient radial glow washes ── */
html body {
  background: linear-gradient(155deg, var(--surface-lowest) 0%, var(--surface) 100%);
  background-attachment: fixed;
}
/* Single full-viewport layer carrying both corner washes. `inset: 0`
   cleanly replaces each template's body::before (old grid) with NO leftover
   position longhands (the previous top/right-only override left the
   template's inset:0 → over-constrained box → invisible glow). z-index -1
   keeps it behind all content; transparent wrappers (below) stop opaque
   containers from masking it. */
html body::before {
  content: ''; position: fixed; inset: 0; pointer-events: none; z-index: -1;
  background:
    radial-gradient(ellipse 800px 600px at 0% 0%, rgba(46, 155, 255, 0.08) 0%, transparent 60%),
    radial-gradient(ellipse 700px 500px at 100% 100%, rgba(46, 155, 255, 0.06) 0%, transparent 60%);
}
/* Wrappers must be transparent or the glow (z-index -1) is masked. */
html body .app,
html body .layout,
html body .page-shell,
html body .container,
html body main { background: transparent; }

/* ── A3. Topbar + nav: hairline divider, sentence-case links, no tracking ── */
html body header { border-bottom: 0.5px solid rgba(255, 255, 255, 0.05); }
html body header a,
html body nav a,
html body .nav a,
html body .header-meta a { text-transform: none; letter-spacing: 0; }

/* ── B. Glass cards (rest) — every elevated interactive surface ── */
html body .tile,
html body .recording-card,
html body .person-card,
html body .item,
html body .meeting-item,
html body .card,
html body .skill,
html body .upload-card,
html body .chunk-card,
html body .glass-card {
  background: linear-gradient(135deg, rgba(255,255,255,0.030) 0%, rgba(255,255,255,0.010) 100%);
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  border: 0.5px solid rgba(255, 255, 255, 0.07);
  border-radius: 12px;
  transition: transform 320ms var(--ease-refined),
              border-color 320ms var(--ease-refined),
              background 320ms var(--ease-refined),
              box-shadow 320ms var(--ease-refined);
}
/* Ensure the extended hover targets (stats, list rows) animate the lift
   smoothly rather than snapping. */
html body .module-card,
html body .stat-card,
html body .list-row,
html body .cell,
html body .stat,
html body .status-strip .cell {
  transition: transform 320ms var(--ease-refined),
              border-color 320ms var(--ease-refined),
              box-shadow 320ms var(--ease-refined),
              background 320ms var(--ease-refined);
}
/* ── B2. Hover — deliberately obvious: lift + accent border + glow ── */
html body .tile:hover,
html body .recording-card:hover,
html body .person-card:hover,
html body .item:hover,
html body .meeting-item:hover,
html body .card:hover,
html body .skill:hover,
html body .upload-card:hover,
html body .chunk-card:hover,
html body .glass-card:hover,
html body .module-card:hover,
html body .stat-card:hover,
html body .list-row:hover,
html body .cell:hover,
html body .stat:hover,
html body .status-strip .cell:hover {
  /* !important so no template selector (incl. compounds) can flatten it. */
  transform: translateY(-4px) !important;
  border-color: rgba(var(--accent-rgb), 0.40) !important;
  box-shadow: var(--tile-hover-shadow) !important;
  background:
    linear-gradient(180deg, rgba(var(--accent-rgb), 0.05) 0%, var(--tile-hover-wash) 100%) !important;
}
/* ── B3. Active / click ── */
html body .tile:active,
html body .recording-card:active,
html body .person-card:active,
html body .item:active,
html body .meeting-item:active,
html body .card:active,
html body .skill:active,
html body .upload-card:active,
html body .chunk-card:active,
html body .glass-card:active {
  transform: translateY(-1px) scale(0.99);
  transition-duration: var(--motion-instant);
}
/* CTA arrow nudge on card hover */
html body .tile:hover .arrow,
html body .recording-card:hover .arrow,
html body .card:hover .arrow { transform: translateX(4px); }

/* ── D. List rows — hover background, no lift ── */
html body .history-row,
html body .result,
html body .book-row,
html body .file-row,
html body .speaker-row,
html body .queue-row,
html body .risk-row,
html body .row-item {
  border-radius: 8px;
  transition: background var(--motion-fast) var(--ease-refined),
              transform var(--motion-fast) var(--ease-refined);
}
html body .history-row:hover,
html body .result:hover,
html body .book-row:hover,
html body .file-row:hover,
html body .speaker-row:hover,
html body .queue-row:hover,
html body .risk-row:hover,
html body .row-item:hover { background: rgba(255, 255, 255, 0.025); }

/* ── G. Buttons — de-cap + no tracking everywhere; canonical .btn ── */
html body button,
html body .btn,
html body [class*="-btn"] { text-transform: none; letter-spacing: 0; }
html body .btn {
  background: rgba(255, 255, 255, 0.04);
  border: 0.5px solid rgba(255, 255, 255, 0.08);
  color: var(--text-secondary);
  border-radius: 7px;
  font-weight: 500;
  transition: transform var(--motion-fast) var(--ease-refined),
              background var(--motion-fast) var(--ease-refined),
              border-color var(--motion-fast) var(--ease-refined);
}
html body .btn:hover { background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.14); transform: translateY(-1px); }
html body .btn:active { transform: scale(0.98); transition-duration: 80ms; }
html body .btn-primary, html body .btn.primary {
  background: rgba(var(--accent-rgb), 0.12);
  border-color: rgba(var(--accent-rgb), 0.30);
  color: #6fbeff;
}
html body .btn-primary:hover, html body .btn.primary:hover {
  background: rgba(var(--accent-rgb), 0.20);
  border-color: rgba(var(--accent-rgb), 0.45);
  box-shadow: 0 0 24px rgba(var(--accent-rgb), 0.20);
  transform: translateY(-1px);
}
html body .btn-danger, html body .danger-btn, html body .btn.danger {
  color: var(--danger); border-color: rgba(239,68,68,0.25);
}
html body .btn-danger:hover, html body .danger-btn:hover, html body .btn.danger:hover { background: rgba(239,68,68,0.08); }

/* ── H. Form inputs ── */
html body input[type="text"],
html body input[type="search"],
html body input[type="datetime-local"],
html body input[type="email"],
html body input[type="password"],
html body textarea,
html body select {
  background: rgba(255, 255, 255, 0.025);
  border: 0.5px solid rgba(255, 255, 255, 0.06);
  border-radius: 8px;
  color: var(--text-primary);
  font-family: var(--font-sans);
  transition: border-color var(--motion-fast) var(--ease-refined);
}
html body input::placeholder, html body textarea::placeholder { color: var(--text-faint); }
html body input:focus,
html body textarea:focus,
html body select:focus { outline: none; border-color: rgba(var(--accent-rgb), 0.30); box-shadow: none; }

/* ── I. Filter chips / pills ── */
html body .filter-chip,
html body .qv-btn {
  /* DIS-05: crisp radius, and a slim VISIBLE height. The 44px tap floor made
     these chunky boxes on mobile; cap the visible box at --space400 (32px)
     while the .qv-btn::after overlay keeps the real 44px tap target. */
  border-radius: var(--r-sm); min-height: var(--space400); min-width: 0;
  font-size: max(11px, var(--fs-floor)); font-weight: 500;
  letter-spacing: 0; text-transform: none;
  background: transparent; border: 0.5px solid rgba(255,255,255,0.10);
  color: var(--text-muted);
  transition: background var(--motion-fast) var(--ease-refined),
              border-color var(--motion-fast) var(--ease-refined),
              color var(--motion-fast) var(--ease-refined);
}
html body .filter-chip:hover, html body .qv-btn:hover { background: rgba(255,255,255,0.04); }
html body .filter-chip.active, html body .qv-btn.active {
  background: rgba(var(--accent-rgb), 0.10);
  border-color: rgba(var(--accent-rgb), 0.25);
  color: #6fbeff;
}

/* ── Cursor-follow spotlight (hub polish #2) — soft radial wash that tracks
   the pointer inside a card. Delegated mousemove (phntm-shell.js) sets
   --mx/--my per card. Excludes .recording-card — its ::after is the status
   LED — so the spotlight there would clobber a functional indicator. ── */
html body .tile, html body .person-card, html body .item, html body .meeting-item,
html body .card, html body .skill, html body .upload-card, html body .chunk-card,
html body .glass-card { position: relative; overflow: hidden; }
html body .tile::after, html body .person-card::after, html body .item::after,
html body .meeting-item::after, html body .card::after, html body .skill::after,
html body .upload-card::after, html body .chunk-card::after, html body .glass-card::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  opacity: 0; transition: opacity 280ms ease-out; z-index: 0;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%),
                              rgba(46, 155, 255, 0.07), transparent 55%);
}
html body .tile:hover::after, html body .person-card:hover::after, html body .item:hover::after,
html body .meeting-item:hover::after, html body .card:hover::after, html body .skill:hover::after,
html body .upload-card:hover::after, html body .chunk-card:hover::after, html body .glass-card:hover::after {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  html body .tile::after, html body .person-card::after, html body .item::after,
  html body .meeting-item::after, html body .card::after, html body .skill::after,
  html body .upload-card::after, html body .chunk-card::after, html body .glass-card::after {
    transition: none;
  }
}

/* ── P17.6 friendly error card (Linear / Stripe pattern) ────────────────── */
.phntm-error-card {
  border: 0.5px solid var(--azul-dim, #3f5468); border-left: 3px solid var(--amber, #d69e2e);
  border-radius: 10px; padding: 0.95rem 1.05rem; background: rgba(255,255,255,0.015);
  max-width: 460px; font-family: var(--mono, ui-monospace, monospace);
}
/* P18.3: signal dot + stacked title/message head. */
.phntm-error-card .ec-head { display: flex; gap: 0.6rem; align-items: flex-start; }
.phntm-error-card .ec-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  margin-top: 0.35rem; background: var(--amber, #d69e2e); }
.phntm-error-card .ec-text { min-width: 0; }
.phntm-error-card .ec-title { font-size: 0.95rem; color: var(--text, #dde7f2); margin-bottom: 0.35rem; }
.phntm-error-card .ec-body { font-size: 0.82rem; color: var(--text-muted, #5a6b7d); line-height: 1.5; }
.phntm-error-card .ec-detail {
  font-size: max(0.68rem, var(--fs-floor)); color: var(--text-dim, #8098b0); margin-top: 0.5rem;
  background: rgba(0,0,0,0.3); padding: 0.4rem 0.55rem; border-radius: 6px; overflow-x: auto; white-space: pre-wrap;
}
.phntm-error-card .ec-actions { display: flex; gap: 0.5rem; margin-top: 0.7rem; flex-wrap: wrap; }
.phntm-error-card .ec-btn {
  font-family: inherit; font-size: max(0.74rem, var(--fs-floor)); cursor: pointer; padding: 0.42rem 0.75rem;
  border-radius: 7px; text-decoration: none; border: 0.5px solid var(--azul-dim, #3f5468);
}
.phntm-error-card .ec-primary { background: rgba(46, 155, 255,0.10); color: var(--azul, #2e9bff); }
.phntm-error-card .ec-primary:hover { background: rgba(46, 155, 255,0.18); }
.phntm-error-card .ec-ghost { background: transparent; color: var(--text-muted, #5a6b7d); }
.phntm-error-card .ec-ghost:hover { color: var(--azul, #2e9bff); }
.phntm-error-card .ec-foot { font-size: max(0.64rem, var(--fs-floor)); color: var(--text-dim, #8098b0); margin-top: 0.6rem; }

/* ── P17.12 keyboard list selection (j/k) ───────────────────────────────── */
.kbd-active { outline: 2px solid var(--azul, #2e9bff); outline-offset: -1px; }

/* ── P17.14 loading skeletons (LinkedIn / Linear pattern) ───────────────── */
.phntm-skel { position: relative; overflow: hidden;
  background: rgba(255,255,255,0.04); border-radius: 6px; }
.phntm-skel::after { content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(46, 155, 255,0.07), transparent);
  transform: translateX(-100%); animation: phntm-skel-shimmer 1.4s ease-in-out infinite; }
.phntm-skel-row { height: 1rem; margin: 0.4rem 0; }
.phntm-skel-card { height: 64px; margin-bottom: 0.5rem; }
@keyframes phntm-skel-shimmer { 100% { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .phntm-skel::after { animation: none; } }

/* TOOLS: the two-tab strip that unifies repositories (arsenal) and skills
   under one nav surface. Tokens only, no literals. */
.tool-tabs { display: flex; gap: var(--space100); margin-bottom: var(--space200); }
.tool-tabs .btn { text-decoration: none; }
