/* ===== gross_profit section, shared rules (HTML forms, scoped) =====
   The gross_profit_html shell's rules, plus the one rule more than one form in
   this section wears. 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 SECTION'S LINKS (every gp_*.css sorts before
   gross_profit.css), so the shell's rules come last in document order.
   Two selectors are declared on both sides - .gp-home-drill-modal and
   .gp-month-drill-modal, both out of the scrollbar rule below - and both pairs
   declare disjoint properties (this file: scrollbar-width and scrollbar-color;
   the children: background, border-radius, padding, max-width, overflow-y), so
   there is no tie for the link order to break. No selector is declared in two
   children.

   THREE SCOPES, NOT ONE, because the two drill modals LEAVE this form's root.
   window.pxShowOverlay('gp-home-drill-overlay', { mode: 'viewport' }) moves
   that node into the shared layout's #px-modal-portal while it is open, out of
   .gp-dashboard entirely, and the modal's content wears this file's .gp-table,
   .gp-currency, .gp-positive, .gp-negative, the two badges and the
   --px-chart-* tokens. So:

     - a rule whose selector already NAMES .gp-dashboard is not wrapped -
       wrapping it would cost it a class and change which declaration wins;
     - anything the portal can carry is scoped on the union
       :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay),
       the two overlay classes being what those nodes keep wherever in the
       document they are;
     - everything else is scoped :where(.gp-dashboard).

   :where() adds ZERO specificity, so no rule changes which declaration wins.
   The dark token block gains one point in the move onto .gp-dashboard, which
   is what keeps it beating the light values on the same element.

   THE ROOT RULE DROPS overflow: auto AND GAINS flex: 1 0 auto. The root is a
   flex item inside the shared layout's scroller, .px-nav-content, which owns
   the vertical scroll; overflow on the root would stop the port scrolling.
   The one exception is the loading rule's clip, while the loader shows.
   overflow: auto was inert vertically here (a minimum and no maximum, so the
   box never scrolled) but it did clip horizontal overflow: if a child overflows
   horizontally, the fix is overflow-x: clip on that child, never on this root.
   RECORDED AS A DEVIATION for the owner rather than decided here.
   min-height follows the layout's --px-nav-content-height less 16px - the 16
   is the dependency layout's own padding: 8px 0.

   THE TWO SCROLLBAR DECLARATIONS ARE FOLDED INTO THE ROOT RULE rather than
   written as a second bare .gp-dashboard rule: the same subject and no cascade
   change. The four ::-webkit- selectors stay as their own bare rules; their
   modal halves go under the overlay scope.

   DESIGNER GATE: gp-live, on the shell root. The designer runs no Python, so
   the three families that hide content until JavaScript runs would leave the
   canvas showing an empty dashboard under a full-bleed loader. Each hiding
   declaration is split into its own rule gated on .gp-dashboard.gp-live, which
   gross_profit.mjs adds on the first line of the shell's init and removes on
   the first line of its teardown. The compound stays INSIDE :where(): unwrapped
   it computes (0,2,0) and beats the .visible reveal at (0,2,0) on document
   order, and the section never reveals.

   THE NOISE IMAGE PATH IS the file-relative ../noise.png. An external sheet
   resolves a relative url against ITSELF, so the app-relative _/theme/noise.png
   would resolve to _/theme/gross_profit/_/theme/noise.png: a 404, and the grain
   would disappear with nothing thrown.

   @keyframes gpSpin, gpSlideIn and gpModalFadeIn are unscoped.
   Keyframes are global and all three names are already gp-prefixed, so there
   is nothing to rename; gpModalFadeIn is animated on by both drill modals,
   whose own assets deliberately do not redeclare it. */

/* =============================================
   GP CHART HUES (Light - Default)
   The surface / text / border / shadow tokens are the unified --px-* set
   (3T-08, OD-01), supplied by PX_TOKENS_CSS. Only the chart-series hues below
   have no unified equivalent, so they are declared here under the
   --px-chart-* prefix.

   On the union rather than :root, so the tokens travel with a portaled
   modal; a :root block in a head-linked asset would also reach every
   other screen in the app.
   ============================================= */
.gp-dashboard,
.gp-home-drill-overlay,
.gp-month-drill-overlay,
[data-theme="dark"] .gp-home-root.px-print-ink,
[data-theme="dark"] .gp-kpi-grid-inner.px-print-ink,
[data-theme="dark"] .gp-home-drill-overlay.px-print-ink {
  --px-chart-emerald: #059669;
  --px-chart-coral: #dc2626;
  --px-chart-cyan: #0891b2;
  --px-chart-violet: #7c3aed;
  --px-chart-amber: #d97706;
  --px-chart-projected-bg: repeating-linear-gradient(45deg, transparent, transparent 4px, rgba(148, 163, 184, 0.08) 4px, rgba(148, 163, 184, 0.08) 8px);
}

