/* ============================================================
   ProdWeek — isaacbd design system
   Extracted & adapted from stagehand/panel.css for a full-page
   web dashboard. Palette: #10648e blue, #fe00c1 pink accent.
   Fonts: Barlow Condensed / Barlow / Courier Prime.
   ============================================================ */

:root {
  --pw-primary:        #10648e;
  --pw-primary-dark:   #0d5478;
  --pw-accent:         #fe00c1;
  --pw-bg:             #f4f6f8;
  --pw-surface:        #ffffff;
  --pw-border:         #e0e8ee;
  --pw-border-input:   #d0d8e0;
  --pw-text:           #1a1a2e;
  --pw-text-secondary: #5a6b7c;
  --pw-text-tertiary:  #4a5a6a;
  --pw-muted:          #9aa6b0;

  --pw-success-bg:     #d1edde;
  --pw-success-text:   #155724;
  --pw-warn-bg:        #fff8e1;
  --pw-warn-border:    #f5c200;
  --pw-warn-text:      #5a4000;
  --pw-error-bg:       #fde8e8;
  --pw-error-border:   #e9a0a0;
  --pw-error-text:     #7a1a1a;

  --pw-sidebar-bg:     var(--pw-primary);
  --pw-sidebar-active: var(--pw-primary-dark);

  --pw-radius:         6px;
  --pw-radius-lg:      8px;

  --pw-font-head: 'Barlow Condensed', 'Barlow', sans-serif;
  --pw-font-body: 'Barlow', -apple-system, sans-serif;
  --pw-font-mono: 'Courier Prime', monospace;
}

/* ── Blackout theme (dark) ──
   Applied as data-theme="dark" on <html>; "system" resolves to dark via the
   same attribute (app.js watches prefers-color-scheme). Every surface colour
   routes through these tokens; charts re-read them on theme change. */
