/* G3 — operations dashboard styles
 *
 * Brand colors and typography per BRAND_STYLE_GUIDE.md v1. Touch-first
 * sizing per BUILD_PLAN.md (44px min tap target, 60px+ preferred for
 * primary actions). Layout assumes 7-10in touch displays as the eventual
 * target while staying usable on desktop / phone in the meantime.
 */

:root {
  /* Primary brand */
  --g3-dark: #1F2933;
  --g3-blue: #2E8B96;
  --g3-terracotta: #E85F2C;

  /* Neutrals */
  --g3-white: #FFFFFF;
  --g3-soft-white: #F7F5F2;
  --g3-light-grey: #E8EEF3;
  --g3-mid-grey: #6B7785;
  --g3-body: #1F2933;

  /* Semantic */
  --g3-success: #0F766E;
  --g3-warning: #B45309;
  --g3-alert: #B91C1C;
  --g3-info: #0369A1;

  /* Touch-first sizing */
  --g3-tap-min: 44px;
  --g3-tap-primary: 60px;

  /* Spacing scale */
  --g3-s-1: 4px;
  --g3-s-2: 8px;
  --g3-s-3: 12px;
  --g3-s-4: 16px;
  --g3-s-5: 24px;
  --g3-s-6: 32px;
  --g3-s-7: 48px;

  /* Radius */
  --g3-r-sm: 6px;
  --g3-r-md: 10px;
  --g3-r-lg: 14px;
  --g3-r-pill: 999px;

  /* ────────────────────────────────────────────────────────────
     G3 brand palette — derived from the logo (SDG-aligned), 2026-05-26
     ────────────────────────────────────────────────────────────
     The G3 logo's Guam-shape mosaic is the UN Sustainable Development
     Goals color palette. That gives us a mission-aligned, defensible,
     externally-recognizable set of brand colors instead of arbitrary
     hand-picked tones.

     Primary brand: orange (the logo ring + dominant dot color).
     Secondary brand: green (the "Green Growth" half of the org name,
     with multiple SDG green dots in the logo).
     SDG accents: full named tag palette for surfaces that need many
     distinct chip colors (machine-type pills, training categories,
     etc.). Used opt-in, not as defaults. */

  /* ─── Primary brand (G3 orange) ─── */
  --accent:        #F16B2C;  /* G3 logo orange — primary interactive */
  --accent-hot:    #D14E18;  /* terracotta — hover / active */
  --accent-soft:   #FEF1E9;  /* light orange tint — hover surfaces, callout bg */
  --accent-deep:   #A8390F;  /* dark terracotta — text-on-orange, focus rings */
  --accent-text:   #A8390F;  /* body link / details summary color — darker than
                              * --accent for comfortable reading on white.
                              * Flips to a lighter orange in dark mode. */
  --accent-border: #F16B2C;  /* alias kept for layer-1 sweep callers */

  /* ─── Secondary brand (G3 green — the "Green Growth" axis) ─── */
  --brand-green:       #4C9F38;  /* balanced UI-chrome green (SDG #3) */
  --brand-green-soft:  #E8F4DF;  /* tint — surfaces, badges */
  --brand-green-deep:  #2E6622;  /* deep — text-on-green */

  /* ─── SDG accent palette (named tag colors) ─── */
  /* Use when you need >2 distinct colored chips. Don't use these as
   * default text/border/background — they're for tag/badge/category
   * surfaces with deliberate semantic meaning. */
  --sdg-red:    #E5243B;  /* SDG #1 No Poverty */
  --sdg-orange: #FD9D24;  /* SDG #11 Sustainable Cities */
  --sdg-yellow: #FCC30B;  /* SDG #7 Affordable Energy */
  --sdg-lime:   #56C02B;  /* SDG #15 Life on Land */
  --sdg-forest: #3F7E44;  /* SDG #13 Climate Action */
  --sdg-teal:   #26BDE2;  /* SDG #6 Clean Water */
  --sdg-blue:   #0A97D9;  /* SDG #14 Life Below Water */
  --sdg-navy:   #19486A;  /* SDG #17 Partnerships */
  --sdg-pink:   #DD1367;  /* SDG #10 Reduced Inequalities */
  --sdg-wine:   #A21942;  /* SDG #8 Decent Work */
}


/* ────────────────────────────────────────────────────────────────
   Dark mode (per-user, localStorage-persisted via base.html)
   ────────────────────────────────────────────────────────────────
   Strategy: redefine the SURFACE-role tokens in dark mode. Because
   ~255 places in this file already reference these tokens (and most
   inline styles in templates do too), the redefine cascades through
   the whole staff dashboard automatically.

   Tokens that flip in dark mode:
     --g3-white       page bg / card surface          (light: #FFF → dark: #0F1419)
     --g3-soft-white  raised / nested surfaces        (light: #F7F5F2 → dark: #1A2128)
     --g3-light-grey  borders / dividers              (light: #E8EEF3 → dark: #2D3848)
     --g3-dark        primary text                    (light: #1F2933 → dark: #E5E9ED)
     --g3-mid-grey    secondary text                  (light: #6B7785 → dark: #9CA3AF)
     --g3-body        body text                       (light: #1F2933 → dark: #E5E9ED)
     --accent-soft    subtle orange surface tint      (light: #FEF1E9 → dark: #3B1F0F)
     --brand-green-soft  subtle green surface tint    (light: #E8F4DF → dark: #1A2F0F)

   Tokens that DO NOT flip (intentional):
     --accent / --accent-hot / --brand-green / --brand-green-deep —
       brand colors stay the same in both themes; they're meant to
       maintain identity contrast on both light + dark surfaces.
     --g3-success / --g3-warning / --g3-alert / --g3-info — semantic
       colors stay saturated; they read against both themes.
     --sdg-*  — tag colors stay fixed.

   Carve-out: `color: var(--g3-white)` is used in ~30 places as
   "white text on a colored background" (buttons, table-th, badges,
   pills). Those would flip to dark text in dark mode otherwise, so
   the exception block below restores literal #FFFFFF text on those
   surfaces. */
[data-theme="dark"] {
  /* Tuned 2026-05-26 after first-pass eyeballing the dashboard in
   * dark mode. Initial values (#0F1419 / #1A2128) felt stark and
   * borders sat too prominent. Softer palette below: page bg lifts
   * to deep slate (not near-black), surfaces lift a half-step more
   * to give cards visible elevation, borders quiet down. */
  --g3-white:           #151B24;  /* page bg + card surface (was #0F1419) */
  --g3-soft-white:      #1E2632;  /* raised / nested surfaces (was #1A2128) */
  --g3-light-grey:      #2A3240;  /* borders / dividers (was #2D3848 — softer) */
  --g3-dark:            #E8ECEF;  /* primary text */
  --g3-mid-grey:        #A8B2BD;  /* secondary text (was #9CA3AF — brighter) */
  --g3-body:            #E8ECEF;  /* body text */
  --accent-soft:        #3B1F0F;  /* dark orange tint surface */
  --accent-text:        #F1864E;  /* link / details summary on dark — lighter
                                   * than --accent so contrast lifts on slate */
  --brand-green-soft:   #1A2F0F;  /* dark green tint surface */
}

/* Carve-out 1: text-on-colored-background stays literal white in
 * dark mode regardless of --g3-white redefinition. Add new classes
 * here when they fit the "white text on colored bg" pattern. */
[data-theme="dark"] .pf-btn,
[data-theme="dark"] .pf-table th,
[data-theme="dark"] .pf-nav__link.is-active,
[data-theme="dark"] .pf-badge,
[data-theme="dark"] .pf-tier-tag,
[data-theme="dark"] .pf-stage-pill,
[data-theme="dark"] .pf-kanban__count,
[data-theme="dark"] .pf-callout--accent strong,
[data-theme="dark"] .g3-detail__pill--accent,
[data-theme="dark"] .g3-detail__pill--warning,
[data-theme="dark"] .g3-detail__pill--alert,
[data-theme="dark"] .g3-detail__pill--success {
  color: #FFFFFF;
}

/* Carve-out 2: header chrome + nav links use var(--g3-soft-white)
 * for text in light mode. That token flips to a DARK color in dark
 * mode, which makes the header title + nav links ghostly. Restore
 * light-on-dark explicitly. The header background is also tuned to
 * a slightly different dark than the page bg so the chrome has
 * visual weight + the orange divider pops. */
[data-theme="dark"] .pf-header {
  background: #0E131A;       /* slightly deeper than page bg */
  color: #E8ECEF;
}
[data-theme="dark"] .pf-brand,
[data-theme="dark"] .pf-brand__name {
  color: #F0F3F6;
}
[data-theme="dark"] .pf-nav__link {
  color: #C9D1DB;
}
[data-theme="dark"] .pf-nav__link:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #F0F3F6;
}
[data-theme="dark"] .pf-nav__theme-toggle {
  color: #C9D1DB;
}
[data-theme="dark"] .pf-nav__theme-toggle:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #F0F3F6;
}
/* "More ▾" dropdown panel sits inside the header but pops over body
 * content — keep it on the surface-soft scale so it reads as a
 * floating panel, not a continuation of the header strip. */
[data-theme="dark"] .pf-nav__more-panel {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
}

/* Footer mirrors the header treatment — same chrome-text concerns. */
[data-theme="dark"] .pf-footer {
  background: #0E131A;
  border-top-color: #2A3240;
  color: #C9D1DB;
}
[data-theme="dark"] .pf-footer a {
  color: var(--accent);
}

/* Subtle elevation: in dark mode, add a soft shadow under cards so
 * they read as raised surfaces rather than flat differently-colored
 * rectangles. Light mode already gets the lift from the off-white
 * vs white contrast. */
[data-theme="dark"] .pf-card,
[data-theme="dark"] .g3-detail-card,
[data-theme="dark"] .g3-detail-card--open,
[data-theme="dark"] .g3-detail__actionbar {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

/* Form inputs in dark mode — many inline-styled inputs across the
 * codebase set border/padding but leave background as UA default
 * (white). In dark mode that renders as a bright white box on a
 * dark page. Force the default to flow through tokens. Inline
 * styles can still override per-element when needed. */
[data-theme="dark"] input[type="text"],
[data-theme="dark"] input[type="email"],
[data-theme="dark"] input[type="tel"],
[data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="date"],
[data-theme="dark"] input[type="search"],
[data-theme="dark"] input[type="password"],
[data-theme="dark"] input[type="url"],
[data-theme="dark"] select,
[data-theme="dark"] textarea {
  background: var(--g3-white);
  color: var(--g3-body);
  border-color: var(--g3-light-grey);
}
[data-theme="dark"] input::placeholder,
[data-theme="dark"] textarea::placeholder {
  color: var(--g3-mid-grey);
  opacity: 0.7;
}
/* `code` blocks (used for the public request URL display) similarly
 * default to light grey bg. Force token. */
[data-theme="dark"] code {
  background: var(--g3-soft-white);
  color: var(--g3-body);
}


* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--g3-white);
  color: var(--g3-body);
  font-family: 'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a {
  /* Body links use --accent-text (dark terracotta in light mode,
   * lighter orange in dark mode) for comfortable reading. The bright
   * --accent is reserved for identity-loud surfaces (headings, stats,
   * kanban col-heads, table-th, etc.). */
  color: var(--accent-text);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

code {
  font-family: 'Consolas', 'Menlo', monospace;
  background: var(--g3-light-grey);
  padding: 2px 6px;
  border-radius: var(--g3-r-sm);
  font-size: 0.92em;
}


/* ---------- Header ---------- */

.pf-header {
  background: var(--g3-dark);
  color: var(--g3-soft-white);
  border-bottom: 4px solid var(--accent);
}

.pf-header__inner {
  max-width: 1280px;
  margin: 0 auto;
  /* Compact header band — content area ~60px tall so the round logo
   * (height 84px) overhangs by ~12px top + ~12px bottom for visual
   * presence. allow-overflow on the wrapper isn't needed since the
   * logo's negative margins keep layout flow stable. */
  padding: var(--g3-s-2) var(--g3-s-5);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--g3-s-5);
  flex-wrap: wrap;
  min-height: 60px;
}

.pf-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--g3-s-3);
  color: var(--g3-white);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.01em;
}
.pf-brand:hover { text-decoration: none; }

.pf-brand__logo {
  display: block;
  width: 84px;
  height: 84px;
  /* PNG ships with an opaque white background; clip to a circle so the
   * white corners don't show against the dark header band. */
  border-radius: 50%;
  object-fit: cover;
  /* Negative vertical margins let the round logo overhang the header
   * band without expanding it. Header content is ~60px tall, logo is
   * 84px — so ~12px sticks out above and below. */
  margin-top: -12px;
  margin-bottom: -12px;
}

/* Legacy gradient placeholder, kept for any template that still uses it */
.pf-brand__mark {
  display: inline-block;
  width: 28px;
  height: 28px;
  border-radius: var(--g3-r-sm);
  background: linear-gradient(135deg, var(--g3-dark) 0 50%, var(--g3-blue) 50% 100%);
  border: 1px solid rgba(255,255,255,0.18);
}

.pf-nav {
  display: flex;
  gap: var(--g3-s-2);
  flex-wrap: wrap;
}

