/* ==========================================================================
   Parsewave Console base + component layer
   --------------------------------------------------------------------------
   Served as /static/ui.css after /static/tokens.css.

   Everything here is driven by tokens.css. No raw colour literals below this
   line except where a value is genuinely non-thematic (e.g. transparent).

   Scope notes:
   - Component classes are prefixed `pw-` where an unprefixed name could collide.
     Compatibility names used by shared components remain supported deliberately.
   - Nothing here uses `!important` except the reduced-motion guard.
   ========================================================================== */

/* ---- Self-hosted typefaces ---------------------------------------------- */
/* Variable fonts: one file covers the whole weight axis. SIL OFL 1.1 —
   licences in public/fonts/. font-display:swap so text paints immediately. */
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/static/fonts/inter-latin.woff2') format('woff2-variations');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/static/fonts/inter-latin-ext.woff2') format('woff2-variations');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono Variable';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('/static/fonts/jetbrains-mono-latin.woff2') format('woff2-variations');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono Variable';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('/static/fonts/jetbrains-mono-latin-ext.woff2') format('woff2-variations');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* ==========================================================================
   1. Base / reset
   ========================================================================== */

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

/* The `hidden` attribute must beat our own display values. Several components
   here set display:flex/grid (.pw-notice, .pw-field, .pw-cluster, .pw-stat...),
   which would otherwise override the UA's `[hidden]{display:none}` and leave
   supposedly-hidden nodes visible. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--tracking-body);
  /* Inter feature set worth turning on deliberately:
       cv05  single-storey 'g'      — cleaner at UI sizes
       cv08  upper-case 'I' w/ serifs — disambiguates I / l / 1 in IDs and tokens
       cv11  single-storey 'a'      — matches cv05's tone
       ss03  curved 'l'             — again, l vs 1 vs I
       calt  contextual alternates
     This app is full of hostnames, token names and hex ids where I/l/1 and 0/O
     confusion actually costs the reader something. */
  font-feature-settings: 'cv05' 1, 'cv08' 1, 'cv11' 1, 'ss03' 1, 'calt' 1;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Cross-page React navigation keeps the current screen in place while the next
   page chunk loads. This thin progress rail confirms the click without blanking
   the document or rebuilding the shared sidebar. */
body.pw-route-loading {
  cursor: progress;
}
body.pw-route-loading::after {
  position: fixed;
  z-index: var(--z-toast);
  top: 0;
  right: 0;
  left: 0;
  height: 2px;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent-border);
  content: '';
  pointer-events: none;
  transform: scaleX(0.12);
  transform-origin: left;
  animation: pw-route-progress 900ms var(--ease-out) infinite;
}
@keyframes pw-route-progress {
  0% { transform: scaleX(0.08); opacity: 0.72; }
  65% { transform: scaleX(0.78); opacity: 1; }
  100% { transform: scaleX(0.96); opacity: 0.82; }
}

/* Signed-out Console login. Authentication begins only from the explicit
   GitHub button; the surrounding surface stays deliberately quiet. */
.pw-login-page {
  position: relative;
  min-height: 100svh;
  overflow-x: hidden;
  background: var(--bg);
}
.pw-login-page::before {
  position: fixed;
  top: 50%;
  left: 50%;
  width: min(76vmin, 620px);
  aspect-ratio: 1;
  background: url('/static/brand/parsewave-logo-icon.png') center / contain no-repeat;
  filter: brightness(1.6) saturate(0.55);
  opacity: 0.055;
  pointer-events: none;
  content: '';
  transform: translate(-50%, -50%);
}
.pw-login-shell {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  min-height: 100svh;
  padding: var(--space-5) var(--space-4);
}
.pw-login-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  justify-self: center;
  color: var(--text);
}
.pw-login-brand__mark {
  width: 26px;
  height: 26px;
  object-fit: contain;
}
.pw-login-brand__name {
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
}
.pw-login-brand__product {
  padding-left: 7px;
  border-left: 1px solid var(--border-strong);
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  letter-spacing: var(--tracking-caption);
  text-transform: uppercase;
}
.pw-login-card {
  display: grid;
  gap: var(--space-5);
  width: min(100%, 360px);
  padding: var(--space-7);
  background-color: color-mix(in srgb, var(--surface-1) 94%, transparent);
  background-image: var(--gradient-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md), inset 0 1px 0 color-mix(in srgb, var(--text) 4%, transparent);
  text-align: center;
  backdrop-filter: blur(14px);
}
.pw-login-card__intro h1 {
  font-size: clamp(1.45rem, 5vw, 1.7rem);
}
.pw-login-card__intro p {
  margin-top: var(--space-2);
  color: var(--text-2);
  font-size: var(--fs-caption);
}
.pw-login-card__action {
  width: 100%;
  height: 42px;
}
.pw-login-card__note {
  color: var(--text-3);
  font-size: var(--fs-micro);
  line-height: var(--lh-body);
}
@media (max-width: 600px) {
  .pw-login-shell {
    padding: var(--space-4);
  }
  .pw-login-page::before { width: min(112vw, 440px); }
  .pw-login-card {
    width: min(100%, 340px);
    padding: var(--space-6);
  }
}

/* Numeric columns should align. Opt in with .pw-tnum or on tables/stats. */
.pw-tnum,
.pw-stat-value,
.pw-table td,
.pw-code,
code,
kbd,
pre,
samp {
  font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  color: var(--text);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  /* Stop long hostnames and token names from being hyphen-broken mid-word while
     still allowing sensible wrapping. */
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); letter-spacing: var(--tracking-h1); }
h2 { font-size: var(--fs-h2); letter-spacing: var(--tracking-h2); }
h3 { font-size: var(--fs-h3); letter-spacing: var(--tracking-h3); }
h4, h5, h6 { font-size: var(--fs-body); letter-spacing: var(--tracking-body); }

/* Mono needs slightly negative tracking to sit alongside Inter without looking
   wide, and lining/tabular figures so columns of ids align. */
code, kbd, samp, pre, .pw-mono {
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums lining-nums;
}

p { margin: 0 0 var(--space-3); }
p:last-child { margin-bottom: 0; }

a {
  color: var(--accent-text);
  text-decoration: none;
}
/* Component links own their hover treatment. Underlines belong to prose links, not
   card launchers, navigation, buttons, or command rows. */
a:not([class]):hover,
.pw-prose-link:hover { text-decoration: underline; }

hr {
  height: 1px;
  margin: var(--space-5) 0;
  border: 0;
  background: var(--border);
}

