/* ===== portal_engagement_html (HTML form, scoped) =====
   The Portal Engagement shell's styling. Loaded eagerly from
   anvil.yaml native_deps.head_html, which is what styles the designer canvas as
   well as the running app.

   THIS FILE SORTS LAST AMONG THE SEVEN PORTAL ENGAGEMENT LINKS (every pe_*.css
   sorts before portal_engagement.css).

   NO SUCH TIE EXISTS, and that was checked rather than assumed. This file
   declares .pe-shell, .pe-grid, .pe-stack, .pe-status-glyph, .pe-legend*,
   .pe-swatch*, .pe-triangle, .pe-info, .pe-tooltip, .pe-state-*, .pe-meta, the
   two overlay ids, the two section ids, and the four names lifted off the
   template's inline style attributes (.pe-header-block, .pe-h1, .pe-lede,
   .pe-offstage). The six child assets declare .pe-cycle-*, .pe-filters-*,
   .pe-seg*, .pe-search*, .pe-matrix-*, .pe-cell*, .pe-plot-*, .pe-risk-label,
   .pe-drawer-*, .pe-panel-*, .pe-figure*, .pe-check-*. No name is declared on
   both sides, so no child rule changes which declaration wins.

   WHAT DID CHANGE. A head-linked asset loses an equal-specificity tie to the
   dependency's px-theme-chrome block, which ensure_theme_injected() appends to
   the head at runtime, and to theme.css. One rule here was winning such a tie
   by document order only: .pe-state-panel's padding against
   .px-card { padding: 20px }. It is written doubled below.

   ROOT RULE, BARE CLASS, ON ITS OWN LINE, so it outranks the :where()-scoped
   rules below and so the dark restatement stays readable as
   [data-theme="dark"] .pe-shell {.

   min-height: 100vh AND padding: 20px ARE KEPT BYTE FOR BYTE. This screen
   deliberately scrolls inside its own box - pxSuppressParentScroll(shell,
   { scrollSelf: true }) writes overflow: auto onto it at runtime - so the two
   slide panels can pin to the viewport. Changing that box is a behaviour
   change and is the owner's call.

   flex: 1 0 auto. The root of an HTML form is a flex item inside the shared
   layout's scroller, .px-nav-content: #pe-shell IS the flex item and that
   runtime overflow: auto write lands on it, which would otherwise take the
   automatic minimum size away and let the port shrink the screen to itself.
   flex-shrink: 0 keeps the automatic minimum size. Same declaration, for the
   same reason, as
   theme/assets/owings/owings.css and theme/assets/rotacloud/rotacloud.css.

   THE DESIGNER GATE. The designer runs no Python, so the three rules that hide
   the whole screen until the script runs are split out and gated on the live
   class pe-live, which portal_engagement.mjs adds to this root in
   peSuppressScroll and removes in peRestoreScroll. Without the gate the canvas
   would be an empty box.

   NO KEYFRAMES, no @font-face and no url() in this file, so there is nothing
   to prefix or rewrite. */

/* =============================================
   PORTAL ENGAGEMENT - ACCENT & LAYOUT
   ============================================= */
.pe-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  flex: 1 0 auto;
  padding: 20px;
  gap: 18px;
  position: relative;
  background-color: var(--px-bg-elevated);
  background-image:
    radial-gradient(circle at top left, color-mix(in srgb, var(--accent) 10%, transparent), transparent 40%),
    linear-gradient(180deg, #eff6ff 0%, var(--px-bg-elevated) 100%);
}
/* The light palette. pe_plot.mjs puts the shared px-print-ink on the plot card
   while a dark page prints, so the chart it redraws for paper reads these too. */
.pe-shell,
[data-theme="dark"] .pe-shell .px-print-ink {
  --accent: #2563eb;
  --accent-hover: #1d4ed8;
  --accent-subtle: rgba(37, 99, 235, 0.10);
  --accent-text: #ffffff;
  --accent-rgb: 37, 99, 235;
  --px-loading-accent: #2563eb;
  --pe-improving: #2f9e5f;
  --pe-stable: #98a2ac;
  --pe-declining-rgb: 214, 69, 69;
  --pe-declining: rgb(var(--pe-declining-rgb));
  --pe-awaiting: #b9c2cc;
  --pe-risk-wash: rgba(var(--pe-declining-rgb), 0.10);
  --pe-risk-line: rgba(var(--pe-declining-rgb), 0.45);
  --pe-surface: #ffffff;
  --pe-seq-low: #cde2fb;
  --pe-seq-high: #0d366b;
}
/* Screen only, so a dark page prints with the light palette above. */
@media screen {
  [data-theme="dark"] .pe-shell {
    --accent: #60a5fa;
    --accent-hover: #93c5fd;
    --accent-subtle: rgba(96, 165, 250, 0.14);
    --accent-text: #0f172a;
    --accent-rgb: 96, 165, 250;
    --px-loading-accent: #60a5fa;
    --pe-improving: #4ade80;
    --pe-declining-rgb: 250, 140, 140;
    --pe-awaiting: #94a3b8;
    --pe-risk-wash: rgba(var(--pe-declining-rgb), 0.16);
    --pe-risk-line: rgba(var(--pe-declining-rgb), 0.55);
    --pe-surface: var(--px-bg-card);
    --pe-seq-low: #4a7fc0;
    --pe-seq-high: #9ec5f4;
    background-color: var(--px-bg-primary);
    background-image:
      radial-gradient(circle at top left, color-mix(in srgb, var(--accent) 18%, transparent), transparent 28%),
      linear-gradient(180deg, #10254a 0%, var(--px-bg-deep) 100%);
  }
}

/* =============================================
   HEADER BLOCK - the three declarations lifted off
   the template's inline style attributes. No .px-*
   rule declares any of these properties on these
   elements, so none of the three needs doubling.
   ============================================= */
:where(.pe-shell) .pe-header-block {
  margin-bottom: -2px;
}
:where(.pe-shell) .pe-h1 {
  font-family: var(--px-font);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--px-text-primary);
  margin: 0;
}
:where(.pe-shell) .pe-lede {
  font-family: var(--px-font);
  font-size: 0.85rem;
  color: var(--px-text-muted);
  margin: 0 0 0.5rem;
}

