/* ============================================================================
   Apollo Shell — constellation-as-the-page redesign (Phase 1)
   - dark only (light theme retired)
   - left sidebar hidden, replaced by a floating crystal dock
   - space backdrop behind every view so panels float "over the constellation"
   Loaded last so it overrides styles.css where needed.
   ============================================================================ */

/* ---- force dark, retire the light/dark toggle UI ---- */
html:not(.theme-dark){ /* safety: should never happen now, but keep dark */ }
.theme-toggle{ display:none !important; }

/* ---- space backdrop (sits behind all views; constellation feel everywhere) ---- */
body::before{
  content:''; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:#000000;   /* pure black space — the only light is the sun in-scene */
}
#starfield-bg{ position:fixed; inset:0; z-index:0; pointer-events:none; }

/* ---- hide the old sidebar; main goes full-bleed ----
   The shell is a CSS grid (250px sidebar + 1fr main). Hiding the sidebar leaves
   the grid with an empty 250px column, so collapse it to a single column. */
#view-dashboard .sidebar{ display:none !important; }
#view-dashboard.active{ grid-template-columns: 1fr !important; }
#view-dashboard .main{
  margin-left:0 !important; width:100% !important; max-width:100% !important;
  position:relative; z-index:1;
}

/* give NON-constellation views breathing room above the dock.
   On the constellation we want true full-bleed (no bottom gap). */
body:not(.apollo-active) .main{ padding-bottom:120px !important; }

/* Same solid navy as the Houston/QA/Under/Payments panels, on every other
   view (Dashboard, KPIs, Event Hawk, Bounce, Calendar, Mgmt, Regions, Map,
   Clients) — one consistent background instead of the black starfield
   showing through behind some views and not others. */
body:not(.apollo-active) #view-dashboard .main{
  background:rgba(14,14,16,1); min-height:100vh;
}

/* ============================================================================
   FULL-BLEED CONSTELLATION
   The Apollo shell is a flex column (header + sections). Make the constellation
   block flex-fill the viewport so the stage goes edge-to-edge with no gap.
   ============================================================================ */
body.apollo-active #view-apollo > .apollo-shell{ padding:0 !important; gap:0 !important; min-height:100vh; position:relative; }
/* QA / Underperformers are no longer top tabs — they're dock buttons now */
body.apollo-active .apollo-section-nav{ display:none !important; }
/* The constellation canvas is pinned to the WHOLE viewport so nothing can leave
   a band at the top. Everything else (header, search, dock) floats above it. */
body.apollo-active .apollo-constellation-block{ position:static; margin:0 !important; }
body.apollo-active .constellation-stage{
  position:fixed !important; inset:0 !important; width:100vw !important; height:100vh !important;
  min-height:100vh !important; border-radius:0 !important; border:none !important; z-index:1;
}
/* header (APOLLO v5.0 + RIP ANDY + SYSTEM ONLINE) floats over the constellation,
   with comfortable inset so the badges aren't jammed against the top edge.
   absolute (not fixed) so it stays inside the apollo-shell stacking context and
   paints ABOVE the fixed canvas; high z-index guarantees it's on top. */
body.apollo-active .apollo-header{
  position:absolute !important; top:0; left:0; right:0; z-index:40 !important;
  margin:0 !important; padding:16px 24px !important; min-height:0 !important;
  background:transparent !important; pointer-events:none;
}
body.apollo-active .apollo-header > *{ pointer-events:auto; }
/* nudge the corner badge off the very edge (abs-pos children ignore header padding) */
body.apollo-active .apollo-status-block{ top:14px; right:20px; }
/* NOTE: a `.constellation-search{ top:72px !important; }` rule used to live
   here, from when the search bar sat directly under the APOLLO badge in the
   header and needed pushing down to clear it. Both now live together in
   .constellation-topbar (styles.css) which handles their layout itself —
   the leftover !important here was fighting that flexbox, forcing the
   search bar ~70px below where it belongs. Removed. */

/* ============================================================================
   QA / UNDERPERFORMERS as crystal overlay panels (opened from the dock)
   ============================================================================ */