code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-size: 0.9375em;
}

pre {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  overflow-x: auto;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  line-height: var(--lh-ui);
}

:where(code):not(pre code) {
  padding: 0.125em 0.375em;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-2);
}

kbd {
  padding: 0.1em 0.4em;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-micro);
  color: var(--text-2);
}

img, svg, video, canvas { max-width: 100%; }

/* ---- Focus: one visible ring everywhere -------------------------------- */
/* The audit found 20 files setting outline:none and 13 pages with no :focus
   rule at all. This restores a keyboard-visible ring app-wide. */
:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm);
}
/* Never remove the ring for keyboard users, even if a page tries. */
:focus:not(:focus-visible) { outline: none; }

::selection {
  background: var(--accent-soft-hover);
  color: var(--text);
}

/* Scrollbars — subtle, themed. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--surface-4) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--surface-4);
  border: 2px solid transparent;
  border-radius: var(--radius-full);
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background-color: var(--border-strong); background-clip: content-box; }

/* ==========================================================================
   2. Layout primitives
   ========================================================================== */

.pw-page {
  --page-accent: var(--accent);
  --page-accent-soft: var(--accent-soft);
  --page-accent-border: var(--accent-border);

  position: relative;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-7) var(--space-7) var(--space-10);
}
.pw-page[tabindex='-1']:focus {
  outline: none;
}
.pw-page[data-page='servers'],
.pw-page[data-page='assignments'] {
  --page-accent: var(--data-cyan);
  --page-accent-soft: var(--data-cyan-soft);
  --page-accent-border: color-mix(in srgb, var(--data-cyan) 36%, transparent);
}
.pw-page[data-page='subscriptions'],
.pw-page[data-page='athena-usage'] {
  --page-accent: var(--data-violet);
  --page-accent-soft: var(--data-violet-soft);
  --page-accent-border: color-mix(in srgb, var(--data-violet) 36%, transparent);
}
.pw-page[data-page='pool-capacity'] {
  --page-accent: var(--data-gold);
  --page-accent-soft: var(--data-gold-soft);
  --page-accent-border: color-mix(in srgb, var(--data-gold) 36%, transparent);
}
.pw-page[data-page='observability'] {
  --page-accent: var(--data-coral);
  --page-accent-soft: var(--data-coral-soft);
  --page-accent-border: color-mix(in srgb, var(--data-coral) 36%, transparent);
}
.pw-page[data-page='ask-access'] {
  --page-accent: var(--data-sky);
  --page-accent-soft: var(--data-sky-soft);
  --page-accent-border: color-mix(in srgb, var(--data-sky) 36%, transparent);
}
.pw-page[data-page='github-rate-limits'] {
  --page-accent: var(--data-gold);
  --page-accent-soft: var(--data-gold-soft);
  --page-accent-border: color-mix(in srgb, var(--data-gold) 36%, transparent);
}
.pw-page[data-page='bucket-tokens'] {
  --page-accent: var(--data-sky);
  --page-accent-soft: var(--data-sky-soft);
  --page-accent-border: color-mix(in srgb, var(--data-sky) 36%, transparent);
}
.pw-page[data-page='deployments'] {
  --page-accent: var(--data-violet);
  --page-accent-soft: var(--data-violet-soft);
  --page-accent-border: color-mix(in srgb, var(--data-violet) 36%, transparent);
}
.pw-page--prose { max-width: var(--content-max-prose); }

.pw-page-masthead {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  margin-bottom: var(--space-7);
  padding: var(--space-2) 0 var(--space-5);
}
.pw-page-masthead::before {
  position: absolute;
  z-index: -1;
  top: -10px;
  right: 0;
  width: min(32vw, 320px);
  height: 112px;
  background-image:
    linear-gradient(var(--page-accent-border) 1px, transparent 1px),
    linear-gradient(90deg, var(--page-accent-border) 1px, transparent 1px);
  background-position: 100% 0;
  background-size: 22px 22px;
  opacity: 0.22;
  mask-image: linear-gradient(90deg, transparent 0%, black 45%, black 100%);
  pointer-events: none;
  content: '';
}
.pw-page-masthead::after {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    var(--page-accent) 0,
    var(--page-accent-border) 20%,
    var(--border) 55%,
    transparent 100%
  );
  content: '';
}
.pw-page-masthead__titles {
  min-width: 0;
  max-width: 760px;
}
.pw-page-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  color: var(--page-accent);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  line-height: var(--lh-ui);
  letter-spacing: var(--tracking-micro);
  text-transform: uppercase;
}
.pw-page-eyebrow::before {
  width: 20px;
  height: 2px;
  border-radius: var(--radius-full);
  background: var(--page-accent);
  box-shadow: 0 0 0 3px var(--page-accent-soft);
  content: '';
}
.pw-page-masthead__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text);
  font-size: var(--fs-h1);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-h1);
}
.pw-page-masthead__description {
  max-width: 68ch;
  margin: var(--space-2) 0 0;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}
.pw-page-masthead__actions {
  display: flex;
  flex: 0 1 auto;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  min-width: 0;
}
.pw-page-toolbar {
  position: sticky;
  top: var(--space-3);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  min-width: 0;
  margin: 0 0 var(--space-7);
  padding: var(--space-2);
  background: color-mix(in srgb, var(--surface-1) 97%, var(--page-accent));
  border: 1px solid color-mix(in srgb, var(--page-accent) 28%, var(--border));
  border-radius: var(--radius-md);
  box-shadow:
    inset 3px 0 0 color-mix(in srgb, var(--page-accent) 82%, transparent),
    inset 0 1px 0 color-mix(in srgb, var(--page-accent) 12%, transparent);
  backdrop-filter: blur(16px) saturate(1.08);
}
/*
 * Wide operations screens should read as one command rail, not a tab card stacked on
 * a second filter card. Keep the two rows on smaller screens where forcing everything
 * inline would make controls illegible.
 */