/* The two mount points whose DOM nodes are moved into the slide panels. They
   were style="display:none;" on the template; the slots inside them are
   invisible on the designer canvas by design. */
:where(.pe-shell) .pe-offstage {
  display: none;
}

/* =============================================
   DASHBOARD CONTENT BOX
   ============================================= */
/* peShowState writes `display` inline on all three of these on every state
   change, and an inline style beats a stylesheet, so the gated rule below only
   covers the moment before the first render. It is split from the base rule and
   gated on the live class so the designer canvas, which runs no Python and
   therefore never gets pe-live, shows the content laid out rather than a blank
   box. */
:where(.pe-shell) #pe-content {
  flex-direction: column;
  gap: 18px;
}
:where(.pe-shell.pe-live) #pe-content,
:where(.pe-shell.pe-live) #pe-error-panel,
:where(.pe-shell.pe-live) #pe-awaiting-panel {
  display: none;
}

/* =============================================
   GRID
   ============================================= */
:where(.pe-shell) .pe-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(320px, 0.85fr);
  gap: 18px;
  align-items: start;
}
:where(.pe-shell) .pe-stack {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}
@media (max-width: 1100px) {
  :where(.pe-shell) .pe-grid { grid-template-columns: 1fr; }
}

/* =============================================
   FAMILY STATUS GLYPH - one definition, shared by
   the adoption matrix cells and the side panel's
   adoption checklist. Size and font come from the
   caller's own class; colour and shape live here.
   ============================================= */
:where(.pe-shell) .pe-status-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  line-height: 1;
  flex-shrink: 0;
}
:where(.pe-shell) .pe-status-glyph.met {
  color: var(--px-success-text);
  background: var(--px-success-wash);
  font-weight: 700;
}
:where(.pe-shell) .pe-status-glyph.partial {
  color: var(--px-warning-text);
  background: var(--px-warning-wash);
  font-weight: 700;
}
:where(.pe-shell) .pe-status-glyph.missed {
  color: var(--px-danger);
  background: var(--px-danger-wash);
  font-weight: 700;
}
:where(.pe-shell) .pe-status-glyph.not_eligible {
  color: var(--px-text-muted);
  background: transparent;
}
:where(.pe-shell) .pe-status-glyph.awaiting {
  color: var(--px-text-muted);
  background: transparent;
  border: 1px dashed var(--px-border-strong);
}

/* =============================================
   LEGEND STRIP - always visible, never toggled
   ============================================= */
:where(.pe-shell) .pe-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  align-items: center;
  padding: 0.75rem 1.25rem;
  background: var(--px-bg-card);
  border: 1px solid var(--px-border);
  border-radius: var(--px-radius);
  box-shadow: var(--px-shadow);
  font-family: var(--px-font);
  font-size: 0.78rem;
  color: var(--px-text-secondary);
}
:where(.pe-shell) .pe-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}
:where(.pe-shell) .pe-swatch {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-block;
  box-shadow: 0 0 0 2px var(--pe-surface);
}
:where(.pe-shell) .pe-swatch.awaiting { background: var(--pe-awaiting); }
/* The colour scale itself, in the legend: the same three tokens the
   plot lerps a dot's colour out of, in the same order, so the strip
   cannot describe a ramp the chart is not drawing. */
:where(.pe-shell) .pe-swatch-gradient {
  width: 96px;
  height: 10px;
  border-radius: 5px;
  display: inline-block;
  background: linear-gradient(
    90deg,
    var(--pe-declining),
    var(--pe-stable),
    var(--pe-improving)
  );
}
:where(.pe-shell) .pe-swatch-zone {
  width: 18px;
  height: 12px;
  border-radius: 3px;
  background: var(--pe-risk-wash);
  border: 1px dashed var(--pe-risk-line);
  display: inline-block;
}
:where(.pe-shell) .pe-swatch-median {
  width: 0;
  height: 14px;
  border-left: 2px dashed var(--px-text-muted);
  display: inline-block;
}
:where(.pe-shell) .pe-triangle {
  color: var(--pe-declining);
  font-size: 0.95rem;
  line-height: 1;
}