.pf-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--g3-tap-min);
  padding: 0 var(--g3-s-4);
  color: var(--g3-soft-white);
  font-weight: 500;
  font-size: 15px;
  border-radius: var(--g3-r-md);
  transition: background-color 0.12s ease;
}
.pf-nav__link:hover {
  background: rgba(255,255,255,0.08);
  text-decoration: none;
}
.pf-nav__link.is-active {
  background: var(--accent);
  color: var(--g3-white);
}

/* Nav link with an inline SVG icon (from _icons.html macros). Adds the
 * row-gap between icon and label without disturbing text-only nav links. */
.pf-nav__link--icon { gap: 6px; }
.pf-nav__more-link--icon {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Theme toggle in the nav. Icon-only button that swaps moon ↔ sun
 * based on the active [data-theme] attribute on <html>. Click handler
 * in base.html. */
.pf-nav__theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--g3-tap-min);
  height: var(--g3-tap-min);
  background: none;
  border: none;
  color: var(--g3-soft-white);
  cursor: pointer;
  border-radius: var(--g3-r-md);
  transition: background-color 0.12s ease;
  padding: 0;
}
.pf-nav__theme-toggle:hover {
  background: rgba(255, 255, 255, 0.08);
}
/* Icon visibility: light mode shows moon ("switch to dark"), dark
 * mode shows sun ("switch to light"). The opposite icon is hidden. */
.pf-theme-icon-dark { display: none; }
[data-theme="dark"] .pf-theme-icon-light { display: none; }
[data-theme="dark"] .pf-theme-icon-dark { display: inline-flex; }


/* ---------- Layout ---------- */

.pf-main {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--g3-s-6) var(--g3-s-5);
  min-height: calc(100vh - 200px);
}

.pf-section {
  margin-bottom: var(--g3-s-7);
}

.pf-h1 {
  font-size: 30px;
  font-weight: 700;
  color: var(--g3-dark);
  margin: 0 0 var(--g3-s-2);
  letter-spacing: -0.01em;
}

.pf-h2 {
  font-size: 18px;
  font-weight: 700;
  color: var(--accent);
  margin: 0 0 var(--g3-s-3);
}

.pf-h3 {
  font-size: 15px;
  font-weight: 600;
  color: var(--g3-dark);
  margin: 0 0 var(--g3-s-2);
}

.pf-lede {
  font-size: 17px;
  color: var(--g3-mid-grey);
  margin: 0 0 var(--g3-s-6);
}

.pf-eyebrow {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1.2px;
  color: var(--g3-mid-grey);
  margin-bottom: var(--g3-s-2);
}


/* ---------- Grid ---------- */

.pf-grid {
  display: grid;
  gap: var(--g3-s-5);
  margin-bottom: var(--g3-s-6);
}
.pf-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pf-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pf-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.pf-grid--5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.pf-grid--6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }

@media (max-width: 1100px) {
  .pf-grid--4, .pf-grid--5, .pf-grid--6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 800px) {
  .pf-grid--2, .pf-grid--3, .pf-grid--4, .pf-grid--5, .pf-grid--6 {
    grid-template-columns: 1fr;
  }
}


/* ---------- Dashboard header (title + action row) ---------- */

.pf-dash-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--g3-s-5);
  flex-wrap: wrap;
  margin-bottom: var(--g3-s-5);
}

.pf-dash-actions {
  display: flex;
  gap: var(--g3-s-2);
  flex-wrap: wrap;
}


/* ---------- Cards ---------- */

.pf-card {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-lg);
  padding: var(--g3-s-5);
}

.pf-card--accent {
  border-left: 4px solid var(--accent);
}

.pf-card--warning {
  border-left: 4px solid var(--g3-terracotta);
  background: #FFF4ED;
}

.pf-card--alert {
  border-left: 4px solid var(--g3-alert);
  background: #FEF2F2;
}

.pf-card__stat {
  font-size: 36px;
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
  margin: var(--g3-s-2) 0;
}


/* ---------- Callouts ---------- */

.pf-callout {
  border-radius: var(--g3-r-md);
  padding: var(--g3-s-4) var(--g3-s-5);
  margin: var(--g3-s-5) 0;
}

.pf-callout--info {
  background: var(--g3-light-grey);
  color: var(--g3-body);
}

.pf-callout--accent {
  background: var(--g3-soft-white);
  border-left: 4px solid var(--accent);
}

.pf-callout--warning {
  background: #FFF4ED;
  border-left: 4px solid var(--g3-terracotta);
}

.pf-callout--success {
  background: #E7F8F4;
  border-left: 4px solid var(--g3-success);
  color: #064E3B;
}

.pf-callout--error {
  background: #FEF2F2;
  border-left: 4px solid var(--g3-alert);
  color: #7F1D1D;
}


/* ---------- Buttons ---------- */

.pf-btn {
  /* Primary CTAs use the logo's deep green (the "Green Growth" half
   * of the brand) instead of orange. Saturated orange wears on the
   * eye when it's the always-present primary CTA on a sticky action
   * bar; deep green is calmer to dwell on, semantically reads as
   * "go / approve / save," and keeps the button on-palette. Orange
   * stays as the accent identity color elsewhere (headers, badges,
   * links, kanban col-heads, etc.). Decided 2026-05-26. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--g3-tap-primary);
  padding: 0 var(--g3-s-5);
  background: var(--brand-green-deep);
  color: var(--g3-white);
  border: none;
  border-radius: var(--g3-r-md);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  text-align: center;          /* labels with line wraps stay centered */
  transition: background-color 0.15s ease, transform 0.06s ease;
}
.pf-btn:hover { background: #1F4A18; text-decoration: none; }
.pf-btn:active { transform: translateY(1px); }

.pf-btn--secondary {
  /* Demoted to neutral chrome (was orange-outlined 2px). The 2px
   * orange outline made secondary buttons command attention nearly
   * as much as the primary CTA, which made any page with multiple
   * actions feel orange-heavy. Now: subtle grey 1px outline with
   * body-text color. Reads as "alt action" without competing for
   * the eye. Inline-styled overrides that color this red/etc. are
   * unaffected. */
  background: var(--g3-soft-white);
  color: var(--g3-dark);
  border: 1px solid var(--g3-mid-grey);
}
.pf-btn--secondary:hover { background: var(--g3-light-grey); }

.pf-btn--terracotta {
  background: var(--g3-terracotta);
}
.pf-btn--terracotta:hover { background: #a8541f; }

.pf-btn--small {
  min-height: var(--g3-tap-min);
  padding: 0 var(--g3-s-4);
  font-size: 14px;
}


/* ---------- Badges ---------- */

.pf-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 10px;
  border-radius: var(--g3-r-pill);
  font-size: 12px;
  font-weight: 600;
  color: var(--g3-white);
  background: var(--g3-mid-grey);
  text-transform: none;
  letter-spacing: 0;
  text-align: center;
}
.pf-badge--quoted { background: var(--g3-mid-grey); }
.pf-badge--pending { background: var(--g3-terracotta); }
.pf-badge--paid { background: var(--g3-success); }
.pf-badge--overdue { background: var(--g3-alert); }
.pf-badge--completed { background: var(--accent); }


/* ---------- Tables ---------- */

.pf-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  overflow: hidden;
}

.pf-table th,
.pf-table td {
  text-align: left;
  padding: var(--g3-s-3) var(--g3-s-4);
  border-bottom: 1px solid var(--g3-light-grey);
}

.pf-table th {
  background: var(--accent);
  color: var(--g3-white);
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.pf-table tr:last-child td { border-bottom: none; }
.pf-table tr:hover td { background: var(--g3-soft-white); }

/* Inputs inside table cells must shrink to fit their column instead
 * of forcing the table past its parent card. Without this, the global
 * .pf-inline-input min-width:180px keeps 7-column tables (e.g. Settings
 * Materials) wider than the viewport. */
.pf-table .pf-inline-input,
.pf-table .pf-inline-select {
  min-width: 0;
  width: 100%;
}

/* Belt-and-suspenders wrapper for tables that legitimately need more
 * horizontal real-estate than their card. Scrolls inside instead of
 * busting the card border. Apply on the parent <div>. */
.pf-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}


/* ---------- Triage screen (master-detail split) ---------- */
/* Left column = scrollable list of submissions. Right column = full
 * detail of the selected row. Clicking a left-column entry reloads
 * with ?id=submission_id so back-button + bookmarks Just Work. */

.pf-triage-split {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: var(--g3-s-4);
  align-items: start;
}

@media (max-width: 900px) {
  .pf-triage-split { grid-template-columns: 1fr; }
}

.pf-triage-list {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-lg);
  padding: var(--g3-s-2);
  max-height: 70vh;
  overflow-y: auto;
}

.pf-triage-list__items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pf-triage-list__item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--g3-s-3) var(--g3-s-3);
  border-radius: var(--g3-r-sm);
  color: var(--g3-body);
  text-decoration: none;
  border-left: 3px solid transparent;
  transition: background-color 0.1s ease, border-color 0.1s ease;
  min-height: var(--g3-tap-min);
}
.pf-triage-list__item:hover {
  background: var(--g3-light-grey);
  text-decoration: none;
}
.pf-triage-list__item.is-selected {
  background: var(--g3-white);
  border-left-color: var(--accent);
  box-shadow: 0 1px 4px rgba(15,32,48,0.06);
}

.pf-triage-list__name {
  font-weight: 600;
  font-size: 14px;
  color: var(--g3-dark);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pf-triage-list__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.pf-tier-tag {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: var(--g3-r-pill);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--g3-white);
  background: var(--g3-mid-grey);
}
.pf-tier-tag--tier1   { background: var(--accent); }
.pf-tier-tag--tier2   { background: var(--g3-terracotta); }
.pf-tier-tag--unknown { background: var(--g3-mid-grey); }
.pf-tier-tag--urgent  { background: var(--g3-alert); }
.pf-tier-tag--warn    { background: var(--g3-warning); }
.pf-tier-tag--repeat  { background: var(--g3-success); }


.pf-triage-detail {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-blue);
  border-radius: var(--g3-r-lg);
  padding: var(--g3-s-5);
  /* min-width:0 lets the 1fr grid cell actually shrink when the detail
   * panel contains long unbroken strings (e.g. Tally signed URLs in
   * upload_files). Without this, the cell expands to content width and
   * pushes the layout past the viewport. */
  min-width: 0;
  /* Break long URLs / unbroken strings inside the panel rather than
   * letting them stretch the panel horizontally. */
  overflow-wrap: anywhere;
  word-break: break-word;
}

.pf-triage-detail__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--g3-s-4);
  flex-wrap: wrap;
  margin-bottom: var(--g3-s-4);
  padding-bottom: var(--g3-s-3);
  border-bottom: 1px solid var(--g3-light-grey);
}

.pf-triage-detail__flags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-2);
  justify-content: flex-end;
  max-width: 60%;
}

.pf-triage-detail__body {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: var(--g3-s-5);
  padding: var(--g3-s-3) 0;
}

@media (max-width: 800px) {
  .pf-triage-detail__body { grid-template-columns: 1fr; }
}

.pf-triage-detail__col {
  display: flex;
  flex-direction: column;
}

.pf-triage-detail__extra {
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-white);
  border-radius: var(--g3-r-md);
  border: 1px solid var(--g3-light-grey);
  margin-top: var(--g3-s-3);
}

.pf-plain-list {
  margin: var(--g3-s-2) 0 0;
  padding: 0;
  list-style: none;
  font-size: 14px;
  color: var(--g3-body);
}
.pf-plain-list li {
  margin: 2px 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.pf-mid { color: var(--g3-mid-grey); }

.pf-dl {
  margin: var(--g3-s-2) 0 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--g3-s-1) var(--g3-s-4);
  font-size: 13px;
}
.pf-dl dt {
  color: var(--g3-mid-grey);
  font-weight: 500;
}
.pf-dl dd {
  margin: 0;
  /* Long unbroken strings (Tally signed URLs in upload_files /
   * link_inspiration, etc.) must wrap inside the dd cell rather than
   * expanding the column and pushing the layout past viewport. */
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* Action row sits at the bottom of the detail panel. Each action gets
 * its own row so the multi-input ones (Need More Info / Decline) don't
 * collide with the card's right edge on narrow master-detail layouts.
 * The form inside wraps onto a second line if width is tight. Buttons
 * stay full touch-size (no shrinking) since this may end up on a tablet
 * at the bench. */
.pf-triage-detail__actions {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-3);
  margin-top: var(--g3-s-4);
  padding-top: var(--g3-s-4);
  border-top: 1px solid var(--g3-light-grey);
  align-items: stretch;
}

.pf-triage-action {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-2);
  margin: 0;
  /* Centered horizontally for the simple single-button forms (Quote);
   * the with-input variant overrides to stretch full width. */
  justify-content: center;
}
.pf-triage-action--with-input {
  justify-content: flex-start;
}
.pf-triage-action--with-input .pf-inline-input,
.pf-triage-action--with-input .pf-inline-select {
  flex: 1 1 160px;
  min-width: 0;
}
.pf-triage-action--with-input .pf-btn {
  flex: 0 0 auto;
}

.pf-inline-form {
  display: flex;
  align-items: center;
  gap: var(--g3-s-2);
  margin: 0;
}

.pf-inline-input,
.pf-inline-select {
  min-height: var(--g3-tap-min);
  padding: 0 var(--g3-s-3);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  font-family: inherit;
  font-size: 14px;
  background: var(--g3-white);
  color: var(--g3-body);
}
.pf-inline-input { min-width: 180px; }
.pf-inline-input:focus,
.pf-inline-select:focus {
  outline: 2px solid var(--g3-blue);
  outline-offset: -1px;
}