@media (min-width: 1360px) {
  .pw-page-toolbar > :where(.space-y-2, .space-y-3):has(> .pw-toolbar) {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: center;
    gap: var(--space-2);
  }
  .pw-page-toolbar > :where(.space-y-2, .space-y-3):has(> .pw-toolbar) > * {
    margin-block: 0 !important;
  }
  .pw-page-toolbar > :where(.space-y-2, .space-y-3):has(> .pw-toolbar) > .pw-toolbar {
    min-width: 0;
  }
  /*
   * Subscription filters carry two independent scopes plus search. Usage attribution
   * now carries seven views plus its window and search controls. Squeezing either set
   * beside its tabs can make the second grid column push beyond the page, so these two
   * command rails keep a full-width filter row.
   */
  :is(main[data-page='subscriptions'], main[data-page='usage-attribution'])
    .pw-page-toolbar
    > :where(.space-y-2, .space-y-3):has(> .pw-toolbar) {
    grid-template-columns: minmax(0, 1fr);
  }
  main[data-page='subscriptions'] .pw-page-toolbar .pw-toolbar {
    position: relative;
  }
  main[data-page='subscriptions'] .pw-page-toolbar .pw-toolbar__meta {
    position: absolute;
    right: 0;
    bottom: 11px;
    margin: 0;
  }
}
.pw-page-views-frame {
  position: relative;
  min-width: 0;
  max-width: 100%;
}
.pw-page-views {
  min-width: 0;
  max-width: 100%;
  overscroll-behavior-inline: contain;
  scrollbar-color: var(--border-strong) transparent;
  scrollbar-width: thin;
  /* PageViews positions the selected tab inside the 32px fades. Scroll snapping
     would pull that deliberate inset back to the obscured edge. */
}
.pw-page-views .pw-tabs {
  gap: var(--space-1);
  min-width: max-content;
  width: max-content;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  border-bottom: 0;
}
.pw-page-views .pw-tab {
  margin: 0;
  min-height: 38px;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: calc(var(--radius-md) - 3px);
}
.pw-page-views .pw-tab:hover {
  background: var(--surface-2);
  color: var(--text);
}
.pw-page-views .pw-tab[aria-selected='true'] {
  background: var(--page-accent-soft);
  color: var(--page-accent);
  box-shadow: inset 0 0 0 1px var(--page-accent-border), var(--shadow-sm);
}
.pw-page-views-frame::before,
.pw-page-views-frame::after {
  position: absolute;
  z-index: 2;
  top: 1px;
  bottom: 1px;
  width: 32px;
  opacity: 0;
  pointer-events: none;
  content: '';
  transition: opacity var(--duration-fast) var(--ease);
}
.pw-page-views-frame::before {
  left: 0;
  background: linear-gradient(90deg, var(--surface-1), transparent);
}
.pw-page-views-frame::after {
  right: 0;
  background: linear-gradient(270deg, var(--surface-1), transparent);
}
.pw-page-views-frame[data-overflow-left='true']::before,
.pw-page-views-frame[data-overflow-right='true']::after {
  opacity: 1;
}

.pw-section-block__heading {
  padding-left: var(--space-3);
  border-left: 2px solid var(--page-accent);
}
.pw-section-block__title {
  text-wrap: pretty;
}

.pw-page-header {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-4);
  /* Fading rule instead of a full-width line: it terminates the header without
     boxing the page in. */
  border-bottom: 0;
}
.pw-page-header::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 1px;
  background: var(--gradient-rule);
}
.pw-page-header__titles { min-width: 0; }
.pw-page-title {
  font-size: var(--fs-h1);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-h1);
}
.pw-page-subtitle {
  max-width: 62ch;                   /* a real measure — long subtitles were
                                        running the full 1600px viewport */
  margin: var(--space-2) 0 0;
  color: var(--text-3);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}
.pw-page-header__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.pw-section { margin-bottom: var(--space-8); }
.pw-section__header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.pw-section__title {
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-h2);
}
.pw-section__hint {
  /* Real supporting copy uses --text-3 (5.1:1), not the decorative-only --text-faint. */
  color: var(--text-3);
  font-size: var(--fs-caption);
}

/* Auto-fitting grid — replaces the many bespoke card grids. */
.pw-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(var(--pw-grid-min, 260px), 1fr));
}
.pw-grid--wide { --pw-grid-min: 360px; }
.pw-grid--narrow { --pw-grid-min: 200px; }

.pw-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.pw-stack { display: grid; gap: var(--space-3); }
.pw-stack--tight { gap: var(--space-2); }
.pw-spacer { flex: 1 1 auto; }

/* ==========================================================================
   3. Surfaces: card / panel
   ========================================================================== */

.pw-card {
  /* Two layers: the sheen sits over the flat surface colour, so the card has an
     apparent top edge. Deliberately ~3% — you should not be able to name it as a
     gradient, only notice the card looks lit. */
  background-color: var(--surface-1);
  background-image: var(--gradient-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025);
}
.pw-card--flush { padding: 0; overflow: hidden; }
.pw-card--inset { background: var(--bg-inset); }

.pw-card__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.pw-card--flush > .pw-card__header {
  margin-bottom: 0;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
}
.pw-card__title { font-size: var(--fs-h3); }
.pw-card__kicker {
  margin-bottom: var(--space-1);
  /* A kicker is a real label, so it reads at --text-3, not the decorative-only --text-faint. */
  color: var(--text-3);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-micro);
  text-transform: uppercase;
}
.pw-card__body { color: var(--text-2); font-size: var(--fs-small); }
.pw-card__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}

/* Interactive card (a whole card that is a link/button). */
.pw-card--link {
  display: block;
  color: inherit;
  transition: border-color var(--duration) var(--ease),
    background var(--duration) var(--ease);
}
.pw-card--link:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
  text-decoration: none;
}

/* ==========================================================================
   4. Stat tile
   ========================================================================== */
/* The audit found two contradictory stat idioms 30px apart on one page, and
   labels rendering as "0identity links" because the number and label were
   adjacent inline nodes with no separator. This owns the pattern. */

.pw-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4);
  background-color: var(--surface-1);
  background-image: var(--gradient-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-width: 0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025);
}
.pw-stat__label,
.metric-label {
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: var(--fw-regular);
  letter-spacing: var(--tracking-small);
  text-transform: none;              /* sentence case reads calmer than SHOUTING */
  line-height: var(--lh-ui);
}
.pw-stat__value {
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 1.5rem;                /* 24px, mono runs larger than sans */
  font-weight: var(--fw-medium);    /* mono at 600 gets heavy fast */
  font-variant-numeric: tabular-nums lining-nums;
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
}
.pw-stat__value--sm { font-size: var(--fs-h2); }
/* Unit/suffix beside a value always gets breathing room. */
.pw-stat__unit {
  margin-left: var(--space-1);
  color: var(--text-3);
  font-size: var(--fs-small);
  font-weight: var(--fw-regular);
}
.pw-stat__hint {
  color: var(--text-3);
  font-size: var(--fs-caption);
  line-height: var(--lh-ui);
}
.pw-stat--ok    .pw-stat__value { color: var(--success-text); }
.pw-stat--warn  .pw-stat__value { color: var(--warning-text); }
.pw-stat--err   .pw-stat__value { color: var(--danger-text); }
.pw-stat--muted .pw-stat__value { color: var(--text-3); }