:root[data-theme="dark"] {
  --pw-primary:        #4aa3d4;   /* brand blue lifted to read on dark */
  --pw-primary-dark:   #6db8e0;
  --pw-bg:             #10161d;
  --pw-surface:        #1a232c;
  --pw-border:         #2b3844;
  --pw-border-input:   #364554;
  --pw-text:           #e8edf2;
  --pw-text-secondary: #9db0c2;
  --pw-text-tertiary:  #c2cdd8;
  --pw-muted:          #6b7a8a;

  --pw-success-bg:     #16362a;
  --pw-success-text:   #7dd8a5;
  --pw-warn-bg:        #3a3210;
  --pw-warn-border:    #9c7f00;
  --pw-warn-text:      #ead38a;
  --pw-error-bg:       #40201f;
  --pw-error-border:   #7a3b3b;
  --pw-error-text:     #f0a0a0;

  --pw-sidebar-bg:     #0d1a26;   /* stage-black wings, not bright brand blue */
  --pw-sidebar-active: #16303f;
}
:root[data-theme="dark"] .pw-widget { border-color: var(--pw-border); }
:root[data-theme="dark"] .pw-widget-stat.green .wv { color: #5dc389; }
/* Some browsers render a <select>'s native option popup using the OS's own
   light-mode default rather than inheriting the select's background, which
   left every dropdown showing light text on a light popup in Blackout —
   force it explicitly (found 2026-07-05). */
:root[data-theme="dark"] select option {
  background: var(--pw-surface);
  color: var(--pw-text);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: var(--pw-font-body);
  font-size: 14px;
  background: var(--pw-bg);
  color: var(--pw-text);
  line-height: 1.5;
  min-height: 100vh;
}

/* ── App shell ── */
.pw-app { display: flex; min-height: 100vh; }

.pw-sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--pw-sidebar-bg);
  color: #fff;
  display: flex;
  flex-direction: column;
  padding: 16px 0;
  transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  overflow: hidden;
}
.pw-brand {
  padding: 4px 18px 16px;
  font-family: var(--pw-font-head);
  font-weight: 900;
  font-size: 22px;
  text-transform: uppercase;
  letter-spacing: 2px;
  line-height: 1;
}
.pw-brand .dot { color: var(--pw-accent); margin-left: 2px; }
.pw-brand-short { display: none; }
.pw-nav { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.pw-nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  color: rgba(255,255,255,0.75);
  text-decoration: none;
  font-family: var(--pw-font-mono);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  transition: background 0.15s, color 0.15s;
}
.pw-nav a:hover { background: rgba(255,255,255,0.08); color: #fff; }
.pw-nav-signout {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 18px;
  color: rgba(255,255,255,0.55);
  text-decoration: none;
  font-family: var(--pw-font-mono);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  transition: color 0.15s;
}
.pw-nav-signout:hover { color: rgba(255,255,255,0.9); }
.pw-nav a.active { color: #fff; background: var(--pw-sidebar-active); }
.nav-divider { height: 1px; margin: 6px 18px; background: rgba(255,255,255,0.12); }
.pw-sidebar--collapsed .nav-divider { margin: 6px 14px; }
.pw-nav a.active::before {
  content: ''; width: 3px; height: 16px; background: var(--pw-accent);
  border-radius: 3px; margin-left: -18px; margin-right: 15px;
}

/* max-width keeps widgets readable on ultrawides; the auto margins centre the
   capped column in the leftover space (auto margins absorb flex free space) —
   without them the dashboard pinned left with dead space on wide screens
   (Known bugs, 2026-07-05). width:100% keeps it full-bleed below the cap. */
.pw-main { flex: 1; padding: 24px 28px; overflow-y: auto; max-width: 1400px; width: 100%; margin: 0 auto; }

/* ── Collapsible sidebar ── */
.pw-sidebar--collapsed { width: 56px; }
.pw-sidebar--collapsed .pw-brand {
  padding: 8px 0;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pw-sidebar--collapsed .pw-brand-full { display: none; }
.pw-sidebar--collapsed .pw-brand-short {
  display: block;
  font-size: 16px;
  line-height: 1;
  letter-spacing: 1px;
}
.pw-sidebar--collapsed .pw-era-wrap { display: none; }
.pw-sidebar--collapsed .pw-signout-wrap .nav-label { display: none; }
.pw-sidebar--collapsed .pw-nav-signout { justify-content: center; padding: 8px 0; }
.nav-icon { flex-shrink: 0; width: 18px; display: inline-flex; align-items: center; justify-content: center; }
.nav-icon svg { width: 15px; height: 15px; display: block; }
.nav-label { overflow: hidden; transition: opacity 0.15s; white-space: nowrap; }
.pw-sidebar--collapsed .nav-label { display: none; }
.pw-sidebar--collapsed .pw-nav a { justify-content: center; padding: 10px 0; }
.pw-sidebar--collapsed .pw-nav a.active::before { display: none; }
.sidebar-toggle-btn {
  background: none;
  border: none;
  color: rgba(255,255,255,0.45);
  cursor: pointer;
  padding: 6px 18px;
  width: 100%;
  display: flex;
  justify-content: flex-end;
  transition: color 0.15s;
}
.sidebar-toggle-btn svg { display: block; }
.sidebar-toggle-btn:hover { color: rgba(255,255,255,0.9); }
.pw-sidebar--collapsed .sidebar-toggle-btn { justify-content: center; padding: 6px 0; }

/* ── Headings ── */
.pw-h1 {
  font-family: var(--pw-font-head);
  font-weight: 900;
  font-size: 28px;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 4px;
}
.pw-eyebrow {
  font-family: var(--pw-font-mono);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--pw-accent);
  margin-bottom: 6px;
}
.pw-section-label {
  font-family: var(--pw-font-mono);
  font-weight: 700;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--pw-primary-dark);
  margin-bottom: 12px;
  display: block;
}

/* ── Cards ── */
.pw-card {
  background: var(--pw-surface);
  border: 1.5px solid var(--pw-border);
  border-radius: var(--pw-radius-lg);
  padding: 16px 18px;
  margin-bottom: 16px;
}
.pw-grid { display: grid; gap: 16px; }
.pw-grid--2 { grid-template-columns: repeat(2, 1fr); }
.pw-grid--3 { grid-template-columns: repeat(3, 1fr); }
.pw-grid--4 { grid-template-columns: repeat(4, 1fr); }

/* ── Stat box ── */
.pw-stat {
  background: var(--pw-surface);
  border: 1.5px solid var(--pw-border);
  border-radius: var(--pw-radius-lg);
  padding: 16px;
  text-align: center;
}
.pw-stat .num {
  font-family: var(--pw-font-head);
  font-size: 34px;
  font-weight: 900;
  line-height: 1;
  color: var(--pw-primary);
}
.pw-stat .lbl {
  font-family: var(--pw-font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--pw-text-secondary);
  margin-top: 4px;
}
.pw-stat.green .num { color: #198754; }
.pw-stat.pink  .num { color: var(--pw-accent); }
.pw-stat.red   .num { color: #c0392b; }

/* ── Labels & inputs ── */
label {
  display: block;
  font-family: var(--pw-font-mono);
  font-weight: 700;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 6px;
  color: var(--pw-primary-dark);
}
input[type=text], input[type=email], input[type=password],
input[type=number], input[type=date], select, textarea {
  width: 100%;
  border: 1.5px solid var(--pw-border-input);
  border-radius: var(--pw-radius);
  font-family: var(--pw-font-body);
  font-size: 13px;
  padding: 8px 10px;
  background: var(--pw-surface);
  color: var(--pw-text);
  transition: border-color 0.15s;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--pw-primary); }
select { cursor: pointer; }

.pw-field-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.pw-field { display: flex; flex-direction: column; flex: 1; min-width: 140px; }

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 16px;
  border-radius: var(--pw-radius);
  font-family: var(--pw-font-head);
  font-weight: 900;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 1px;
  cursor: pointer;
  border: none;
  transition: opacity 0.15s, background 0.15s;
}
.btn:hover { opacity: 0.88; }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-primary { background: var(--pw-primary); color: #fff; }
.btn-primary:hover { opacity: 1; background: var(--pw-primary-dark); }
.btn-ghost {
  background: transparent;
  color: var(--pw-primary);
  border: 1.5px solid #c8d4de;
  padding: 8px 14px;
}
.btn-ghost:hover { border-color: var(--pw-primary); opacity: 1; }

/* ── Tables ── */
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left;
  font-family: var(--pw-font-mono);
  font-weight: 700;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--pw-text-secondary);
  padding: 8px 8px;
  border-bottom: 2px solid var(--pw-border);
}
td { padding: 8px 8px; border-bottom: 1px solid #eef2f5; }
tr:last-child td { border-bottom: none; }
tbody tr:hover { background: #fafbfc; }

/* ── Badges ── */
.pw-badge {
  font-family: var(--pw-font-mono);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 2px 7px;
  border-radius: 10px;
  white-space: nowrap;
}
.pw-badge--open   { background: var(--pw-success-bg); color: var(--pw-success-text); }
.pw-badge--closed { background: #edf1f4; color: var(--pw-text-secondary); }
.pw-badge--full   { background: #fff3cd; color: #856404; }

/* ── Alerts ── */
.pw-warn {
  background: var(--pw-warn-bg);
  border: 1.5px solid var(--pw-warn-border);
  border-radius: var(--pw-radius);
  padding: 8px 12px;
  font-size: 12px;
  color: var(--pw-warn-text);
  line-height: 1.4;
}
.pw-error {
  background: var(--pw-error-bg);
  border: 1.5px solid var(--pw-error-border);
  border-radius: var(--pw-radius);
  padding: 8px 12px;
  font-size: 12px;
  color: var(--pw-error-text);
}

/* ── Login ── */
.pw-login {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--pw-primary);
}
.pw-login-card {
  background: var(--pw-surface);
  border-radius: var(--pw-radius-lg);
  padding: 32px 28px;
  width: 340px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.2);
}
.pw-login-card .pw-brand { color: var(--pw-text); padding: 0 0 20px; }

/* ── Widget dashboard grid ──
   Positioning/collision/resize is owned by Gridstack.js (.grid-stack /
   .grid-stack-item, see index.html for the CDN include) — this file only
   styles the widget chrome inside each item's .grid-stack-item-content. */
.pw-grid-dash {
  margin-top: 18px;
}

.pw-widget {
  background: var(--pw-surface);
  border: 1.5px solid var(--pw-border);
  border-radius: var(--pw-radius-lg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 0.18s cubic-bezier(0.22, 1, 0.36, 1),
              background 0.25s, border-color 0.25s;
}
/* Quiet lift on hover — feedback that widgets are live, nothing more */
.pw-grid-dash .pw-widget:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.07);
}
body, .pw-sidebar, .pw-card, .pw-stat { transition: background 0.25s, border-color 0.25s, color 0.25s; }
@media (prefers-reduced-motion: reduce) {
  .pw-widget, body, .pw-sidebar, .pw-card, .pw-stat { transition: none; }
  .pw-grid-dash .pw-widget:hover { transform: none; }
}

.pw-widget__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px 6px;
  border-bottom: 1px solid var(--pw-border);
  flex-shrink: 0;
}
.pw-widget__title {
  flex: 1;
  font-family: var(--pw-font-mono);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--pw-text-secondary);
}
.pw-widget__body {
  flex: 1;
  overflow: auto;
  padding: 10px 12px;
  min-height: 0;
}
.pw-widget__body--flush { padding: 0; }