/* hidden while on the constellation */
body.apollo-active [data-apollo-section="help"],
body.apollo-active [data-apollo-section="underperformers"],
body.apollo-active [data-apollo-section="payments"],
body.apollo-active [data-apollo-section="houston"]{ display:none !important; }
/* shown as a centered crystal panel when its dock button is active */
body.apollo-panel-help [data-apollo-section="help"],
body.apollo-panel-underperformers [data-apollo-section="underperformers"],
body.apollo-panel-payments [data-apollo-section="payments"],
body.apollo-panel-houston [data-apollo-section="houston"]{
  display:block !important;
  /* !important needed: `.apollo-shell > :not(...)` (specificity 0,3,0) otherwise
     pins these to position:relative/z-index:1 and the panel renders behind everything. */
  /* Center with inset+margin:auto (NOT translate -50%): a translate-based center
     lands on half-pixels and, combined with backdrop-filter, blurs the text. */
  /* Leave 104px clear at the bottom so the floating dock never covers content,
     and fade the last rows out (mask) so the scroll edge looks soft, not cut. */
  position:fixed !important; inset:18px 0 104px !important; margin:auto !important; transform:none !important;
  width:min(1600px,95vw); height:max-content; max-height:calc(100vh - 150px); overflow:auto; z-index:70 !important;
  -webkit-mask-image:linear-gradient(to bottom, #000 calc(100% - 30px), transparent);
  mask-image:linear-gradient(to bottom, #000 calc(100% - 30px), transparent);
  /* Solid, opaque panel (no backdrop-filter on the panel itself): a large
     backdrop-blur promotes the panel to a GPU layer that rasterizes its TEXT
     soft/blurry. The blurred constellation behind comes from #apollo-panel-backdrop. */
  background:rgba(14,14,16,1) !important; border:1px solid rgba(255, 255, 255,.3); border-radius:22px;
  padding:28px;
  box-shadow:0 36px 90px rgba(0,0,0,.62), inset 0 1px 0 rgba(255,255,255,.08);
}
/* The panel lives inside <main> (position:relative; z-index:1), a stacking
   context BELOW #apollo-panel-backdrop (z65) — so the backdrop painted on top and
   stole the clicks (closing the panel). Lift <main> above the backdrop while a
   panel is open so the panel (and its buttons) are actually clickable. */
body.apollo-panel-help main.main,
body.apollo-panel-underperformers main.main,
body.apollo-panel-payments main.main,
body.apollo-panel-houston main.main{ z-index:66 !important; }

/* All 4 dock panels (Houston, QA, Underperformers, Payments) go full-screen
   edge-to-edge instead of the centered crystal popup — no constellation
   peeking around the edges. Source order beats the shared rule above (same
   specificity, later wins) so this overrides the centered/blurred version. */
body.apollo-panel-help [data-apollo-section="help"],
body.apollo-panel-underperformers [data-apollo-section="underperformers"],
body.apollo-panel-payments [data-apollo-section="payments"],
body.apollo-panel-houston [data-apollo-section="houston"]{
  inset:0 !important; width:100vw !important; max-width:100vw !important;
  height:100vh !important; max-height:100vh !important;
  border-radius:0 !important; border:none !important;
  padding:36px 36px 128px !important;
}

/* Expanded QA Center inside the panel: lay the 3 cards out as a responsive flex
   row that fills the (now wider) panel. The original absolute ±px spread was built
   for the old full-width Apollo page and clipped / cramped the columns. */
body.apollo-panel-help [data-apollo-section="help"][data-qa-layout="expanded"] .apollo-qa-carousel{
  display:flex !important; gap:22px !important; height:auto !important; overflow:visible !important;
  align-items:flex-start !important; justify-content:stretch !important; padding:4px 2px;
}
body.apollo-panel-help [data-apollo-section="help"][data-qa-layout="expanded"] .apollo-tool{
  position:static !important; transform:none !important; left:auto !important; top:auto !important;
  flex:1 1 0 !important; width:auto !important; min-width:0 !important; max-width:none !important;
  max-height:calc(100vh - 250px) !important; overflow:auto !important;
  opacity:1 !important; filter:none !important;
}
/* Blur the constellation behind the panel by filtering the canvas ITSELF, not via
   backdrop-filter: a full-screen backdrop-filter + the fixed panel/dock on top made
   Chromium render the whole overlay blurry. This blurs only the constellation. */
body.apollo-panel-help .constellation-stage,
body.apollo-panel-underperformers .constellation-stage,
body.apollo-panel-payments .constellation-stage,
body.apollo-panel-houston .constellation-stage{ filter:blur(7px) !important; }
/* The full-screen constellation sits at z-index 9000; drop it below the panel. */
body.apollo-panel-help .constellation-stage.is-fullscreen,
body.apollo-panel-underperformers .constellation-stage.is-fullscreen,
body.apollo-panel-payments .constellation-stage.is-fullscreen,
body.apollo-panel-houston .constellation-stage.is-fullscreen{ z-index:1 !important; }

/* Plain dim overlay (NO backdrop-filter — see note above). */
#apollo-panel-backdrop{ display:none; position:fixed; inset:0; z-index:65; background:rgba(4,7,14,.62); }
#apollo-panel-close{ display:none; position:fixed; z-index:73; top:max(7vh,18px); right:max(4vw,18px);
  width:42px; height:42px; border-radius:16px; align-items:center; justify-content:center;
  background:rgba(182,182,182,.36); border:1px solid rgba(255,255,255,.28); color:#f1f5f9; font-size:18px;
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px);
  box-shadow:0 4px 30px rgba(0,0,0,.1); cursor:pointer; }
#apollo-panel-close:hover{ background:rgba(210,210,210,.46); border-color:rgba(255,255,255,.5); color:#ffffff; }
body.apollo-panel-help #apollo-panel-backdrop,
body.apollo-panel-underperformers #apollo-panel-backdrop,
body.apollo-panel-payments #apollo-panel-backdrop,
body.apollo-panel-houston #apollo-panel-backdrop{ display:block; }
/* Houston is deliberately absent: the Weekly Review queue shows no X, so the
   On hold shelf can have that whole corner. It closes with Escape, wired in
   ensurePanelChrome. The other three panels keep the button. */
body.apollo-panel-help #apollo-panel-close,
body.apollo-panel-underperformers #apollo-panel-close,
body.apollo-panel-payments #apollo-panel-close{ display:flex; }

/* ============================================================================
   HOUSTON — mission-report HUD (Jarvis-style readout, not a plain card list)
   ============================================================================ */