/* ==========================================================================
   5. Buttons
   ========================================================================== */
/* One button contract, including distinct safe and destructive modifiers. */

.btn,
.pw-btn {
  --pw-btn-bg: var(--surface-2);
  --pw-btn-bg-hover: var(--surface-3);
  --pw-btn-fg: var(--text);
  --pw-btn-border: var(--border-strong);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  height: 38px;
  background: var(--pw-btn-bg);
  color: var(--pw-btn-fg);
  border: 1px solid var(--pw-btn-border);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease),
    border-color var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}
.btn:hover,
.pw-btn:hover {
  background: var(--pw-btn-bg-hover);
  text-decoration: none;
}
.btn:active,
.pw-btn:active { transform: translateY(0.5px); }

/* Disabled controls remain visibly and functionally unavailable. */
.btn:disabled,
.btn[disabled],
.btn.disabled,
.pw-btn:disabled,
.pw-btn[disabled],
.pw-btn.disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
  pointer-events: none;
}
.btn[aria-busy='true'],
.pw-btn[aria-busy='true'] { cursor: progress; }

/* Variants */
.btn.primary, .btn-primary, .pw-btn--primary {
  --pw-btn-bg: var(--gradient-accent);
  --pw-btn-bg-hover: var(--gradient-accent-hover);
  --pw-btn-fg: var(--on-accent);
  --pw-btn-border: transparent;
  /* A 1px inner top highlight is what makes a button feel physical rather than
     painted. Pairs with the gradient's implied light source. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), var(--shadow-sm);
}
.btn.danger, .btn-danger, .pw-btn--danger {
  --pw-btn-bg: var(--gradient-danger);
  --pw-btn-bg-hover: var(--gradient-danger);
  --pw-btn-fg: var(--on-danger);
  --pw-btn-border: transparent;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), var(--shadow-sm);
}
/* Destructive but secondary — outline treatment. */
.pw-btn--danger-outline {
  --pw-btn-bg: transparent;
  --pw-btn-bg-hover: var(--danger-bg);
  --pw-btn-fg: var(--danger-text);
  --pw-btn-border: var(--danger-border);
}
.btn.ghost, .pw-btn--ghost {
  --pw-btn-bg: transparent;
  --pw-btn-bg-hover: var(--surface-2);
  --pw-btn-border: transparent;
  --pw-btn-fg: var(--text-2);
}
.btn.subtle, .pw-btn--subtle {
  --pw-btn-bg: transparent;
  --pw-btn-bg-hover: var(--surface-2);
  --pw-btn-border: var(--border);
  --pw-btn-fg: var(--text-2);
}

/* Sizes */
.btn.tiny, .pw-btn--tiny {
  height: 32px;
  padding: 0 10px;
  font-size: var(--fs-micro);
  border-radius: var(--radius-sm);
}
.btn.sm, .pw-btn--sm {
  height: 36px;
  padding: 0 var(--space-3);
  font-size: var(--fs-caption);
}
.btn.lg, .pw-btn--lg {
  height: 44px;
  padding: 0 var(--space-5);
  font-size: var(--fs-body);
}
.pw-btn--block { width: 100%; }
/* Square icon-only button — needs an aria-label at the call site. */
.pw-btn--icon { width: 36px; padding: 0; }
.pw-btn--icon.pw-btn--sm { width: 36px; }
.pw-btn--icon.pw-btn--tiny { width: 32px; }

.pw-btn-group {
  display: inline-flex;
  align-items: center;
}
.pw-btn-group > .btn:not(:first-child),
.pw-btn-group > .pw-btn:not(:first-child) {
  margin-left: -1px;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
.pw-btn-group > .btn:not(:last-child),
.pw-btn-group > .pw-btn:not(:last-child) {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

/* ==========================================================================
   6. Form controls
   ========================================================================== */

.pw-field { display: grid; gap: var(--space-2); min-width: 0; }
.pw-label {
  color: var(--text-2);
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
}
.pw-label__required { color: var(--danger-text); margin-left: 2px; }
.pw-hint { color: var(--text-3); font-size: var(--fs-caption); line-height: var(--lh-ui); }
.pw-error {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--danger-text);
  font-size: var(--fs-caption);
}

.pw-input,
.pw-select,
.pw-textarea {
  width: 100%;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  background-color: var(--surface-2);
  background-image: var(--gradient-raised);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: var(--fs-small);
  line-height: var(--lh-ui);
  transition: border-color var(--duration-fast) var(--ease),
    box-shadow var(--duration-fast) var(--ease);
}
.pw-input { height: 38px; }
.pw-textarea { min-height: 88px; padding: var(--space-3); resize: vertical; }
.pw-input--mono, .pw-textarea--mono { font-family: var(--font-mono); }

.pw-input::placeholder,
.pw-textarea::placeholder { color: var(--text-faint); }

.pw-input:hover,
.pw-select:hover,
.pw-textarea:hover { border-color: var(--text-faint); }

.pw-input:focus,
.pw-select:focus,
.pw-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--shadow-focus);
}
.pw-input:focus-visible,
.pw-select:focus-visible,
.pw-textarea:focus-visible { outline: none; }

.pw-input:disabled,
.pw-select:disabled,
.pw-textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--bg-inset);
}
.pw-input[aria-invalid='true'],
.pw-select[aria-invalid='true'],
.pw-textarea[aria-invalid='true'] { border-color: var(--danger); }

.pw-select {
  height: 38px;
  padding-right: var(--space-7);
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}

/* Checkbox / radio — sized so they never inherit a page's input{width:100%} */
.pw-check {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--space-2);
  cursor: pointer;
  font-size: var(--fs-small);
  color: var(--text-2);
}
.pw-check > input[type='checkbox'],
.pw-check > input[type='radio'] {
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  margin: 2px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.pw-check:has(> input:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
}
.pw-check > input[type='checkbox']:disabled,
.pw-check > input[type='radio']:disabled { cursor: not-allowed; }

.pw-search { position: relative; }
.pw-search > .pw-input { padding-left: var(--space-8); }
.pw-search__icon {
  position: absolute;
  top: 50%;
  left: var(--space-3);
  transform: translateY(-50%);
  color: var(--text-3);
  pointer-events: none;
  line-height: 0;
}

/* ==========================================================================
   7. Badges / chips
   ========================================================================== */

.pw-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border: 1px solid var(--neutral-border);
  border-radius: var(--radius-full);
  background: var(--neutral-bg);
  color: var(--neutral-text);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  line-height: 1.5;
  white-space: nowrap;
}
.pw-badge--ok   { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
.pw-badge--warn { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); }
.pw-badge--err  { background: var(--danger-bg);  border-color: var(--danger-border);  color: var(--danger-text); }
.pw-badge--info { background: var(--info-bg);    border-color: var(--info-border);    color: var(--info-text); }
.pw-badge--accent { background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent-text); }
.pw-badge--square { border-radius: var(--radius-sm); }