/* ---------- Quote queue ---------- */

.pf-quote-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--g3-s-4);
  flex-wrap: wrap;
  margin-bottom: var(--g3-s-3);
}

.pf-quote-form {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-3);
  padding-top: var(--g3-s-3);
  border-top: 1px solid var(--g3-light-grey);
}

.pf-quote-form__inputs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--g3-s-3);
  align-items: end;
}
@media (max-width: 900px) {
  .pf-quote-form__inputs { grid-template-columns: repeat(2, 1fr); }
}

.pf-quote-form__inputs label {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-1);
}
.pf-quote-form__inputs .pf-inline-input { width: 100%; min-width: 0; }

.pf-checkbox-label {
  display: flex;
  flex-direction: row !important;
  align-items: center;
  gap: var(--g3-s-2);
  font-size: 14px;
  min-height: var(--g3-tap-min);
}
.pf-checkbox-label input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--g3-blue);
}

.pf-quote-form__actions {
  display: flex;
  gap: var(--g3-s-2);
  flex-wrap: wrap;
  justify-content: center;
  /* Force full-width so justify-content has horizontal space to work
   * with. Without this the div shrinks to its content (the buttons)
   * and centering becomes a no-op. */
  width: 100%;
}


/* ---------- Kanban board ---------- */

/* Break the kanban out of the standard 1280px page container so it gets
 * the full viewport width. The trick: pull the section's left/right
 * margins out to the viewport edges (with a small inset for breathing
 * room). Combined with overflow-x: auto on .pf-kanban below, this lets
 * many populated columns scroll horizontally instead of crowding. */
.pf-kanban-wrap {
  margin-left: calc(50% - 50vw + var(--g3-s-5));
  margin-right: calc(50% - 50vw + var(--g3-s-5));
}

.pf-kanban {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(260px, 1fr);
  gap: var(--g3-s-3);
  overflow-x: auto;
  padding: var(--g3-s-1);
}

/* Phones: stack columns vertically as a list per stage. The breakout
 * margins are reset here so the kanban fits the standard mobile gutter. */
@media (max-width: 800px) {
  .pf-kanban-wrap {
    margin-left: 0;
    margin-right: 0;
  }
  .pf-kanban {
    grid-auto-flow: row;
    grid-auto-columns: 1fr;
    grid-template-columns: 1fr;
  }
}

.pf-kanban__col {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  padding: var(--g3-s-3);
  min-height: 240px;
  display: flex;
  flex-direction: column;
}

.pf-kanban__col-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--g3-s-1) var(--g3-s-3);
  border-bottom: 2px solid var(--accent);
  margin-bottom: var(--g3-s-3);
}

.pf-kanban__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 22px;
  padding: 0 8px;
  background: var(--accent);
  color: var(--g3-white);
  font-size: 12px;
  font-weight: 700;
  border-radius: var(--g3-r-pill);
}

.pf-kanban__cards {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
}

.pf-kanban__card {
  display: block;
  padding: var(--g3-s-3);
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-blue);
  border-radius: var(--g3-r-sm);
  font-size: 13px;
  color: var(--g3-body);
  text-decoration: none;
  transition: transform 0.08s ease, box-shadow 0.12s ease;
}
.pf-kanban__card:hover {
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(15,32,48,0.08);
}
.pf-kanban__card--fresh { border-left-color: var(--g3-success); }
.pf-kanban__card--mid   { border-left-color: var(--g3-warning); }
.pf-kanban__card--stale { border-left-color: var(--g3-alert); }

.pf-kanban__card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--g3-s-1);
}
.pf-kanban__card-head strong {
  color: var(--g3-blue);
  font-size: 13px;
  letter-spacing: 0.2px;
}
.pf-kanban__days {
  font-size: 11px;
  color: var(--g3-mid-grey);
}

.pf-kanban__customer {
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 4px;
  color: var(--g3-dark);
}
.pf-kanban__quote {
  font-weight: 700;
  font-size: 16px;
  color: var(--g3-dark);
  margin-bottom: 4px;
}
.pf-kanban__meta {
  color: var(--g3-mid-grey);
  font-size: 12px;
  margin-bottom: 6px;
}
.pf-kanban__next {
  margin-top: var(--g3-s-2);
  padding-top: var(--g3-s-2);
  border-top: 1px dashed var(--g3-light-grey);
  color: var(--g3-body);
  font-size: 12.5px;
}
.pf-kanban__due {
  margin-top: 4px;
  color: var(--g3-terracotta);
  font-size: 12px;
  font-weight: 500;
}
.pf-kanban__empty {
  text-align: center;
  color: var(--g3-mid-grey);
  font-size: 13px;
  padding: var(--g3-s-4) 0;
}


/* ---------- Job detail ---------- */

.pf-detail-form {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-3);
  margin-top: var(--g3-s-3);
}

.pf-detail-form label {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-1);
}

.pf-notes-list {
  margin: 0;
  padding-left: var(--g3-s-5);
  font-size: 14px;
}
.pf-notes-list li {
  padding: var(--g3-s-1) 0;
  border-bottom: 1px dashed var(--g3-light-grey);
}
.pf-notes-list li:last-child { border-bottom: none; }


/* ---------- Chip input (failure-mode tags) ---------- */
.pf-chip-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-1);
  padding: var(--g3-s-2);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  background: var(--g3-white);
  min-height: var(--g3-tap-min);
}
.pf-chip-input:focus-within {
  outline: 2px solid var(--g3-blue);
  outline-offset: -1px;
}

.pf-chip-input__chips {
  display: contents;  /* let chips flow with the entry input via parent flex */
}

.pf-chip-input__entry {
  flex: 1 1 160px;
  min-width: 120px;
  border: none;
  outline: none;
  padding: 4px 6px;
  font-family: inherit;
  font-size: 14px;
  background: transparent;
  color: var(--g3-body);
}

.pf-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 4px 3px 10px;
  background: var(--g3-blue);
  color: var(--g3-white);
  border-radius: var(--g3-r-pill);
  font-size: 12px;
  font-weight: 500;
}
.pf-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 2px;
  background: rgba(255, 255, 255, 0.18);
  color: var(--g3-white);
  border: none;
  border-radius: 50%;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.pf-chip__remove:hover { background: rgba(255, 255, 255, 0.32); }

.pf-chip-suggestions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-1);
  margin-top: var(--g3-s-2);
}

.pf-chip-suggest {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  background: var(--g3-soft-white);
  color: var(--g3-blue);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-pill);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.1s ease, color 0.1s ease;
}
.pf-chip-suggest:hover {
  background: var(--g3-blue);
  color: var(--g3-white);
  border-color: var(--g3-blue);
}


/* ---------- Modal ("Jump to production?" prompt + future use) ---------- */
.pf-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--g3-s-5);
}
.pf-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 32, 48, 0.55);
  cursor: pointer;
}
.pf-modal__panel {
  position: relative;
  background: var(--g3-white);
  border-radius: var(--g3-r-lg);
  padding: var(--g3-s-5) var(--g3-s-6);
  max-width: 520px;
  width: 100%;
  box-shadow: 0 20px 60px rgba(15, 32, 48, 0.30);
  z-index: 1;
}
.pf-modal__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-3);
  margin-top: var(--g3-s-4);
}


/* ---------- Production tab ---------- */

/* Headline strip — 5 little stat tiles across the top */
.pf-prod-strip {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--g3-s-3);
}
@media (max-width: 800px) {
  .pf-prod-strip { grid-template-columns: repeat(2, 1fr); }
}

.pf-prod-stat {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-1);
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
}
.pf-prod-stat--alert {
  background: #FEF2F2;
  border-color: var(--g3-alert);
}
.pf-prod-stat--warn {
  background: #FFF4ED;
  border-color: var(--g3-terracotta);
}
.pf-prod-stat__label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--g3-mid-grey);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.pf-prod-stat__value {
  font-size: 28px;
  font-weight: 700;
  color: var(--g3-dark);
  line-height: 1;
}


/* Card grid for Active prints + Ready for pickup sections */
.pf-prod-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
  gap: var(--g3-s-4);
}

.pf-prod-card {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-blue);
  border-radius: var(--g3-r-lg);
  padding: var(--g3-s-4) var(--g3-s-5);
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
}
.pf-prod-card--active { border-left-color: var(--g3-warning); }
.pf-prod-card--ready  { border-left-color: var(--g3-success); }

.pf-prod-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--g3-s-3);
  flex-wrap: wrap;
}
.pf-prod-card__id {
  font-weight: 700;
  color: var(--g3-blue);
  font-family: 'Consolas', 'Menlo', monospace;
  margin-right: var(--g3-s-2);
}
.pf-prod-card__customer {
  font-weight: 600;
  color: var(--g3-dark);
}
.pf-prod-card__flags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-1);
}

/* Cancel-job ✕ at the top-right of each production card. Subtle by
 * default (mid-grey, no chrome); terracotta on hover so it reads as
 * a destructive shortcut. Deep-links to /jobs/{id}#cancel-job — the
 * hash auto-opens the Cancel/Decline accordion. UX-B2 follow-up. */
.pf-prod-card__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: var(--g3-s-1);
  border-radius: var(--g3-r-sm);
  color: var(--g3-mid-grey);
  font-size: 14px;
  line-height: 1;
  text-decoration: none;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.pf-prod-card__close:hover,
.pf-prod-card__close:focus {
  background: var(--g3-light-grey);
  color: var(--g3-terracotta);
  text-decoration: none;
}

/* Inline expand-panel on Active cards — holds the Change-printers
 * checkbox grid. Slides under the actions row; visually grouped with
 * the card via a top border. */
.pf-prod-card__panel {
  margin-top: var(--g3-s-3);
  padding-top: var(--g3-s-3);
  border-top: 1px dashed var(--g3-light-grey);
}
.pf-prod-card__desc {
  margin: 0;
  font-size: 14px;
  color: var(--g3-body);
}
.pf-prod-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-2);
  margin-top: var(--g3-s-2);
  padding-top: var(--g3-s-2);
  border-top: 1px solid var(--g3-light-grey);
}

/* Queue table — highlight due-soon rows */
.pf-prod-row--due-soon td {
  background: #FFF4ED !important;
}


/* ---------- Deposit-status pill (Money card) ---------- */
.pf-pill-deposit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 2px 10px;
  border-radius: var(--g3-r-pill);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--g3-white);
  letter-spacing: 0;
  text-align: center;
}
.pf-pill-deposit--yes     { background: var(--g3-success); }
.pf-pill-deposit--pending { background: var(--g3-terracotta); }


/* ---------- Stage pill (job detail H1) ---------- */
.pf-stage-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 12px;
  margin-left: var(--g3-s-2);
  border-radius: var(--g3-r-pill);
  font-size: 13px;
  font-weight: 600;
  color: var(--g3-white);
  letter-spacing: 0;
  text-align: center;
  vertical-align: middle;
  white-space: nowrap;
  background: var(--g3-mid-grey);
}
.pf-stage-pill--inbox,
.pf-stage-pill--need-info,
.pf-stage-pill--quoting    { background: var(--g3-mid-grey); }
.pf-stage-pill--quote-sent { background: var(--accent); }
.pf-stage-pill--deposit    { background: #16A34A; }
.pf-stage-pill--printing   { background: var(--g3-terracotta); }
.pf-stage-pill--ready      { background: #0E7490; }
.pf-stage-pill--completed  { background: #064E3B; }
.pf-stage-pill--declined   { background: var(--g3-alert); }


/* ---------- Seeded pill (Job Detail H1) ----------
   Marker on any active_jobs row inserted by dev/scenarios.py (seeded=1).
   Terracotta to signal 'test data, will be wiped by Reset seeded data'
   without looking like an error. Sits inline with the stage pill. */
.pf-seeded-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 3px 10px;
  margin-left: 6px;
  border-radius: var(--g3-r-pill);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--g3-white);
  background: var(--g3-terracotta);
  letter-spacing: 0.4px;
  text-transform: uppercase;
  vertical-align: middle;
}


/* ---------- Balance-outstanding gate (Ready cards on /production) ----------
   Replaces the "Mark completed" button when balance_due > 0. Mirrors the
   "Deposit short" pattern from the Queue section. Matched yellow palette
   to var(--g3-warning) so it visually flags but doesn't read as an error. */
.pf-balance-gate {
  background: #FEF3C7;
  border: 1px solid #FCD34D;
  border-radius: var(--g3-r-md);
  padding: var(--g3-s-2) var(--g3-s-3);
  color: var(--g3-warning);
  font-size: 13px;
  font-weight: 600;
}
.pf-balance-gate p {
  color: var(--g3-mid-grey);
  font-weight: 400;
}
.pf-balance-gate a {
  color: var(--g3-warning);
  font-weight: 600;
  text-decoration: underline;
}


/* ---------- "Today" brief callout (Dashboard) ----------
   Read-only embed of the most recent daily_briefs row. Visual treatment
   is restrained — it's context, not chrome — so the Action Inbox keeps
   focus. Sits in the right column of the dashboard split on desktop. */
.pf-today {
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-blue);
  border-radius: var(--g3-r-md);
  padding: var(--g3-s-3) var(--g3-s-4);
}
.pf-today__head {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: var(--g3-s-3);
  margin-bottom: var(--g3-s-2);
  flex-wrap: wrap;
}
.pf-today__when {
  font-size: 11.5px;
}
.pf-today__body {
  font-size: 14px;
  line-height: 1.55;
  white-space: pre-wrap;
  color: var(--g3-body);
  /* Cap the height so long prose doesn't stretch the row beyond the
     inbox column. Brief stays one screenful; scroll inside the card
     if it runs long. */
  max-height: 480px;
  overflow-y: auto;
}