/* Sales Output — today's-breakdown donut + legend + day nav (2026-08-25).
   Donut chosen over a ranked-bar list (tried first, reverted) for
   compactness/shareability at Isaac's request — a doughnut is an
   all-pairs color form, so it's capped at 3 validated categorical slots
   + a neutral "Other" wedge (dataviz skill, color-formula.md), not 8. */
.pw-salesout-daynav {
  display: flex; align-items: center; gap: 6px;
}
.pw-salesout-daynav button {
  border: 1px solid var(--pw-border, rgba(128,128,128,0.3));
  background: transparent; border-radius: 6px; cursor: pointer;
  width: 22px; height: 22px; display: flex; align-items: center; justify-content: center;
  color: inherit; font-size: 13px; line-height: 1;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.pw-salesout-daynav button:hover:not(:disabled) {
  background: var(--pw-primary, #10648e); border-color: var(--pw-primary, #10648e); color: #fff;
}
.pw-salesout-daynav button:disabled { opacity: 0.3; cursor: default; }
.pw-salesout-legend-row {
  display: flex; align-items: center; gap: 7px; padding: 3px 0; font-size: 12px;
  border-radius: 4px; transition: background-color 0.15s ease;
}
.pw-salesout-legend-row:hover { background: var(--pw-bg, rgba(128,128,128,0.08)); }
.pw-salesout-legend-swatch {
  flex: 0 0 13px; width: 13px; height: 13px; border-radius: 3px;
  transition: transform 0.15s ease;
  display: flex; align-items: center; justify-content: center;
}
.pw-salesout-legend-row:hover .pw-salesout-legend-swatch { transform: scale(1.25); }
/* Isaac, 2026-08-25: more than 3 real hues in a donut/pie fails colorblind-
   safe separation (verified with the dataviz skill's validator — some pair
   always reads as "the same color" past 3 slots, all-pairs adjacency being
   the constraint). A number on each tail wedge, matching its legend row,
   gets the "which is which" clarity he wanted without more hues. */
.pw-salesout-legend-num {
  font-family: var(--pw-font-mono); font-size: 8px; font-weight: 700;
  color: #fff; line-height: 1; text-shadow: 0 0 1px rgba(0,0,0,0.6);
}
.pw-salesout-legend-name {
  flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-salesout-legend-value {
  flex: 0 0 auto; white-space: nowrap; margin-left: 6px;
  font-family: var(--pw-font-mono); font-size: 11px; font-weight: 700; color: var(--pw-text-secondary);
}
/* External (HTML, not canvas-drawn) donut tooltip — Chart.js's default
   tooltip paints onto the canvas itself, which clips at the donut's own
   96x96 bounds (found live, 2026-08-25: text overlapped unreadably).
   position:fixed + document.body escapes that clipping entirely. */
.pw-salesout-tooltip {
  position: fixed; opacity: 0; pointer-events: none; z-index: 1000;
  transform: translate(-50%, calc(-100% - 10px));
  background: var(--pw-surface, #fff); color: var(--pw-text, #0b0b0b);
  border: 1px solid var(--pw-border, rgba(128,128,128,0.3));
  border-radius: 6px; padding: 4px 9px; font-size: 12px; font-weight: 600;
  white-space: nowrap; box-shadow: 0 2px 8px rgba(0,0,0,0.15);
  transition: opacity 0.1s ease;
}

/* Time-window picker (Key Metrics, Avg House %) — lives in the widget HEADER
   (see mountPeriodSelect in widgets.js), not the body, so it doesn't eat into
   a widget's fixed body height and clip content below it. */
.pw-widget-period { display: inline-flex; align-items: center; margin: 0 4px; }
.pw-period-select {
  font-family: var(--pw-font-mono);
  font-size: 10px;
  padding: 2px 4px;
  border: 1px solid var(--pw-border-input);
  border-radius: 4px;
  background: var(--pw-surface);
  color: var(--pw-text-secondary);
  max-width: 100px;
}

/* Stat cards widget — big numbers in a grid that wraps 2×2 when the widget
   is narrow, instead of cramming four cells side by side. The 1px gap over a
   border-coloured background draws the hairline dividers in both directions. */
.pw-widget-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(105px, 1fr));
  /* Rows were entirely implicit (no grid-template-rows / grid-auto-rows),
     so each row sized to its own content height while the grid CONTAINER
     was still forced to height:100% above — the leftover space between the
     content-sized rows and that 100% just sat blank at the bottom (found
     2026-08-01, once the column-wrap fix above stopped masking it as an
     orphaned cell instead). 1fr rows make every row share the container's
     full height equally, so the cells' own vertical-centering actually has
     something to centre within. */
  grid-auto-rows: 1fr;
  gap: 1px;
  background: var(--pw-border);
  height: 100%;
  align-items: stretch;
}
.pw-widget-stat {
  background: var(--pw-surface);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 4px 6px;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  text-align: center;
  container-type: size;
}
.pw-widget-stat .wv {
  font-family: var(--pw-font-head);
  font-weight: 900;
  /* scale the number with its own cell (width AND height) so it fits the
     widget at any size Isaac drags it to */
  font-size: clamp(15px, min(19cqi, 38cqb), 32px);
  line-height: 1;
  color: var(--pw-primary);
}
/* Short cell (one-row widget): the yield sub-line goes, number + label stay */
@container (max-height: 88px) {
  .pw-widget-stat .wsub { display: none; }
}
.pw-widget-stat .wl {
  font-family: var(--pw-font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--pw-text-secondary);
  margin-top: 3px;
}
.pw-widget-stat .wsub {
  font-size: 11px;
  line-height: 1.3;
  color: var(--pw-text-secondary);
  margin-top: 2px;
  max-width: 100%;
}
.pw-widget-stat.pink .wv  { color: var(--pw-accent); }
.pw-widget-stat.green .wv { color: #198754; }

/* Avg house widget — large centred % */
.pw-widget-avghous {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  text-align: center;
  gap: 4px;
}
.pw-widget-avghous .big-num {
  font-family: var(--pw-font-head);
  font-weight: 900;
  font-size: 52px;
  line-height: 1;
  color: var(--pw-primary);
}
.pw-widget-avghous .sub {
  font-family: var(--pw-font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--pw-text-secondary);
}

/* Priority alert — traffic-light TILES (Key Metrics style, 2026-07-03
   redesign). Each tile: tier label, big projected-% number (display-clamped
   at "100%+"), show name, days/sold sub-line. Full-tile tint carries the
   tier colour (from _urgency() in metrics.py, passed as --tier); label text
   means colour is never the only signal. One headline sentence above the
   grid states the worst show's takeaway in plain English. Only the critical
   tier may pulse — attention is rationed. Tiles click through to the show
   modal. */
.pw-ptile-headline {
  font-size: 13px;
  font-weight: 600;
  color: var(--pw-text);
  padding: 1px 2px 5px;
  flex: none;
}
.pw-ptile-headline::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--tier);
  margin-right: 7px;
}
/* Priority Alert fills whatever height it is dragged to (2026-07-28).
   The body is a flex column: headline and the "view all" toggle are fixed,
   and .pw-ptile-scroll takes exactly the remaining space. Before this the
   widget had one content height, so every grid row either clipped it or left
   dead space below it. min-height:0 is required — a flex child defaults to
   min-content and would refuse to shrink, pushing the overflow outward. */
.pw-widget__body:has(.pw-ptile-grid) {
  display: flex;
  flex-direction: column;
  height: 100%;
}
/* Keeps `flex: 1` so the region always fills the widget and scrolls when the
   content is taller — sizing it to content instead was tried on 2026-07-28
   and let the body overflow the widget at small heights rather than scroll.
   The dead-air problem it was trying to solve is fixed in the DOM instead:
   the "view all" toggle now lives INSIDE this scroller, directly after the
   tile grid, so leftover height falls below the toggle rather than opening a
   gap between the tiles and it. min-height:0 is required — a flex child
   defaults to min-content and would refuse to shrink. */
.pw-ptile-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  /* Tiles and toggle stack from the top; slack collects at the bottom. */
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.pw-ptile-scroll > .pw-ptile-grid { flex: 0 0 auto; }
/* Tiles STRETCH to fill the space left over, rather than sitting at a fixed
   height with a gap beneath. Grid rows are 110px and the tile stack doesn't
   divide into that evenly once the headline and toggle are taken off, so a
   fixed tile height guarantees either a scrollbar or a wasted strip at every
   other size. 1fr rows absorb the remainder instead. */
.pw-ptile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  /* Upper bound as well as lower. Rows stretch to absorb leftover height, but
     only to a point: once every show is on screen there is nothing left to
     show, and a 220px-tall tile looks broken where a little space below reads
     correctly as "that is all of them". */
  /* 96px is what a complete tile needs: tier, projection + range, show name,
     days/sold, comparison chip. Below that the name clips off, so the floor
     is set here AND enforced as a minimum widget height (_WIDGET_MIN_H) so
     the widget cannot be dragged into a size that renders nameless tiles. */
  /* 124px is the tile's MEASURED natural height: tier label 15, projection +
     range 31, show name 16, days/sold 15, comparison chip 16, plus gaps and
     padding. Set below this and the lines used to squash rather than
     overflow (see .pw-ptile > * above), which looked mangled while measuring
     clean. Enforced as a minimum widget height too (_WIDGET_MIN_H). */
  /* Upper bound is max-content, NOT a fixed 160px (2026-07-28). The old cap
     let rows stretch into leftover height on the theory that a gap beneath
     the tiles looked worse than taller tiles. Measured, it is the other way
     round: a tile's content is ~114px, so a 160px row left 46px of dead air
     INSIDE every tile — the number floated in the middle of an empty box.
     Stretching only pays when there is more content to reveal, and there
     never is: the row count is fixed by how many shows fit. max-content lets
     a tile be exactly as tall as it needs and no taller, and adapts by itself
     if a tile ever grows a line. */
  grid-auto-rows: minmax(124px, max-content);
  gap: 8px;
  align-content: start;
  /* auto, not 100%: the grid is now a flex child of .pw-ptile-scroll sized by
     its own rows, and stretching it to the scroller's full height would
     re-open the gap this change exists to close. */
  height: auto;
}
/* The headline is the biggest fixed cost in the body. Two lines maximum, so
   a long show name can't eat the row a tile needs. */