/* Status dot — pair with text, never colour alone. */
.pw-dot {
  width: 7px;
  height: 7px;
  flex: 0 0 7px;
  border-radius: 50%;
  background: var(--neutral-text);
}
.pw-dot--ok   { background: var(--success); }
.pw-dot--warn { background: var(--warning); }
.pw-dot--err  { background: var(--danger); }
.pw-dot--info { background: var(--info); }

/* Shared label and separator details used by compact status chips. */
.chip-label {
  color: var(--text-3);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
}
.chip-sep { color: var(--text-faint); margin: 0 var(--space-1); }

/* ==========================================================================
   8. Tables
   ========================================================================== */

.pw-table-wrap {
  overflow-x: auto;
  container-type: inline-size;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  box-shadow: var(--shadow-sm);
}
.pw-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-small);
}
.pw-table th {
  position: sticky;
  top: 0;
  z-index: var(--z-base);
  padding: var(--space-3) var(--space-4);
  background-color: var(--surface-2);
  background-image: var(--gradient-raised);
  border-bottom: 1px solid var(--border);
  color: var(--text-3);
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-small);
  text-transform: none;
  text-align: left;
  white-space: nowrap;
}
.pw-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: var(--text-2);
  vertical-align: middle;
  transition: background-color var(--duration-fast) var(--ease);
}
.pw-table tbody tr:last-child td { border-bottom: 0; }
.pw-table tbody tr:hover td { background: var(--surface-2); }
.pw-table--zebra tbody tr:nth-child(even) td {
  background: color-mix(in srgb, var(--surface-2) 38%, var(--surface-1));
}
.pw-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.pw-table__actions { width: 1%; white-space: nowrap; text-align: right; }
.pw-table--compact th,
.pw-table--compact td { padding: var(--space-2) var(--space-3); }
/* A spanning empty or error cell is as wide as the table's min-width, so on a narrow
   screen its message sat to the right of the scrollport where nobody scrolls. Pin the
   message to the visible box instead; 100cqw is the wrap's own width, not the table's. */
.pw-table-wrap--wide .pw-table td[colspan] > .pw-empty {
  position: sticky;
  left: 0;
  box-sizing: border-box;
  width: 100cqw;
}
.pw-table-wrap--wide .pw-table td[colspan] > .pw-notice {
  position: sticky;
  left: 0;
  box-sizing: border-box;
  max-width: calc(100cqw - 2 * var(--space-4));
}
.pw-table caption {
  padding: var(--space-3) var(--space-4);
  color: var(--text-3);
  font-size: var(--fs-caption);
  text-align: left;
}

/* Sortable header button */
.pw-table th > button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 32px;
  margin-block: calc(var(--space-2) * -1);
  padding: var(--space-2) 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.pw-table th > button:hover { color: var(--text); }

/* ==========================================================================
   9. Tabs / segmented control
   ========================================================================== */

.pw-tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--border);
}
.pw-tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-3);
  margin-bottom: -1px;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-3);
  font-family: inherit;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease),
    border-color var(--duration-fast) var(--ease);
}
.pw-tab__label {
  display: inline-flex;
  min-width: 0;
  align-items: center;
  gap: 7px;
  line-height: 1;
}
.pw-tab__label > svg {
  width: 17px;
  height: 17px;
  flex: 0 0 17px;
}
.pw-tab:hover { color: var(--text); }
.pw-tab[aria-selected='true'] {
  color: var(--text);
  border-bottom-color: var(--accent);
}
.pw-tab__count {
  display: inline-flex;
  min-width: 20px;
  height: 18px;
  align-items: center;
  justify-content: center;
  margin-left: 0;
  padding: 0 5px;
  background: var(--surface-3);
  border-radius: var(--radius-sm);
  color: var(--text-3);
  font-size: var(--fs-micro);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.pw-segmented {
  display: inline-flex;
  padding: 2px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.pw-segmented > button {
  min-height: 32px;
  padding: var(--space-1) var(--space-3);
  background: none;
  border: 0;
  border-radius: calc(var(--radius-md) - 4px);
  color: var(--text-3);
  font-family: inherit;
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}
.pw-segmented > button:hover { color: var(--text); }
.pw-segmented > button[aria-pressed='true'],
.pw-segmented > button.active {
  background: var(--surface-4);
  color: var(--text);
}

/* ==========================================================================
   10. Dialog (native <dialog>)
   ========================================================================== */
/* Replaces ~50 hand-rolled modals. Native <dialog> gives focus trapping,
   Escape-to-close, inert background and focus restore for free — the audit
   found NOTHING in the app trapped focus and only one page handled Escape. */

.pw-dialog {
  width: min(560px, calc(100vw - 2 * var(--space-5)));
  max-height: calc(100vh - 2 * var(--space-8));
  max-height: calc(100dvh - 2 * var(--space-8));
  padding: 0;
  background: var(--surface-1);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  overflow: visible;
}
.pw-dialog--wide { width: min(880px, calc(100vw - 2 * var(--space-5))); }
.pw-dialog--narrow { width: min(420px, calc(100vw - 2 * var(--space-5))); }

.pw-dialog::backdrop {
  background: rgba(3, 5, 8, 0.66);
  backdrop-filter: blur(2px);
}

.pw-dialog__form {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 2 * var(--space-8));
  max-height: calc(100dvh - 2 * var(--space-8));
  min-height: 0;
  overflow: hidden;
  margin: 0;
}
.pw-dialog__header {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
}
.pw-dialog__title { font-size: var(--fs-h3); }
.pw-dialog__subtitle {
  margin: var(--space-1) 0 0;
  color: var(--text-3);
  font-size: var(--fs-caption);
}
.pw-dialog__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--space-5);
  overflow-y: auto;
  overscroll-behavior: contain;
  color: var(--text-2);
  font-size: var(--fs-small);
}
.pw-dialog__footer {
  flex: 0 0 auto;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  border-bottom-left-radius: var(--radius-xl);
  border-bottom-right-radius: var(--radius-xl);
}
.pw-dialog__footer > .pw-spacer { flex: 1 1 auto; }