/* =============================================
   INFO TOOLTIP ("?" affordance)
   ============================================= */
:where(.pe-shell) .pe-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin-left: 0.3rem;
  border-radius: 50%;
  border: 1px solid var(--px-border-strong);
  background: transparent;
  color: var(--px-text-muted);
  font-family: var(--px-font);
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  user-select: none;
  flex-shrink: 0;
  padding: 0;
}
:where(.pe-shell) .pe-info:hover,
:where(.pe-shell) .pe-info:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
  outline: none;
}
:where(.pe-shell) .pe-info:focus-visible {
  outline: 2px solid var(--px-focus-ring);
  outline-offset: 2px;
}
/* NOT :where(.pe-shell)-scoped, deliberately. _peShowTooltip appends the tip to
   document.body, i.e. the node is OUTSIDE .pe-shell and a scoped rule would
   never match it: every "?" tip on the screen would render as unstyled black
   text in the top-left corner. AGENTS.md's unscoped-rule ban covers
   * / body / html / :root; this is the screen's own private class. */
.pe-tooltip {
  position: fixed;
  z-index: 900;
  max-width: 280px;
  padding: 0.5rem 0.7rem;
  border-radius: var(--px-radius-sm);
  background: var(--px-bg-card);
  border: 1px solid var(--px-border-strong);
  box-shadow: var(--px-shadow-lg);
  font-family: var(--px-font);
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--px-text-secondary);
  pointer-events: none;
}

/* =============================================
   EMPTY / ERROR STATES
   ============================================= */
/* Doubled: both state panels carry .px-card, whose padding: 20px is (0,1,0)
   and comes later in the cascade than this file. Left single-class, the
   two whole-screen states would shrink to a 20px box. */
:where(.pe-shell) .px-card.pe-state-panel {
  padding: 2.5rem 1.75rem;
  text-align: center;
  font-family: var(--px-font);
}
:where(.pe-shell) .pe-state-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--px-text-primary);
  margin: 0 0 0.5rem;
}
:where(.pe-shell) .pe-state-body {
  font-size: 0.85rem;
  color: var(--px-text-muted);
  margin: 0 auto;
  max-width: 620px;
  line-height: 1.6;
}
:where(.pe-shell) .pe-state-detail {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  border-radius: var(--px-radius-sm);
  background: var(--px-bg-elevated);
  border: 1px solid var(--px-border);
  font-family: var(--px-mono);
  font-size: 0.72rem;
  color: var(--px-text-secondary);
  text-align: left;
  white-space: pre-wrap;
  word-break: break-word;
}
:where(.pe-shell) .pe-state-panel.error .pe-state-title { color: var(--px-danger); }

/* =============================================
   HEADER + META
   ============================================= */
:where(.pe-shell) .pe-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  font-family: var(--px-mono);
  font-size: 0.68rem;
  letter-spacing: 0.03em;
  color: var(--px-text-muted);
  text-transform: uppercase;
}

/* =============================================
   SLIDE PANELS - engagement stacks the drawer
   over the home panel
   ============================================= */
:where(.pe-shell) #pe-drawer-overlay { z-index: 620; }
:where(.pe-shell) #pe-drawer-overlay .px-slide-panel { z-index: 621; width: 620px; }

/* =============================================
   FILTER ROW STACKING
   ============================================= */
/* .px-section-reveal animates on `transform`, and its resting state is
   translateY(0) - still a transform, so the section stays a stacking
   context for good. That traps the home type-ahead menu inside it: the
   menu's z-index can only compete with its siblings INSIDE this
   section, so the KPI strip and the plot, which come later in the DOM
   and are stacking contexts of their own, paint straight over it and
   the lower options become unreadable and unclickable.

   Ending the reveal on `transform: none` drops the stacking context
   without touching the animation - a transform interpolates against
   `none` as the identity, so the slide in is unchanged. Scoped to this
   one section rather than done in theme.css: every other
   .px-section-reveal on every other screen keeps the behaviour it was
   written against, and this is the only one that has to host an
   overflowing menu. */
:where(.pe-shell) #pe-filters-section.px-section-reveal.visible {
  transform: none;
}

/* =============================================
   PLOT STACKING
   ============================================= */
/* The chart's tooltip is appended inside the plot card, and the card is
   now unclipped so the tooltip can leave it (see the .pe-plot rules in
   the plot template). Every later section is a stacking context for the
   same reason as above, so without an order of its own the plot would
   hand its tooltip out only for the legend and the matrix to paint over
   it. Kept well BELOW the filter row's own menu (z-index 40), which
   still has to open over the plot. */
:where(.pe-shell) #pe-plot-section {
  position: relative;
  z-index: 5;
}