/* ---------- Dashboard split (Action Inbox + Today brief) ----------
   Side-by-side on desktop with the inbox holding 60% (where the action
   lives) and the brief 40% (context). Collapses to a single column
   below 900px so the brief drops under the inbox on phone/tablet.
   `--solo` modifier kicks in when no brief is cached — inbox occupies
   the full width as a single column with no empty gutter. */
.pf-dash-split {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: var(--g3-s-4);
  align-items: start;
}
.pf-dash-split--solo {
  grid-template-columns: 1fr;
}
.pf-dash-split__inbox,
.pf-dash-split__brief {
  min-width: 0;
}
@media (max-width: 900px) {
  .pf-dash-split {
    grid-template-columns: 1fr;
  }
}


/* ---------- Action Inbox (Dashboard) ----------
   One ordered list of "what needs you next." Each row: icon · main
   text block · action button. Mobile collapses to single column with
   the action button below the text. */
.pf-action-inbox {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.pf-action-row {
  display: grid;
  grid-template-columns: 36px 1fr auto;
  align-items: center;
  gap: var(--g3-s-3);
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-mid-grey);
  border-radius: var(--g3-r-md);
}
/* The row-link wrapper participates in the parent grid via
 * display:contents so children (icon + main) keep their original grid
 * positions. The link itself spans them as a single click target. */
.pf-action-row__link {
  display: contents;
  color: inherit;
  text-decoration: none;
}
.pf-action-row__link--inert {
  /* Non-job rows render the same shell as a <div> for layout parity;
   * no hover / cursor / click affordance. */
  cursor: default;
}
.pf-action-row--linked {
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
.pf-action-row--linked:hover {
  background: var(--g3-soft-white);
}
.pf-action-row--linked:focus-within {
  outline: 2px solid var(--g3-blue);
  outline-offset: -2px;
}
.pf-action-row--linked .pf-action-row__link:hover .pf-action-row__headline {
  color: var(--g3-blue);
}
.pf-action-row__icon {
  font-size: 22px;
  text-align: center;
  line-height: 1;
}
.pf-action-row__main {
  min-width: 0;
}
.pf-action-row__headline {
  font-size: 14px;
  font-weight: 600;
  color: var(--g3-body);
}
.pf-action-row__subject {
  font-size: 12.5px;
  color: var(--g3-mid-grey);
  margin-top: 2px;
}
/* Per-kind accent stripe — color reads the urgency at a glance. */
.pf-action-row--sla-breach        { border-left-color: var(--g3-alert); }
.pf-action-row--quote-pending     { border-left-color: var(--g3-blue); }
.pf-action-row--ready-handoff     { border-left-color: var(--g3-success); }
.pf-action-row--deposit-cleared   { border-left-color: var(--g3-success); }
.pf-action-row--untriaged-sla     { border-left-color: var(--g3-mid-grey); }
.pf-action-row--aging-balance     { border-left-color: var(--g3-warning); }
.pf-action-row--printing-in-progress { border-left-color: var(--g3-terracotta); }
.pf-action-row--stale-job         { border-left-color: var(--g3-terracotta); }
.pf-action-row--photo-permission  { border-left-color: var(--g3-blue); }
.pf-action-row--completed-no-photo { border-left-color: var(--g3-mid-grey); }
/* BL-D: aged variants reuse the urgency hierarchy — ghost watch reads
   as warning (yellow), stalled and balance-aging-on-ready as alert
   (red). Same visual grammar as the kanban age-bucket colors. */
.pf-action-row--deposit-ghost-watch     { border-left-color: var(--g3-warning); }
.pf-action-row--deposit-stalled         { border-left-color: var(--g3-alert); }
.pf-action-row--balance-aging-on-ready  { border-left-color: var(--g3-alert); }

@media (max-width: 640px) {
  .pf-action-row {
    grid-template-columns: 36px 1fr;
    grid-template-areas:
      "icon main"
      ".    action";
    row-gap: var(--g3-s-2);
  }
  .pf-action-row__icon { grid-area: icon; }
  .pf-action-row__main { grid-area: main; }
  .pf-action-row > .pf-btn { grid-area: action; justify-self: start; }
}


/* ---------- Nav "More" dropdown ----------
   <details> + <summary> based — keyboard-accessible and works on every
   browser without JS. Panel is absolutely positioned so it overlays
   content rather than reflowing the nav. */
.pf-nav__more {
  position: relative;
  display: inline-block;
}
.pf-nav__more-toggle {
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.pf-nav__more-toggle::-webkit-details-marker { display: none; }
.pf-nav__more[open] > .pf-nav__more-toggle {
  background: var(--g3-light-grey);
  border-radius: var(--g3-r-md);
}
.pf-nav__more-panel {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 200px;
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  box-shadow: 0 6px 24px rgba(15, 32, 48, 0.08);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Above the sticky action bar (z-index 50) on /jobs/{id}. Nav
   * popovers should always sit above page-level overlays. */
  z-index: 100;
}
.pf-nav__more-link {
  display: block;
  padding: 8px 12px;
  border-radius: var(--g3-r-sm);
  font-size: 14px;
  font-weight: 500;
  color: var(--g3-body);
  text-decoration: none;
}
.pf-nav__more-link:hover,
.pf-nav__more-link:focus {
  background: var(--g3-soft-white);
  color: var(--g3-blue);
}
@media (max-width: 640px) {
  .pf-nav__more-panel {
    right: auto;
    left: 0;
  }
}


/* ---------- Contact list (Contact+meta card) ---------- */
.pf-contact-list {
  list-style: none;
  margin: var(--g3-s-2) 0;
  padding: 0;
  font-size: 13px;
}
.pf-contact-list li {
  padding: 3px 0;
  display: flex;
  gap: var(--g3-s-2);
  align-items: baseline;
}
.pf-contact-list__label {
  min-width: 70px;
  color: var(--g3-mid-grey);
  font-weight: 500;
}


/* ---------- Record-a-payment quick-fill row ---------- */
/* Label sits on its own line above the two quick-fill buttons —
 * previously the label was inline with the buttons which read awkwardly
 * (the larger buttons aligned with the small label text). */
.pf-payment-quickfill {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
  margin: 0 0 var(--g3-s-3);
}
.pf-payment-quickfill__label {
  color: var(--g3-mid-grey);
  font-size: 12px;
  font-weight: 500;
}
.pf-payment-quickfill__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-2);
}


/* ---------- Decline refund fieldset ---------- */
.pf-decline-refund {
  margin: var(--g3-s-3) 0 0;
  padding: var(--g3-s-3) var(--g3-s-4);
  border: 1px dashed var(--g3-alert);
  border-radius: var(--g3-r-sm);
  background: #FEF6F6;
}
.pf-decline-refund legend {
  padding: 0 var(--g3-s-2);
  color: var(--g3-alert);
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 1.2px;
}


/* ---------- Notes card (4th tile in the top grid on job detail) ---------- */
.pf-notes-card {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
}
.pf-notes-card__customer {
  background: #FFF8E8;
  border-left: 3px solid var(--g3-warning);
  padding: var(--g3-s-2) var(--g3-s-3);
  border-radius: var(--g3-r-sm);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--g3-body);
  /* Long unbroken strings (URLs in notes) wrap inside the card. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
.pf-notes-card__customer-label {
  display: block;
  font-weight: 600;
  font-size: 11px;
  color: var(--g3-warning);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  margin-bottom: 2px;
}
.pf-notes-card__order {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-1);
}
.pf-notes-card__order-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--g3-mid-grey);
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.pf-notes-card__list {
  margin: 0;
  padding-left: var(--g3-s-4);
  font-size: 12px;
  line-height: 1.45;
  color: var(--g3-body);
}
.pf-notes-card__list li {
  margin: 2px 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.pf-notes-card__link {
  font-size: 11.5px;
  color: var(--g3-blue);
  margin-top: var(--g3-s-1);
}


/* ---------- Detail form stacked layout ---------- */
/* Used inside narrow half-width columns (Payments + Decline side-by-
 * side). Each label/control gets its own row so the form fits. */
.pf-detail-form__stack {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-3);
}


/* ---------- Sticky primary-action bar (Job detail) ---------- */
/* State-driven action bar pinned under the H1 on /jobs/{id}. Stays at
 * the top of the viewport (position: sticky, top: 0) as the operator
 * scrolls so the next stage transition is always one tap away. The
 * pf-header isn't sticky, so top:0 docks the bar flush to the viewport
 * once the header scrolls past. Per-stage rendering rules live in
 * ui/templates/jobs/_partials/_action_bar.html. */
.pf-action-bar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-4);
  padding: var(--g3-s-3) var(--g3-s-4);
  margin-bottom: var(--g3-s-5);
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  box-shadow: 0 2px 6px rgba(15, 32, 48, 0.06);
}

.pf-action-bar__primary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-3);
  flex: 1 1 auto;
}

.pf-action-bar__form {
  display: inline-flex;
  margin: 0;
}

.pf-action-bar__cta {
  /* Primary CTA sized for touch + desktop. Borrows pf-btn--primary
   * styling with a slight bump for prominence. */
  min-height: var(--g3-tap-primary);
  font-size: 16px;
  font-weight: 600;
  padding: 0 var(--g3-s-5);
}

.pf-action-bar__cta[disabled],
.pf-action-bar__cta:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.pf-action-bar__gate-note {
  flex-basis: 100%;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--g3-warning);
}

.pf-action-bar__secondary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-3);
}

.pf-action-bar__shortcut {
  display: inline-flex;
  align-items: center;
  min-height: var(--g3-tap-min);
  padding: 0 var(--g3-s-3);
  color: var(--g3-mid-grey);
  font-size: 13.5px;
  font-weight: 500;
  border-radius: var(--g3-r-sm);
  border: 1px solid var(--g3-light-grey);
  background: var(--g3-soft-white);
  text-decoration: none;
}
.pf-action-bar__shortcut:hover,
.pf-action-bar__shortcut:focus {
  background: var(--g3-white);
  color: var(--g3-blue);
  border-color: var(--g3-blue);
  text-decoration: none;
}

/* When a shortcut is rendered as a <button> inside a POST form (the
 * demote affordance does this so it can have state-changing semantics),
 * strip the browser-default button chrome so it visually matches the
 * <a> shortcuts pixel-for-pixel. */
button.pf-action-bar__shortcut {
  font: inherit;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.pf-action-bar__demote-form {
  display: inline-flex;
  margin: 0;
}

/* Modifier for backward / cautionary shortcuts (demote). Solid
 * terracotta at rest signals "going backward — be deliberate" with
 * the same visual weight as the DELETE / Cancel / Record-delay
 * buttons elsewhere. Hover darkens (matches pf-btn--terracotta) so
 * the interaction reads as a solid CTA, not a subtle link. */
.pf-action-bar__shortcut--demote {
  color: var(--g3-white);
  background: var(--g3-terracotta);
  border-color: var(--g3-terracotta);
}
.pf-action-bar__shortcut--demote:hover,
.pf-action-bar__shortcut--demote:focus {
  color: var(--g3-white);
  background: #a8541f;
  border-color: #a8541f;
}


/* ---------- Accordion (low-frequency sections on job detail) ---------- */
/* <details>/<summary> styling so the collapse interaction matches the
 * rest of the design. Default styles for <summary> make a default
 * triangle marker; we replace it with a chevron + per-section title +
 * count badge. */
.pf-accordion {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  margin-bottom: var(--g3-s-3);
  overflow: hidden;
}
.pf-accordion[open] {
  background: var(--g3-white);
  box-shadow: 0 1px 3px rgba(15, 32, 48, 0.04);
}
.pf-accordion__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--g3-s-3);
  padding: var(--g3-s-3) var(--g3-s-4);
  cursor: pointer;
  user-select: none;
  list-style: none;
  font-size: 14.5px;
}
.pf-accordion__head::-webkit-details-marker { display: none; }
.pf-accordion__head::before {
  content: '▸';
  display: inline-block;
  color: var(--g3-mid-grey);
  font-size: 11px;
  width: 14px;
  transition: transform 0.15s ease;
}
.pf-accordion[open] > .pf-accordion__head::before {
  transform: rotate(90deg);
}
.pf-accordion__title {
  flex: 1 1 auto;
  font-weight: 600;
  color: var(--g3-dark);
}
.pf-accordion__count {
  font-size: 11.5px;
  color: var(--g3-mid-grey);
  font-weight: 500;
  letter-spacing: 0.3px;
}
.pf-accordion__body {
  padding: 0 var(--g3-s-4) var(--g3-s-4);
  border-top: 1px solid var(--g3-light-grey);
}
.pf-accordion__body > *:first-child {
  margin-top: var(--g3-s-3);
}

/* Inline variant — used inside other cards (e.g. Production Active
 * prints cards). Less chrome since the parent card already provides
 * visual containment. */