/*
 * A token editor is deliberately a full-height sheet on a phone.  Mobile browsers
 * resize the visual viewport when a select/input opens its keyboard; centring a long
 * dialog in the old layout viewport could put the footer underneath that keyboard,
 * making a perfectly valid Save button impossible to tap.  The header and footer stay
 * fixed while only the body scrolls, and both actions retain a comfortable touch target.
 */
@media (max-width: 600px) {
  .pw-dialog,
  .pw-dialog--wide,
  .pw-dialog--narrow {
    width: calc(100vw - 24px);
    max-height: calc(100vh - 24px);
    max-height: calc(100dvh - 24px);
  }
  .pw-dialog__form {
    max-height: calc(100vh - 24px);
    max-height: calc(100dvh - 24px);
  }
  .pw-token-edit-dialog {
    /* The generated top-1/2 utility is emitted after this stylesheet.  Make the
       sheet's viewport anchors explicit; otherwise the browser still computes a
       centred 820px sheet from a 50% top edge. */
    top: 12px !important;
    bottom: 12px !important;
    max-height: none;
    /* Tailwind 4 emits translate utilities through the independent `translate`
       property.  Clear the old transform and retain only horizontal centring;
       otherwise both properties apply -50% on X and the sheet leaves the viewport. */
    transform: none !important;
    translate: -50% 0 !important;
  }
  .pw-token-edit-dialog .pw-dialog__form {
    height: 100%;
    max-height: none;
  }
  .pw-token-edit-dialog .pw-dialog__header,
  .pw-token-edit-dialog .pw-dialog__body,
  .pw-token-edit-dialog .pw-dialog__footer {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
  .pw-token-edit-dialog .pw-dialog__footer {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
  }
  .pw-token-edit-dialog .pw-dialog__footer > .pw-react-button {
    width: 100%;
    min-width: 0;
  }
}

/* Legacy class kept so tests/athenaUsageUi.test.js keeps matching. */
.modal-backdrop { z-index: var(--z-modal); }

/* ==========================================================================
   11. Toasts + inline notices
   ========================================================================== */

.pw-toasts {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: var(--z-toast);
  display: grid;
  gap: var(--space-2);
  width: min(400px, calc(100vw - 2 * var(--space-5)));
  pointer-events: none;
}
.pw-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--neutral-text);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  color: var(--text);
  font-size: var(--fs-small);
  pointer-events: auto;
  animation: pw-toast-in var(--duration-slow) var(--ease-out);
}
.pw-toast--ok   { border-left-color: var(--success); }
.pw-toast--warn { border-left-color: var(--warning); }
.pw-toast--err  { border-left-color: var(--danger); }
.pw-toast--info { border-left-color: var(--info); }
.pw-toast__body { flex: 1; min-width: 0; }
.pw-toast__title { font-weight: var(--fw-semibold); }
.pw-toast__detail {
  margin-top: 2px;
  color: var(--text-3);
  font-size: var(--fs-caption);
  overflow-wrap: anywhere;
}
.pw-toast__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  min-width: 24px;
  min-height: 24px;
  padding: 0 var(--space-1);
  background: none;
  border: 0;
  color: var(--text-3);
  font-size: var(--fs-body);
  line-height: 1;
  cursor: pointer;
}
.pw-toast__close:hover { color: var(--text); }
.pw-toast.pw-toast--leaving { animation: pw-toast-out var(--duration) var(--ease) forwards; }

/* Toasts fade in place rather than sliding. Anything that travels across the
   screen on appearance competes with the content the operator is reading. */
@keyframes pw-toast-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes pw-toast-out {
  to { opacity: 0; }
}

.pw-notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: 14px var(--space-4);
  background: var(--neutral-bg);
  border: 1px solid var(--neutral-border);
  border-left-width: 2px;
  border-radius: var(--radius-md);
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-ui);
}
.pw-notice--ok   { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); }
.pw-notice--warn { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); }
.pw-notice--err  { background: var(--danger-bg);  border-color: var(--danger-border);  color: var(--danger-text); }
.pw-notice--info { background: var(--info-bg);    border-color: var(--info-border);    color: var(--info-text); }
.pw-notice__title { font-weight: var(--fw-semibold); }

/* ==========================================================================
   12. Empty / loading states
   ========================================================================== */

.pw-empty {
  display: grid;
  gap: var(--space-2);
  justify-items: center;
  padding: var(--space-8) var(--space-5);
  text-align: center;
  color: var(--text-3);
}
.pw-empty__icon { color: var(--text-faint); line-height: 0; }
.pw-empty__title {
  color: var(--text-2);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
}
.pw-empty__detail {
  max-width: 46ch;
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}
.pw-empty__actions { margin-top: var(--space-2); }

.pw-spinner {
  display: inline-block;
  width: 15px;
  height: 15px;
  border: 2px solid var(--surface-4);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: pw-spin 0.7s linear infinite;
}
.pw-spinner--lg { width: 26px; height: 26px; border-width: 3px; }
@keyframes pw-spin { to { transform: rotate(360deg); } }

.pw-skeleton {
  background: var(--gradient-shimmer);
  background-size: 400% 100%;
  border-radius: var(--radius-sm);
  animation: pw-shimmer 1.3s ease-in-out infinite;
}
.pw-skeleton--text { height: 0.75em; margin: 0.25em 0; }
.pw-skeleton--line { height: 12px; }
.pw-skeleton--title { height: 18px; width: 42%; }
.pw-skeleton--pill { height: 20px; width: 84px; border-radius: var(--radius-full); }

/* Composed placeholders. These exist so a loading view occupies the SAME space
   the real content will, which is what stops the page reflowing when data
   lands. A spinner in an empty container does the opposite: it collapses the
   box, then the content expands it again — read as a jump. */
.pw-skeleton-card {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background-color: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.pw-skeleton-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
}
.pw-skeleton-row > .pw-skeleton { height: 12px; flex: 1; }
.pw-skeleton-row > .pw-skeleton:first-child { flex: 0 0 22%; }
.pw-skeleton-row > .pw-skeleton:last-child { flex: 0 0 12%; }

/* Fade the placeholder out and the content in, in place — no movement. */
.pw-fade-in { animation: pw-fade var(--duration-slow) var(--ease); }
@keyframes pw-fade { from { opacity: 0; } to { opacity: 1; } }