.pw-ptile-headline {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.pw-ptile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow: hidden;
  text-align: center;
  gap: 2px;
  padding: 12px 8px 10px;
  border-radius: var(--pw-radius-lg);
  background: color-mix(in srgb, var(--tier) 9%, var(--pw-surface));
  border: 1.5px solid color-mix(in srgb, var(--tier) 35%, var(--pw-border));
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
/* Tile lines keep their natural height (2026-07-28). Flex children default to
   flex-shrink:1, so when the tile was shorter than its content the LINES
   squashed instead of overflowing — every text box compressed, names sliced
   through the middle, and scrollHeight still equalled clientHeight so no
   overflow check could see it. That is why the tile measured clean while
   looking mangled. */
.pw-ptile > * { flex: 0 0 auto; }

.pw-ptile:hover, .pw-ptile:focus-visible {
  border-color: var(--tier);
  outline: none;
}
.pw-ptile:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--tier) 40%, transparent); }
.pw-ptile-actions {
  position: absolute;
  top: 5px;
  right: 5px;
  display: flex;
  gap: 3px;
  opacity: 0;
  transition: opacity 0.15s;
}
.pw-ptile:hover .pw-ptile-actions,
.pw-ptile:focus-within .pw-ptile-actions { opacity: 1; }
.pw-ptile-action-btn {
  width: 20px;
  height: 20px;
  border-radius: 5px;
  border: none;
  background: color-mix(in srgb, var(--pw-surface) 80%, transparent);
  color: var(--pw-text-secondary);
  font-size: 11px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.pw-ptile-action-btn:hover { background: var(--pw-surface); color: var(--pw-text); }
.pw-ptile-action-btn svg { width: 12px; height: 12px; display: block; }

/* Roadmap 9b: hover copy button for per-show rows (Shows Table, Revenue
   Forecast) — same icon language as the priority tile actions, but inline
   with the row's name so tables don't need an extra column. */
.pw-row-copy {
  width: 18px;
  height: 18px;
  margin-left: 6px;
  border-radius: 5px;
  border: none;
  background: transparent;
  color: var(--pw-text-secondary);
  font-size: 11px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: -3px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s;
}
tr:hover .pw-row-copy, .pw-fc-row:hover .pw-row-copy,
.pw-row-copy:focus-visible { opacity: 1; }
.pw-row-copy:hover { background: var(--pw-border); color: var(--pw-text); }
.pw-row-copy svg { width: 11px; height: 11px; display: block; }
.pw-ptile__label {
  font-family: var(--pw-font-mono);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--tier);
}
/* "IN RUN" chip (PLAN.md step 3, in-run pace alert) — a quiet marker next to
   the tier label so an in-run WATCH tile reads distinctly from a pre-opening
   one at a glance (different benchmark, different big-number meaning). Not
   tier-coloured on purpose — it's a category, not a severity signal. */