/* =============================================
   GP CHART HUES (Dark)
   ============================================= */
[data-theme="dark"] .gp-dashboard,
[data-theme="dark"] .gp-home-drill-overlay,
[data-theme="dark"] .gp-month-drill-overlay {
  --px-chart-emerald: #34d399;
  --px-chart-coral: #ff6b6b;
  --px-chart-cyan: #00d4ff;
  --px-chart-violet: #a78bfa;
  --px-chart-amber: #fbbf24;
  --px-chart-projected-bg: repeating-linear-gradient(45deg, transparent, transparent 4px, rgba(148, 163, 184, 0.05) 4px, rgba(148, 163, 184, 0.05) 8px);
}

[data-theme="dark"] .gp-dashboard {
  background:
    radial-gradient(circle at top left, rgba(52, 211, 153, 0.12), transparent 40%),
    linear-gradient(180deg, #022c22 0%, #0f172a 100%);
}

.gp-dashboard, .gp-dashboard *, .gp-dashboard *::before, .gp-dashboard *::after { box-sizing: border-box; }

/* =============================================
   DASHBOARD LAYOUT
   ============================================= */
.gp-dashboard {
  font-family: var(--px-font-display);
  /* Fills the content area without owning a scroll. The layout's
     .px-nav-content is the one vertical scroll port; this box only has
     to reach the bottom of it so the background gradient does not stop
     short on a page with little content.

     The 16px is NOT arbitrary: .px-nav-content is
     `height: var(--px-nav-content-height)` with `padding: 8px 0` under
     border-box, so the space it actually offers a child is that height
     minus those two 8px bands. Matching it exactly fills the content area
     and overflows by nothing, so no second scrollbar comes back. Change
     that padding in the dependency and this constant must change with it.
     In the designer the screen sits outside .px-nav-layout, so the variable
     is unset and this min-height drops (cosmetic, accepted). */
  min-height: calc(var(--px-nav-content-height) - 16px);
  flex: 1 0 auto;
  background:
    radial-gradient(circle at top left, rgba(5, 150, 105, 0.08), transparent 40%),
    linear-gradient(180deg, #ecfdf5 0%, #f1f5f9 100%);
  padding: 1.5rem;
  position: relative;
  isolation: isolate;
  z-index: 0;
  color: var(--px-text-primary);
  scrollbar-width: thin;
  scrollbar-color: var(--px-chart-violet) transparent;
}

.gp-dashboard::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background-image: url('../noise.png');
  background-repeat: repeat;
  opacity: 0.015;
  pointer-events: none;
  z-index: 0;
}

/* A child combinator, so NO anvil:name ON ANY DIRECT CHILD OF THE ROOT: a
   named element is reparented into an <anvil-dropzone> with display: contents,
   this rule would land on the dropzone, which generates no box, and the
   section would silently lose its stacking. */
.gp-dashboard > * {
  position: relative;
}

/* Lifted off the header mount point's style="margin-bottom: 2rem;", which an
   HTML template may not carry. Same name shape as owings.css's
   .ow-header-block, declaration byte for byte. */
:where(.gp-dashboard) .gp-header-block {
  margin-bottom: 2rem;
}

/* =============================================
   HIDE ANVIL DEFAULT SPINNERS
   Only hides spinners within .gp-dashboard scope -
   Anvil's global page-level spinner is unaffected.
   ============================================= */
.gp-dashboard .anvil-spinner,
.gp-dashboard .anvil-loading-spinner,
.gp-dashboard .anvil-app-loading-spinner {
  display: none !important;
}

/* =============================================
   SCROLLBAR (purple theme)
   The .gp-dashboard half of each rule is bare (it names the root); the two
   modal halves are scoped on the overlay classes they keep through the portal.
   The shorthand pair for the root itself is folded into the root rule above.
   ============================================= */
.gp-dashboard::-webkit-scrollbar { width: 6px; height: 6px; }
.gp-dashboard::-webkit-scrollbar-track { background: transparent; }
.gp-dashboard::-webkit-scrollbar-thumb {
  background: var(--px-chart-violet);
  border-radius: 3px;
}
.gp-dashboard::-webkit-scrollbar-thumb:hover {
  background: #9333ea;
}

:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-home-drill-modal,
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-month-drill-modal {
  scrollbar-width: thin;
  scrollbar-color: var(--px-chart-violet) transparent;
}
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-home-drill-modal::-webkit-scrollbar,
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-month-drill-modal::-webkit-scrollbar { width: 6px; height: 6px; }
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-home-drill-modal::-webkit-scrollbar-track,
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-month-drill-modal::-webkit-scrollbar-track { background: transparent; }
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-home-drill-modal::-webkit-scrollbar-thumb,
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-month-drill-modal::-webkit-scrollbar-thumb {
  background: var(--px-chart-violet);
  border-radius: 3px;
}
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-home-drill-modal::-webkit-scrollbar-thumb:hover,
:where(.gp-home-drill-overlay, .gp-month-drill-overlay) .gp-month-drill-modal::-webkit-scrollbar-thumb:hover {
  background: #9333ea;
}

/* =============================================
   LOADING OVERLAY (scoped to dashboard)
   ============================================= */
:where(.gp-dashboard) .gp-loading-overlay {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(248, 250, 252, 0.95);
  backdrop-filter: blur(8px);
  display: none;
  justify-content: center;
  align-items: center;
  z-index: 500;
}

[data-theme="dark"] :where(.gp-dashboard) .gp-loading-overlay {
  background: rgba(15, 23, 42, 0.95);
}

/* Designer gate. The markup ships the overlay with `active` already on it, and
   only gpHideLoading - Python the designer never runs - takes it off, so
   ungated the canvas is a full-bleed loader over an empty dashboard. */
:where(.gp-dashboard.gp-live) .gp-loading-overlay.active {
  display: flex;
}

/* (0,2,0): :has takes its argument's specificity. While the loader shows, the
   dashboard is exactly the content area's height and clips the hidden sections,
   so the loader centres on screen and nothing scrolls. clip, not hidden: hidden
   makes a scroll box focus can move. */
:where(.gp-dashboard.gp-live):has(> .gp-loading-overlay.active) {
  height: calc(var(--px-nav-content-height) - 16px);
  overflow: hidden;
  overflow: clip;
}

:where(.gp-dashboard) .gp-loader {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}

:where(.gp-dashboard) .gp-loader-ring {
  width: 56px;
  height: 56px;
  border: 3px solid var(--px-border);
  border-top-color: var(--px-chart-emerald);
  border-radius: 50%;
  animation: gpSpin 0.8s linear infinite;
}

@keyframes gpSpin { to { transform: rotate(360deg); } }

:where(.gp-dashboard) .gp-loader-text {
  font-family: 'Space Mono', monospace;
  font-size: 0.8rem;
  color: var(--px-text-muted);
  letter-spacing: 0.1em;
}
:where(.gp-dashboard) .gp-loader-subtext {
  font-family: var(--px-font-display);
  font-size: 0.85rem;
  color: var(--px-text-secondary);
  text-align: center;
  max-width: 320px;
}
:where(.gp-dashboard) .gp-loader-countdown {
  font-family: 'Space Mono', monospace;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--px-chart-emerald);
  letter-spacing: 0.05em;
}
:where(.gp-dashboard) .gp-loader-stalled {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  max-width: 340px;
}
:where(.gp-dashboard) .gp-loader.stalled .gp-loader-ring,
:where(.gp-dashboard) .gp-loader.stalled .gp-loader-subtext,
:where(.gp-dashboard) .gp-loader.stalled .gp-loader-countdown { display: none; }
:where(.gp-dashboard) .gp-loader.stalled .gp-loader-stalled { display: flex; }
:where(.gp-dashboard) .gp-loader-stalled-msg {
  font-family: var(--px-font-display);
  font-size: 0.9rem;
  color: var(--px-text-secondary);
  text-align: center;
  line-height: 1.5;
}
:where(.gp-dashboard) .gp-loader-retry {
  font-family: var(--px-font-display);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--px-ink-on-bright);
  background: var(--px-chart-emerald);
  border: none;
  border-radius: 8px;
  padding: 0.6rem 1.5rem;
  cursor: pointer;
  transition: filter 0.2s;
}
:where(.gp-dashboard) .gp-loader-retry:hover { filter: brightness(1.08); }
:where(.gp-dashboard) .gp-loader-retry:focus-visible {
  outline: 2px solid var(--px-focus-ring);
  outline-offset: 2px;
}