.pf-accordion--inline {
  background: transparent;
  border: 1px solid var(--g3-light-grey);
  margin-top: var(--g3-s-3);
  margin-bottom: 0;
  box-shadow: none;
}
.pf-accordion--inline[open] {
  background: var(--g3-soft-white);
}
.pf-accordion--inline .pf-accordion__head {
  padding: var(--g3-s-2) var(--g3-s-3);
  font-size: 13px;
}
.pf-accordion--inline .pf-accordion__body {
  padding: 0 var(--g3-s-3) var(--g3-s-3);
}


/* ---------- Pick-printers expand row (Production Queue) ---------- */
.pf-pick-printers-row td {
  background: var(--g3-soft-white);
  padding: var(--g3-s-4) var(--g3-s-5) !important;
  border-top: 2px solid var(--g3-blue);
}


/* ---------- Danger zone (centered delete) ---------- */
.pf-danger-zone__form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--g3-s-3);
  max-width: 540px;
  margin: 0 auto;
  text-align: center;
}
.pf-danger-zone__remember {
  font-size: 12.5px;
  color: var(--g3-mid-grey);
  align-items: flex-start;
  text-align: left;
  max-width: 480px;
}
.pf-danger-zone__note {
  font-size: 12px;
  margin: 0;
  max-width: 480px;
}

/* Bright-red variant for the DELETE THIS JOB button. Bigger + more
 * authoritative than pf-btn--terracotta so it reads as "this is
 * destructive, look twice." */
.pf-btn--danger {
  background: var(--g3-alert);
  color: var(--g3-white);
  letter-spacing: 0.6px;
  padding: 0 var(--g3-s-6);
  min-width: 280px;
}
.pf-btn--danger:hover { background: #8c1414; }


/* ---------- Risk widget (job detail) ---------- */
/* Pill + dropdowns side by side. The pill mirrors the current value
 * with a semantic color (green / amber / red / grey / muted). All
 * updates POST via fetch — no page reload — so the operator can scrub
 * through values without the page jumping. */

.pf-risk-widget {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-1);
}

.pf-risk-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-1);
  align-items: center;
}

.pf-risk-pill {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  padding: 3px 10px;
  border-radius: var(--g3-r-pill);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--g3-white);
  background: var(--g3-mid-grey);
  letter-spacing: 0;
}
.pf-risk-pill--low     { background: var(--g3-success); }
.pf-risk-pill--medium  { background: var(--g3-warning); }
.pf-risk-pill--high    { background: var(--g3-alert); }
.pf-risk-pill--unknown { background: var(--g3-mid-grey); }
.pf-risk-pill--none {
  background: transparent;
  color: var(--g3-mid-grey);
  border: 1px dashed var(--g3-light-grey);
  padding: 2px 9px;
}


/* ---------- Channel pills + Mark-as-sent buttons ---------- */
/* Sent messages get a color-coded channel pill (WhatsApp / Email / IG / FB)
 * in place of the generic "Sent" badge. The Mark-as-sent button row uses
 * the same color palette so the operator gets a consistent visual mapping
 * between "pick channel" and "pill rendered after sent". */

.pf-pill-channel {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: var(--g3-r-pill);
  font-size: 12px;
  font-weight: 600;
  color: var(--g3-white);
  letter-spacing: 0;
}
.pf-pill-channel--whatsapp { background: #25D366; }
.pf-pill-channel--email    { background: var(--g3-mid-grey); }
.pf-pill-channel--instagram { background: #E1306C; }
.pf-pill-channel--facebook  { background: #1877F2; }

.pf-mark-sent-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--g3-s-2);
  width: 100%;
  margin: 0;
}

.pf-channel-btn {
  /* Override pf-btn defaults: smaller text, channel-specific colors.
   * Keeps the 44px tap target via pf-btn--small. */
  color: var(--g3-white);
  border: none;
}
.pf-channel-btn--whatsapp { background: #25D366; }
.pf-channel-btn--whatsapp:hover { background: #1da851; }
.pf-channel-btn--email    { background: var(--g3-mid-grey); }
.pf-channel-btn--email:hover { background: #525c68; }
.pf-channel-btn--instagram { background: #E1306C; }
.pf-channel-btn--instagram:hover { background: #b3245a; }
.pf-channel-btn--facebook  { background: #1877F2; }
.pf-channel-btn--facebook:hover { background: #1259c2; }


/* ---------- Thread view ---------- */

.pf-message-textarea {
  width: 100%;
  min-height: 180px;
  padding: var(--g3-s-3);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  font-family: inherit;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--g3-body);
  background: var(--g3-white);
  resize: vertical;
}
.pf-message-textarea:focus {
  outline: 2px solid var(--g3-blue);
  outline-offset: -1px;
}

.pf-message-sent {
  margin: var(--g3-s-3) 0 0;
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-soft-white);
  border-left: 4px solid var(--g3-success);
  border-radius: var(--g3-r-sm);
  font-family: inherit;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--g3-body);
  white-space: pre-wrap;
}


/* ---------- Daily Brief ---------- */

.pf-brief-body {
  margin: var(--g3-s-2) 0 0;
  padding: var(--g3-s-4) var(--g3-s-5);
  background: var(--g3-soft-white);
  border-left: 4px solid var(--g3-blue);
  border-radius: var(--g3-r-sm);
  font-family: inherit;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--g3-body);
  white-space: pre-wrap;
}


/* ---------- Paste / drop zone (quote queue) ---------- */

.pf-paste-zone {
  margin-top: var(--g3-s-3);
  padding: var(--g3-s-5);
  background: var(--g3-soft-white);
  border: 2px dashed var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  text-align: center;
  outline: none;
  transition: border-color 0.12s ease, background-color 0.12s ease;
  cursor: text;
}
.pf-paste-zone:focus {
  border-color: var(--g3-blue);
  background: #F0F6FB;
}
.pf-paste-zone.is-dragover {
  border-color: var(--g3-blue);
  border-style: solid;
  background: #E7F1FB;
}
.pf-paste-zone__hint {
  color: var(--g3-mid-grey);
  font-size: 14px;
  line-height: 1.6;
}
.pf-paste-zone__pick {
  color: var(--g3-blue);
  cursor: pointer;
  text-decoration: underline;
}
.pf-paste-zone__preview {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
  align-items: center;
}
.pf-paste-zone__preview img {
  max-width: 100%;
  max-height: 280px;
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  background: var(--g3-white);
}


/* When the page is loaded with #ready-to-quote in the URL (after the
 * triage Quote redirect), land the section a comfortable distance from
 * the viewport top instead of pinned to the very edge. Same trick as
 * the filter-pills scroll-margin. */
#ready-to-quote {
  scroll-margin-top: var(--g3-s-4);
}


/* ---------- Tier toggle (Quote-build Ready cards) ---------- */

.pf-tier-toggle {
  display: inline-flex;
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-pill);
  padding: 2px;
  gap: 2px;
}
.pf-tier-toggle__opt {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  margin: 0;
}
.pf-tier-toggle__opt input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.pf-tier-toggle__opt span {
  display: inline-block;
  padding: 4px 12px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--g3-mid);
  border-radius: var(--g3-r-pill);
  transition: background-color 0.12s ease, color 0.12s ease;
}
.pf-tier-toggle__opt input[type="radio"]:checked + span {
  background: var(--g3-blue);
  color: var(--g3-white);
}
.pf-tier-toggle__opt:hover span {
  color: var(--g3-body);
}
.pf-tier-toggle__opt input[type="radio"]:checked:hover + span {
  color: var(--g3-white);
}


/* ---------- Filter pills (All Quotes list) ---------- */

.pf-filter-pills {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--g3-s-2);
  margin-bottom: var(--g3-s-4);
  /* When the page is loaded with #filters in the URL (after a pill
   * click), land the filter bar a comfortable distance from the
   * viewport top instead of pinned to the very edge. */
  scroll-margin-top: var(--g3-s-4);
}

.pf-pill {
  display: inline-flex;
  align-items: center;
  min-height: var(--g3-tap-min);
  padding: 0 var(--g3-s-4);
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-pill);
  color: var(--g3-body);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
.pf-pill:hover {
  text-decoration: none;
  background: var(--g3-light-grey);
}
.pf-pill.is-active {
  background: var(--g3-blue);
  border-color: var(--g3-blue);
  color: var(--g3-white);
}

/* Alert-variant pill — used for the "Stalled" filter on /jobs to read
   as a warning at rest (not just when active). Active state still wins
   visually so the operator can see which filter is applied. */
.pf-pill--alert {
  border-color: var(--g3-alert);
  color: var(--g3-alert);
}
.pf-pill--alert:hover {
  background: #FEE2E2;
}
.pf-pill--alert.is-active {
  background: var(--g3-alert);
  border-color: var(--g3-alert);
  color: var(--g3-white);
}

/* Small count badge inside a pill (e.g., "Stalled · 3"). Defaults to a
   contrast color against the pill background; flips when the pill is
   active so it stays readable on the colored backdrop. */
.pf-pill__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 6px;
  margin-left: 6px;
  border-radius: var(--g3-r-pill);
  background: var(--g3-alert);
  color: var(--g3-white);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
}
.pf-pill.is-active .pf-pill__count {
  background: var(--g3-white);
  color: var(--g3-alert);
}


/* ---------- Footer ---------- */

.pf-footer {
  padding: var(--g3-s-5);
  background: var(--g3-soft-white);
  border-top: 1px solid var(--g3-light-grey);
  text-align: center;
  font-size: 13px;
  color: var(--g3-mid-grey);
}


/* ---------- Command palette (Ctrl-K overlay) ---------- */

.pf-cmdk {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
  font-family: 'Inter', sans-serif;
}

.pf-cmdk--hidden {
  display: none;
}

.pf-cmdk__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 32, 48, 0.55);  /* G3 Dark, translucent */
  backdrop-filter: blur(2px);
}

.pf-cmdk__panel {
  position: relative;
  width: min(640px, 92vw);
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: 10px;
  box-shadow: 0 24px 64px rgba(15, 32, 48, 0.35);
  overflow: hidden;
}

.pf-cmdk__input {
  flex: none;
  width: 100%;
  padding: 16px 20px;
  border: none;
  border-bottom: 1px solid var(--g3-light-grey);
  font-size: 16px;
  font-family: inherit;
  color: var(--g3-body);
  outline: none;
  background: var(--g3-white);
}

.pf-cmdk__input::placeholder {
  color: var(--g3-mid-grey);
}

.pf-cmdk__list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
  overflow-y: auto;
  flex: 1;
}

.pf-cmdk__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 20px;
  cursor: pointer;
  user-select: none;
  font-size: 14px;
}

.pf-cmdk__item.is-active {
  background: var(--g3-soft-white);
  border-left: 3px solid var(--g3-blue);
  padding-left: 17px;
}

.pf-cmdk__label {
  color: var(--g3-body);
  font-weight: 500;
}

.pf-cmdk__label--danger {
  color: var(--g3-terracotta);
}

.pf-cmdk__hint {
  color: var(--g3-mid-grey);
  font-size: 12px;
}

.pf-cmdk__empty {
  padding: 24px 20px;
  text-align: center;
  color: var(--g3-mid-grey);
  font-size: 13px;
  list-style: none;
}

.pf-cmdk__footer {
  flex: none;
  padding: 10px 20px;
  border-top: 1px solid var(--g3-light-grey);
  background: var(--g3-soft-white);
  font-size: 11px;
  color: var(--g3-mid-grey);
}

.pf-cmdk__footer--error {
  background: #FEF2E8;        /* terracotta-tint */
  color: var(--g3-terracotta);
  font-weight: 500;
}

.pf-cmdk__footer kbd {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--g3-light-grey);
  border-radius: 4px;
  background: var(--g3-white);
  font-family: inherit;
  font-size: 10px;
  color: var(--g3-body);
  margin: 0 2px;
}


/* ---------- Audit timeline (Job detail · UX-B1b) ---------- */
/* Chronological merged feed rendered between the 4-up summary grid and
 * the Payments section. Vertical-rail visual cue helps the eye scan the
 * chronological order. Kind-specific colors on the left rail mark
 * refunds and failures so they stand out from notes / payments. */
.pf-timeline-section {
  /* Tighter than default pf-section margin; the timeline reads as a
   * panel rather than a major page section. */
  margin-bottom: var(--g3-s-6);
}

.pf-timeline {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  padding: var(--g3-s-4);
}

.pf-timeline__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--g3-s-3);
}

.pf-timeline__count {
  font-size: 12px;
}

.pf-timeline__empty {
  font-size: 13px;
  margin: var(--g3-s-2) 0 var(--g3-s-3);
}

.pf-timeline__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 2px solid var(--g3-light-grey);
}

.pf-timeline__item {
  display: grid;
  grid-template-columns: 28px 1fr;
  align-items: start;
  gap: var(--g3-s-2);
  padding: var(--g3-s-2) 0 var(--g3-s-2) var(--g3-s-3);
  margin-left: -1px;
  border-left: 3px solid transparent;
  font-size: 13px;
}

.pf-timeline__item + .pf-timeline__item {
  border-top: 1px dashed var(--g3-light-grey);
}

.pf-timeline__icon {
  font-size: 16px;
  line-height: 1.2;
}

.pf-timeline__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pf-timeline__ts {
  font-size: 11.5px;
  color: var(--g3-mid-grey);
  font-weight: 500;
  letter-spacing: 0.02em;
}

.pf-timeline__text {
  color: var(--g3-body);
  word-break: break-word;
}

/* Kind modifiers — colored left-rail accent so refunds and failures
 * pop out of the feed at a glance. */