/* Respect the motion preference: hold a static tint rather than shimmering. */
@media (prefers-reduced-motion: reduce) {
  .pw-skeleton { animation: none; background: var(--surface-2); }
}
@keyframes pw-shimmer {
  from { background-position: 100% 50%; }
  to   { background-position: 0 50%; }
}

/* Progress — always pair with role="progressbar" + aria-valuenow. */
.pw-progress {
  height: 6px;
  overflow: hidden;
  background: var(--surface-3);
  border-radius: var(--radius-full);
}
.pw-progress__bar {
  height: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: width var(--duration-slow) var(--ease);
}
.pw-progress__bar--ok   { background: var(--success); }
.pw-progress__bar--warn { background: var(--warning); }
.pw-progress__bar--err  { background: var(--danger); }

/* ==========================================================================
   13. Utilities
   ========================================================================== */

.pw-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Skip link — visible only on focus. */
.pw-skip-link {
  position: absolute;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-tooltip);
  padding: var(--space-2) var(--space-3);
  background: var(--accent);
  color: var(--on-accent);
  border-radius: var(--radius);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  transform: translateY(-200%);
  transition: transform var(--duration) var(--ease);
}
.pw-skip-link:focus { transform: none; text-decoration: none; }

.pw-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.pw-break { overflow-wrap: anywhere; }
.pw-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.pw-caption {
  color: var(--text-3);
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-micro);
  text-transform: uppercase;
}
.pw-muted { color: var(--text-3); }
.pw-faint { color: var(--text-faint); }
.pw-text-ok   { color: var(--success-text); }
.pw-text-warn { color: var(--warning-text); }
.pw-text-err  { color: var(--danger-text); }

/* Decorative glyphs (emoji icons) must be hidden from screen readers at the
   call site with aria-hidden; this just stops them affecting line box height. */
.pw-icon { line-height: 0; flex: 0 0 auto; }

/* ==========================================================================
   14. Motion preference
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   15. Responsive
   ========================================================================== */
@media (max-width: 900px) {
  .pw-page { padding: var(--space-4) var(--space-4) var(--space-8); }
  .pw-page-header { flex-direction: column; align-items: stretch; }
  .pw-page-masthead {
    flex-direction: column;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
  }
  .pw-page-masthead__actions { justify-content: flex-start; }
  .pw-page-toolbar {
    top: var(--space-2);
    margin-right: 0;
    margin-left: 0;
    padding-right: var(--space-2);
    padding-left: var(--space-2);
  }
}
@media (max-width: 1024px) {
  .pw-page-masthead::before { display: none; }
  .pw-page-eyebrow {
    margin-bottom: var(--space-4);
    padding-left: var(--space-9);
  }
  .pw-page-masthead__title--menu-offset { padding-left: var(--space-9); }
  .pw-page-toolbar .pw-page-views-frame { margin-inline-start: var(--space-8); }
}
@media (max-width: 600px) {
  .pw-grid { --pw-grid-min: 100%; }
  .pw-assignment-total { font-size: var(--fs-h1); }
  .pw-toasts { right: var(--space-3); left: var(--space-3); bottom: var(--space-3); width: auto; }
  .pw-page-masthead__actions {
    width: 100%;
    justify-content: flex-start;
  }
  .pw-page-toolbar {
    gap: 6px;
    padding: 6px;
    border-radius: var(--radius-md);
  }
  .pw-page-toolbar > :where(.space-y-2, .space-y-3) {
    display: grid;
    gap: 6px;
  }
  .pw-page-toolbar > :where(.space-y-2, .space-y-3) > * {
    margin-block: 0 !important;
  }
  .pw-page-toolbar .pw-page-views {
    padding-bottom: 0;
    scrollbar-width: none;
  }
  .pw-page-toolbar .pw-page-views::-webkit-scrollbar {
    display: none;
  }
  /* Below 600px the toolbar used to be one sideways-scrolling row, which hid every
     control past the first two with no hint that they existed. Wrap instead: the
     search takes a full row and the other controls flow beneath it. A wrapped toolbar
     is too tall to stay sticky on a phone, so it scrolls with the page here. */
  .pw-page-toolbar {
    position: static;
  }
  .pw-page-toolbar .pw-toolbar {
    flex-wrap: wrap;
    overflow: visible;
  }
  .pw-page-toolbar .pw-toolbar > * {
    flex: 1 1 auto;
    min-width: 0;
  }
  .pw-page-toolbar .pw-toolbar > .pw-search,
  .pw-page-toolbar .pw-toolbar > :where(.w-full) {
    flex-basis: 100%;
    width: 100%;
    min-width: 0;
  }
  .pw-page-toolbar .pw-segmented {
    flex-wrap: wrap;
  }
  .pw-page-toolbar .pw-segmented > button {
    flex: 1 1 auto;
  }
  .pw-page-toolbar .pw-fleet-toolbar {
    gap: 6px;
  }
  .pw-page-toolbar .pw-athena-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .pw-page-toolbar .pw-athena-toolbar > * {
    flex: 1 1 auto;
    min-width: 0;
  }
  .pw-page-toolbar .pw-athena-toolbar__tokens {
    width: 100%;
    flex: 1 1 100%;
    flex-wrap: wrap;
    padding-top: 6px;
  }
  .pw-page-toolbar .pw-athena-toolbar__tokens > * {
    flex: 1 1 auto;
    min-width: 0;
  }
  .pw-page-toolbar .pw-athena-toolbar__tokens > .pw-search {
    flex-basis: 100%;
    width: 100%;
    min-width: 0;
  }
  .pw-page-toolbar .pw-athena-toolbar .pw-toolbar__meta {
    display: none;
  }
  .pw-toolbar__meta {
    width: auto;
    margin-left: 0;
    padding: 0 var(--space-1);
    white-space: nowrap;
  }
  .pw-btn,
  .btn {
    min-height: 44px;
  }
  .pw-react-button:not([data-size='tiny']) {
    min-height: 44px !important;
  }
  .pw-react-button[data-size='tiny'] {
    min-height: 40px !important;
    min-width: 40px !important;
  }
  .pw-react-button[data-size='icon'] {
    min-width: 44px !important;
    width: 44px !important;
  }
  .pw-btn--icon,
  .pw-btn--icon.pw-btn--sm,
  .pw-btn--icon.pw-btn--tiny {
    width: 44px;
  }
  .pw-page-views .pw-tab,
  .pw-tabs .pw-tab {
    min-height: 44px;
  }
  .pw-segmented > button {
    min-height: 40px;
    min-width: 40px;
  }
  .pw-input,
  .pw-select {
    min-height: 40px;
  }
  .pw-page button.pw-badge,
  .pw-table th button {
    min-height: 40px;
  }
  .pw-table-wrap--wide .pw-table th:first-child,
  .pw-table-wrap--wide .pw-table td:first-child {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--surface-1);
    box-shadow: 8px 0 12px -12px rgba(0, 0, 0, 0.95);
  }
  .pw-table-wrap--wide .pw-table th:first-child {
    z-index: 3;
    background: var(--surface-2);
  }
  .pw-table-wrap--wide .pw-table--zebra tbody tr:nth-child(even) td:first-child {
    background: var(--bg-inset);
  }
  .pw-table-wrap--wide .pw-table tbody tr:hover td:first-child {
    background: var(--surface-2);
  }
}