/* =============================================
   SECTION ANIMATIONS
   The `visible` class is added only by animateSections, which the shell's
   Python calls, so both opacity/transform pairs are split out and gated on
   gp-live; ungated, every section and the KPI grid sit invisible and 20px low
   on the designer canvas and staff cannot drag what they cannot see.
   ============================================= */
:where(.gp-dashboard) .gp-section-container {
  margin-bottom: 2rem;
  transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1), transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
:where(.gp-dashboard.gp-live) .gp-section-container {
  opacity: 0;
  transform: translateY(20px);
}
:where(.gp-dashboard) .gp-section-container.visible {
  opacity: 1;
  transform: translateY(0);
}

:where(.gp-dashboard) .gp-kpi-grid {
  margin-bottom: 2rem;
  transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1), transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
:where(.gp-dashboard.gp-live) .gp-kpi-grid {
  opacity: 0;
  transform: translateY(20px);
}
:where(.gp-dashboard) .gp-kpi-grid.visible {
  opacity: 1;
  transform: translateY(0);
}

/* =============================================
   CARD BASE
   ============================================= */
:where(.gp-dashboard) .gp-card {
  background: var(--px-bg-card);
  border-radius: 16px;
  padding: 1.5rem;
  border: 1px solid var(--px-border);
  box-shadow: var(--px-shadow);
}