.pf-timeline__item--refund {
  border-left-color: var(--g3-terracotta);
}
.pf-timeline__item--failure {
  border-left-color: var(--g3-warning);
}
.pf-timeline__item--payment {
  border-left-color: var(--g3-success);
}
.pf-timeline__item--message {
  border-left-color: var(--g3-info);
}
.pf-timeline__item--note {
  border-left-color: var(--g3-blue);
}

/* End-of-timeline Cancel/Decline accordion. Inherits .pf-accordion
 * base styles; adds a top margin so it sits visually attached to the
 * timeline list as the "endpoint" affordance. */
.pf-timeline__cancel {
  margin-top: var(--g3-s-4);
}

/* Payments section wrap — replaces the former pf-grid--2 side-by-side
 * (Payments + Decline) once Decline moved into the timeline area. The
 * remaining single Payments card stays full-width. */
.pf-payments-wrap {
  display: block;
}


/* ---------- Two-column job-detail layout (UX-B1c) ---------- */
/* Main column (lifecycle: summary, timeline, payments, primary
 * accordions) sits next to an aside (reference data: Risk, Files, PDFs,
 * Portfolio permission, Customer notes, Danger zone) on desktop. On
 * mobile, the columns stack in source order — main first, then aside.
 *
 * The action bar lives OUTSIDE this layout so it spans full width and
 * stays sticky-pinned to the viewport top regardless of column. */
.pf-job-layout {
  display: block;
}

@media (min-width: 1024px) {
  .pf-job-layout {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
    gap: var(--g3-s-5);
    align-items: start;
  }
}

.pf-job-main,
.pf-job-aside {
  display: block;
  min-width: 0;  /* let grid children shrink properly when content overflows */
}

/* Aside `<section>` blocks tighten their margins — the right rail is
 * a sidebar, not a series of equal-weight page sections. */
.pf-job-aside > .pf-section {
  margin-bottom: var(--g3-s-5);
}

/* Customer-notes preview block inside the Contact + meta summary card.
 * Replaces the dropped Notes card from the old 4-up grid (UX-B1c). */
.pf-contact-card__customer-notes {
  margin-top: var(--g3-s-3);
  padding-top: var(--g3-s-2);
  border-top: 1px dashed var(--g3-light-grey);
  font-size: 13px;
  color: var(--g3-body);
  line-height: 1.4;
}

.pf-contact-card__customer-notes-label {
  display: inline;
  font-weight: 600;
  color: var(--g3-mid-grey);
  margin-right: 4px;
}


/* ---------- Inline-edit (UX-B2) ---------- */
/* [data-inline-edit-form] auto-saves on input + blur via fetch. The
 * status indicator next to each form gets a data-state attribute that
 * the JS toggles among "saving" / "saved" / "error" so each state can
 * color differently. */
.pf-inline-status {
  display: inline-block;
  min-width: 0;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--g3-mid-grey);
  margin-left: var(--g3-s-2);
  transition: color 0.15s ease;
}
.pf-inline-status[data-state="saving"] { color: var(--g3-mid-grey); }
.pf-inline-status[data-state="saved"]  { color: var(--g3-success); }
.pf-inline-status[data-state="error"]  { color: var(--g3-alert); }

/* Compact input variant for inline-edit fields rendered inside the
 * Production summary card's <dd> cells. Tighter padding, fits the
 * column width without overflowing (box-sizing covers padding+border;
 * min-width:0 overrides the user-agent default on <input type="date">
 * which otherwise pushes ~180px wide on Chrome/Windows), no visible
 * border by default — reads as text until the user focuses. */
.pf-inline-input--cell {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  padding: 2px 6px;
  border: 1px solid transparent;
  border-radius: var(--g3-r-sm);
  background: transparent;
  font: inherit;
  font-size: 13.5px;
  color: var(--g3-body);
  transition: border-color 0.12s ease, background 0.12s ease;
}
.pf-inline-input--cell:hover {
  border-color: var(--g3-light-grey);
}
.pf-inline-input--cell:focus {
  outline: none;
  border-color: var(--g3-blue);
  background: var(--g3-white);
}
.pf-inline-input--cell:placeholder-shown {
  color: var(--g3-mid-grey);
}

/* Select variant — show the dropdown chevron explicitly since
 * appearance:none removed the native widget chrome on some browsers. */
select.pf-inline-input--cell {
  appearance: auto;
  -webkit-appearance: auto;
  cursor: pointer;
}

/* The "Other…" text input that reveals below the dropdown when the
 * user picks the __other__ sentinel option. Stacks under the select
 * with a small gap; inherits the cell input styling so it visually
 * matches. */
.pf-inline-input--other {
  margin-top: 4px;
}

/* Form container for inline-edit fields rendered inside the Production
 * summary card's <dd> cells. Stacks vertically (input, optional Other…
 * input, status indicator) so nothing overflows horizontally even on
 * narrow viewports. min-width:0 lets the input shrink past its
 * min-content under flex/grid constraints. */
.pf-inline-form--cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  max-width: 100%;
  margin: 0;
}


/* ============================================================
   UX-D: keyboard shortcuts on /triage
   ============================================================ */

/* Small key-hint badge next to action button labels. Subtle so it
   doesn't compete with the button text but visible enough that a new
   operator notices the shortcut exists. */
.pf-key-hint {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  font-family: var(--g3-font-mono, ui-monospace, "SF Mono", monospace);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(0, 0, 0, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 3px;
  vertical-align: baseline;
}

/* Secondary / terracotta button variants tint the hint background so
   it doesn't muddy. Borders use white-ish for contrast on colored
   buttons. */
.pf-btn--secondary .pf-key-hint {
  background: rgba(0, 0, 0, 0.08);
  border-color: rgba(0, 0, 0, 0.2);
  color: rgba(31, 41, 51, 0.7);
}

/* Keymap overlay — centered floating panel triggered by ? */
.pf-triage-keymap {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 32, 48, 0.55); /* G3 Dark @ alpha */
}