.pw-ptile__chip {
  font-family: var(--pw-font-mono);
  font-weight: 700;
  font-size: 8px;
  letter-spacing: 0.5px;
  color: var(--pw-text-secondary);
  background: color-mix(in srgb, var(--pw-text-secondary) 15%, transparent);
  border-radius: 4px;
  padding: 1px 4px;
  margin-left: 5px;
  vertical-align: middle;
}
.pw-ptile__num {
  font-family: var(--pw-font-head);
  font-weight: 900;
  font-size: 30px;
  line-height: 1.05;
  color: var(--tier);
}
.pw-ptile__name {
  font-size: 11px;
  font-weight: 600;
  color: var(--pw-text);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pw-ptile__sub {
  font-family: var(--pw-font-mono);
  font-size: 10px;
  color: var(--pw-text-secondary);
  /* Never wrap: a wrapped sub-line makes tile height unpredictable and the
     fit-to-widget maths in renderWidgetPriority clip the bottom row
     (Isaac's dashboard, 2026-07-06). */
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Applied by renderWidgetPriority when the painted grid overflows the widget:
   tighter tiles first, scrolling as the last resort. */
.pw-ptile-grid--compact .pw-ptile { padding: 7px 6px 6px; gap: 1px; }
.pw-ptile-grid--compact .pw-ptile__num { font-size: 21px; }
/* The 124px row floor above is the natural height of a FULL-SIZE tile. Compact
   mode shrinks every font in the tile, so its content measures 100px — holding
   it at 124 forced a scrollbar over 24px of air that nothing needed
   (2026-07-28). 104 keeps a 4px buffer over the measured maximum. Re-measure
   this if the compact font sizes change; it is a measurement, not a taste. */
.pw-ptile-grid--compact { grid-auto-rows: minmax(104px, max-content); }
.pw-ptile-grid--compact .pw-ptile__name { font-size: 10px; }
.pw-ptile--urgent {
  animation: pw-ptile-pulse 1.8s ease-in-out infinite;
}
@keyframes pw-ptile-pulse {
  0%, 100% { background-color: color-mix(in srgb, var(--tier) 9%, var(--pw-surface)); }
  50%      { background-color: color-mix(in srgb, var(--tier) 24%, var(--pw-surface)); }
}
@media (prefers-reduced-motion: reduce) {
  .pw-ptile--urgent {
    animation: none;
    background-color: color-mix(in srgb, var(--tier) 18%, var(--pw-surface));
  }
}
/* Header pill, not a full-width strip under the tiles (2026-07-28). As a
   strip it was a 33px line item in the height budget and forced the widget
   into the next Gridstack size up; in the header it is free. Sized and
   spaced to sit alongside .pw-priority-tune. */
.pw-priority-toggle {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  background: none;
  border: 1px solid var(--pw-border, rgba(128, 128, 128, 0.3));
  border-radius: 12px;
  font-family: var(--pw-font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--pw-primary);
  cursor: pointer;
  white-space: nowrap;
}
.pw-priority-toggle:hover { color: var(--pw-accent); }
.pw-priority-more-holder { display: inline-flex; margin-right: 6px; }

/* Era toggle in sidebar */
.pw-era-wrap {
  margin: 8px 14px;
  padding: 8px 10px;
  background: rgba(255,255,255,0.07);
  border-radius: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.pw-era-label {
  font-family: var(--pw-font-mono);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: rgba(255,255,255,0.6);
  flex: 1;
}
.pw-era-value {
  font-family: var(--pw-font-mono);
  font-size: 10px;
  text-transform: uppercase;
  color: var(--pw-accent);
  font-weight: 700;
  letter-spacing: 0.5px;
  white-space: nowrap;
}
/* Theme row: let the <select> take the row's spare width so "HOUSE LIGHTS"
   isn't clipped (its label doesn't need to grow like the Data toggle's does). */
#theme-wrap .pw-era-label { flex: 0 0 auto; }

/* Era switch: a two-option segmented control, not a bare checkbox — the
   previous single toggle + dynamically-changing text label ("Since Mar 2023"
   / "All history") gave no visual cue for which state was active, so it
   read as ambiguous or "backwards" (found 2026-07-05). Both options are
   always shown; the active one is highlighted, removing the ambiguity. */
.pw-era-wrap { flex-wrap: wrap; }
.pw-era-wrap .pw-era-label { flex: 0 0 auto; }
.pw-era-switch {
  flex: 1;
  display: flex;
  background: rgba(0,0,0,0.25);
  border-radius: 5px;
  padding: 2px;
  gap: 2px;
}
.pw-era-btn {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  border: none;
  background: transparent;
  color: rgba(255,255,255,0.55);
  font-family: var(--pw-font-mono);
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding: 5px 4px;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}
.pw-era-btn:hover { color: rgba(255,255,255,0.85); }
.pw-era-btn--active {
  background: var(--pw-accent);
  color: #fff;
}
.pw-era-btn--active:hover { color: #fff; }

.pw-link-btn {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  background: transparent;
  color: var(--pw-primary);
  cursor: pointer;
  padding: 2px 4px;
}
.pw-link-btn:hover { text-decoration: underline; }

/* Widget permissions settings grid */
.pw-perms-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.pw-perms-table th { text-align: center; padding: 8px; }
.pw-perms-table th:first-child { text-align: left; }
.pw-perms-table td { padding: 7px 8px; border-bottom: 1px solid #eef2f5; text-align: center; }
.pw-perms-table td:first-child { text-align: left; font-weight: 600; }
.pw-perms-table tr:last-child td { border-bottom: none; }

/* ── Edit mode ── */
.pw-dash-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.pw-widget { position: relative; }
.pw-widget__drag-handle {
  display: none;
  cursor: grab;
  color: rgba(0,0,0,0.25);
  font-size: 14px;
  line-height: 1;
  padding: 0 4px 0 0;
  user-select: none;
}
.pw-widget__remove {
  display: none;
  cursor: pointer;
  color: rgba(0,0,0,0.3);
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
  user-select: none;
}
.pw-widget__remove:hover { color: var(--pw-error-text, #c0392b); }

/* Header copy-stats button (roadmap 9b generalisation, 2026-07-06): only
   visible on widget hover/focus, and only rendered at all for widgets that
   registered a _copyText provider. */
.pw-widget__copy {
  border: none;
  background: none;
  cursor: pointer;
  color: rgba(0,0,0,0.28);
  padding: 2px 3px;
  border-radius: 4px;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.pw-widget:hover .pw-widget__copy,
.pw-widget__copy:focus-visible { opacity: 1; }
.pw-widget__copy:hover { color: var(--pw-primary); background: var(--pw-border); }
.pw-widget__copy svg { width: 13px; height: 13px; display: block; }

/* Widget methodology tooltip — always visible (not just edit mode), so a
   number can be sense-checked at a glance without entering Customise.
   The tip itself is a single shared element appended to <body> (see
   initInfoTooltip in widgets.js) and positioned via JS with `fixed`, since
   .pw-widget's overflow:hidden (needed for table/chart content) would
   otherwise clip an absolutely-positioned tip nested inside it. */
.pw-widget__info-wrap { position: relative; display: inline-flex; align-items: center; outline: none; }
.pw-widget__info {
  cursor: help;
  color: rgba(0,0,0,0.28);
  font-size: 12px;
  margin: 0 5px;
  user-select: none;
}
.pw-widget__info-wrap:hover .pw-widget__info,
.pw-widget__info-wrap:focus .pw-widget__info { color: var(--pw-primary); }
.pw-info-tip {
  display: none;
  position: fixed;
  width: 260px;
  background: var(--pw-text);
  color: #fff;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 11px;
  line-height: 1.5;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  z-index: 500;
  box-shadow: 0 8px 24px rgba(0,0,0,0.25);
}
.pw-info-tip p { margin: 0 0 6px; }
.pw-info-tip__source { color: rgba(255,255,255,0.6); font-style: italic; }
/* The accuracy line sits between the one-line summary and the source, set
   apart because "how far can I trust this" is the second thing a reader
   wants and shouldn't be mistaken for more description (2026-07-27). */
.pw-info-tip__accuracy {
  border-left: 2px solid var(--pw-accent);
  padding-left: 8px;
  color: rgba(255,255,255,0.85);
}
.pw-info-tip a {
  display: inline-block;
  margin-top: 2px;
  color: var(--pw-accent);
  text-decoration: none;
  font-weight: 700;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.pw-info-tip a:hover { text-decoration: underline; }
/* Dark theme: --pw-text is near-white there, so the light-mode trick of
   "tip background = text colour" becomes white-on-white (Isaac, 2026-07-07).
   Give the tip an explicit dark surface instead. */
:root[data-theme="dark"] .pw-widget__info { color: rgba(255,255,255,0.35); }
:root[data-theme="dark"] .pw-info-tip {
  background: #232e3a;
  color: #e8edf2;
  border: 1px solid var(--pw-border);
}
:root[data-theme="dark"] .pw-info-tip__source { color: #9db0c2; }
:root[data-theme="dark"] .pw-info-tip__accuracy { color: #d6e0ea; }
.pw-grid-dash--editing .pw-widget__drag-handle { display: inline-block; }
.pw-grid-dash--editing .pw-widget__remove { display: inline-block; }
.pw-grid-dash--editing .pw-widget { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.pw-grid-dash--editing .pw-widget__head { background: rgba(16,100,142,0.03); cursor: grab; }

/* Edit-mode wiggle — calmer than the original (0.25° over 2.4s, was 0.8°/0.6s) */
@keyframes pw-wiggle {
  0%, 100% { transform: rotate(0deg); }
  25%       { transform: rotate(-0.25deg); }
  75%       { transform: rotate(0.25deg); }
}
.pw-grid-dash--editing .pw-widget {
  animation: pw-wiggle 2.4s ease-in-out infinite;
  transform-origin: center;
}
.grid-stack-item.ui-draggable-dragging .pw-widget,
.grid-stack-item.ui-resizable-resizing .pw-widget {
  animation: none; /* don't wiggle the item actively being dragged/resized */
}

/* Widget placeholder / loading */
.pw-widget-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--pw-text-secondary);
  font-family: var(--pw-font-mono);
  font-size: 11px;
  letter-spacing: 1px;
}
.pw-widget-disabled {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  gap: 6px;
  color: var(--pw-muted);
  font-size: 12px;
}

/* ── Responsive ── */
@media (max-width: 820px) {
  .pw-app { flex-direction: column; }
  /* Sidebar becomes a wrapping top bar so every control stays visible and
     tappable — the old overflow-x:auto strip hid Settings/theme/era/sign-out
     off-screen with no affordance. */
  .pw-sidebar {
    width: 100%;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
    overflow: visible;
    padding: 8px 12px;
  }
  .pw-brand { padding: 4px 6px; font-size: 20px; }
  .pw-nav {
    flex: 1 1 100%;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 2px 4px;
    margin-top: 0;
  }
  .pw-nav a { padding: 8px 12px; }
  .pw-nav a.active::before { display: none; }
  .pw-nav .nav-divider { display: none; }
  .pw-era-wrap, #theme-wrap { margin: 0; }
  .pw-era-label { flex: 0 0 auto; }
  .pw-signout-wrap { margin-left: auto; padding: 0 !important; }
  .sidebar-toggle-btn { display: none; }
  .pw-main { padding: 16px; }
  .pw-grid--3, .pw-grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .pw-grid--2, .pw-grid--3, .pw-grid--4 { grid-template-columns: 1fr; }
  /* Delta chips must never exceed the card width — let text wrap on narrow
     screens (inline style sets nowrap; !important beats it here only). */
  .pw-delta-chip { white-space: normal !important; text-align: center; }
}

/* ── Breakdowns widget bars (A5, 2026-07-03) ──
   The old .pw-priority-bar class these replaced was deleted when Priority
   Alert became tiles, which silently flattened every breakdown bar to 0px. */
.pw-bd-bar {
  height: 6px;
  border-radius: 3px;
  background: #edf1f4;
  overflow: hidden;
}
.pw-bd-bar__fill {
  height: 100%;
  border-radius: 3px;
}

/* ── Users panel (Settings, superuser) ── */
.pw-users-list { display: flex; flex-direction: column; gap: 6px; }
.pw-user-row {
  border: 1px solid var(--pw-border);
  border-radius: var(--pw-radius-lg);
  background: var(--pw-surface);
}
.pw-user-row > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 14px;
}
.pw-user-row > summary::-webkit-details-marker { display: none; }
.pw-user-row > summary::before {
  content: '▸'; color: var(--pw-text-secondary); font-size: 11px; transition: transform 0.15s;
}
.pw-user-row[open] > summary::before { transform: rotate(90deg); }
.pw-user-name { font-weight: 700; font-size: 14px; }
.pw-user-email { color: var(--pw-text-secondary); font-size: 12px; font-family: var(--pw-font-mono); }
.pw-user-rolebadge {
  margin-left: auto;
  font-family: var(--pw-font-mono);
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  padding: 3px 9px; border-radius: 11px;
  background: #eef2f5; color: var(--pw-text-secondary);
}
.pw-role-superuser { background: #e7f0f6; color: var(--pw-primary); }
.pw-role-full      { background: #e6f4ec; color: #198754; }
.pw-role-manager   { background: #fdf0e5; color: #b9640a; }
.pw-role-intern    { background: #eef2f5; color: #5a6b7c; }
.pw-user-you {
  font-family: var(--pw-font-mono); font-size: 9px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.5px;
  padding: 2px 7px; border-radius: 9px; background: var(--pw-accent); color: #fff;
}
.pw-user-editor {
  padding: 14px; border-top: 1px solid var(--pw-border);
  display: flex; flex-direction: column; gap: 12px;
}
#user-new-form { margin-bottom: 12px; border: 1px solid var(--pw-border); border-radius: var(--pw-radius-lg); }
#user-new-form { border-top: none; }
.pw-user-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px; align-items: end;
}
.pw-user-grid label {
  display: flex; flex-direction: column; gap: 4px;
  font-family: var(--pw-font-mono); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.5px; color: var(--pw-text-secondary);
}
.pw-user-grid input, .pw-user-grid select {
  font-family: var(--pw-font-body); font-size: 13px; font-weight: 400;
  text-transform: none; letter-spacing: 0; color: var(--pw-text);
  padding: 7px 9px; border: 1px solid var(--pw-border); border-radius: 6px; background: var(--pw-surface);
}
.pw-user-inline-btn { display: flex; align-items: flex-end; }
.pw-widget-toggles-label {
  font-family: var(--pw-font-mono); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.5px; color: var(--pw-text-secondary);
}
.pw-widget-toggles { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.pw-widget-toggle {
  display: flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer;
  min-width: 150px;
}
.pw-user-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pw-user-msg { font-family: var(--pw-font-mono); font-size: 11px; }
.pw-user-created {
  margin-bottom: 12px; padding: 12px 14px;
  border: 1px solid #b7e0c6; border-radius: var(--pw-radius-lg);
  background: var(--pw-success-bg); color: var(--pw-success-text);
  font-size: 13px; line-height: 1.5;
}
.pw-user-created code {
  font-family: var(--pw-font-mono); font-weight: 700;
  background: rgba(0,0,0,0.06); padding: 2px 6px; border-radius: 4px;
}

/* ── Speeding Up / Slowing Down (2026-07-28) ──────────────────────────
   Grouped into behind / keeping up rather than one ranked list: the question
   is "who is off-pace", which is a short list and a count, not a leaderboard
   of everything on sale. Bars are one-directional within a group, so length
   reads as size-of-gap without needing a centre line to decode. */
.pw-widget__body:has(.pw-mom-scroll) { display: flex; flex-direction: column; height: 100%; }
.pw-mom-headline { font-size: 12.5px; font-weight: 600; line-height: 1.35; padding-bottom: 7px; flex: none; }
.pw-mom-scroll { flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.pw-mom-group + .pw-mom-group { margin-top: 10px; }
.pw-mom-grouphead {
  font-family: var(--pw-font-mono); font-size: 9.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.07em; padding-bottom: 3px;
}
.pw-mom-row {
  display: grid;
  /* Name gets the room: it is what you read first. The bar only has to
     rank at a glance, so it does not need half the widget. */
  grid-template-columns: minmax(0, 1.7fr) 28px minmax(40px, 1.5fr) 42px 30px;
  align-items: center; gap: 7px; padding: 3px 0; font-size: 11.5px;
}
.pw-mom-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pw-mom-days, .pw-mom-tkts {
  font-family: var(--pw-font-mono); font-size: 10px;
  color: var(--pw-text-secondary); text-align: right;
}
.pw-mom-track { height: 9px; border-radius: 3px; background: var(--pw-border); overflow: hidden; }
.pw-mom-bar { display: block; height: 100%; border-radius: 3px; }
.pw-mom-val { font-family: var(--pw-font-mono); font-size: 11px; font-weight: 700; text-align: right; }
.pw-mom-foot { font-size: 10px; color: var(--pw-text-secondary); padding-top: 6px; flex: none; }

/* Projection range, under the headline number it qualifies (2026-07-28).
   A crisp "24%" beside a 4.5-49.8% band was the model saying "I don't know"
   while the tile said otherwise. */
.pw-ptile__band {
  /* Inline with the number, not on its own line: a separate line pushed the
     show NAME out of the tile at the smallest widget height, and a range
     without a show attached is worse than no range. */
  font-family: var(--pw-font-mono);
  font-size: 9.5px;
  font-weight: 400;
  color: var(--pw-text-secondary);
  letter-spacing: 0.02em;
  white-space: nowrap;
  vertical-align: 0.35em;
}
/* A number produced by a CEILING rather than by the model. Dotted underline
   only — it must read as a caveat, not an alarm; the tier colour is already
   carrying the urgency. */
.pw-ptile__num--capped {
  text-decoration: underline dotted currentColor 1.5px;
  text-underline-offset: 3px;
}
/* Near-zero sales: the RANGE has taken the headline slot because there are
   too few tickets sold for a point figure to mean anything (2026-07-28,
   KICKOFF q4). Smaller than a point number for the obvious reason — "5-50%"
   is more than twice the glyphs of "24%" and the tile column fits about 16
   characters — and lighter in weight so it reads as a spread rather than as
   a bigger, more emphatic claim. The tier colour is unchanged: the alarm is
   an observation about sales so far and does not depend on the projection. */
.pw-ptile__num--range {
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.pw-ptile-grid--compact .pw-ptile__num--range { font-size: 16px; }

/* §43 trust chip — a measured "how much to trust this projection" pill,
   shown inline next to any printed forecast number (tile, revenue forecast
   row, show-detail modal). Sized/styled off the same base as .pw-ptile__chip
   (the IN RUN marker) but colour-coded by grade. GUESS is deliberately
   muted grey, not red — it means "unknown", not "alarm". */
.pw-trust-chip {
  display: inline-block;
  font-family: var(--pw-font-mono);
  font-weight: 700;
  font-size: 8px;
  letter-spacing: 0.3px;
  border-radius: 4px;
  padding: 1px 4px;
  margin-left: 4px;
  vertical-align: middle;
  white-space: nowrap;
}
.pw-trust-chip--firm {
  color: #198754;
  background: color-mix(in srgb, #198754 15%, transparent);
}
.pw-trust-chip--rough {
  color: #e67e22;
  background: color-mix(in srgb, #e67e22 15%, transparent);
}
.pw-trust-chip--guess {
  color: var(--pw-text-secondary);
  background: color-mix(in srgb, var(--pw-text-secondary) 15%, transparent);
}
/* Tile form: a dot, taken OUT of the inline flow. Absolute so it cannot
   lengthen the number line (a 134px tile has ~19px of slack there — the full
   pill wrapped it and cost the tile 21px of height, overflowing the scroller).
   The number line gets position:relative + a reserved right gutter below, so
   the dot never lands on the band text. Colour carries the grade; the full
   sentence is in the title. */
.pw-trust-chip--dot {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 8px;
  height: 8px;
  padding: 0;
  margin: 0;
  border-radius: 50%;
  background: currentColor;
}
/* nowrap is belt AND braces: the dot can no longer cause a wrap, but a long
   band on a narrow tile could still wrap this line on its own, and a number
   broken across two lines is wrong here regardless of what caused it. */
.pw-ptile__num {
  position: relative;
  padding-right: 12px;
  white-space: nowrap;
}

/* The firm/rough hexes above are the LIGHT-theme greens/ambers; at full
   saturation they sit too close to the dark surface (#1a232c) to read at 8px.
   Same lift the .pw-widget-stat.green .wv override does, but taken from the
   theme's own dark success/warn text tokens rather than a second hand-picked
   hex. GUESS needs no override — it already keys off --pw-text-secondary,
   which the dark block redefines. */
:root[data-theme="dark"] .pw-trust-chip--firm {
  color: var(--pw-success-text);
  background: color-mix(in srgb, var(--pw-success-text) 15%, transparent);
}
:root[data-theme="dark"] .pw-trust-chip--rough {
  color: var(--pw-warn-text);
  background: color-mix(in srgb, var(--pw-warn-text) 15%, transparent);
}
/* Must come AFTER the dark grade rules and match their specificity: those set
   a 15%-alpha BACKGROUND for the pill form, which outranked the dot's
   `background: currentColor` and rendered the dark firm/rough dots at 15%
   opacity — nearly invisible (the grey GUESS dot looked fine only because it
   has no dark override, which is exactly why the bug was easy to miss). The
   dot is a solid shape, so it wants the grade colour at full strength in both
   themes. */
:root[data-theme="dark"] .pw-trust-chip--dot,
.pw-trust-chip--dot { background: currentColor; }

/* Forecast Lab unit toggle (2026-09-26) */
.pw-fl-seg { display: inline-flex; gap: 2px; padding: 2px; border: 1.5px solid var(--pw-border); border-radius: 7px; background: var(--pw-surface); }
.pw-fl-seg button { appearance: none; border: none; background: transparent; color: var(--pw-text-secondary);
  font-family: var(--pw-font-mono); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
  padding: 6px 12px; border-radius: 5px; cursor: pointer; }
.pw-fl-seg button:hover { color: var(--pw-text); }
.pw-fl-seg button.active { background: var(--pw-accent); color: #fff; }
.pw-fl-seg button:focus-visible { outline: 2px solid var(--pw-accent); outline-offset: 2px; }
/* Forecast Lab tables: rows are ruled by their own border-top; the global
   td rule and light-only hover would draw white lines in dark mode. */
.pw-fl-table td { border-bottom: none; color: var(--pw-text); }
.pw-fl-table tbody tr:hover { background: var(--pw-bg); }

/* ── Approved locations (Settings → Users, 2026-10-24) ── */
.pw-loc-block { margin: 14px 0 6px; }
.pw-loc-table { width: 100%; border-collapse: collapse; font-size: 12px; margin: 4px 0 8px; }
.pw-loc-table th { text-align: left; font-weight: 600; color: var(--pw-text-secondary); padding: 4px 6px; border-bottom: 1px solid var(--pw-border, #ddd); }
.pw-loc-table td { padding: 5px 6px; border-bottom: 1px solid var(--pw-border, #eee); vertical-align: middle; }
.pw-loc-empty { font-size: 12px; color: var(--pw-text-secondary); margin: 4px 0 8px; }
.pw-loc-add { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.pw-loc-add input { width: auto; flex: 1 1 140px; min-width: 0; margin: 0; }
.pw-loc-hint { flex-basis: 100%; font-size: 11px; color: var(--pw-text-secondary); }
.pw-loc-block { max-width: 100%; overflow-x: auto; }
@media (max-width: 600px) {
  .pw-loc-table th:nth-child(3), .pw-loc-table td:nth-child(3) { display: none; }
  .pw-loc-table th, .pw-loc-table td { padding: 4px 3px; }
  .pw-loc-table code { font-size: 11px; }
  .pw-loc-table .loc-revoke { padding: 3px 6px !important; }
}
#loc-wait p, .pw-login-card h2 + p, .pw-login-card p { margin: 0 0 10px; line-height: 1.45; }
/* The new-user form starts hidden; the editor's display rule was overriding [hidden]. */
.pw-user-editor[hidden] { display: none; }

/* ── First-sign-in welcome card (2026-10-24) ── */
.pw-welcome {
  background: var(--pw-surface);
  border: 1px solid var(--pw-border);
  border-left: 4px solid var(--pw-accent);
  border-radius: var(--pw-radius-lg, 10px);
  padding: 16px 20px;
  margin: 10px 0 16px;
  font-size: 14px;
  line-height: 1.5;
}
.pw-welcome[hidden] { display: none; }
.pw-welcome-title { font-family: var(--pw-font-head); font-size: 20px; margin: 0 0 6px; }
.pw-welcome p { margin: 0 0 6px; }
.pw-welcome ul { margin: 0 0 12px; padding-left: 20px; }
.pw-welcome li { margin: 3px 0; }
.pw-welcome-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.pw-welcome-actions .btn { font-size: 12px; padding: 6px 12px; text-decoration: none; }
.pw-welcome-dismiss { margin-left: auto; }
@media (max-width: 600px) {
  .pw-welcome { padding: 14px; }
  .pw-welcome-dismiss { margin-left: 0; }
}

/* ── Show Watch: "What to do now" panel (2026-10-24) ── */
.pw-watch-push {
  border-left: 3px solid var(--pw-accent);
  background: rgba(254, 0, 193, 0.05);
  border-radius: 4px;
  padding: 6px 10px;
  margin: 0 0 10px;
  font-size: 12px;
  line-height: 1.45;
}
.pw-watch-push ul { margin: 0; padding-left: 0; list-style: none; }
.pw-watch-push li { margin: 2px 0; }