@media (pointer: coarse) {
  /* A keyboard shortcut is noise on a touch screen. */
  .pw-kbd-hint { display: none; }
  .pw-btn,
  .btn,
  .pw-tab,
  .pw-react-button:not([data-size='tiny']) {
    min-height: 44px;
  }
  .pw-react-button[data-size='tiny'],
  .pw-segmented > button {
    min-height: 40px;
    min-width: 40px;
  }
  .pw-react-button[data-size='icon'] {
    min-width: 44px;
    width: 44px;
  }
}

/* Print — operators do print capacity reports. */
@media print {
  .sidebar,
  .pw-toasts,
  .pw-page-header__actions,
  .pw-page-masthead__actions,
  .pw-page-toolbar { display: none !important; }
  body { background: #fff; color: #000; }
  .pw-card { border-color: #ccc; break-inside: avoid; }
}

/* ==========================================================================
   16. Visual anchors: icon tiles, meters, sparklines
   --------------------------------------------------------------------------
   The app had zero sparklines and zero meters. For an operations console that
   is the main reason it looked flat — text in boxes, with the numbers carrying
   no shape. These give data a form, and give cards something to anchor on.
   All pure CSS + inline SVG. No charting library.
   ========================================================================== */

/* ---- Icon tile ---------------------------------------------------------- */
/* A tinted square behind an icon. This is what stops a card being three lines
   of text: it gives the eye somewhere to land and carries the semantic colour. */
.pw-icon-box {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius);
  background: var(--surface-3);
  color: var(--text-2);
  /* 1px inner top highlight — the same light-source language as the buttons. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.pw-icon-box svg { display: block; }
.pw-icon-box--lg { width: 38px; height: 38px; border-radius: var(--radius-md); }
.pw-icon-box--sm { width: 26px; height: 26px; border-radius: var(--radius-sm); }

.pw-icon-box--accent  { background: var(--accent-soft);  color: var(--accent-text); }
.pw-icon-box--ok      { background: var(--success-bg);   color: var(--success-text); }
.pw-icon-box--warn    { background: var(--warning-bg);   color: var(--warning-text); }
.pw-icon-box--err     { background: var(--danger-bg);    color: var(--danger-text); }
.pw-icon-box--info    { background: var(--info-bg);      color: var(--info-text); }

/* ---- Meter ------------------------------------------------------------- */
/* Utilisation / capacity. Taller than .pw-progress and it can carry threshold
   marks, because "83% of quota" wants a shape, not just a number. */
.pw-meter {
  position: relative;
  height: 8px;
  overflow: hidden;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
}
.pw-meter__fill {
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transition: width var(--duration-slow) var(--ease);
}
.pw-meter__fill--ok   { background: var(--success); }
.pw-meter__fill--warn { background: var(--warning); }
.pw-meter__fill--err  { background: var(--danger); }
/* Threshold tick, positioned with --at (a percentage). */
.pw-meter__mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  left: var(--at, 80%);
  width: 1px;
  background: var(--text-faint);
}
.pw-meter__mark--reference {
  width: 2px;
  background: var(--accent-text);
  border-radius: var(--radius-full);
  transform: translateX(-1px);
}
.pw-meter--tall { height: 12px; }

/* Label row above a meter: name left, value right, both on one baseline. */
.pw-meter-row {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.pw-meter-row__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.pw-meter-row__label { color: var(--text-2); font-size: var(--fs-caption); }
.pw-meter-row__value {
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
}

/* ---- Sparkline --------------------------------------------------------- */
/* Inline trend, sized by its container. See PW.sparkline(). */
.pw-spark {
  display: block;
  width: 100%;
  height: 34px;
  overflow: visible;
}
.pw-spark__line { fill: none; stroke: var(--accent-text); stroke-width: 1.5; }
.pw-spark__area { fill: var(--accent-soft); stroke: none; }
.pw-spark__dot  { fill: var(--accent-text); }
.pw-spark--ok   .pw-spark__line { stroke: var(--success-text); }
.pw-spark--ok   .pw-spark__area { fill: var(--success-bg); }
.pw-spark--ok   .pw-spark__dot  { fill: var(--success-text); }
.pw-spark--warn .pw-spark__line { stroke: var(--warning-text); }
.pw-spark--warn .pw-spark__area { fill: var(--warning-bg); }
.pw-spark--warn .pw-spark__dot  { fill: var(--warning-text); }
.pw-spark--err  .pw-spark__line { stroke: var(--danger-text); }
.pw-spark--err  .pw-spark__area { fill: var(--danger-bg); }
.pw-spark--err  .pw-spark__dot  { fill: var(--danger-text); }

/* ---- Field list -------------------------------------------------------- */
/* Label/value pairs — the workhorse of an ops detail panel. Values are mono so
   ids, hostnames and counts align down the column. */
.pw-fields { display: grid; gap: 0; }
.pw-field-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-small);
}
.pw-field-row:last-child { border-bottom: 0; }
.pw-field-row__key { color: var(--text-3); }
.pw-field-row__val {
  color: var(--text);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
  overflow-wrap: anywhere;
}

/* ---- Card hover: a deliberate lift, not just a colour change ----------- */
.pw-card--link,
.pw-card--interactive {
  transition: background var(--duration) var(--ease),
    border-color var(--duration) var(--ease),
    transform var(--duration) var(--ease),
    box-shadow var(--duration) var(--ease);
}
.pw-card--link:hover,
.pw-card--interactive:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
@media (prefers-reduced-motion: reduce) {
  .pw-card--link:hover,
  .pw-card--interactive:hover { transform: none; }
}