.pf-triage-keymap__panel {
  background: var(--g3-white);
  color: var(--g3-body, #1F2933);
  padding: 22px 28px;
  border-radius: 8px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
  max-width: 480px;
  width: calc(100vw - 32px);
}

.pf-table--keymap td {
  padding: 6px 12px;
  font-size: 13px;
}

.pf-table--keymap kbd {
  display: inline-block;
  padding: 1px 6px;
  font-family: var(--g3-font-mono, ui-monospace, "SF Mono", monospace);
  font-size: 12px;
  font-weight: 600;
  background: #E8EEF3; /* Light Grey */
  border: 1px solid var(--g3-light-grey, #D1D9E0);
  border-radius: 3px;
}


/* ============================================================
   UX-F: settings tab strip + bookkeeping month picker
   ============================================================ */

/* Sticky settings-page tab strip. Stays under the main nav so the
   operator can switch sections without scrolling back up. */
.pf-settings-tabs {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 8px 12px;
  margin: 0 0 18px 0;
  background: var(--g3-soft-white, #F7F5F2);
  border-bottom: 1px solid var(--g3-light-grey, #E8EEF3);
}

.pf-settings-tabs__tab {
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 500;
  color: var(--g3-mid-grey, #6B7785);
  text-decoration: none;
  border-radius: 4px;
  border: 1px solid transparent;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}

.pf-settings-tabs__tab:hover {
  background: rgba(0, 75, 150, 0.06); /* G3 Blue tint */
  color: var(--g3-blue, #2E8B96);
}

.pf-settings-tabs__tab.is-active {
  background: var(--g3-blue, #2E8B96);
  color: var(--g3-white);
  border-color: var(--g3-blue, #2E8B96);
}

/* Month picker form on /bookkeeping — inline layout with select +
   optional clear button. */
.pf-month-picker {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

/* Month-over-month compare card. Selected card uses accent; previous
   stays neutral so the eye reads which is which at a glance. */
.pf-month-compare__deltas {
  background: var(--g3-soft-white, #F7F5F2);
}

.pf-delta-pos {
  color: var(--g3-success, #0F766E);
  font-weight: 600;
}

.pf-delta-neg {
  color: var(--g3-alert, #B91C1C);
  font-weight: 600;
}

.pf-delta-flat {
  color: var(--g3-mid-grey, #6B7785);
}


/* ---------- Files drop zones (job detail Files accordion) ----------
 *
 * One drop zone per subfolder (working/, final/) inside the Files
 * accordion on /jobs/{id}. Drag-and-drop + paste + click-to-pick all
 * land here. The hover preview popup (.pf-file-preview) is appended
 * to <body> at runtime, not nested inside the row, so positioning
 * isn't constrained by the accordion's overflow.
 */

.pf-files-section {
  padding: var(--g3-s-2) 0;
}
.pf-files-section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
}

.pf-drop-zone {
  margin: 0 0 var(--g3-s-2);
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-soft-white);
  border: 2px dashed var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  text-align: center;
  outline: none;
  cursor: pointer;
  transition: border-color 0.12s ease, background-color 0.12s ease;
  user-select: none;
}
.pf-drop-zone:focus,
.pf-drop-zone.is-focused {
  border-color: var(--g3-blue);
  background: #F0F6FB;
}
.pf-drop-zone.is-dragover {
  border-color: var(--g3-terracotta);
  border-style: solid;
  background: rgba(197, 102, 48, 0.08);
}
.pf-drop-zone.is-busy {
  cursor: progress;
  opacity: 0.85;
}
.pf-drop-zone__hint {
  color: var(--g3-mid-grey);
  font-size: 13px;
  line-height: 1.5;
}
.pf-drop-zone__pick {
  color: var(--g3-blue);
  text-decoration: underline;
}

/* Inline paste-label prompt for working/ pastes. Single-line, sits
 * just above the file list while the operator types an optional tag. */
.pf-paste-label {
  display: flex;
  align-items: center;
  gap: var(--g3-s-2);
  padding: 6px 8px;
  margin-bottom: 6px;
  background: #FFF8E6;
  border-left: 3px solid var(--g3-terracotta);
  border-radius: var(--g3-r-sm);
  font-size: 13px;
}
.pf-paste-label__icon {
  color: var(--g3-terracotta);
  font-weight: 600;
}
.pf-paste-label__text {
  color: var(--g3-body);
}
.pf-paste-label__input {
  flex: 1 1 auto;
  min-width: 120px;
  padding: 4px 8px;
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  font-family: inherit;
  font-size: 13px;
}

/* File list rows. The partial uses <ul.pf-file-list><li.pf-file-row>;
 * each row is a 3-cell grid: name → meta → delete. */
.pf-file-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.pf-file-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: var(--g3-s-2);
  padding: 4px 6px;
  border-radius: var(--g3-r-sm);
  font-size: 13px;
  transition: background-color 0.08s ease;
}
.pf-file-row:hover {
  background: var(--g3-soft-white, #F4F6F8);
}
.pf-file-row__link {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.pf-file-row__link:hover .pf-file-row__name {
  text-decoration: underline;
  color: var(--g3-blue);
}
.pf-file-row__name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--g3-font-mono, monospace);
}
.pf-file-row__meta {
  color: var(--g3-mid-grey);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pf-file-row__delete {
  background: none;
  border: 1px solid transparent;
  color: var(--g3-mid-grey);
  font-size: 14px;
  line-height: 1;
  padding: 2px 6px;
  border-radius: var(--g3-r-sm);
  cursor: pointer;
  transition: color 0.1s ease, border-color 0.1s ease, background-color 0.1s ease;
}
.pf-file-row__delete:hover {
  color: var(--g3-terracotta);
  border-color: var(--g3-terracotta);
  background: rgba(197, 102, 48, 0.06);
}
.pf-file-row--empty {
  color: var(--g3-mid-grey);
  font-style: italic;
  padding: 6px 8px;
}

/* Hover preview popup. Lives at document.body so accordions / scroll
 * containers don't clip it. Positioned absolutely; the JS sets
 * top/left from getBoundingClientRect + window.scrollY. */
.pf-file-preview {
  position: absolute;
  z-index: 2000;
  padding: 6px;
  background: var(--g3-white, #FFFFFF);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  box-shadow: 0 8px 24px rgba(15, 32, 48, 0.18);
  pointer-events: none;
}
.pf-file-preview__img {
  display: block;
  max-width: 360px;
  max-height: 360px;
  border-radius: 2px;
  background: var(--g3-soft-white);
}

/* Inline upload-error rows (per file, dismissable). Lives below the
 * file list in the affected section. */
.pf-file-errors {
  margin-top: var(--g3-s-2);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pf-file-errors__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  gap: var(--g3-s-2);
  align-items: baseline;
  padding: 4px 8px;
  background: #FDECEA;
  border-left: 3px solid #B91C1C;
  border-radius: var(--g3-r-sm);
  font-size: 12.5px;
}
.pf-file-errors__icon {
  color: #B91C1C;
}
.pf-file-errors__name {
  font-family: var(--g3-font-mono, monospace);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-file-errors__detail {
  color: var(--g3-body);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-file-errors__dismiss {
  background: none;
  border: none;
  color: var(--g3-mid-grey);
  cursor: pointer;
  font-size: 13px;
  padding: 0 2px;
}
.pf-file-errors__dismiss:hover {
  color: #B91C1C;
}


/* ---------- Daily Brief — visual treatment (v25) ----------
 *
 * The brief body is JSON-encoded by Claude (see BRIEF_SYSTEM_PROMPT)
 * and parsed by core.brief_render before render. The template
 * _brief_card.html renders the parsed structure inside .pf-today.
 *
 * Visual hierarchy:
 *   - Severity-count chips at top: "1 urgent · 2 soon · ..."
 *   - Section headers for TODAY'S FOCUS / STATE / NICE-TO-HAVE
 *   - Each bullet: colored left-border + severity badge + linkified text
 *
 * Severity colors borrow the kanban age-bucket palette already in use:
 *   urgent → alert (red)
 *   soon   → warning (yellow)
 *   ready  → blue
 *   later  → mid-grey
 *
 * The legacy .pf-today + .pf-today__body styles still apply when the
 * parser falls back to raw text — that path uses
 * .pf-today__body--fallback to keep the pre-wrap behavior visible.
 */

/* Severity-count chip strip — first thing the eye lands on. */
.pf-brief-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 var(--g3-s-3);
}
.pf-brief-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  color: var(--g3-body);
}
.pf-brief-chip__dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--g3-mid-grey);
}
.pf-brief-chip--urgent { border-color: var(--g3-alert); }
.pf-brief-chip--urgent .pf-brief-chip__dot { background: var(--g3-alert); }
.pf-brief-chip--soon { border-color: var(--g3-warning); }
.pf-brief-chip--soon .pf-brief-chip__dot { background: var(--g3-warning); }
.pf-brief-chip--ready { border-color: var(--g3-blue); }
.pf-brief-chip--ready .pf-brief-chip__dot { background: var(--g3-blue); }
.pf-brief-chip--later { border-color: var(--g3-mid-grey); }
.pf-brief-chip--later .pf-brief-chip__dot { background: var(--g3-mid-grey); }

/* Section header — small, all-caps, muted. Sits above each
 * today_focus / state / nice_to_have block. */
.pf-brief-section {
  margin: 0 0 var(--g3-s-3);
}
.pf-brief-section:last-child {
  margin-bottom: 0;
}
.pf-brief-section__title {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--g3-mid-grey);
  margin: 0 0 6px;
}

/* Bullet list. Each item is a flex row: badge + text. The colored
 * left border telegraphs urgency without depending on the badge. */
.pf-brief-bullets {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pf-brief-bullet {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-mid-grey);
  border-radius: var(--g3-r-sm);
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--g3-body);
}
.pf-brief-bullet--urgent { border-left-color: var(--g3-alert); }
.pf-brief-bullet--soon   { border-left-color: var(--g3-warning); }
.pf-brief-bullet--ready  { border-left-color: var(--g3-blue); }
.pf-brief-bullet--later  { border-left-color: var(--g3-mid-grey); }

.pf-brief-bullet__text {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}

/* Severity badge — small all-caps pill at the start of each bullet.
 * Mirrors the chip-strip colors so the eye links count-to-row. */
.pf-brief-badge {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--g3-white);
  background: var(--g3-mid-grey);
  flex: 0 0 auto;
  white-space: nowrap;
}
.pf-brief-badge--urgent { background: var(--g3-alert); }
.pf-brief-badge--soon   { background: var(--g3-warning); color: var(--g3-ink, #1A2433); }
.pf-brief-badge--ready  { background: var(--g3-blue); }
.pf-brief-badge--later  { background: var(--g3-mid-grey); }

/* Auto-linked Job IDs inside bullet text + state paragraph. Inline
 * link styling — keeps the row scannable without screaming. */
.pf-brief-jobid {
  color: var(--g3-blue);
  text-decoration: none;
  font-family: var(--g3-font-mono, monospace);
  font-size: 0.95em;
  border-bottom: 1px dotted var(--g3-blue);
}
.pf-brief-jobid:hover {
  text-decoration: none;
  border-bottom-style: solid;
}

/* STATE paragraph — plain prose, slightly relaxed vs bullets. */
.pf-brief-state {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--g3-body);
}

/* Fallback path: JSON decode failed, render the body verbatim. The
 * legacy .pf-today__body already does pre-wrap; this variant just
 * tags the case so future styling can differentiate (e.g. a banner
 * suggesting Regenerate). */
.pf-today__body--fallback {
  /* No visual change for now — inherits pre-wrap from .pf-today__body. */
}


/* ---------- Printer picker (job-detail Contact+meta) ----------
 *
 * Dropdown-with-checkboxes pattern built on native <details>. The
 * trigger summary looks like a chunky button that shows current
 * selection as printer chips; clicking expands the panel with one
 * checkbox per active fleet member. JS in printer_picker.js adds
 * click-outside-to-close + a Cancel button that reverts the
 * checkbox state to the snapshot taken on panel open.
 */

.pf-printer-picker {
  /* Block-level so the trigger fills the dd cell and the absolute
   * panel below can anchor to it without breaking the surrounding
   * grid layout. position: relative establishes the containing block
   * for the panel's absolute positioning. */
  display: block;
  position: relative;
  width: 100%;
  min-width: 0;
}
.pf-printer-picker > .pf-printer-picker__trigger {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  min-height: 28px;
  font-size: 13px;
  user-select: none;
  /* min-width: 0 is essential — without it, the chip strip's children
   * push their natural content width through the flex chain and the
   * chip names overflow the trigger boundary instead of truncating. */
  min-width: 0;
  /* overflow: hidden enforces the boundary visually as a backstop in
   * case any descendant escapes the truncation chain below. */
  overflow: hidden;
  transition: border-color 0.1s ease, background-color 0.1s ease;
}
.pf-printer-picker > .pf-printer-picker__trigger::-webkit-details-marker {
  display: none;  /* Hide the native triangle; we render our own caret */
}
.pf-printer-picker > .pf-printer-picker__trigger::marker {
  /* Firefox path — newer Firefoxes ignore list-style: none on summary
   * and need ::marker explicitly cleared. */
  content: "";
}
.pf-printer-picker > .pf-printer-picker__trigger:hover {
  border-color: var(--g3-blue);
  background: var(--g3-soft-white);
}
.pf-printer-picker[open] > .pf-printer-picker__trigger {
  border-color: var(--g3-blue);
  background: var(--g3-soft-white);
}
.pf-printer-picker__empty {
  color: var(--g3-mid-grey);
  font-style: italic;
}
.pf-printer-picker__caret {
  color: var(--g3-mid-grey);
  font-size: 10px;
  margin-left: auto;
  transition: transform 0.12s ease;
}
.pf-printer-picker[open] .pf-printer-picker__caret {
  transform: rotate(180deg);
}

/* Current-selection chip strip inside the trigger. Each chip carries
 * the printer's icon + name; multi-printer assignments show two-plus
 * chips side-by-side (or stacked when the trigger is narrow). */
.pf-printer-picker__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  /* min-width: 0 + flex: 1 1 auto so the chip strip shrinks to the
   * trigger's available width instead of pushing its content past
   * the boundary. The caret sits to the right of the chip strip. */
  flex: 1 1 auto;
  min-width: 0;
}
.pf-printer-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px 1px 2px;
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--g3-body);
  /* Keep the chip name on a single line. The trigger wraps via the
   * chip strip's flex-wrap, not by breaking individual chip text. */
  white-space: nowrap;
  /* min-width: 0 + max-width: 100% lets the chip shrink to fit the
   * available chip-strip width instead of pushing past it. */
  min-width: 0;
  max-width: 100%;
}
.pf-printer-chip__name {
  /* The truncation chain: chip__name shrinks below its natural
   * content width (min-width: 0 in flex context), then overflow:
   * hidden + text-overflow: ellipsis renders the visual "...". */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pf-printer-chip__icon,
.pf-printer-chip__fallback {
  display: inline-flex;
  width: 18px;
  height: 18px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--g3-light-grey);
  color: var(--g3-body);
  font-size: 10px;
  font-weight: 700;
  flex: 0 0 auto;
  object-fit: cover;
}
.pf-printer-chip__icon {
  background: transparent;  /* image fills, no fallback bg */
}

/* Panel — floats as a popover anchored to the trigger. The Production
 * card on /jobs/{id} sits in a 2-column layout where the dd cell can
 * be ~200px wide; inline expansion (the previous attempt) made the
 * checkbox grid + button labels wrap to unreadable widths. The
 * popover model breaks out of the dd cell's width constraint so
 * labels render cleanly. It overlaps the adjacent CONTACT+META card
 * when open — acceptable per operator preference ("overlay to render
 * cleanly"). Strong shadow + white background communicate the
 * floating-above-page state.
 *
 * Sizing: min-width 320px fits the longest display label
 * ("ATLAS (Prusa Core One+ #01)") at default font size. max-width
 * keeps it from getting unwieldy on wide viewports. */
.pf-printer-picker__panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 100;
  min-width: 320px;
  max-width: 440px;
  width: max-content;
  padding: var(--g3-s-3);
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-sm);
  box-shadow: 0 8px 24px rgba(15, 32, 48, 0.18);
}
.pf-printer-picker__fieldset {
  border: 0;
  margin: 0;
  padding: 0;
}
.pf-printer-picker__grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: var(--g3-s-2);
}
.pf-printer-option {
  display: grid;
  grid-template-columns: 18px 24px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--g3-r-sm);
  cursor: pointer;
  font-size: 13px;
}
.pf-printer-option:hover {
  background: var(--g3-soft-white);
}
.pf-printer-option input[type="checkbox"] {
  margin: 0;
}
.pf-printer-option__icon,
.pf-printer-option__fallback {
  width: 24px;
  height: 24px;
  border-radius: 4px;
  background: var(--g3-light-grey);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--g3-body);
  object-fit: cover;
}
.pf-printer-option__icon {
  background: transparent;
}
.pf-printer-option__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pf-printer-option__tag {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--g3-mid-grey);
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--g3-soft-white);
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.pf-printer-picker__orphans {
  margin-top: var(--g3-s-2);
  padding: 6px 8px;
  background: #FFF8E6;
  border-left: 3px solid var(--g3-warning);
  border-radius: var(--g3-r-sm);
  font-size: 12px;
  color: var(--g3-body);
}
.pf-printer-picker__actions {
  display: flex;
  gap: var(--g3-s-2);
  margin-top: var(--g3-s-2);
  padding-top: var(--g3-s-2);
  border-top: 1px solid var(--g3-light-grey);
}


/* ---------- Fleet management page (/printers) ----------
 *
 * Two sections: Active fleet (list of pf-fleet-row, one per printer
 * with inline edit forms + icon upload + Archive button) and a
 * collapsed Archived section with Restore buttons.
 */

.pf-fleet-list {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
  margin-top: var(--g3-s-2);
}
.pf-fleet-row {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: var(--g3-s-3);
  align-items: start;
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-left: 4px solid var(--g3-blue);
  border-radius: var(--g3-r-md);
}
.pf-fleet-row--archived {
  border-left-color: var(--g3-mid-grey);
  background: var(--g3-soft-white);
  opacity: 0.85;
}
.pf-fleet-row__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
}
.pf-fleet-row__img,
.pf-fleet-row__fallback {
  width: 48px;
  height: 48px;
  border-radius: 8px;
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  object-fit: cover;
}
.pf-fleet-row__fallback {
  font-size: 22px;
  font-weight: 700;
  color: var(--g3-mid-grey);
}
.pf-fleet-row__body {
  min-width: 0;
}
.pf-fleet-row__name {
  font-size: 15px;
  font-weight: 600;
  color: var(--g3-body);
  margin-bottom: var(--g3-s-2);
}
.pf-fleet-row__tag {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--g3-mid-grey);
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--g3-soft-white);
  margin-left: 6px;
  letter-spacing: 0.04em;
}
.pf-fleet-row__edit-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-2);
  align-items: flex-end;
  margin: 0 0 var(--g3-s-2);
}
.pf-fleet-row__field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 220px;
  flex: 1 1 auto;
}
.pf-fleet-row__field--narrow {
  min-width: 80px;
  flex: 0 0 auto;
}
.pf-fleet-row__checkbox {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--g3-body);
}
.pf-fleet-row__icon-edit {
  margin-top: var(--g3-s-2);
}
.pf-fleet-row__icon-toggle {
  cursor: pointer;
  font-size: 12px;
  color: var(--g3-blue);
  user-select: none;
}
.pf-fleet-row__icon-panel {
  margin-top: var(--g3-s-2);
  padding: var(--g3-s-2);
  background: var(--g3-soft-white);
  border-radius: var(--g3-r-sm);
}
.pf-fleet-row__icon-form {
  display: flex;
  align-items: center;
  gap: var(--g3-s-2);
  flex-wrap: wrap;
}
.pf-fleet-row__actions {
  align-self: start;
}

.pf-fleet-add-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--g3-s-3);
  align-items: flex-end;
}


/* ============================================================
 * STAFF DASHBOARD MOBILE BREAKPOINTS (Phase M.5, 2026-05-23)
 * ============================================================
 * G3 dash.host is desktop-first but Shawn sometimes checks it from
 * a phone. These rules make the staff surfaces phone-usable without
 * a full redesign:
 *   - Compact header (small logo, no brand text, horizontal-scroll nav)
 *   - Tables become horizontally scrollable instead of overflowing
 *   - Detail pages get tighter padding and stack action rows
 *   - Wide grids collapse to single column (already partially handled
 *     elsewhere via the 800px breakpoints — this is the 767px polish layer)
 *
 * 767px = matches the member portal's mobile cutoff so device behavior
 * is consistent across dash/members. Phones get this; iPad-portrait
 * and up keeps the desktop layout. */