.houston-head{ margin-bottom:18px; }
.houston-eyebrow{
  display:flex; align-items:center; gap:7px; font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10.5px; font-weight:700; letter-spacing:.16em; color:#f1f5f9; margin-bottom:6px;
}
.houston-eyebrow-dot{
  width:6px; height:6px; border-radius:50%; background:#f1f5f9;
  box-shadow:0 0 8px 2px rgba(241,245,249,.6); animation:houston-pulse 1.8s ease-in-out infinite;
}
@keyframes houston-pulse{ 0%,100%{ opacity:1; } 50%{ opacity:.35; } }
#houston-title{ font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; letter-spacing:.02em; }
#houston-subtitle{ font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:12px; }

/* Faint schematic grid behind the whole panel — a HUD backdrop, not decoration
   that competes with the report itself (fades out toward the bottom). */
#houston-console::before{
  content:''; position:absolute; inset:0; z-index:0; pointer-events:none; border-radius:inherit;
  background-image:radial-gradient(circle at 1px 1px, rgba(255,255,255,.10) 1px, transparent 1.4px);
  background-size:26px 26px; opacity:.6;
  -webkit-mask-image:linear-gradient(to bottom, #000, transparent 80%);
  mask-image:linear-gradient(to bottom, #000, transparent 80%);
}
.houston-head{ position:relative; z-index:1; }

/* ===== Morning Brief =====================================================
   Read-only health scan, sits above the review queue. Colour carries meaning
   here and nowhere else in the panel: red is reserved for critical, which per
   house rules means a real failure. High and medium use depth of blue, not a
   traffic light, so nobody reads the colour and skips the sentence. */
.widget-brief{
  padding:16px 18px 14px; margin-bottom:16px; border-radius:16px; position:relative;
  background:linear-gradient(165deg, rgba(20,32,64,.82), rgba(10,17,38,.86));
  border:1px solid rgba(120,150,225,.24);
  box-shadow:0 16px 40px rgba(4,10,28,.42), inset 0 1px 0 rgba(255,255,255,.10);
}
/* The "On hold" shelf moved down to the Apollo Brain rail, so the only thing
   left at the top right is the panel's close button (42px at right:max(4vw,18px)).
   The title row clears that; every row below runs the full width. */
.brief-head{ padding-right:clamp(72px, 8vw, 110px); }
.brief-meta{ padding-right:0; }
.brief-head{ min-width:0; }
.brief-head-left{ min-width:0; }
.brief-meta{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:10px; }
.brief-eyebrow{
  display:inline-flex; align-items:center; gap:7px;
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:9.5px; letter-spacing:.16em; color:#9fb4e8; margin-bottom:7px;
}
.brief-dot{
  width:6px; height:6px; border-radius:50%; background:#60a5fa;
  box-shadow:0 0 0 3px rgba(96,165,250,.20); animation:briefPulse 2.4s ease-in-out infinite;
}
@keyframes briefPulse{ 0%,100%{ opacity:1 } 50%{ opacity:.35 } }
.brief-title{ margin:0; font-size:17.5px; font-weight:800; color:#fff; letter-spacing:-.01em; }
.brief-sub{
  margin:3px 0 0; font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10px; letter-spacing:.05em; color:#93a5c9; text-transform:uppercase;
}
.brief-pill{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:9.5px; letter-spacing:.06em; text-transform:uppercase; font-weight:700;
  padding:5px 10px; border-radius:999px; white-space:nowrap;
}
.brief-pill.is-critical{ color:#fecaca; background:rgba(185,28,28,.30); border:1px solid rgba(248,113,113,.45); }
.brief-pill.is-high{ color:#dbeafe; background:rgba(37,99,235,.30); border:1px solid rgba(147,178,255,.42); }
.brief-pill.is-medium{ color:#c7d5f2; background:rgba(71,92,140,.28); border:1px solid rgba(130,155,205,.30); }
.brief-btn{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10px; letter-spacing:.06em; text-transform:uppercase; font-weight:700;
  color:#dbeafe; background:rgba(37,99,235,.24); border:1px solid rgba(147,178,255,.38);
  padding:7px 13px; border-radius:9px; cursor:pointer; transition:background .15s, transform .15s;
}
.brief-btn:hover:not(:disabled){ background:rgba(37,99,235,.40); transform:translateY(-1px); }
.brief-btn:disabled{ opacity:.5; cursor:default; }

.brief-list{ margin-top:13px; display:flex; flex-direction:column; gap:5px; }
.brief-row{
  display:grid; grid-template-columns:auto auto 1fr auto; align-items:center; gap:11px;
  padding:8px 11px; border-radius:10px;
  background:rgba(255,255,255,.045); border:1px solid rgba(255,255,255,.07);
  border-left:3px solid rgba(130,155,205,.45);
  transition:background .15s, border-color .15s;
}
.brief-row:hover{ background:rgba(255,255,255,.08); }
.brief-row.is-critical{ border-left-color:#ef4444; background:rgba(127,29,29,.16); }
.brief-row.is-critical:hover{ background:rgba(127,29,29,.24); }
.brief-row.is-high{ border-left-color:#60a5fa; }
.brief-sev{ display:inline-flex; color:#93a5c9; }
.brief-row.is-critical .brief-sev{ color:#f87171; }
.brief-row.is-high .brief-sev{ color:#60a5fa; }
.brief-logo{
  width:26px; height:26px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center;
  font-weight:800; font-size:12px; color:#dbeafe; flex:0 0 auto;
  background:linear-gradient(150deg, rgba(59,92,170,.85), rgba(24,42,88,.9));
  box-shadow:0 0 0 1px rgba(255,255,255,.18);
}
.brief-body{ min-width:0; }
.brief-client{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:9.5px; letter-spacing:.07em; text-transform:uppercase; color:#93a5c9; margin-bottom:2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.brief-headline{ font-size:12.5px; font-weight:700; color:#fff; line-height:1.25; }
.brief-detail{ font-size:11px; color:#b6c4e0; line-height:1.35; margin-top:1px; }
.brief-age{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:9px; color:#7f92b8; letter-spacing:.04em; margin-left:4px;
}
.brief-actions{ display:flex; gap:6px; flex:0 0 auto; }
.brief-mini{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:9px; letter-spacing:.05em; text-transform:uppercase; font-weight:700;
  color:#c7d5f2; background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.13);
  padding:5px 9px; border-radius:7px; cursor:pointer; transition:background .15s, color .15s;
}
.brief-mini:hover{ background:rgba(255,255,255,.15); color:#fff; }
.brief-mini.is-primary{ color:#dbeafe; background:rgba(37,99,235,.30); border-color:rgba(147,178,255,.42); }
.brief-mini.is-primary:hover{ background:rgba(37,99,235,.48); }
.brief-more{
  margin-top:10px; width:100%; font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10px; letter-spacing:.06em; text-transform:uppercase; font-weight:700;
  color:#9fb4e8; background:transparent; border:1px dashed rgba(147,178,255,.30);
  padding:9px; border-radius:10px; cursor:pointer; transition:background .15s;
}
.brief-more:hover{ background:rgba(147,178,255,.10); color:#dbeafe; }
.brief-empty{ display:flex; align-items:center; gap:14px; margin-top:15px; padding:14px 15px;
  border-radius:12px; background:rgba(37,99,235,.12); border:1px solid rgba(147,178,255,.24); }
.brief-empty-mark{
  width:34px; height:34px; border-radius:50%; flex:0 0 auto;
  display:flex; align-items:center; justify-content:center; font-size:17px; font-weight:800;
  color:#dbeafe; background:rgba(37,99,235,.35); box-shadow:0 0 0 1px rgba(147,178,255,.40);
}
.brief-empty strong{ display:block; color:#fff; font-size:13.5px; }
.brief-empty span{ display:block; color:#b6c4e0; font-size:11.5px; margin-top:2px; }
.brief-inline-link{
  background:none; border:none; padding:0; cursor:pointer; font:inherit;
  color:#93c5fd; text-decoration:underline; text-underline-offset:2px;
}
.brief-inline-link:hover{ color:#dbeafe; }
@media (prefers-reduced-motion: reduce){ .brief-dot{ animation:none } }

.review-queue-stat{ display:flex; align-items:center; gap:12px; margin-top:10px; }
.review-queue-stat-num{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:18px; font-weight:800;
  color:#ffffff;
}

/* Name search. Sits where the "reviewed this cycle" caption used to, on the
   same baseline as the counter, in the same glass as the cards. */
.review-search{
  position:relative; display:flex; align-items:center; gap:8px;
  width:min(340px, 40vw); padding:0 10px; height:32px; border-radius:12px;
  background:rgba(182,182,182,.20); border:1px solid rgba(255,255,255,.22);
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px);
  transition:border-color .14s ease, background .14s ease;
}
.review-search:focus-within{ border-color:rgba(255,255,255,.5); background:rgba(200,200,200,.28); }
.review-search-icon{ width:14px; height:14px; flex-shrink:0; color:#cbd5e1; }
/* Selector deliberately doubled up (.review-search .review-search-input rather
   than the class alone): the dark theme paints every bare `input` with a solid
   #111 fill, which outranked a single class and showed as a grey rectangle
   sitting inside this rounded pill. The field carries no fill of its own; the
   label around it is the visible control. */
.review-search .review-search-input{
  flex:1; min-width:0; border:none; background:transparent; outline:none; padding:0;
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:11.5px; color:#ffffff;
}
.review-search-input::placeholder{ color:#cbd5e1; opacity:.75; }
/* The type=search widget's own clear button is inconsistent across platforms
   and lands on top of ours, so it is switched off. */
.review-search-input::-webkit-search-cancel-button{ -webkit-appearance:none; appearance:none; }
.review-search-clear{
  display:none; flex-shrink:0; width:18px; height:18px; padding:0; line-height:1;
  border:none; border-radius:50%; cursor:pointer;
  background:rgba(255,255,255,.14); color:#e2e8f0; font-size:13px;
}
.review-search-clear:hover{ background:rgba(255,255,255,.26); color:#ffffff; }
.review-search.is-filled .review-search-clear{ display:block; }
.review-search-count{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:10px; letter-spacing:.08em;
  text-transform:uppercase; color:#cbd5e1; white-space:nowrap;
}

/* The sweep-complete toast lived here. It is gone: the counter dropping back
   to zero says it by itself, and the notice was an interruption for something
   nobody has to act on. */

/* 5-up card grid. Each .review-row is one grid cell; its expanded
   .review-drop-row spans every column (grid-column:1/-1 below) so it opens
   as its own full-width strip right where it was clicked, pushing later
   cards down a row — no JS reflow needed, CSS Grid auto-placement does it. */
.review-queue-list{
  list-style:none; margin:0; padding:0; position:relative; z-index:1;
  display:grid; grid-template-columns:repeat(5, minmax(0, 1fr)); gap:14px;
}
/* Only degrades below 5 on genuinely small windows — the panel this list
   lives in is already capped at min(1600px,95vw) (see the
   body.apollo-panel-houston rule above), so a fixed 5-up is the right
   default at every normal desktop width; this is just the mobile fallback. */
@media (max-width:900px){ .review-queue-list{ grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); } }
.houston-empty{
  grid-column:1/-1;
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:11.5px; color:#5b7a94; font-style:italic;
}

/* ---- Card — logo/avatar + name on top, a 3-stat strip, problem badges
   only when there's something to flag. Fades/slides in on (re)render,
   staggered per card via inline animation-delay (see renderReviewQueueList). ---- */
.review-row{ list-style:none; opacity:0; animation:review-row-in .32s ease-out forwards; }
@keyframes review-row-in{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:translateY(0); } }
/* Ready/Hide click: dissolve the card in place before the list re-renders
   fresh. A scale+fade reads as "this one's done" without the sideways slide
   fighting the grid's own reflow. */
.review-row.is-leaving{
  animation:none; transition:opacity .2s ease, transform .2s ease;
  opacity:0; transform:scale(.92); pointer-events:none;
}
/* The open drop (grid-column:1/-1 — Notebook + KPIs, can be tall) used to
   just fade to invisible while still reserving its full height for the
   whole transition, leaving a big dead gap in the grid until the list
   re-rendered. Collapsing grid-template-rows 1fr -> 0fr instead genuinely
   shrinks the row to nothing, so the gap actually closes instead of just
   going transparent. */
.review-drop-row{ list-style:none; grid-column:1 / -1; display:grid; grid-template-rows:1fr; transition:grid-template-rows .2s ease-out; }
.review-drop-row > .review-drop{ overflow:hidden; min-height:0; }
.review-drop-row.is-leaving{ grid-template-rows:0fr; }
.review-drop-row.is-leaving .review-drop{ opacity:0; transition:opacity .12s ease; }

/* css.glass recipe — same material as the dock, the Apollo topbar and the
   About panel. Replaces the cyan-tinted card this used to be. */
.review-row-main{
  position:relative; display:flex; flex-direction:column; gap:12px; height:100%;
  padding:14px 14px 22px; border-radius:16px; cursor:pointer;
  background:rgba(182,182,182,.36); border:1px solid rgba(255,255,255,.28);
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px);
  box-shadow:0 4px 30px rgba(0,0,0,.1);
  transition:background .14s ease, border-color .14s ease, transform .14s ease;
}
@media (hover:hover) and (pointer:fine){
  .review-row-main:hover{ background:rgba(210,210,210,.46); border-color:rgba(255,255,255,.5); transform:translateY(-2px); }
}
.review-row.is-open .review-row-main{ background:rgba(210,210,210,.46); border-color:rgba(255,255,255,.55); }
.review-chevron{
  display:flex; position:absolute; left:50%; bottom:6px; transform:translateX(-50%);
  color:#cbd5e1; transition:transform .16s ease, color .16s ease;
}
.review-row.is-open .review-chevron{ transform:translateX(-50%) rotate(180deg); color:#ffffff; }

/* Logo on top, name below, city below that — stacked and centered, not the
   old side-by-side layout. */
.review-card-top{ display:flex; flex-direction:column; align-items:center; gap:8px; text-align:center; }
/* Cache-first logo avatar — instant colored-initial fallback (same level-
   color family as the constellation's planets, also used as the ring color)
   swapped for a real company logo lazily, only once the card scrolls into
   view (see reviewObserveAvatar in app.js) — never all at once. */
.review-avatar{
  position:relative; width:54px; height:54px; border-radius:50%; flex-shrink:0; overflow:hidden;
  display:flex; align-items:center; justify-content:center;
  /* No dark inset rim — it ringed every client logo in black once the cards
     went to light glass. The inline style in reviewAvatarHtml sets the actual
     hairline; this is just the fallback if that ever goes away. */
  box-shadow:0 0 0 1px rgba(255,255,255,.30);
}
.review-avatar-fallback{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:18px; font-weight:800; color:#fff;
  text-shadow:0 1px 2px rgba(0,0,0,.4);
}
.review-avatar-img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; border-radius:50%; }

.review-row-info{ min-width:0; width:100%; display:flex; flex-direction:column; align-items:center; gap:1px; }
/* Text sits on light glass now, so it moves up from the old dim blue-greys
   that only worked against the near-black card. */
.review-row-name{ max-width:100%; font-size:13px; font-weight:700; color:#ffffff; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.review-row-sub{ max-width:100%; font-size:11px; color:#e2e8f0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* 3-column stat strip, divided by hairlines — From/Sector/Budget-style. */
.review-card-stats{
  display:grid; grid-template-columns:repeat(3, 1fr);
  border-top:1px solid rgba(255,255,255,.28); padding-top:10px;
}
.review-card-stat{
  display:flex; flex-direction:column; align-items:center; gap:2px; text-align:center;
  border-left:1px solid rgba(255,255,255,.22);
}
.review-card-stat:first-child{ border-left:none; }
.review-card-stat-label{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:8.5px; letter-spacing:.08em;
  text-transform:uppercase; color:#e2e8f0;
}
.review-card-stat-val{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:12.5px; font-weight:800; color:#ffffff;
}

.review-row-badges{ display:flex; gap:6px; flex-wrap:wrap; }
.review-badge{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:9.5px; font-weight:700;
  letter-spacing:.04em; text-transform:uppercase; padding:3px 8px; border-radius:16px; white-space:nowrap;
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px);
}
/* Problem badges keep red: these are genuine error states (payment issue,
   dormant), the one place colour still carries meaning. */
.review-badge-problem{ color:#fecaca; background:rgba(248,113,113,.30); border:1px solid rgba(248,113,113,.55); }
.review-badge-ok{ color:#f1f5f9; background:rgba(182,182,182,.36); border:1px solid rgba(255,255,255,.28); }
.review-badge-neutral{ color:#f1f5f9; background:rgba(182,182,182,.36); border:1px solid rgba(255,255,255,.28); }

/* ---- Expanded drop — full KPIs, per-problem recommendations, the shared
   Client Notebook (scoped 'review'), and the Ready action. ---- */
.review-drop{
  display:flex; flex-direction:column; gap:14px; margin-top:6px; padding:16px;
  /* Glass rim + radius to match the cards, but the fill stays dark: this drop
     carries the notebook and full KPI readout, and the light 36% tint would
     cost too much contrast on that much text. */
  border-radius:16px; background:rgba(4,10,22,.75); border:1px solid rgba(255,255,255,.28);
  animation:houston-drop-in .18s ease-out;
}
@keyframes houston-drop-in{ from{ opacity:0; transform:translateY(-4px); } to{ opacity:1; transform:translateY(0); } }

/* Two-column split: Notebook on the left, KPIs + problems/recommendations on
   the right. Only reachable now that Houston is a full-screen panel (see the
   full-screen override above) — there's finally room for it side by side. */
/* Notes | findings | IO code. The third column is narrower than the other two
   on purpose: it answers one yes-or-no question, so giving it an equal share
   would take width away from the two columns that hold real reading. */
.review-drop-split{ display:grid; grid-template-columns:1fr 1fr 0.62fr; gap:28px; align-items:start; }
.review-drop-col-notebook{ min-width:0; border-right:1px solid rgba(255,255,255,.20); padding-right:28px; }
.review-drop-col-info{ min-width:0; display:flex; flex-direction:column; gap:16px; }
.review-drop-col-io{
  min-width:0; display:flex; flex-direction:column; gap:10px;
  border-left:1px solid rgba(255,255,255,.20); padding-left:28px;
}
@media (max-width:1240px){
  /* Two columns before one: the IO answer drops under the notes rather than
     squeezing the findings into a gutter. */
  .review-drop-split{ grid-template-columns:1fr 1fr; }
  .review-drop-col-io{ grid-column:1 / -1; border-left:none; padding-left:0;
    border-top:1px solid rgba(255,255,255,.20); padding-top:16px; }
}
@media (max-width:900px){
  .review-drop-split{ grid-template-columns:1fr; }
  .review-drop-col-notebook{ border-right:none; padding-right:0; border-bottom:1px solid rgba(255,255,255,.20); padding-bottom:16px; }
}

.review-io-head{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--gold,#c8a54a); opacity:.85;
}
.review-io-body{ display:flex; flex-direction:column; align-items:flex-start; gap:9px; }
.review-io-loading{ font-size:12px; font-style:italic; color:rgba(230,201,119,.45); }

/* Two states, both always on screen, so the answer and the way to change it are
   the same control. Gold for the chosen one: this panel is Apollo's own, and
   Apollo's palette is gold on near-black.
   The track is glass: blurred, translucent, with a lit top edge and a shadow
   cast inward, so it sits IN the panel rather than on it. */
.review-io-choice{
  position:relative;
  display:inline-flex; padding:4px; gap:4px;
  border:1px solid rgba(200,165,74,.22); border-radius:999px;
  background:linear-gradient(180deg, rgba(58,50,32,.55), rgba(12,11,9,.62));
  backdrop-filter:blur(10px) saturate(130%);
  -webkit-backdrop-filter:blur(10px) saturate(130%);
  /* Every highlight is gold, never white. A white rim on a gold-on-black panel
     reads as a smudge of another palette; the same lift done in the panel's own
     colour keeps the glass and loses the sticker. */
  box-shadow:
    inset 0 1px 0 rgba(200,165,74,.28),       /* lit top edge, in gold */
    inset 0 -1px 0 rgba(0,0,0,.45),           /* shaded bottom edge */
    0 6px 18px rgba(0,0,0,.45);
}
/* The specular sweep across the top half. A separate layer so it stays put
   while the pill underneath slides between the two options. */
.review-io-choice::before{
  content:''; position:absolute; inset:1px 1px 45% 1px;
  border-radius:999px 999px 40% 40% / 999px 999px 100% 100%;
  background:linear-gradient(180deg, rgba(200,165,74,.10), rgba(200,165,74,0));
  pointer-events:none;
}
.review-io-opt{
  position:relative;
  padding:6px 15px; border:none; border-radius:999px; cursor:pointer;
  background:transparent; color:rgba(230,201,119,.55);
  font-family:inherit; font-size:12.5px; font-weight:600; letter-spacing:.01em;
  transition:background .16s ease, color .16s ease, box-shadow .16s ease;
}
.review-io-opt:hover{ color:#e6c977; background:rgba(200,165,74,.10); }
/* The chosen half: a gold bead of glass. Gradient rather than flat fill, a
   white highlight along its own top edge, and a warm glow under it. */
.review-io-opt.is-on{
  color:#1a1508; font-weight:700;
  background:linear-gradient(180deg, #e6c977 0%, var(--gold,#c8a54a) 55%, #a8862f 100%);
  /* Its own top edge lifts with a paler gold rather than white, so the bead
     still catches light without a rim of a different colour on it. */
  box-shadow:
    inset 0 1px 0 rgba(247,225,160,.60),
    inset 0 -1px 2px rgba(90,66,10,.45),
    0 2px 10px rgba(200,165,74,.30);
}
.review-io-opt.is-on:hover{ background:linear-gradient(180deg, #f0d78d 0%, #d3b055 55%, #b08f33 100%); }
/* The unchosen half of the pair reads as "not yet" on its own, so it needs no
   red: nothing here is an error, it is just work still to do. */
.review-io-opt:focus-visible{ outline:2px solid var(--gold,#c8a54a); outline-offset:2px; }

.review-io-unknown{ font-size:12.5px; color:rgba(230,201,119,.45); }

/* Second question in the same column, under the IO answer. A hairline in the
   panel's own gold separates them, so the two headings do not read as one
   block with a stray subtitle. */
.review-io-group{
  display:flex; flex-direction:column; gap:10px;
  margin-top:16px; padding-top:16px;
  border-top:1px solid rgba(200,165,74,.16);
}
/* Several options, not two, and every label is a phrase rather than a word. Wrapped
   inside one pill track they came out lopsided — two rows of different widths in
   a shape built for one. So this one stacks: same glass, same gold bead on the
   chosen row, one answer per row, all of them the same width. */
/* Sized by its longest label, not by the column: left to stretch it ran to the
   panel's edge while the IO pill above stopped a third of the way in, and two
   controls answering two questions in one column want the same right edge. */
.review-io-stack{
  position:relative;
  display:grid; gap:3px; width:max-content; max-width:100%; padding:4px;
  border:1px solid rgba(200,165,74,.22); border-radius:14px;
  background:linear-gradient(180deg, rgba(58,50,32,.55), rgba(12,11,9,.62));
  backdrop-filter:blur(10px) saturate(130%);
  -webkit-backdrop-filter:blur(10px) saturate(130%);
  box-shadow:
    inset 0 1px 0 rgba(200,165,74,.28),
    inset 0 -1px 0 rgba(0,0,0,.45),
    0 6px 18px rgba(0,0,0,.45);
}
/* No specular sweep here, unlike the pill above. Across two options it reads as
   glass; across four rows it lands on the first one and makes it look half
   chosen, which is exactly the thing this control has to be unambiguous about. */
/* Left-aligned and full width: four phrases centred at four different lengths
   read as a ragged block, while a shared left edge reads as a list. */
.review-io-stack .review-io-opt{
  width:100%; text-align:left; padding:8px 12px; border-radius:10px;
}
/* The team calls these setups by number, so the number leads and the phrase
   explains it. Monospace and fixed width so the three labels line up. */
.review-io-opt-numbered{ display:flex; align-items:center; gap:9px; }
.review-io-opt-num{
  flex-shrink:0; width:18px; height:18px; border-radius:6px;
  display:inline-flex; align-items:center; justify-content:center;
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10.5px; font-weight:800; line-height:1;
  background:rgba(200,165,74,.16); color:#e6c977;
}
.review-io-opt.is-on .review-io-opt-num{ background:rgba(26,21,8,.28); color:#1a1508; }

@media (prefers-reduced-motion: reduce){ .review-io-opt{ transition:none; } }

.review-drop-kpis{ display:flex; gap:22px; flex-wrap:wrap; }
.review-drop-kpi{ display:flex; flex-direction:column; align-items:center; gap:2px; text-align:center; }
.review-drop-kpi span{
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:9px; letter-spacing:.1em;
  text-transform:uppercase; color:#cbd5e1;
}
.review-drop-kpi b{ font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:15px; color:#ffffff; }
.review-drop-acctid{ font-size:12px !important; cursor:pointer; border-bottom:1px dashed rgba(255,255,255,.4); transition:color .12s ease; }
.review-drop-acctid:hover{ color:#ffffff; }

.review-drop-problems{ display:flex; flex-direction:column; gap:12px; }
.review-drop-problem-label{
  display:inline-block; margin-bottom:5px; font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace;
  font-size:10px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:#f87171;
}
.review-drop-recs{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:5px; }
.review-drop-recs li{ font-size:12px; line-height:1.45; color:#cfe4ef; padding-left:12px; position:relative; }
.review-drop-recs li::before{
  content:''; position:absolute; left:0; top:7px; width:4px; height:4px; border-radius:50%; background:#f1f5f9;
}
.review-drop-clear{ font-size:12.5px; color:#e2e8f0; font-style:italic; }

.review-drop-actions{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding-top:12px; border-top:1px solid rgba(255,255,255,.20);
}
.review-drop-actions-left{ display:flex; align-items:center; gap:8px; }
.review-view-profile-btn{
  background:rgba(182,182,182,.36); border:1px solid rgba(255,255,255,.28); color:#f1f5f9;
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px); box-shadow:0 4px 30px rgba(0,0,0,.1);
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:10.5px; font-weight:700;
  letter-spacing:.05em; padding:8px 14px; border-radius:16px; cursor:pointer; transition:background .12s ease;
}
@media (hover:hover) and (pointer:fine){ .review-view-profile-btn:hover{ background:rgba(210,210,210,.46); } }
.review-hide-btn,
.review-park-btn{
  background:rgba(182,182,182,.36); border:1px solid rgba(255,255,255,.28); color:#f1f5f9;
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px); box-shadow:0 4px 30px rgba(0,0,0,.1);
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:10.5px; font-weight:700;
  letter-spacing:.05em; padding:8px 14px; border-radius:16px; cursor:pointer; transition:background .12s ease, color .12s ease;
}
@media (hover:hover) and (pointer:fine){ .review-hide-btn:hover, .review-park-btn:hover{ background:rgba(210,210,210,.46); color:#ffffff; } }
/* Primary action — same indigo→cyan brand gradient as the dock's active
   state, so "Ready" reads as the one prominent call-to-action on the card. */
.review-ready-btn{
  display:inline-flex; align-items:center; gap:7px; border:none; cursor:pointer;
  background:rgba(225,225,225,.5); border:1px solid rgba(255,255,255,.55) !important; color:#ffffff;
  backdrop-filter:blur(8.3px); -webkit-backdrop-filter:blur(8.3px);
  font-family:'JetBrains Mono','IBM Plex Mono',ui-monospace,monospace; font-size:11.5px; font-weight:800;
  letter-spacing:.05em; text-transform:uppercase; padding:9px 18px; border-radius:16px;
  box-shadow:0 4px 30px rgba(0,0,0,.1);
  transition:transform .12s ease, filter .12s ease;
}
.review-ready-btn:hover{ filter:brightness(1.08); transform:translateY(-1px); }
.review-ready-btn:active{ transform:translateY(0); }

/* the Apollo "tools" dock items (QA / Under) get a subtle accent */
/* The panel buttons (QA, Under, Payments, Houston) used to carry a navy tint
   and an indigo→cyan gradient when active, which made them the one coloured
   thing in an otherwise neutral dock. They now use the same glass as every
   other dock item — active reads as brighter glass, not a different hue. */
.dock-item[data-sec]{ background:rgba(255,255,255,.05); }
.dock-item[data-sec].active{
  background:rgba(255,255,255,.20); color:#fff; border-color:rgba(255,255,255,.5);
  box-shadow:0 10px 26px rgba(0,0,0,.45),
             inset 0 1px 0 rgba(255,255,255,.6),
             inset 0 -2px 7px rgba(255,255,255,.08);
}

/* ============================================================================
   CRYSTAL DOCK
   ============================================================================ */
#apollo-dock{
  position:fixed; left:50%; bottom:26px; transform:translateX(-50%);
  display:flex; align-items:center; gap:6px; padding:11px 14px; z-index:80;
  border-radius:22px;
  /* Glossy clear crystal — neutral, no color. */
  background:rgba(255,255,255,.07);
  border:1px solid rgba(255,255,255,.20);
  backdrop-filter:blur(26px) saturate(135%); -webkit-backdrop-filter:blur(26px) saturate(135%);
  box-shadow:0 20px 60px rgba(0,0,0,.5),
             inset 0 1px 0 rgba(255,255,255,.30),
             inset 0 -1px 0 rgba(255,255,255,.05);
  max-width:calc(100vw - 32px);
}
#apollo-dock .dock-sep{ width:1px; height:38px; margin:0 4px; background:rgba(255,255,255,.14); }
.dock-item{
  appearance:none; border:1px solid rgba(255,255,255,.10); background:rgba(255,255,255,.05);
  width:56px; height:56px; border-radius:15px; cursor:pointer; color:#e8eef7;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
  transition:transform .16s ease, background .16s ease, box-shadow .16s ease, border-color .16s ease;
  position:relative;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.12);
}
.dock-item .dock-ico{ font-size:20px; line-height:1; }
.dock-item .dock-ico svg{ width:21px; height:21px; }
.dock-item .dock-lbl{ font-size:8.5px; font-weight:700; letter-spacing:.2px; color:#cfd8e6; white-space:nowrap; }
.dock-item:hover{ transform:translateY(-7px); background:rgba(255,255,255,.13);
  box-shadow:0 12px 26px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.24); }
.dock-item.active{
  background:rgba(255,255,255,.20); color:#fff; border-color:rgba(255,255,255,.5);
  box-shadow:0 10px 26px rgba(0,0,0,.45),
             inset 0 1px 0 rgba(255,255,255,.6),
             inset 0 -2px 7px rgba(255,255,255,.08);
}
.dock-item.active .dock-lbl{ color:#fff; }
/* tooltip on hover */
.dock-item::after{
  content:attr(data-tip); position:absolute; bottom:calc(100% + 10px); left:50%; transform:translateX(-50%);
  background:rgba(18,22,30,.92); border:1px solid rgba(255,255,255,.18); color:#eef2f8;
  font-size:11px; font-weight:600; padding:5px 9px; border-radius:8px; white-space:nowrap;
  opacity:0; pointer-events:none; transition:opacity .14s; box-shadow:0 8px 20px rgba(0,0,0,.5);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
}
.dock-item:hover::after{ opacity:1; }
.dock-item.dock-account{ background:transparent; border:1px solid rgba(255,255,255,.22); padding:0; overflow:hidden; }
.dock-item.dock-account .dock-avatar{ width:100%; height:100%; border-radius:14px; object-fit:cover; display:block; }

/* dock stays visible in full-screen focus mode but lifts slightly so it never
   collides with the client popup; tweak here if it ever overlaps. */
body.cnst-fullscreen #apollo-dock{ bottom:18px; }

@media (max-width:760px){
  .dock-item{ width:48px; height:48px; }
  .dock-item .dock-lbl{ display:none; }
}