/* =============================================
   TYPOGRAPHY
   ============================================= */
:where(.gp-dashboard) .gp-value {
  font-family: 'Space Mono', monospace;
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.2;
}
:where(.gp-dashboard) .gp-label {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--px-text-muted);
}

/* =============================================
   PROJECTED / PARTIAL BADGES
   Both badges are written into the drill tables, which the portal carries, so
   all three take the union scope.
   ============================================= */
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-projected {
  border-style: dashed !important;
  background: var(--px-chart-projected-bg) !important;
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-projected-badge {
  display: inline-block;
  font-size: 0.5rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  padding: 1px 4px;
  border-radius: 3px;
  background: rgba(217, 119, 6, 0.1);
  color: color-mix(in srgb, var(--px-chart-amber) 65%, var(--px-text-primary));
  margin-left: 4px;
  vertical-align: middle;
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-partial-badge {
  display: inline-block;
  font-size: 0.5rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  padding: 1px 4px;
  border-radius: 3px;
  background: rgba(100, 116, 139, 0.1);
  color: var(--px-text-muted);
  margin-left: 4px;
  vertical-align: middle;
}

/* =============================================
   TABLE BASE
   Both drill modals hold a .gp-table, so the whole family takes the union.
   ============================================= */
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table {
  width: 100%;
  max-width: 100%;
  table-layout: auto;
  border-collapse: collapse;
  font-size: 0.85rem;
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--px-text-muted);
  padding: 0.75rem;
  text-align: left;
  border-bottom: 2px solid var(--px-border);
  cursor: pointer;
  user-select: none;
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th:hover {
  color: var(--px-text-primary);
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table td {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--px-border);
  color: var(--px-text-secondary);
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table tr:hover td {
  background: var(--px-bg-elevated);
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table .gp-currency {
  font-family: 'Space Mono', monospace;
  text-align: right;
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table .gp-positive { color: color-mix(in srgb, var(--px-chart-emerald) 65%, var(--px-text-primary)); }
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table .gp-negative { color: var(--px-chart-coral); }

:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th[data-sort-type] { position: relative; padding-right: 1.2rem; }
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th[data-sort-type]::after {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.55rem;
  color: var(--px-text-muted);
  content: "\2195";
}
/* The chevron classes are the ones window.pxSortTable toggles
   (sort-asc / sort-desc), scoped to .gp-table so theme.css's .px-table
   chevrons never reach these headers. */
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th.sort-asc::after { content: "\25B2" !important; opacity: 1 !important; color: color-mix(in srgb, var(--px-chart-cyan) 65%, var(--px-text-primary)); }
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th.sort-desc::after { content: "\25BC" !important; opacity: 1 !important; color: color-mix(in srgb, var(--px-chart-cyan) 65%, var(--px-text-primary)); }

/* =============================================
   TOOLTIP
   ============================================= */
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-tooltip {
  position: relative;
  cursor: help;
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-tooltip .gp-tooltip-text {
  visibility: hidden;
  background: var(--px-bg-card);
  color: var(--px-text-secondary);
  border: 1px solid rgba(124, 58, 237, 0.3);
  padding: 0.75rem 1rem;
  border-radius: 10px;
  font-size: 0.7rem;
  line-height: 1.5;
  position: absolute;
  z-index: 100;
  bottom: 125%;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
  opacity: 0;
  transition: opacity 0.2s;
}
[data-theme="dark"] :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-tooltip .gp-tooltip-text {
  border-color: rgba(167, 139, 250, 0.3);
  box-shadow: 0 8px 24px rgba(0,0,0,0.3);
}
:where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-tooltip:hover .gp-tooltip-text {
  visibility: visible;
  opacity: 1;
}

/* =============================================
   DRILL-DOWN PANEL
   ============================================= */
:where(.gp-dashboard) .gp-drilldown {
  margin-top: 1rem;
  padding: 1rem;
  background: var(--px-bg-elevated);
  border-radius: 12px;
  border: 1px solid var(--px-border);
  display: none;
}
:where(.gp-dashboard) .gp-drilldown.open {
  display: block;
  animation: gpSlideIn 0.3s ease;
}
@keyframes gpSlideIn {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes gpModalFadeIn {
  from { opacity: 0; transform: scale(0.97); }
  to { opacity: 1; transform: scale(1); }
}
:where(.gp-dashboard) .gp-drilldown-title {
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
  color: var(--px-text-primary);
}
:where(.gp-dashboard) .gp-drilldown-close {
  float: right;
  cursor: pointer;
  font-size: 1.2rem;
  color: var(--px-text-muted);
  padding: 0 0.5rem;
  line-height: 1;
}
:where(.gp-dashboard) .gp-drilldown-close:hover {
  color: var(--px-text-primary);
}

/* =============================================
   SPARKLINE CONTAINER
   ============================================= */
:where(.gp-dashboard) .gp-sparkline {
  height: 40px;
  margin-top: 0.5rem;
}

/* =============================================
   SECTION HEADING
   Declared once, here, and worn by three forms: gp_coverage_html's "Data
   Quality & Coverage" heading, gp_home_table_html's per-home heading and
   gp_monthly_chart_html's own "Monthly Revenue vs Cost" heading. Scoped to
   one of the three it would strip the other two of their size, weight,
   colour, spacing and flex layout with nothing thrown. All three uses sit
   inside the section cards, never inside either drill overlay, so the shell
   scope alone is right.
   ============================================= */
:where(.gp-dashboard) .gp-section-title {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--px-text-primary);
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* =============================================
   MOBILE
   ============================================= */
@media (max-width: 768px) {
  .gp-dashboard { padding: 0.75rem; }
  :where(.gp-dashboard) .gp-card { padding: 1rem; border-radius: 12px; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table { font-size: 0.75rem; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th { padding: 0.5rem 0.4rem; font-size: 0.6rem; letter-spacing: 0.5px; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table td { padding: 0.4rem; }
  :where(.gp-dashboard) .gp-value { font-size: 1.3rem; }

  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-tooltip .gp-tooltip-text {
    white-space: normal;
    max-width: 260px;
    width: max-content;
    left: 0;
    right: auto;
    bottom: auto;
    top: 125%;
    transform: none;
  }
}
@media (max-width: 480px) {
  .gp-dashboard { padding: 0.5rem; }
  :where(.gp-dashboard) .gp-card { padding: 0.75rem; border-radius: 10px; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table { font-size: 0.7rem; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table th { padding: 0.4rem 0.3rem; font-size: 0.55rem; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table td { padding: 0.35rem 0.3rem; }
  :where(.gp-dashboard, .gp-home-drill-overlay, .gp-month-drill-overlay) .gp-table .gp-currency { font-size: 0.7rem; }
}

:where(.gp-dashboard) .gp-chart-error-banner {
  display: none;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  margin-bottom: 1rem;
  border-radius: 8px;
  background: var(--px-chart-amber);
  color: var(--px-ink-on-bright);
  font-size: 0.8rem;
  font-weight: 500;
  font-family: var(--px-font-display);
}

/* The print block's :root takes the same union as the light tokens above: an
   unscoped :root in a head-linked asset would repaint every screen in the app
   on print, not only while this screen is mounted. The ApexCharts class is
   scoped for the same reason. */
@media print {
  .gp-dashboard,
  .gp-home-drill-overlay,
  .gp-month-drill-overlay {
    --px-bg-deep: #ffffff !important;
    --px-bg-card: #ffffff !important;
    --px-bg-elevated: #f8fafc !important;
    --px-text-primary: #0f172a !important;
    --px-text-secondary: #334155 !important;
    --px-text-muted: #64748b !important;
    --px-border: rgba(0,0,0,0.12) !important;
    --px-shadow: none !important;
    --px-chart-emerald: #059669 !important;
    --px-chart-coral: #dc2626 !important;
    --px-chart-cyan: #0891b2 !important;
    --px-chart-violet: #7c3aed !important;
    --px-chart-amber: #d97706 !important;
  }
  .gp-dashboard {
    background: #ffffff !important;
  }
  .gp-dashboard::before {
    display: none !important;
  }
  :where(.gp-dashboard) .apexcharts-canvas {
    background: #ffffff !important;
  }
}