@media (max-width: 767px) {

  /* Compact header band. The 84px overhanging logo is too big and
   * the brand text wraps awkwardly on phone. */
  .pf-header__inner {
    padding: var(--g3-s-2) var(--g3-s-3);
    gap: var(--g3-s-3);
    min-height: 48px;
    flex-wrap: nowrap;
  }
  .pf-brand__logo {
    width: 40px;
    height: 40px;
    margin-top: -4px;
    margin-bottom: -4px;
  }
  .pf-brand__name {
    /* Hide the wordmark text on phone — the logo alone is the brand. */
    display: none;
  }

  /* Nav becomes a horizontal scroll strip rather than wrapping
   * onto three lines. Hide the scrollbar visually but keep momentum
   * scroll behavior. */
  .pf-nav {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 0;
    padding-right: var(--g3-s-3);
    /* Fade the right edge to hint at scroll. */
    mask-image: linear-gradient(to right, black calc(100% - 24px), transparent);
  }
  .pf-nav::-webkit-scrollbar { display: none; }
  .pf-nav__link {
    font-size: 14px;
    padding: 0 var(--g3-s-3);
    flex-shrink: 0;
  }
  /* "More ▾" details element inside the nav needs special handling —
   * its summary should also be a non-shrinking nav item. */
  .pf-nav__more {
    flex-shrink: 0;
  }

  /* Tighter main padding. */
  .pf-main {
    padding: var(--g3-s-4) var(--g3-s-3);
  }

  /* Tables: instead of forcing card-stack restructure (which would
   * require per-template work), let wide tables scroll horizontally
   * with a soft hint. Members touch-drag to see hidden columns. */
  .pf-table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
    /* The thead/tbody/tr need to keep their structure since the
     * `display: block` cascades. Force them back. */
  }
  .pf-table thead, .pf-table tbody, .pf-table tfoot {
    display: table;
    width: 100%;
    table-layout: auto;
  }
  .pf-table tr {
    display: table-row;
  }
  .pf-table th, .pf-table td {
    /* Prevent ultra-narrow columns; let content drive width. */
    white-space: normal;
  }

  /* Footer: stack the lines + center on phone. */
  .pf-footer {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    padding: var(--g3-s-4) var(--g3-s-3);
    font-size: 12px;
  }
  .pf-footer kbd {
    /* Hide the Ctrl+K hint — no keyboard shortcuts on phone. */
    display: none;
  }

  /* Dashboard tile grids: ensure they're single column at phone width.
   * The existing 800px breakpoint already does this for .pf-grid--* but
   * any per-page grids should also collapse. */
  .pf-dash-head {
    flex-direction: column;
    align-items: stretch;
    gap: var(--g3-s-3);
  }
  .pf-dash-actions {
    width: 100%;
    justify-content: flex-start;
  }

  /* Forms in cards: stack inputs full-width on phone. */
  .pf-detail-form input,
  .pf-detail-form select,
  .pf-detail-form textarea {
    width: 100%;
    max-width: 100%;
  }
}


/* ============================================================
   Detail-page skeleton (5-section template)
   ============================================================
   Every entity detail page (member, order/job, machine) inherits this
   shape. Five sections, in fixed order:

     §1 .g3-detail__hero        — identity + status pills + 1-line subtitle
     §2 .g3-detail__actionbar   — sticky CTAs with locked slot positions
     §3 .g3-detail__main        — 2-col grid of always-expanded cards
     §4 .g3-detail__secondary   — collapsed-by-default card stack
     §5 .g3-detail__admin       — quiet, always-collapsed admin block

   Button-placement rules (mechanical):
     - One primary CTA per page → §2 __primary slot
     - Regression-path partner sits immediately right of primary
     - Save-within-card buttons stay INSIDE their card
     - Destructive actions never appear in §3
     - Admin-only actions live ONLY in §5

   See ui/templates/members/detail.html for the reference implementation. */

.g3-detail {
  max-width: 1100px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-5);
}

/* §1 Hero — identity strip */
.g3-detail__hero {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-2);
}
.g3-detail__hero-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-3);
  margin: 0;
  font-size: 30px;
  font-weight: 700;
  color: var(--g3-dark);
  letter-spacing: -0.01em;
  line-height: 1.15;
}
.g3-detail__hero-subtitle {
  font-size: 13.5px;
  color: var(--g3-mid-grey);
  line-height: 1.5;
}

/* Identity pill — small inline status badge next to the H1. */
.g3-detail__pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: var(--g3-r-pill);
  font-size: 12px;
  font-weight: 600;
  background: var(--g3-light-grey);
  color: var(--g3-dark);
  white-space: nowrap;
}
.g3-detail__pill--accent  { background: var(--accent);      color: var(--g3-white); }
.g3-detail__pill--warning { background: var(--g3-warning);  color: var(--g3-white); }
.g3-detail__pill--alert   { background: var(--g3-alert);    color: var(--g3-white); }
.g3-detail__pill--success { background: var(--g3-success);  color: var(--g3-white); }

/* §2 Action bar — sticky CTAs with three explicit slots so the locked
 * button-placement rules are mechanical for the next template author. */
.g3-detail__actionbar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-4);
  padding: var(--g3-s-3) var(--g3-s-4);
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  box-shadow: 0 2px 6px rgba(15, 32, 48, 0.06);
}
.g3-detail__actionbar-slot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-3);
}
.g3-detail__actionbar-slot--primary   { flex: 1 1 auto; }
.g3-detail__actionbar-slot--more      { margin-left: auto; }

/* §3 Main — always-expanded 2-col grid. */
.g3-detail__main {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--g3-s-5);
}
@media (max-width: 900px) {
  .g3-detail__main { grid-template-columns: 1fr; }
}

/* §4 Secondary — stack of collapsed-by-default cards. */
.g3-detail__secondary {
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-3);
}

/* Detail card — the collapsed-by-default <details> pattern. Summary
 * row shows: optional icon · title · summary metric · last-updated · chevron.
 * Expanded view drops full content below the summary line. */
.g3-detail-card {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  overflow: hidden;
}
.g3-detail-card[open] {
  background: var(--g3-white);
}
.g3-detail-card__summary {
  display: grid;
  grid-template-columns: auto 1fr auto auto auto;
  align-items: center;
  gap: var(--g3-s-3);
  padding: var(--g3-s-3) var(--g3-s-4);
  cursor: pointer;
  list-style: none;
  font-size: 14px;
  user-select: none;
}
.g3-detail-card__summary::-webkit-details-marker { display: none; }
.g3-detail-card__summary::marker { display: none; }
.g3-detail-card__summary:hover {
  background: var(--g3-light-grey);
}
.g3-detail-card[open] > .g3-detail-card__summary {
  border-bottom: 1px solid var(--g3-light-grey);
}
.g3-detail-card__icon {
  color: var(--g3-mid-grey);
  display: inline-flex;
}
.g3-detail-card__title {
  font-weight: 600;
  color: var(--g3-dark);
  font-size: 15px;
}
.g3-detail-card__metric {
  font-size: 13px;
  color: var(--g3-mid-grey);
  font-variant-numeric: tabular-nums;
}
.g3-detail-card__metric--alert  { color: var(--g3-alert);   font-weight: 600; }
.g3-detail-card__metric--accent { color: var(--accent);     font-weight: 600; }
.g3-detail-card__updated {
  font-size: 12px;
  color: var(--g3-mid-grey);
  font-variant-numeric: tabular-nums;
}
.g3-detail-card__chevron {
  display: inline-flex;
  color: var(--g3-mid-grey);
  transition: transform 0.12s ease;
}
.g3-detail-card[open] .g3-detail-card__chevron {
  transform: rotate(90deg);
}
.g3-detail-card__body {
  padding: var(--g3-s-4);
}

/* Always-expanded variant — uses card chrome without a <details>
 * wrapper. For load-bearing sections like Profile, Membership, and
 * Notes (when non-empty). */
.g3-detail-card--open {
  background: var(--g3-white);
  border: 1px solid var(--g3-light-grey);
  border-radius: var(--g3-r-md);
  overflow: hidden;
}
.g3-detail-card--open > .g3-detail-card__head {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: var(--g3-s-3);
  padding: var(--g3-s-3) var(--g3-s-4);
  border-bottom: 1px solid var(--g3-light-grey);
}

/* §5 Admin — quiet collapsed accordion at the bottom, holds
 * destructive / admin-only paired actions. Distinct visual treatment
 * (uppercase summary, grey border-top accent) so the eye doesn't
 * land here. Open state flips the accent to alert-red. */
.g3-detail__admin {
  background: var(--g3-soft-white);
  border: 1px solid var(--g3-light-grey);
  border-top: 3px solid var(--g3-mid-grey);
  border-radius: var(--g3-r-md);
  overflow: hidden;
}
.g3-detail__admin[open] {
  border-top-color: var(--g3-alert);
}
.g3-detail__admin-summary {
  display: flex;
  align-items: center;
  gap: var(--g3-s-2);
  padding: var(--g3-s-3) var(--g3-s-4);
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--g3-mid-grey);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}
.g3-detail__admin-summary::-webkit-details-marker { display: none; }
.g3-detail__admin-summary::marker { display: none; }
.g3-detail__admin-summary:hover {
  color: var(--g3-dark);
}
.g3-detail__admin-body {
  padding: var(--g3-s-4);
  display: flex;
  flex-direction: column;
  gap: var(--g3-s-4);
  border-top: 1px solid var(--g3-light-grey);
}
.g3-detail__admin-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--g3-s-3);
  padding-bottom: var(--g3-s-3);
  border-bottom: 1px dashed var(--g3-light-grey);
}
.g3-detail__admin-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}
.g3-detail__admin-row-label {
  flex: 1 1 auto;
  font-size: 14px;
  color: var(--g3-body);
  font-weight: 500;
}

/* ============================================================
   #19 Machine access — icon-tile grid (member detail, 2026-05-30)
   Each tile's icon tints green when the member is cleared on that
   machine type, grey when not. A visually-hidden checkbox backs the
   tile (inline_edit.js saves on toggle). Icons are inline SVG using
   currentColor, sized by the .g3-mi wrapper from icons.machine_icon().
   ============================================================ */
.g3-mi { display: inline-flex; }
.g3-mi svg { width: 100%; height: 100%; display: block; }

.m-access__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 10px;
}
.m-access__form { margin: 0; }
/* sr-only but still focusable for keyboard a11y */
.m-access__check {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  margin: 0; pointer-events: none;
}
.m-access__tile {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 6px; border: 1.5px solid var(--g3-light-grey);
  border-radius: 8px; cursor: pointer; color: var(--g3-mid-grey);
  text-align: center; transition: color .12s, border-color .12s, background .12s;
}
.m-access__tile:hover { border-color: var(--g3-mid-grey); }
.m-access__icon { display: inline-flex; }
.m-access__name { font-size: 12px; line-height: 1.2; }
.m-access__status { min-height: 12px; font-size: 10px; }
/* GRANTED: green icon + name + highlighted tile */
.m-access__check:checked ~ .m-access__icon { color: var(--g3-success); }
.m-access__check:checked ~ .m-access__name { color: var(--g3-dark); font-weight: 600; }
.m-access__tile:has(.m-access__check:checked) {
  border-color: var(--g3-success); background: var(--brand-green-soft);
}
.m-access__check:focus-visible ~ .m-access__icon {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px;
}
/* #30 all-machine-access override ON: every tile reads as cleared (green)
   and the grid is non-interactive — the per-type ticks are moot while the
   override supersedes them at the kiosk. */
.m-access__grid--all { pointer-events: none; opacity: .9; }
.m-access__grid--all .m-access__icon { color: var(--g3-success); }
.m-access__grid--all .m-access__name { color: var(--g3-dark); font-weight: 600; }
.m-access__grid--all .m-access__tile {
  border-color: var(--g3-success); background: var(--brand-green-soft);
}
/* #30 override banner / control */
.m-access__override {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin: 0 0 12px; padding: 10px 12px;
  border-radius: 8px; font-size: 13px; line-height: 1.4;
}
.m-access__override--on {
  background: var(--brand-green-soft); border: 1px solid var(--g3-success);
  color: var(--g3-dark);
}
.m-access__override form { margin: 0; }

/* #19 glyph picker — Settings machine-type icon chooser (radio tiles).
   Selected tile uses the accent highlight (distinct from the member
   grid's green, which specifically means "access granted"). */
.m-pick { display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); gap: 8px; }
.m-pick__tile {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 8px 4px; border: 1.5px solid var(--g3-light-grey); border-radius: 6px;
  cursor: pointer; color: var(--g3-mid-grey); text-align: center;
  transition: color .12s, border-color .12s, background .12s;
}
.m-pick__tile:hover { border-color: var(--g3-mid-grey); }
.m-pick__radio { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.m-pick__icon { display: inline-flex; }
.m-pick__name { font-size: 10px; line-height: 1.15; }
.m-pick__radio:checked ~ .m-pick__icon { color: var(--accent, #E85F2C); }
.m-pick__radio:checked ~ .m-pick__name { color: var(--g3-dark); font-weight: 600; }
.m-pick__tile:has(.m-pick__radio:checked) {
  border-color: var(--accent, #E85F2C); background: var(--accent-soft, #FFF4EF);
}
.m-pick__radio:focus-visible ~ .m-pick__icon {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px;
}
