/* ════════════════════════════════════════════════════════════
   SOFTWARE ENGINEERING PORTAL  ·  styles.css
   BYUI brand · CSS custom properties · light + dark theme
   ════════════════════════════════════════════════════════════ */

/* ─── Reset / Base ─────────────────────────────────────────── */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  line-height: 1.5;
}

a {
  text-decoration: none;
  color: inherit;
}

ul, ol {
  list-style: none;
}

/* === .rich-content ===
   Re-instates browser-default styling for inline-formatted HTML inside any
   container that holds either the HtmlEditor's contenteditable surface or a
   rendered MarkupString from sanitized authoring payload (handbook module
   checklists, future rich-text descriptions, etc.). The global resets above
   strip list bullets and link styling site-wide, which is right for nav/
   chrome but wrong for user-authored body content — this class reinstates
   them only where author content lives. These rules must live un-scoped
   (here, not in a razor.css) because the <a>/<ul>/<ol>/<li> elements inside
   a contenteditable are created dynamically and don't carry Blazor's
   scoped-css attribute. */
.rich-content ul {
  list-style: disc outside;
  padding-left: 1.5rem;
  margin: 0 0 0.5rem;
}

.rich-content ol {
  list-style: decimal outside;
  padding-left: 1.5rem;
  margin: 0 0 0.5rem;
}

.rich-content li {
  margin: 0 0 0.15rem;
}

/* Nested-list markers cycle Word-style instead of repeating "1." at every
   depth: decimal → lower-alpha → lower-roman → repeat (bullets: disc →
   circle → square → repeat). Covers the editor surface and rendered
   content alike. */
.rich-content ol ol { list-style-type: lower-alpha; }
.rich-content ol ol ol { list-style-type: lower-roman; }
.rich-content ol ol ol ol { list-style-type: decimal; }
.rich-content ol ol ol ol ol { list-style-type: lower-alpha; }
.rich-content ol ol ol ol ol ol { list-style-type: lower-roman; }

.rich-content ul ul { list-style-type: circle; }
.rich-content ul ul ul { list-style-type: square; }
.rich-content ul ul ul ul { list-style-type: disc; }
.rich-content ul ul ul ul ul { list-style-type: circle; }
.rich-content ul ul ul ul ul ul { list-style-type: square; }

.rich-content a {
  color: var(--brand-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 500;
}

.rich-content a:hover {
  filter: brightness(1.15);
}

.rich-content img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  margin: 6px 0;
  /* inline-block (overriding the global `img { display: block }` reset) so a
     paragraph's text-align actually centers/right-aligns the image — block
     images ignore text-align. Applies in the editor and the reader alike, so
     the persisted `<p style="text-align:center"><img></p>` renders centered
     in both. */
  display: inline-block;
}

.rich-content p {
  margin: 0 0 8px;
}

/* Intentional blank lines: pressing Enter produces an empty <p></p>, which
   the editor shows as a visible line but normal rendering collapses to zero
   height — so a row of hard returns vanishes. Give empty paragraphs (and
   headings) a non-breaking space so each keeps its line box and the spacing
   the author intended survives.

   Hook: .rich-content is on EVERY rendered surface (handbook docs, checklist
   steps, to-do + one-on-one descriptions, …). The live editor surface also
   carries .rich-content but is contenteditable (ProseMirror sets it), so
   :not([contenteditable]) excludes it — the editor manages its own empties. */
.rich-content:not([contenteditable]) p:empty::before,
.rich-content:not([contenteditable]) h1:empty::before,
.rich-content:not([contenteditable]) h2:empty::before,
.rich-content:not([contenteditable]) h3:empty::before,
.rich-content:not([contenteditable]) h4:empty::before,
.rich-content:not([contenteditable]) h5:empty::before,
.rich-content:not([contenteditable]) h6:empty::before {
  content: "\00a0";
}

.rich-content blockquote {
  border-left: 3px solid var(--border);
  padding-left: 0.75rem;
  margin: 0 0 0.75rem;
  color: var(--text-secondary);
}

.rich-content code {
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, monospace;
  background: var(--bg-inset);
  padding: 0.05rem 0.3rem;
  border-radius: 3px;
  font-size: 0.875em;
}

/* Headings authored via the HtmlEditor's paragraph-style dropdown. The global
   reset zeroes all margins, so re-instate a sensible rhythm; explicit sizes
   keep the hierarchy readable regardless of the heading level the surrounding
   page chrome uses. */
.rich-content h1,
.rich-content h2,
.rich-content h3,
.rich-content h4,
.rich-content h5,
.rich-content h6 {
  font-weight: 700;
  line-height: 1.25;
  margin: 0.75rem 0 0.4rem;
}

.rich-content h1 { font-size: 1.6rem; }
.rich-content h2 { font-size: 1.4rem; }
.rich-content h3 { font-size: 1.2rem; }
.rich-content h4 { font-size: 1.05rem; }
.rich-content h5 { font-size: 0.95rem; }
.rich-content h6 { font-size: 0.85rem; color: var(--text-secondary); }

.rich-content pre {
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, monospace;
  background: var(--bg-inset);
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  margin: 0 0 0.75rem;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  font-size: 0.875em;
}

.rich-content hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 0.75rem 0;
}

/* Tables authored via the HtmlEditor's table tools (also covers tables
   pasted from Excel/Word once sanitized). */
.rich-content table {
  border-collapse: collapse;
  width: 100%;
  margin: 0.5rem 0 0.75rem;
}

.rich-content th,
.rich-content td {
  border: 1px solid var(--border);
  padding: 0.35rem 0.6rem;
  text-align: left;
  vertical-align: top;
}

.rich-content th {
  background: var(--bg-subsection);
  font-weight: 600;
}

.rich-content caption {
  caption-side: top;
  text-align: left;
  padding: 0.25rem 0;
  font-weight: 600;
  color: var(--text-secondary);
}

/* === Paper surfaces ===
   The HTML editor's editing surface and rendered HTML documents always use
   a white "paper" background regardless of theme, so author-chosen colors
   (often Word-pasted literal black text) stay readable without per-theme
   variants. These tokens are intentionally defined ONCE and identical in
   both themes — do not add .dark-theme overrides for them. */
:root {
  --paper-bg: #ffffff;
  --paper-text: #1f2937;
  --paper-muted: #6b7280;
  --paper-subtle: #f3f4f6;
  --paper-border: #d1d5db;
  --paper-diff-ins-bg: #dcfce7;
  --paper-diff-ins-text: #166534;
  --paper-diff-del-bg: #fee2e2;
  --paper-diff-del-text: #991b1b;
  /* Review-comment highlight on the paper surface (theme-independent). */
  --paper-comment-bg: #fff3bf;
  --paper-comment-flash: #ffe08a;
}

/* === Collaborator identity palette ===
   Six fixed hues that tie a person to "who is who" across the collaborative
   editor: remote carets (CollabHtmlEditor), presence chips (CollabPresenceBar),
   and any future collab surface. Theme-independent on purpose so a given
   collaborator keeps the same color in light and dark mode. Indexed by
   (colorIndex % 6); add c6, c7, … here if the cycle ever widens. */
:root {
  --collab-c0: #2563eb;
  --collab-c1: #d97706;
  --collab-c2: #059669;
  --collab-c3: #db2777;
  --collab-c4: #7c3aed;
  --collab-c5: #0891b2;
}

/* Inside a paper surface, the THEMED grays used by .rich-content elements
   flip to fixed paper equivalents — in dark mode the themed tokens are
   light-on-dark and would be unreadable (or invisible) on white. */
.html-editor-surface.rich-content th,
.hb-html-doc__body.rich-content th {
  background: var(--paper-subtle);
}

.html-editor-surface.rich-content th,
.html-editor-surface.rich-content td,
.hb-html-doc__body.rich-content th,
.hb-html-doc__body.rich-content td {
  border-color: var(--paper-border);
}

.html-editor-surface.rich-content blockquote,
.hb-html-doc__body.rich-content blockquote {
  color: var(--paper-muted);
  border-left-color: var(--paper-border);
}

.html-editor-surface.rich-content caption,
.hb-html-doc__body.rich-content caption,
.html-editor-surface.rich-content h6,
.hb-html-doc__body.rich-content h6 {
  color: var(--paper-muted);
}

/* H1–H4 on a paper surface default to the BYUI brand blue so authored
   documents carry the brand without every author reaching for the color
   picker. Paper is always white, so --brand-primary (no dark override) is
   safe here — same reasoning as the brand-blue links on this surface.
   H5/H6 stay neutral/muted: they read as labels, and brand blue at those
   sizes drops below AA contrast. An author-applied color still wins — it
   lands as an inline style, which beats this rule. */
.html-editor-surface.rich-content h1,
.html-editor-surface.rich-content h2,
.html-editor-surface.rich-content h3,
.html-editor-surface.rich-content h4,
.hb-html-doc__body.rich-content h1,
.hb-html-doc__body.rich-content h2,
.hb-html-doc__body.rich-content h3,
.hb-html-doc__body.rich-content h4 {
  color: var(--brand-primary);
}

.html-editor-surface.rich-content code,
.html-editor-surface.rich-content pre,
.hb-html-doc__body.rich-content code,
.hb-html-doc__body.rich-content pre {
  background: var(--paper-subtle);
  color: var(--paper-text);
}

.html-editor-surface.rich-content hr,
.hb-html-doc__body.rich-content hr {
  border-top-color: var(--paper-border);
}

/* ── HTML-document revision diff (approval view) ──
   Produced by HtmlDiffService when a previously published HTML document is
   re-submitted: additions highlighted, removals struck through. The diff
   renders on a paper surface, so the colors are paper-fixed rather than
   themed. */
.rich-content ins.diff-ins {
  background: var(--paper-diff-ins-bg);
  color: var(--paper-diff-ins-text);
  text-decoration: none;
  border-radius: 2px;
  padding: 0 1px;
}

.rich-content del.diff-del {
  background: var(--paper-diff-del-bg);
  color: var(--paper-diff-del-text);
  text-decoration: line-through;
  border-radius: 2px;
  padding: 0 1px;
}

/* Added / removed images get an outline instead of text treatment. */
.rich-content ins.diff-ins img,
.rich-content del.diff-del img {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.rich-content del.diff-del img {
  opacity: 0.5;
}

/* ── Inline HTML-document panel on the item page ──
   The card chrome and header come from the standard .collapsible-section
   pattern (matching Edit Details), so the document folds out of the way of
   the sections below it. */
.hb-html-doc {
  margin-top: 1rem;
}

/* Header row: collapse-toggle button + open-in-new-window link as flex
   siblings (the link can't live inside the header, which is a button). */
.hb-html-doc__headrow {
  display: flex;
  align-items: center;
}

.hb-html-doc__headrow .collapsible-section__header {
  flex: 1 1 auto;
  min-width: 0;
}

.hb-html-doc__open {
  flex-shrink: 0;
  margin-right: 0.75rem;
}

.hb-html-doc__diffbar {
  display: inline-flex;
  gap: 0.35rem;
  margin: 0.25rem 0 0.5rem;
}

.hb-html-doc__legend {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  color: var(--text-tertiary);
}

.hb-html-doc__body {
  /* Rendered documents are paper too — same rationale as the editor surface:
     author colors must read identically for dark- and light-theme readers. */
  background: var(--paper-bg);
  color: var(--paper-text);
  padding: 1rem 1.25rem;
  border-radius: 6px;
  border: 1px solid var(--border);
}

/* Page-layout documents (HandbookItem.FullWidthLayout = false) keep reader
   lines comfortable inside wide containers like the item page's inline panel,
   and get the same "sheet on the desk" lift as the /doc reader so the page
   mode reads consistently everywhere. Full-width docs keep the flat card. */
.hb-html-doc__body--page {
  max-width: 980px;
  margin-left: auto;
  margin-right: auto;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.10);
  padding: 2rem 2.5rem;
}

/* Landscape page documents: wider sheet, matching the editor's landscape cap. */
.hb-html-doc__body--page-landscape {
  max-width: 1240px;
}

/* Narrow screens: the sheet fills the container anyway — drop the lift so
   page mode stops costing space (mirrors the /doc reader's flatten). */
@media (max-width: 1024px) {
  .hb-html-doc__body--page {
    box-shadow: none;
    padding: 1rem 1.25rem;
  }
}

@media print {
  .hb-html-doc__body {
    border: 0;
    padding: 0;
    box-shadow: none;
  }
}

/* Image-loading placeholder for RENDERED content (mirrors the editor's).
   CSS can't detect image load, so app.js toggles .se-img-loading on each
   <img> in a rendered (non-editor) .rich-content surface until it
   loads/errors. Fixed neutral grays (not theme tokens) read on both the
   white paper doc surface and themed cards; an SVG data URI can't reference
   CSS custom properties anyway. */
.rich-content:not([contenteditable]) img.se-img-loading {
  min-width: 160px;
  min-height: 96px;
  border: 1px dashed #d1d5db;
  background-color: #f3f4f6;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23999999'%3E%3Cpath d='M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z'/%3E%3C/svg%3E"),
    linear-gradient(100deg, transparent 35%, rgba(153, 153, 153, 0.18) 50%, transparent 65%);
  background-repeat: no-repeat;
  background-position: center center, 200% 0;
  background-size: 28px 28px, 200% 100%;
  animation: se-content-img-shimmer 1.4s linear infinite;
}

@keyframes se-content-img-shimmer {
  from { background-position: center center, 200% 0; }
  to { background-position: center center, -200% 0; }
}

/* Applied to <body> while an HtmlEditor is in full-screen mode so the page
   behind the fixed editor doesn't scroll. */
.se-editor-fullscreen-lock {
  overflow: hidden;
}

button {
  cursor: pointer;
  border: none;
  background: none;
  font: inherit;
}

img, svg {
  display: block;
}

/* ─── Design Tokens ──────────────────────────────────────────
   Light theme (default)
   ──────────────────────────────────────────────────────────── */
:root {
  /* Tells the browser which palette to render its OWN chrome in — a <select>'s dropdown
     POPUP most visibly, also checkboxes/radios on platforms that skin them and scrollbars.
     That native UI lives outside the page's DOM, so no CSS custom property or class here can
     restyle it directly; color-scheme is the one hook that can. Declared explicitly on both
     themes (light here, dark below) rather than left unset, so the app's own toggle decides
     which palette the popup uses instead of the browser falling back to its own default —
     which is what left a select's dropdown list looking wrong against a dark page even after
     the closed control itself was themed correctly. */
  color-scheme: light;
  /* BYUI brand */
  --brand-primary: #006eb6;
  --brand-primary-dark: #005a94;
  --brand-black: #000000;
  --brand-white: #ffffff;
  --brand-gray: #949598;
  /* Surface */
  --bg-page: #f3f4f6;
  --bg-card: #ffffff;
  --bg-card-elevated: #ffffff;
  --bg-sidebar: #ffffff;
  --bg-subsection: #f8f9fb;
  --bg-inset: #eef1f5;
  /* Recessed form-control fill. In light theme --bg-page already reads as a shaded well
     against a white card, so this just aliases it — no visual change. Dark theme redefines
     this to --bg-inset instead of repeating --bg-page: near-black compresses lightness
     differences, so --bg-page and --bg-card read as the SAME flat tone there, and an input
     that quietly disappears into its card is the recurring bug this token exists to stop
     (see the --bg-subsection pill and --bg-card-elevated notes below for the same root cause
     hitting other surfaces). Any new recessed-surface token needs its dark-theme value
     checked for contrast on its own — a pairing that separates in light mode is not evidence
     it separates in dark mode too. */
  --bg-input: var(--bg-page);
  /* Zebra stripe for dense editable tables — a brand-blue tint, deliberately more saturated
     than the bg-* family so alternate rows read at a glance (budget line items). Pairs
     against --bg-card rows. */
  --table-stripe-bg: #dcebf8;
  --bg-header: #000000;
  --bg-hero: linear-gradient(135deg, #006eb6 0%, #0089dc 60%, #00aaff 100%);
  /* Text */
  --text-primary: #111827;
  --text-secondary: #4b5563;
  --text-tertiary: #9ca3af;
  --text-on-dark: #ffffff;
  /* Borders */
  --border-color: #e5e7eb;
  --border: var(--border-color); /* short alias — newer rules use `var(--border)` for brevity */
  --border-default: rgba(128, 128, 128, 0.15);
  --border-accent: rgba(128, 128, 128, 0.25);
  --border-radius: 10px;
  --border-radius-sm: 6px;
  --border-radius-lg: 16px;
  /* Shadows */
  --shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  --shadow-md: 0 4px 12px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04);
  --shadow-lg: 0 10px 30px rgba(0,0,0,.10), 0 4px 8px rgba(0,0,0,.06);
  /* Sidebar */
  --sidebar-width: 240px;
  --sidebar-collapsed-width: 60px;
  /* Header */
  --header-height: 58px;
  /* Badge (solid pill) */
  --badge-solid-bg: #dc2626;
  --badge-solid-text: #ffffff;
  /* Severity colors */
  --clr-critical-bg: #ef4444;
  --clr-critical-border: #fca5a5;
  --clr-critical-text: #fffbbd;
  --clr-over-capacity: #ef4444;
  --clr-warning-bg: #fffbeb;
  --clr-warning-border: #fcd34d;
  --clr-warning-text: #92400e;
  --clr-info-bg: #eff6ff;
  --clr-info-border: #93c5fd;
  --clr-info-text: #1d4ed8;
  /* Blazor error banner */
  --clr-warning-surface: #fefce8;
  /* Progress */
  --clr-progress-default: #006eb6;
  --clr-progress-warning: #f59e0b;
  --clr-progress-track: #e5e7eb;
  /* Nav active */
  --nav-active-bg: #eff6ff;
  --nav-active-text: #006eb6;
  --nav-hover-bg: #f9fafb;
  --nav-group-bg: #f0f4f8;
  --nav-group-border: #e2e8f0;
  --nav-group-header-bg: #ccdde8;
  /* Links */
  --link-color: #006eb6;
  --link-color-hover: #005a94;
  /* Transitions */
  --transition: 0.2s ease;
  --transition-slow: 0.3s ease;
  /* Form validation */
  --clr-valid: #26b050;
  --clr-invalid: #e50000;
  --clr-error-bg: #b32121;
  /* Success */
  --clr-success-bg: #dcfce7;
  --clr-success-border: #bbf7d0;
  --clr-success-text: #15803d;
  --clr-success-icon: #16a34a;
  /* Training scenario cards (brand-tinted "tonal tile") — a card wall read across a room
     in presentations, so the tint is stronger than an ordinary card surface. */
  --scenario-card-bg: #e8f1f8;
  --scenario-card-border: #b6d3e8;
  --scenario-card-title: #0b3a5c;
  --scenario-card-meta: #31719e;
  --scenario-card-ghost: rgba(0, 110, 182, 0.08);
  /* Needs Review (purple) */
  --clr-needs-review-bg: #faf5ff;
  --clr-needs-review-border: #7c3aed;
  --clr-needs-review-text: #7c3aed;
  /* Activity (pink/magenta) — celebratory accent for Team Activities and All Hands */
  --clr-activity-bg: #fce7f3;
  --clr-activity-border: #ec4899;
  --clr-activity-text: #be185d;
  /* Ignored (gray) */
  --clr-ignored-bg: #f3f4f6;
  --clr-ignored-text: #6b7280;
  --clr-ignored-border: #9ca3af;
  /* Active / green phase */
  --clr-active-bg: #f0fdf4;
  --clr-active-border: #16a34a;
  --clr-active-text: #16a34a;
  /* Header / search (always dark surface) */
  --header-divider-color: #555555;
  --search-bg: #1c1c1c;
  --search-bg-focus: #222222;
  --search-border: #333333;
  --search-placeholder: #666666;
  --search-hint-bg: #333333;
  --search-hint-color: #999999;
  --search-icon-color: #6b7280;
  /* Icon button — theme-aware. Header override sits in .app-header .icon-btn below. */
  --icon-btn-color: var(--text-secondary);
  --icon-btn-hover-bg: rgba(0, 0, 0, 0.06);
  --icon-btn-hover-color: var(--text-primary);
  /* Danger icon buttons need a solid red, not the pale "text-on-red-banner" token. */
  --icon-btn-danger-color: #dc2626;
  --icon-btn-danger-hover-bg: rgba(220, 38, 38, 0.12);
  /* Danger dropdown */
  --dropdown-danger-color: #ef4444;
  /* Notice accent stripes */
  --notice-critical-accent: #ef4444;
  --notice-warning-accent: #f59e0b;
  /* Event calendar dots */
  --event-dot-blue: #3b82f6;
  --event-dot-green: #10b981;
  --event-dot-purple: #8b5cf6;
  /* Toast */
  --toast-bg: #1f2937;
  /* Alert banner urgent (dark-red) */
  --alert-urgent-bg-from: #7f1d1d;
  --alert-urgent-bg-to: #991b1b;
  --alert-urgent-border: #fca5a5;
  --alert-urgent-color: #fef2f2;
  --alert-urgent-accent: #fca5a5;
  --alert-urgent-label-color: #7f1d1d;
  /* Reconnect modal */
  --reconnect-btn-bg: #6b9ed2;
  --reconnect-btn-bg-hover: #3b6ea2;
  --reconnect-ring-color: #0087ff;
  /* Scrum/dark-theme specific overrides */
  --scrum-textarea-border-dark: #374151;
  --scrum-btn-hover-border: #d1d5db;
  /* Ambient glow */
  --glow-primary: rgba(0, 110, 182, 0.06);
  --glow-accent: rgba(0, 170, 255, 0.04);
  --glow-card-shadow: none;
  --glow-card-bg: var(--bg-card);
  --glow-card-border: var(--border-color);
}

/* ─── Dark theme ─────────────────────────────────────────────── */
.dark-theme {
  /* See the light-theme declaration in :root for why this exists — this is the half of the
     pair that actually fixes a select's dropdown popup. */
  color-scheme: dark;
  --bg-page: #0f1117;
  --bg-card: #101319;
  --bg-card-elevated: #343841;
  --bg-sidebar: #13151f;
  --bg-subsection: #202632;
  --bg-inset: #181c25;
  /* --bg-page and --bg-card differ by only a couple RGB units here, so an input using
     --bg-page (light theme's correct, working value) would be visually indistinguishable
     from the card behind it. --bg-inset is far enough above both to actually read as a
     recessed field. */
  --bg-input: var(--bg-inset);
  --table-stripe-bg: #1a2c42;
  --bg-header: #0a0a0a;
  --bg-hero: linear-gradient(135deg, #004f83 0%, #005da0 60%, #007acc 100%);
  --text-primary: #f9fafb;
  --text-secondary: #9ca3af;
  --text-tertiary: #6b7280;
  --border-color: #2d3143;
  --shadow-sm: 0 1px 3px rgba(0,0,0,.3), 0 1px 2px rgba(0,0,0,.2);
  --shadow-md: 0 4px 12px rgba(0,0,0,.4), 0 2px 4px rgba(0,0,0,.2);
  --shadow-lg: 0 10px 30px rgba(0,0,0,.5), 0 4px 8px rgba(0,0,0,.3);
  --badge-solid-bg: #ef4444;
  --badge-solid-text: #ffffff;
  --clr-critical-bg: #ef4444;
  --clr-critical-border: #7f1d1d;
  --clr-critical-text: #ffe9e9;
  --clr-over-capacity: #f87171;
  --clr-warning-bg: #2d2108;
  --clr-warning-border: #78350f;
  --clr-warning-text: #fcd34d;
  --clr-info-bg: #172033;
  --clr-info-border: #1e3a5f;
  --clr-info-text: #93c5fd;
  --nav-active-bg: #172033;
  --nav-active-text: #60b4ff;
  --nav-hover-bg: #1e2130;
  --nav-group-bg: #1a1e2d;
  --nav-group-border: #2a2f45;
  --nav-group-header-bg: #00558f;
  /* Links */
  --link-color: #60b4ff;
  --link-color-hover: #7ec8ff;
  --clr-progress-track: #2d3143;
  /* Success (dark) */
  --clr-success-bg: rgba(21,128,61,.2);
  --clr-success-border: #16a34a;
  --clr-success-text: #4ade80;
  --clr-success-icon: #16a34a;
  --clr-warning-surface: #2d2108;
  /* Training scenario cards (dark) — deep brand-tinted tiles that lift off --bg-page,
     which the plain card surface (#101319) never did. */
  --scenario-card-bg: #0c2540;
  --scenario-card-border: #1e3a5f;
  --scenario-card-title: #d7e9f9;
  --scenario-card-meta: #8db8dc;
  --scenario-card-ghost: rgba(147, 197, 253, 0.12);
  /* Needs Review (purple, dark) */
  --clr-needs-review-bg: #2d1f3d;
  --clr-needs-review-border: #a78bfa;
  --clr-needs-review-text: #c4b5fd;
  /* Activity (pink/magenta, dark) — Team Activities and All Hands */
  --clr-activity-bg: #3b1424;
  --clr-activity-border: #f472b6;
  --clr-activity-text: #f9a8d4;
  /* Ignored (gray, dark) */
  --clr-ignored-bg: #1f2937;
  --clr-ignored-text: #9ca3af;
  --clr-ignored-border: #6b7280;
  /* Active / green phase (dark) */
  --clr-active-bg: rgba(21,128,61,.2);
  --clr-active-border: #16a34a;
  --clr-active-text: #4ade80;
  /* Alert banner urgent (dark) */
  --alert-urgent-bg-from: #450a0a;
  --alert-urgent-bg-to: #7f1d1d;
  --alert-urgent-border: #b91c1c;
  /* Ambient glow (dark) */
  --glow-primary: rgba(0, 110, 182, 0.12);
  --glow-accent: rgba(0, 170, 255, 0.08);
  --glow-card-shadow: 0 0 20px rgba(0, 110, 182, 0.06), 0 0 40px rgba(0, 110, 182, 0.03);
  --glow-card-bg: rgba(26, 29, 39, 0.7);
  --glow-card-border: rgba(45, 49, 67, 0.7);
  /* Icon button (dark theme) */
  --icon-btn-color: #cccccc;
  --icon-btn-hover-bg: rgba(255, 255, 255, 0.08);
  --icon-btn-hover-color: var(--brand-white);
  --icon-btn-danger-color: #f87171;
  --icon-btn-danger-hover-bg: rgba(248, 113, 113, 0.18);
}

/* ════════════════════════════════════════════════════════════
   LAYOUT
   ════════════════════════════════════════════════════════════ */

body {
  background: var(--bg-page);
  color: var(--text-primary);
}

/* Fixed Header */
.app-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-height);
  background: var(--bg-header);
  color: var(--text-on-dark);
  display: flex;
  align-items: center;
  padding: 0 1rem;
  gap: 1rem;
  z-index: 9995;
  box-shadow: 0 1px 4px rgba(0,0,0,.4), 0 4px 15px rgba(160, 120, 220, 0.15);
  outline: none;
}

/* Shell: sidebar + main side-by-side below header */
.layout-shell {
  display: flex;
  min-height: 100vh;
  padding-top: var(--header-height);
}

/* Extra padding when the impersonation banner is visible */
.layout-shell--impersonating {
  padding-top: calc(var(--header-height) + 38px);
  /* Fixed overlays (e.g. the one-on-one notes fly-out) read this to clear the banner too.
     Outside impersonation the overlay falls back to just --header-height. */
  --overlay-top: calc(var(--header-height) + 38px);
}

.layout-shell--impersonating .sidebar-wrap {
  top: calc(var(--header-height) + 38px);
  height: calc(100vh - var(--header-height) - 38px);
}


/* ════════════════════════════════════════════════════════════
   BLAZOR DEFAULTS
   ════════════════════════════════════════════════════════════ */

.valid.modified:not([type=checkbox]) {
  border-color: var(--clr-valid) !important;
}

.invalid {
  border-color: var(--clr-invalid) !important;
  box-shadow: 0 0 0 3px rgba(229, 0, 0, 0.1) !important;
}

.validation-message {
  color: var(--clr-invalid);
  font-size: 0.75rem;
  margin-top: 0.15rem;
}

.blazor-error-boundary {
  background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, var(--clr-error-bg);
  padding: 1rem 1rem 1rem 3.7rem;
  color: var(--brand-white);
}

  .blazor-error-boundary::after {
    content: "An error has occurred."
  }

.darker-border-checkbox.form-check-input {
  border-color: var(--brand-gray);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}

/* ════════════════════════════════════════════════════════════
   PAGE LAYOUT UTILITIES
   ════════════════════════════════════════════════════════════ */

/* Wrap any page content that needs a contained max-width */
.page-wrap {
  padding: 1rem;
  /* max-width: 900px; */
}

/*
  Sticky page header — sits just below the fixed app header.
  Use on any page or section that has a title + action button row
  that should stay visible while scrolling.

  Requires the parent to have padding: 1.5rem for the negative
  margin trick to stretch the bar edge-to-edge.
*/
.page-header {
  position: sticky;
  top: var(--header-height);
  z-index: 9990;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0;
  margin: -1.5rem -1.5rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
  background: linear-gradient(to right, transparent, var(--bg-page) 2rem, var(--bg-page) calc(100% - 2rem), transparent);
  border-image: linear-gradient(to right, transparent, var(--border-color) 2rem, var(--border-color) calc(100% - 2rem), transparent) 1;
}

.page-header__title {
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}

.page-header__count {
  font-weight: 400;
  color: var(--text-secondary);
  font-size: 1rem;
}

.page-header__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* === Tabs component (global) ===
   Used by the Tabs<TItem> component in Components/Layout/Shared/Tabs.razor.
   Page-level uses (e.g., MyTrackedItems) can keep their own scoped overrides
   for layout-specific tweaks, but the visual language lives here so every
   tab strip in the app reads the same way. */
.tabs-container {
  display: flex;
  flex-direction: column;
}

.tabs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Larger row-gap than column-gap so the per-tab border-bottom (active
     indicator) on a wrapped row doesn't jam against the tabs on the row
     below. */
  gap: 0.35rem 0.25rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1rem;
}

.tabs .tab {
  border: none;
  background: transparent;
  padding: 0.5rem 0.9rem;
  cursor: pointer;
  color: var(--text-secondary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  font-weight: 500;
  white-space: nowrap;
  transition: color 80ms ease, border-color 80ms ease;
}

.tabs .tab:hover:not(:disabled) {
  color: var(--text-primary);
}

.tabs .tab.is-active {
  color: var(--brand-primary);
  border-bottom-color: var(--brand-primary);
}

.tabs .tab:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.tabs__trailing {
  margin-left: auto;
  display: flex;
  gap: 0.25rem;
}

/* Tab-styled affordance button (e.g., "+ new step") that sits inline with
   the tab strip via Tabs.InlineAfterTabs. Reads as a tab but never gets
   the active state. */
.tabs .tab--add {
  color: var(--text-tertiary, var(--text-secondary));
  font-weight: 600;
  padding-inline: 0.6rem;
}

.tabs .tab--add:hover:not(:disabled) {
  color: var(--brand-primary);
  background: var(--surface-hover, rgba(0, 110, 182, 0.06));
}

/* Pill / circle number badge for tab labels. Consumer wraps the digit in
   <span class="tab-num">…</span> (see ModuleChecklistAuthor) — the badge
   reads "step 1" without literally needing the word, and the active tab's
   pill flips to a filled brand-primary chip for a clear selected signal. */
.tab .tab-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  height: 1.5rem;
  padding: 0 0.4rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  /* --bg-subsection reads as a distinct chip against --bg-page in both
     themes: in dark theme it's noticeably lighter than the surrounding
     surface; in light theme it's a subtle gray tint. --bg-card was nearly
     identical to --bg-page in dark mode so the pill looked flat. */
  background: var(--bg-subsection);
  color: var(--text-secondary);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1;
  transition: background-color 80ms ease, color 80ms ease, border-color 80ms ease;
}

.tab:hover:not(:disabled) .tab-num {
  border-color: var(--text-primary);
  background: var(--bg-card-elevated, var(--bg-subsection));
  color: var(--text-primary);
}

.tab.is-active .tab-num {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--brand-white);
}

/* Six-dot drag grip rendered as a radial-gradient tiled to make two columns
   of three dots. Opt-in: the consumer adds <span class="tab-handle"/> inside
   the TabTemplate, and the parent <Tabs> enables actual drag-to-reorder via
   the OnReorder callback. The handle itself is purely decorative — the whole
   tab button is the drag source. Mirrors the .hb-folder-admin__handle pattern
   on the folder admin page so the affordance reads the same across the app. */
.tab .tab-handle {
  display: inline-block;
  width: 8px;
  height: 14px;
  margin-right: 0.4rem;
  vertical-align: middle;
  background-image: radial-gradient(circle, var(--text-tertiary) 1px, transparent 1.5px);
  background-size: 4px 5px;
  background-position: 0 1px;
  background-repeat: round;
  opacity: 0.7;
  cursor: grab;
}

.tab:hover:not(:disabled) .tab-handle {
  opacity: 1;
}

.tab[draggable="true"]:active .tab-handle {
  cursor: grabbing;
}

/* Drag/drop visual feedback. is-dragging fades the source tab so the user
   can see which one is in flight; is-drop-before / is-drop-after render a
   vertical insertion bar on the leading or trailing edge of the hovered tab
   to indicate exactly where the dragged tab will land. */
.tabs .tab.is-dragging {
  opacity: 0.45;
}

/* The drop lines are absolute pseudo-elements pinned to the tab edge —
   needs an offset parent. */
.tabs .tab {
  position: relative;
}

.tabs .tab.is-drop-before::before,
.tabs .tab.is-drop-after::after {
  content: "";
  position: absolute;
  top: 0.25rem;
  bottom: 0.25rem;
  width: 3px;
  background: var(--brand-primary);
  border-radius: 2px;
  pointer-events: none;
  z-index: 2;
}

.tabs .tab.is-drop-before::before {
  left: -2px;
}

.tabs .tab.is-drop-after::after {
  right: -2px;
}

/* While a tab drag is in progress, make every tab's inner content non-
   interactive. Without this, the cursor crossing from the button into one
   of its child spans (handle, number pill, title preview) fires a dragleave
   on the button then a dragenter when it bubbles back up, which made the
   insertion-bar indicator flicker on/off as the cursor moved within a tab.
   The button itself stays a drop target — only its descendants are inert. */
.tabs.is-tab-dragging .tab > * {
  pointer-events: none;
}

/* Column wrapper that stacks the number pill on top of an optional tiny
   title preview (see ChecklistAuthor's TabTemplate). Inline-flex so the tab
   button still lays out horizontally next to the drag handle. */
.tab .tab-num-group {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  vertical-align: middle;
  gap: 2px;
}

/* Tiny one-line preview of the step title beneath the number pill. Sized
   well below normal body text so it reads as a label, not a heading. The
   nowrap + min-height keep tabs the same height even when the step has no
   title yet — the consumer renders an nbsp in that case. */
.tab .tab-title-preview {
  font-size: 0.625rem;
  line-height: 1;
  color: var(--text-tertiary, var(--text-secondary));
  white-space: nowrap;
  min-height: 0.7rem;
}

.tab.is-active .tab-title-preview {
  color: var(--brand-primary);
}

.tabs__panel {
  flex: 1;
}

/* === Checklist wizard (global) ===
   Shared by ChecklistWizard (solution checklists, shown inside a dialog) and
   ModuleChecklistWizard (handbook module instances, embedded in pages and on
   the dashboard). Lived in ChecklistWizard.razor.css before — moving here
   means both components present with the same look without each one needing
   to duplicate or import scoped styles. */
.wiz-panel {
  max-width: 560px;
  width: 100%;
}

.wiz-inline {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.wiz-header-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.wiz-toggle-view {
  font-size: 0.8125rem;
  white-space: nowrap;
}

.wiz-progress {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  /* Self-padding now that .module-card__body has zero padding — keeps the
     progress bar from butting against the card's interior edges. */
  padding: 1rem 1.25rem 0.75rem;
}

.wiz-progress__bar {
  flex: 1;
  height: 0.375rem;
  background: var(--bg-inset);
  border-radius: 999px;
  overflow: hidden;
}

.wiz-progress__fill {
  height: 100%;
  background: var(--brand-primary);
  border-radius: 999px;
  transition: width 0.3s ease;
}

.wiz-progress__text {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Step-by-step view */
.wiz-step {
  text-align: center;
  padding: 1.5rem 1.25rem;
  min-height: 160px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.wiz-step__counter {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  margin-bottom: 0.75rem;
}

.wiz-step__title {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 0.5rem;
}

.wiz-step__desc {
  font-size: 0.875rem;
  color: var(--text-secondary);
  max-width: 400px;
  margin-bottom: 0.5rem;
}

.wiz-step__html {
  font-size: 0.9375rem;
  color: var(--text-primary);
  text-align: left;
  max-width: 640px;
  margin: 0 auto 0.75rem;
  line-height: 1.5;
}

.wiz-step__meta {
  font-size: 0.75rem;
  color: var(--clr-success-text);
}

.wiz-actions {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.75rem 0;
}

/* Step dots */
.wiz-dots {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.375rem;
  padding: 0 0 0.25rem;
  max-width: 100%;
}

/* Sticky footer bar that holds the dots + Prev/Mark/Next buttons in the
   step-by-step view. Pins to the bottom of the scrollable card body so long
   step content scrolls under it while the navigation always stays reachable.
   No negative side margin now — the card body has zero padding so the bar
   already spans true edge-to-edge with just its own internal padding.
   Background matches the card body; the top border is the visual separator
   between scrolled content and the persistent actions. */
.wiz-step-footer {
  position: sticky;
  bottom: 0;
  margin-top: 1rem;
  padding: 0.5rem 1.25rem 0.75rem;
  background: var(--bg-card);
  border-top: 1px solid var(--border);
  z-index: 5;
}

.wiz-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  border: 1px solid var(--border-color);
  background: var(--bg-page);
  padding: 0;
  cursor: pointer;
  transition: all 0.15s ease;
}

.wiz-dot--active {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  transform: scale(1.3);
}

.wiz-dot--done {
  background: var(--clr-success-text);
  border-color: var(--clr-success-text);
}

/* A training module's "must finish first" requirement locks every dot after it. The dots stay
   in the row so the learner still sees how much module is left; they just read as unavailable. */
.wiz-dot:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* View All mode. No internal max-height / overflow — the parent container
   (a dialog-panel for the solution wizard, the module-card body for module
   instances) provides the scroll, so a long list scrolls in one place
   instead of creating a nested scroll inside the card. */
.wiz-all-items {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  width: 100%;
  /* Body has zero padding now so the scrollbar can sit at the card edge —
     each child paints its own breathing room. Side padding keeps the row
     cards from butting into the scrollbar; bottom padding mirrors what
     the body used to provide so the last row has breathing room. */
  padding: 0 1.25rem 1.25rem;
}

/* Each step renders as a distinct card-shaped row: filled background lifts
   it off the surrounding surface, padded for breathing room, and a hover
   border accent reinforces that the whole row is clickable. */
.wiz-item {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-subsection);
  cursor: pointer;
  transition: border-color 80ms ease, background-color 80ms ease, box-shadow 80ms ease;
  /* <label> elements default to inline-level shrink-to-fit even with
     display:flex in some browser combos; force full width + border-box so
     each row spans the dialog's content area regardless of how short the
     step title is. */
  width: 100%;
  box-sizing: border-box;
}

.wiz-item:hover {
  border-color: var(--brand-primary);
  box-shadow: 0 1px 4px color-mix(in srgb, var(--brand-primary) 15%, transparent);
}

/* Completed steps stay visually present (so the user can see what they've
   done) but dim back so the next-to-do step has natural focus. The success
   tint on the left edge gives an at-a-glance count of progress when
   scanning the list. */
.wiz-item--done {
  background: color-mix(in srgb, var(--clr-success-text, var(--brand-primary)) 8%, var(--bg-subsection));
  border-left: 3px solid var(--clr-success-text, var(--brand-primary));
  padding-left: calc(0.9rem - 2px);
}

.wiz-item--done .wiz-item__title {
  text-decoration: line-through;
  color: var(--text-secondary);
}

.wiz-item__content {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  flex: 1;
}

.wiz-item__title {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-primary);
}

.wiz-item__desc {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.wiz-item__html {
  font-size: 0.875rem;
  color: var(--text-secondary);
  line-height: 1.45;
}

.wiz-item__meta {
  font-size: 0.75rem;
  color: var(--text-tertiary);
}

/* Links */
.wiz-step__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
  margin-top: 0.5rem;
}

.wiz-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--brand-primary);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  padding: 0.25rem 0.625rem;
  border: 1px solid var(--brand-primary);
  border-radius: 6px;
  transition: background 0.15s ease;
}

.wiz-link:hover {
  background: var(--brand-primary);
  color: var(--brand-white);
  text-decoration: none;
}

.wiz-link--sm {
  font-size: 0.75rem;
  padding: 0.125rem 0.375rem;
}

.wiz-link--hero {
  background: var(--brand-primary);
  color: var(--brand-white);
  font-size: 0.9375rem;
  font-weight: 600;
  padding: 0.5rem 1.125rem;
  border-radius: 8px;
  gap: 0.375rem;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--brand-primary) 25%, transparent);
  transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.wiz-link--hero:hover {
  background: var(--brand-primary);
  filter: brightness(1.1);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--brand-primary) 35%, transparent);
  transform: translateY(-1px);
  color: var(--brand-white);
}

.wiz-item__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-top: 0.125rem;
}

/* === Quick-action buttons in dialogs ===
   Used by HandbookModuleQuickActionsDialog. Each button is a card-shaped
   choice: icon left, title + hint stacked right. Reads as a list of
   distinct paths the user can take from one screen. */
.quick-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.quick-action {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.85rem;
  row-gap: 0.1rem;
  align-items: center;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  cursor: pointer;
  text-align: left;
  color: var(--text-primary);
  transition: border-color 80ms ease, background-color 80ms ease, transform 80ms ease;
}

.quick-action:hover:not(:disabled) {
  border-color: var(--brand-primary);
  background: var(--surface-hover, rgba(0, 110, 182, 0.06));
}

.quick-action:active:not(:disabled) {
  transform: translateY(1px);
}

.quick-action:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.quick-action__icon {
  grid-row: 1 / span 2;
  color: var(--brand-primary);
}

.quick-action__title {
  font-weight: 600;
  color: var(--text-primary);
}

.quick-action__hint {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

/* === Module card ===
   Focused "dialog-card" container used by MyModuleInstance and
   ModuleChecklistView. Same visual language as a dialog panel (rounded
   surface, shadow, generous padding) but rendered inline on the page so
   the URL stays bookmarkable and the dashboard "Resume" link still works. */
.module-card {
  max-width: 640px;
  width: 100%;
  /* Cap to the remaining vertical space below the app's sticky header,
     leaving room for page-wrap padding (1rem top + 1rem bottom) and the
     back-link breadcrumb above the card (~2rem). Without this budget the
     card extends past the viewport and the page itself starts scrolling,
     producing two scrollbars (page + card body). Body scrolls; header and
     footer stay pinned. */
  max-height: calc(100vh - var(--header-height) - 6rem);
  margin: 0 auto;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Training modules render one section per screen, so the 640px cap above — sized for a
   checklist's list of steps — makes a preview look like a thumbnail rather than a slide.
   This variant fills the content column (page-wrap's padding supplies the margin) and
   lets the section content set its own readable measure inside. */
.module-card--wide {
  max-width: none;
}

.module-card__header {
  flex-shrink: 0;
  padding: 1rem 1.25rem 0.75rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-subsection);
  width: 100%;
}

.module-card__title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text-primary);
}

.module-card__subtitle {
  margin: 0.15rem 0 0;
  color: var(--text-secondary);
  font-size: 0.85rem;
}

.module-card__body {
  /* flex:1 + min-height:0 is the canonical recipe for a flex child that
     scrolls. Without min-height:0 the child expands to content height and
     the overflow-y has nothing to clip.
     Zero padding so the scrollbar pins to the card's interior right edge
     and the sticky footer spans true edge-to-edge. Each child element
     (.wiz-progress, .wiz-step, .wiz-all-items, .wiz-step-footer,
     .completion-banner, .empty-state) supplies its own internal padding
     so text content still has breathing room from the edges. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0;
  width: 100%;
}

.module-card__footer {
  flex-shrink: 0;
  padding: 0.75rem 1.25rem;
  border-top: 1px solid var(--border);
  background: var(--bg-subsection);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}

/* Highlights a nav button representing the page the user is currently on.
   Standard accessible signal — screen readers announce "current page" — and
   styled to give a clear visual cue without needing a separate class. */
.btn[aria-current="page"] {
  background: var(--brand-primary);
  color: var(--brand-white);
  border-color: var(--brand-primary);
}

.btn[aria-current="page"]:hover {
  background: var(--brand-primary-dark);
}

/* ════════════════════════════════════════════════════════════
   FORMS
   ════════════════════════════════════════════════════════════ */

/* Link utility — use on any button or element that should look like a link */
.text-link {
  color: var(--link-color);
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  cursor: pointer;
  text-align: left;
}

.text-link:hover {
  color: var(--link-color-hover);
  text-decoration: underline;
}

/* Input / select / textarea appearance */
.form-control {
  padding: 0.55rem 0.75rem;
  border: 1.5px solid var(--border-color);
  border-radius: var(--border-radius-sm);
  background: var(--bg-input);
  color: var(--text-primary);
  font: inherit;
  font-size: 0.9375rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
}

.form-control:hover {
  border-color: var(--brand-primary);
}

.form-control:focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px rgba(0, 110, 182, 0.15);
}

/* Disabled / read-only inputs need to read as "you can see this but can't
   change it" at a glance — recessed background, faded text and border, and a
   no-edit cursor. Hover/focus styles are suppressed so the field doesn't
   tease an interaction it won't respond to.
   background-COLOR, never the `background` shorthand: the shorthand also
   resets background-image/repeat/position, which on a <select> throws away
   the dropdown arrow's no-repeat and right-centre placement while a
   higher-specificity rule (.dark-theme select.form-control) still supplies
   the arrow image — tiling it across the whole field. */
.form-control:disabled,
.form-control[readonly] {
  background-color: color-mix(in srgb, var(--bg-inset, var(--bg-page)) 70%, transparent);
  color: var(--text-tertiary);
  border-color: color-mix(in srgb, var(--border-color) 55%, transparent);
  cursor: not-allowed;
}

.form-control:disabled:hover,
.form-control[readonly]:hover {
  border-color: var(--border-color);
}

select.form-control {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.65rem center;
  padding-right: 2rem;
  cursor: pointer;
}

/* Number input with custom spin buttons
   Wrap an <input type="number"> in .number-input to get styled
   up/down arrows overlaid on the right edge of the input.
   ─────────────────────────────────────────────────────────── */
.number-input {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.number-input input {
  -moz-appearance: textfield;
  padding-right: 1.75rem;
}

.number-input input::-webkit-inner-spin-button,
.number-input input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.number-input__controls {
  position: absolute;
  right: 2px;
  top: 2px;
  bottom: 2px;
  display: flex;
  flex-direction: column;
}

.number-input__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  width: 1.25rem;
  border: none;
  background: var(--bg-page);
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 0;
  font-size: 0.5rem;
  line-height: 1;
  transition: background 0.1s ease, color 0.1s ease;
}

.number-input__btn:first-child {
  border-radius: 2px 2px 0 0;
}

.number-input__btn:last-child {
  border-radius: 0 0 2px 2px;
}

.number-input__btn:hover {
  background: var(--brand-primary);
  color: var(--brand-white);
}

/* Form layout utilities */
.form-row {
  display: flex;
  gap: 1rem;
  margin-bottom: 1rem;
}

fieldset.form-field {
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-sm);
  padding: 0.75rem;
  margin: 0;
}

fieldset.form-field legend {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-secondary);
  padding: 0 0.375rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 0.3rem;
}

.form-field label,
.form-field .form-label {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.form-field--check {
  flex-direction: row;
  align-items: center;
  gap: 0.6rem;
  flex: 0 0 auto;
}

.form-field--check label {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-primary);
}

.form-field--check input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--brand-primary);
  cursor: pointer;
  flex-shrink: 0;
}

.form-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-color);
}

.form-required {
  color: var(--clr-invalid);
  font-weight: 700;
}

.form-hint {
  font-size: 0.75rem;
  margin-top: 0.25rem;
  display: block;
}

.form-hint--error {
  color: var(--clr-invalid);
}

.form-error {
  background: color-mix(in srgb, var(--clr-invalid) 10%, var(--bg-card));
  border: 1px solid var(--clr-invalid);
  color: var(--clr-invalid);
  padding: 0.625rem 0.875rem;
  border-radius: 6px;
  margin: 1rem 0;
  font-size: 0.9rem;
}

/* File-picker pattern — replaces the native <input type="file"> chrome with
   a styled label-button + a sibling span showing the selected filename. The
   underlying <InputFile> is rendered with `hidden` so clicks bubble through
   the wrapping label to trigger the OS file picker. */
.file-picker {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  flex-wrap: wrap;
}

.file-picker__button {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
}

.file-picker__name {
  font-size: 0.875rem;
  color: var(--text-primary);
  word-break: break-all;
}

/* Inline horizontal radio cluster — used wherever a small set of mutually-
   exclusive options sit under a form field label (e.g., the template Category
   picker on the admin page). Wraps on narrow widths instead of overflowing.
   Trailing margin gives the cluster breathing room from whatever form field
   sits below it. */
.radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  align-items: center;
  margin-bottom: 0.5rem;
}

.radio-option {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  user-select: none;
  font-size: 0.875rem;
}

.radio-option input[type="radio"] {
  margin: 0;
}

/* Inline edit panel that expands under a list row. Used by the document
   template admin to surface rename / re-categorize / replace-file controls
   without leaving the page. Stacked form fields with a subtle inset so the
   panel reads as belonging to the row above it. */
.hb-item-edit-panel {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  margin: 0 0 0.5rem 1.5rem;
  background: var(--bg-page);
  border-left: 3px solid var(--brand-primary);
  border-radius: 0 var(--border-radius) var(--border-radius) 0;
}

/* ════════════════════════════════════════════════════════════
   COLLAPSIBLE SECTION
   Reusable disclosure pattern: header with count badge + body.
   Use .collapsible-section.is-collapsed to hide the body.
   ════════════════════════════════════════════════════════════ */

.collapsible-section {
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-card);
  overflow: visible;
  position: relative;
}

.collapsible-section:has(.lp-dropdown__backdrop),
.collapsible-section:has(.cw-dropdown__backdrop),
.collapsible-section:has(.pri-dropdown__backdrop) {
  z-index: 9989;
}

.collapsible-section + .collapsible-section {
  margin-top: 0.75rem;
}

.collapsible-section__header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 1rem;
  background: none;
  border: none;
  width: 100%;
  cursor: pointer;
  font: inherit;
  color: var(--text-primary);
  text-align: left;
}

.collapsible-section__header:hover {
  background: var(--bg-page);
}

/* The hover background must follow the card's rounded corners — the section
   keeps overflow: visible (dropdowns escape it), so the header clips itself:
   top corners while expanded, all four when collapsed (the header IS the
   whole card then). */
.collapsible-section__header {
  border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.collapsible-section.is-collapsed .collapsible-section__header {
  border-radius: var(--border-radius);
}

.collapsible-section__title {
  font-size: 0.875rem;
  font-weight: 600;
}

.collapsible-section__count {
  min-width: 1.375rem;
  height: 1.375rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.375rem;
  text-align: center;
  white-space: nowrap;
  background: var(--bg-page);
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
}

.collapsible-section__count--emphasis {
  background: var(--badge-solid-bg);
  color: var(--badge-solid-text);
  border-color: transparent;
}

.collapsible-section__capacity {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-tertiary);
}

.collapsible-section__chevron {
  margin-left: auto;
  transition: transform 0.2s ease;
  color: var(--text-tertiary);
}

.collapsible-section.is-collapsed .collapsible-section__chevron {
  transform: rotate(-90deg);
}

.collapsible-section__body {
  border-top: 1px solid var(--border-color);
  padding: 0.5rem;
  background: color-mix(in srgb, var(--bg-card) 40%, transparent);
}

.collapsible-section.is-collapsed .collapsible-section__body {
  display: none;
}

/* ════════════════════════════════════════════════════════════
   LOADING SPINNER
   ════════════════════════════════════════════════════════════ */
.loading-spinner {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3rem 1rem;
}

#app-loading {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-page);
}

/* Reusable in-page busy overlay. Add to any page during a long-running
   operation; reuses the same spinner used by #app-loading so the visual
   language is consistent. Translucent backdrop blocks pointer events on
   the underlying UI so the user can't double-click during the wait.
   z-index matches #app-loading (9999) so the overlay sits above ALL
   layout chrome — sticky app header (9995), sticky page header (9990),
   and the sidebar (9989). At a lower z-index those would poke through. */
.busy-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(2px);
  color: var(--brand-white);
  font-weight: 500;
}

.busy-overlay .loading-spinner__svg {
  width: 3rem;
  height: 3rem;
}

.busy-overlay .loading-spinner__track {
  stroke: rgba(255, 255, 255, 0.2);
}

.busy-overlay .loading-spinner__arc {
  stroke: var(--brand-white);
}

/* Dismiss button — top-right corner of the overlay. Mainly useful for the
   dev/test toggle so the overlay can be cleared without reaching the icon
   that's now covered. Real workflow actions clear the overlay automatically
   when they complete; the dismiss is a safety valve for either case. */
.busy-overlay__close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: var(--brand-white);
  transition: background var(--transition);
}

.busy-overlay__close:hover {
  background: rgba(255, 255, 255, 0.25);
}

#app-loading .loading-spinner {
  padding: 0;
}

#app-loading .loading-spinner__svg {
  width: 3rem;
  height: 3rem;
}

.loading-spinner__svg {
  width: 2rem;
  height: 2rem;
  animation: spin 0.9s linear infinite;
}

.loading-spinner__track {
  stroke: var(--border-color);
}

.loading-spinner__arc {
  stroke: var(--brand-primary);
  stroke-linecap: round;
  animation: dash 1.4s ease-in-out infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes dash {
  0%   { stroke-dasharray: 1, 150; stroke-dashoffset: 0; }
  50%  { stroke-dasharray: 90, 150; stroke-dashoffset: -35; }
  100% { stroke-dasharray: 90, 150; stroke-dashoffset: -124; }
}

/* ════════════════════════════════════════════════════════════
   DASHBOARD LAYOUT (two-column shell + labelled card sections)
   ════════════════════════════════════════════════════════════ */

/* Two-column shell: every card section on the left, a standing rail of Upcoming + To-Dos on
   the right. The rail runs beside the whole page — nothing is pushed below it, so there's no
   band of whitespace where a short column ends. align-items: start keeps the two columns
   independent so neither stretches to match the other. */
.dash-shell {
  display: grid;
  grid-template-columns: 3fr 1fr;
  gap: 1rem;
  margin-top: 1rem;
  align-items: start;
}

.dash-shell__main,
.dash-shell__side {
  min-width: 0;
}

/* The rail is bounded by the viewport, not by the main column, and sticks below the two fixed
   headers as the page scrolls. That's what keeps the --fill card's footer actions on screen:
   sized to the main column instead, the card grew past 1300px and its buttons sat ~800px below
   the fold. min-height means a very short window overflows rather than crushing the cards. */
.dash-shell__side {
  /* 3.75rem clears the sticky .page-header (47px) plus the gap above the shell. */
  --dash-rail-top: calc(var(--header-height) + 3.75rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  position: sticky;
  top: var(--dash-rail-top);
  max-height: calc(100dvh - var(--dash-rail-top) - 1rem);
  min-height: 22rem;
}

/* The rail's last card absorbs whatever height the cards above it didn't use and scrolls
   internally, so the rail bottoms out at the fold with its actions reachable. min-height: 0 is
   required — a flex item otherwise refuses to shrink below its content. */
.dash-shell__side > .dash-card--fill {
  flex: 1 1 auto;
  min-height: 0;
}

/* The "right now" pair. Capacity gets two thirds because the Gantt is the widest content on
   the page. Unlike the section panels this row deliberately keeps the default
   `align-items: stretch`, so both cards take the height of the taller one and the pair reads
   as a single band across the top. Each card's footer stays pinned to its own bottom via
   .dash-card__footer's margin-top: auto. */
.dash-top-row {
  display: grid;
  grid-template-columns: 1.2fr 1.8fr;
  gap: 1rem;
}

/* A developer exempt from check-ins has no check-in card: Capacity takes the whole band rather
   than sitting in the narrow column beside an empty one. */
.dash-top-row--solo {
  grid-template-columns: 1fr;
}

.dash-top-row > .dash-card {
  min-width: 0;
}

/* ── Labelled sections ("Needs your action", "Good to know", …) ── */
.dash-section {
  margin-top: 1.5rem;
}

/* Deliberately not styled like .dash-card__title (1rem semibold --text-primary) — the eyebrow
   treatment keeps the group label from competing with the card titles inside the group. */
.dash-section__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.625rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

/* Glowing status orb before the label: a small filled dot with two stacked halos — a tight
   ring plus a soft bloom. Purely decorative (empty ::before content), so it adds color without
   becoming the sole carrier of meaning — the heading text already says what the group is.
   Each section modifier supplies --orb-color. */
.dash-section__title::before {
  content: "";
  flex-shrink: 0;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--orb-color, var(--text-tertiary));
  box-shadow:
    0 0 0 3px color-mix(in srgb, var(--orb-color, var(--text-tertiary)) 20%, transparent),
    0 0 8px 1px color-mix(in srgb, var(--orb-color, var(--text-tertiary)) 65%, transparent);
}

/* --clr-critical-bg, not --clr-critical-text: the critical pair is inverted relative to the
   others — -bg is the saturated red and -text is the pale foreground that sits on top of it,
   whereas --clr-success-text/--clr-info-text are themselves the saturated accents. */
/* Collapse toggle. The <h2> stays the heading (so aria-labelledby keeps working and the orb
   still renders on it) and wraps a button that carries aria-expanded / aria-controls. Header
   mechanics are borrowed from .collapsible-section, but not its card chrome — that would nest a
   card around the section and undo the eyebrow treatment. */
.dash-section__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.dash-section__toggle:hover {
  color: var(--text-primary);
}

.dash-section__chevron {
  transition: transform 0.15s ease;
}

.dash-section.is-collapsed .dash-section__chevron {
  transform: rotate(-90deg);
}

.dash-section.is-collapsed .dash-section__panel {
  display: none;
}

.dash-section--action {
  --orb-color: var(--clr-critical-bg);
}

.dash-section--good {
  --orb-color: var(--clr-success-text);
}

.dash-section--team {
  --orb-color: var(--clr-info-text);
}

/* Recessed surface so the elevated cards inside read as one group.
   Multi-column, not grid, and that is the load-bearing choice: grid rows are as tall as their
   tallest card, so a short card left a dead gap beneath it until the next row (342px in the
   "Good to know" section). Columns pack cards tightly instead, for any mix of heights.
   Native grid masonry would keep source order AND pack tightly, but Chrome 148 supports
   neither `grid-template-rows: masonry` nor `item-pack` — revisit this when it ships.
   The cost: cards read down column 1 then down column 2, not left-to-right, so source order
   is no longer visual priority order. Keep the most important card first regardless. */
.dash-section__panel {
  columns: 21rem;
  column-gap: 1rem;
  /* Symmetric padding, including the bottom. This used to be padding-bottom: 0 on the theory
     that the last card's margin-bottom supplied the gap below the tallest column — it doesn't.
     Chrome truncates a trailing margin at the end of a multicol fragment, so the tallest
     column (the one setting the panel's height) ended flush against the bottom edge while
     shorter columns looked fine. Don't reintroduce the override: the margin that would double
     up with this padding is exactly the one that gets dropped. */
  padding: 1rem;
  background: var(--bg-inset);
  /* --bg-inset sits only ~5/255 below --bg-page in the light theme, so the fill alone doesn't
     read as a container there (in dark it's a clear recess). The border carries the grouping. */
  border: 1px solid var(--border-default);
  border-radius: var(--border-radius-lg);
}

/* Multi-column has no row-gap, so the vertical rhythm comes from the cards themselves.
   break-inside keeps a card from being sliced across the column boundary. */
.dash-section__panel > .dash-card {
  margin-bottom: 1rem;
  break-inside: avoid;
}

/* Every dashboard card hides itself when it has no data, so a section can end up an empty
   inset panel. :has() lets the layout notice that without the page needing to know each
   card's internal visibility rules. */
.dash-section:not(:has(.dash-card)) .dash-section__panel {
  display: none;
}

.dash-section:not(.dash-section--action):not(:has(.dash-card)) {
  display: none;
}

/* The action section is the one worth keeping when empty — an explicit all-clear reassures
   more than a section that silently vanishes. Its orb goes green to match: a red dot next to
   "You're all caught up." reads as a contradiction.

   Both rules require .dash-section--ready, which Home adds only once every action card has
   reported in. The cards render zero DOM while loading, so :has() alone cannot tell "nothing to
   do" from "not loaded yet" — ungated, this showed a false all-clear on every single page load. */
.dash-section--action.dash-section--ready:not(:has(.dash-card)) {
  --orb-color: var(--clr-success-text);
}

.dash-section__allclear {
  display: none;
}

.dash-section--action.dash-section--ready:not(:has(.dash-card)) .dash-section__allclear {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.875rem 1rem;
  background: var(--bg-inset);
  border: 1px solid var(--border-default);
  border-radius: var(--border-radius-lg);
  color: var(--text-secondary);
  font-size: 0.875rem;
}

/* Non-shrinking block for fixed visuals (charts, banners) inside a scrolling card body. */
.dash-card__body {
  flex-shrink: 0;
}

/* The rail drops below the main column before the top-row pair splits, so Capacity keeps its
   width for as long as possible — it's the most width-hungry card on the page. */
@media (max-width: 1400px) {
  .dash-shell {
    grid-template-columns: 1fr;
  }

  /* Stacked below the main column, so there's nothing to stick to and no leftover height to
     absorb — let the rail's cards be their natural size. */
  .dash-shell__side {
    position: static;
    max-height: none;
  }
}

@media (max-width: 900px) {
  .dash-top-row {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  /* Bottom stays 0 — the last card's margin-bottom supplies it (see the base rule). */
  .dash-section__panel {
    padding: 0.75rem 0.75rem 0;
  }
}

/* ════════════════════════════════════════════════════════════
   DASHBOARD CARD (shared chrome — page-specific content stays scoped)
   ════════════════════════════════════════════════════════════ */

.dash-card {
  position: relative;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-default, rgba(128, 128, 128, 0.15));
  border-radius: 10px;
  padding: 1rem 1.25rem;
  box-shadow: var(--shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.04));
  display: flex;
  flex-direction: column;
}

/* Action strip — only one of these classes is added at a time. The default card
   has no strip ("all good" / nothing to do). Discipline matters: if every card
   lights up the signal disappears. */
.dash-card--action::before,
.dash-card--warning::before,
.dash-card--alert::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
}

.dash-card--action::before {
  background: var(--clr-info-text);
}

.dash-card--warning::before {
  background: var(--clr-warning-text);
}

/* --clr-critical-bg, not --clr-critical-text: the critical pair is inverted relative to the
   others (see the .dash-section--action orb above). -text is the pale foreground meant to sit
   ON the red, so using it here painted the most severe strip lighter than the card surface —
   escalating from --warning to --alert made the signal weaker instead of stronger. */
.dash-card--alert::before {
  background: var(--clr-critical-bg);
}

.dash-card__header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.dash-card__title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}

.dash-card__footer {
  display: flex;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.75rem;
}

.dash-card__footer a,
.dash-card__footer button.btn-secondary {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-secondary);
  transition: all 0.15s ease;
}

.dash-card__footer a:hover,
.dash-card__footer button.btn-secondary:hover {
  background: var(--bg-page);
  border-color: var(--border-default, rgba(128, 128, 128, 0.15));
  color: var(--text-primary);
}

.dash-card__empty {
  color: var(--text-tertiary);
  font-size: 0.875rem;
  margin: 0;
}

.dash-card__empty a {
  color: var(--brand-primary);
  text-decoration: none;
}

.dash-card__empty a:hover {
  text-decoration: underline;
}

/* Leading marker for a list row inside a dashboard card, so rows read as items in a list rather
   than as more headings under the 1rem .dash-card__title. Global rather than per-card scoped CSS:
   scoped styles don't cross components, and four cards were about to carry the same eight lines.
   Four deliberate choices:
   - Goes on the row's TITLE element, not the row. Row layouts differ (.hrc-row/.vbc-row are flex,
     .dash-module-row is a 3-column grid), and on the two-line module rows a row-level marker
     centers itself against the subtitle too, floating between the lines. On the title it always
     aligns to the title's own line, whatever the row does.
   - Drawn via clip-path, not a "▸"/"•" text character: real content lands in the row's accessible
     name on some screen readers, and the name should be the item title alone.
   - Colored with --clr-info-text, the same token as the .dash-card--action top strip, so the
     marker belongs to the card's signal. It is also one of the theme-aware tokens — the flat
     --brand-primary has no dark override and goes muddy on the dark card surface.
   - Own margin rather than the row's flex gap, since a grid row has no gap to borrow. */
.dash-bullet::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  width: 5px;
  height: 7px;
  margin-right: 0.45rem;
  background: var(--clr-info-text);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.dash-card__module-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.dash-module-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 0.75rem;
  align-items: center;
  padding: 0.5rem 0;
}

.dash-module-row__main {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.dash-module-row__title {
  font-weight: 600;
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-module-row__title:hover {
  color: var(--brand-primary);
}

.dash-module-row__subtitle {
  color: var(--text-secondary);
  font-size: 0.8rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-module-row__progress {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.progress-mini {
  width: 110px;
  height: 6px;
  background: var(--bg-inset, #e5e7eb);
  border-radius: 999px;
  overflow: hidden;
  display: inline-block;
  vertical-align: middle;
}

.progress-mini__fill {
  display: block;
  height: 100%;
  background: var(--brand-primary);
}

/* ════════════════════════════════════════════════════════════
   DATA TABLE
   ════════════════════════════════════════════════════════════ */

.data-table-wrap {
  overflow-x: auto;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
  color: var(--text-primary);
}

.data-table th {
  text-align: left;
  padding: 0.35rem 0.75rem;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
  border-bottom: 2px solid var(--border-color);
  background: var(--bg-page);
  white-space: nowrap;
}

.data-table td {
  padding: 0.45rem 0.75rem;
  border-bottom: 1px solid var(--border-color);
  vertical-align: middle;
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

.data-table tbody tr:hover td {
  background: var(--nav-hover-bg);
}

.data-table__actions {
  width: 44px;
  white-space: nowrap;
  text-align: right;
  vertical-align: middle;
}

.confirm-delete {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
}

.list-empty {
  color: var(--text-tertiary);
  font-size: 0.875rem;
  padding: 1rem 0;
}

/* ── Sortable column headers ────────────────────────────────── */

.sort-header {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  font-size: inherit;
  font-weight: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: inherit;
  white-space: nowrap;
}

.sort-header:hover {
  color: var(--text-primary);
}

.sort-header__icon {
  transition: transform 0.15s, opacity 0.15s;
  flex-shrink: 0;
}

.sort-header__icon.sort-none {
  opacity: 0.25;
}

.sort-header__icon.sort-asc {
  transform: rotate(180deg);
  opacity: 1;
}

.sort-header__icon.sort-desc {
  transform: rotate(0deg);
  opacity: 1;
}

/* ════════════════════════════════════════════════════════════
   FILTER PILLS
   Reusable toggle-pill bar for filtering lists by category.
   Usage:  .filter-pills  >  .filter-pill  (.is-active)
   ════════════════════════════════════════════════════════════ */

.filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-bottom: 1rem;
}

.filter-pill {
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  color: var(--text-secondary);
  font-size: 0.8125rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.filter-pill:hover {
  border-color: var(--brand-primary);
  color: var(--text-primary);
}

.filter-pill.is-active {
  background: var(--pill-bg, var(--brand-primary));
  border-color: var(--pill-bg, var(--brand-primary));
  color: var(--pill-text, var(--brand-white));
}

/* Segmented toggle — two-option view switcher with a sliding active indicator.
   Use for binary view modes (Calendar/Agenda, Table/Calendar). The number of
   options is fixed at two; the indicator slides via translateX. */
.seg-toggle {
  position: relative;
  display: inline-flex;
  background: var(--bg-inset);
  border: 1px solid var(--border-color);
  border-radius: 999px;
  padding: 0.15rem;
}

.seg-toggle__indicator {
  position: absolute;
  top: 0.15rem;
  bottom: 0.15rem;
  left: 0.15rem;
  width: calc(50% - 0.15rem);
  background: var(--brand-primary);
  border-radius: 999px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
}

.seg-toggle__indicator--right {
  transform: translateX(100%);
}

/* 2-option full-width variant — the base .seg-toggle is 2-option but inline-width;
   this makes it span its container like the 3/4/5 variants. The Discuss position uses
   .seg-toggle__indicator--right. */
.seg-toggle--2 {
  display: flex;
  width: 100%;
}

.seg-toggle--2 .seg-toggle__indicator {
  width: calc(50% - 0.075rem);
}

.seg-toggle--2 .seg-toggle__option {
  flex: 1 1 0;
  justify-content: center;
}

/* 3-option variant — scales the sliding indicator to one-third width and
   provides position modifiers for the three slots. Used by the New Handbook
   Item dialog's Kind picker (Word / File / Link). The options flex to equal
   thirds so the indicator's translate(100% / 200%) lands on each button's
   center column regardless of label length. */
.seg-toggle--3 {
  display: flex;
  width: 100%;
}

.seg-toggle--3 .seg-toggle__indicator {
  width: calc(33.333% - 0.1rem);
}

.seg-toggle--3 .seg-toggle__option {
  flex: 1 1 0;
  justify-content: center;
}

.seg-toggle--4 {
  display: flex;
  width: 100%;
}

.seg-toggle--4 .seg-toggle__indicator {
  width: calc(25% - 0.075rem);
}

.seg-toggle--4 .seg-toggle__option {
  flex: 1 1 0;
  justify-content: center;
}

.seg-toggle--5 {
  display: flex;
  width: 100%;
}

.seg-toggle--5 .seg-toggle__indicator {
  width: calc(20% - 0.06rem);
}

.seg-toggle--5 .seg-toggle__option {
  flex: 1 1 0;
  justify-content: center;
}

.seg-toggle__indicator--pos-1 { transform: translateX(100%); }
.seg-toggle__indicator--pos-2 { transform: translateX(200%); }
.seg-toggle__indicator--pos-3 { transform: translateX(300%); }
.seg-toggle__indicator--pos-4 { transform: translateX(400%); }

.module-type-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

/* Use label.module-type-option (not bare .module-type-option) so this rule's
   specificity (0,2,0) ties with .form-field label's and the later cascade
   position wins. Without the element selector, .form-field label (0,2,0)
   outranks .module-type-option (0,1,0) and the uppercase + tiny-font label
   styling leaks into the module-type cards. */
label.module-type-option {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
  /* 2px border in both states so the box doesn't shift when toggling active —
     the inactive border just uses the muted token. */
  border: 2px solid var(--border);
  border-radius: 6px;
  background: var(--bg-card);
  cursor: pointer;
  transition: border-color 80ms ease, background-color 80ms ease, box-shadow 80ms ease;
  text-transform: none;
  letter-spacing: normal;
  font-size: 0.9rem;
  font-weight: 400;
  color: var(--text-primary);
}

.module-type-option input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.module-type-option__body {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  flex: 1;
  min-width: 0;
}

/* Checkmark badge on the right edge. Hidden by default; revealed when the
   parent option is active. Uses brand-primary fill + white check to match
   the seg-toggle indicator's active treatment. */
.module-type-option__check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: transparent;
  color: transparent;
  border: 2px solid var(--border);
  flex-shrink: 0;
  transition: background-color 80ms ease, color 80ms ease, border-color 80ms ease;
}

label.module-type-option.is-active {
  border-color: var(--brand-primary);
  background: var(--surface-hover, rgba(0, 110, 182, 0.06));
  box-shadow: 0 0 0 3px var(--surface-hover, rgba(0, 110, 182, 0.12));
}

label.module-type-option.is-active .module-type-option__title {
  color: var(--brand-primary);
}

label.module-type-option.is-active .module-type-option__check {
  background: var(--brand-primary);
  color: var(--brand-white);
  border-color: var(--brand-primary);
}

label.module-type-option:hover:not(.is-active):not(.is-disabled) {
  border-color: var(--text-tertiary);
}

.module-type-option.is-disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.module-type-option__title {
  font-weight: 600;
  color: var(--text-primary);
}

.module-type-option__hint {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.seg-toggle__option {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.85rem;
  background: transparent;
  border: none;
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color 0.2s;
  white-space: nowrap;
}

.seg-toggle__option:hover {
  color: var(--text-primary);
}

/* Roving tabindex means only the active option is tabbable — it needs a visible ring. */
.seg-toggle__option:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

.seg-toggle__option.is-active,
.seg-toggle__option.is-active:hover {
  color: var(--brand-white);
  font-weight: 600;
}

.seg-toggle__option svg {
  flex-shrink: 0;
  display: inline-block;
  vertical-align: middle;
}

/* ════════════════════════════════════════════════════════════
   HEADER
   ════════════════════════════════════════════════════════════ */

/* Environment Testing Banner */
#se-portal-testing-overlay {
  cursor: default;
  display: grid;
  justify-content: center;
  align-items: center;
  color: black;
  height: 20px;
  width: 40vw;
  font-size: 0.8rem;
  font-weight: 600;
  position: fixed;
  top: 0;
  background: darkorange;
  left: 50%;
  transform: translateX(-50%);
  border-bottom-left-radius: 25px;
  border-bottom-right-radius: 25px;
  z-index: 30000;
  box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}


.header-left {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-shrink: 0;
  min-width: 0;
}

.hamburger-btn {
  display: none; /* visible only on mobile */
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 36px;
  height: 36px;
  border-radius: var(--border-radius-sm);
  color: var(--text-on-dark);
  flex-shrink: 0;
}

  .hamburger-btn span {
    display: block;
    width: 20px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
    transition: transform var(--transition), opacity var(--transition);
    pointer-events: none;
  }

.header-logo-link {
  display: flex;
  align-items: center;
  border-radius: var(--border-radius-sm);
  transition: opacity var(--transition);
}

  .header-logo-link:hover {
    opacity: 0.85;
  }

.header-logo-bg {
  background: var(--brand-black);
  border-radius: 4px;
  padding: 5px 8px;
  display: flex;
  align-items: center;
}

.byui-logo {
  color: var(--brand-white);
}

.header-title-block {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
  overflow: hidden;
}

.header-app-name {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-on-dark);
  letter-spacing: 0.01em;
}

.header-divider {
  color: var(--header-divider-color);
  font-size: 0.85rem;
}

.header-dept {
  font-size: 0.78rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* Center search */
.header-center {
  flex: 1;
  display: flex;
  justify-content: center;
}

.search-wrapper {
  position: relative;
  width: 100%;
  max-width: 480px;
}

/* The bar's visibility is driven by SearchBarController + MainLayout: when
   no searchable page is active, the wrapper carries `--inactive` and is
   hidden. Both the class and the input's placeholder are part of MainLayout's
   markup, so Blazor's render diff manages them — no JS-vs-Blazor races. */
.search-wrapper--inactive {
  display: none;
}

.search-clear {
  display: none;
}

/* Clear button visibility tracks whether the input has a value. Set via
   a body class because the button itself can be re-rendered by Blazor;
   body lives outside Blazor's render tree, so JS owns this state. */
body.has-search-value .search-clear {
  display: flex;
}

.search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--search-icon-color);
  pointer-events: none;
}

.search-input {
  width: 100%;
  height: 36px;
  padding: 0 2.5rem 0 2.2rem;
  background: var(--search-bg);
  border: 1px solid var(--search-border);
  border-radius: 20px;
  color: var(--text-on-dark);
  font-size: 0.85rem;
  outline: none;
  transition: border-color var(--transition), box-shadow var(--transition), background var(--transition);
}

  .search-input::placeholder {
    color: var(--search-placeholder);
  }

  .search-input:focus {
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 3px rgba(0,110,182,.25);
    background: var(--search-bg-focus);
  }

  .search-input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    display: none;
  }

.search-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--search-icon-color);
  display: flex;
  align-items: center;
  padding: 2px;
  border-radius: 50%;
  transition: color 0.15s ease, background 0.15s ease;
}

.search-clear:hover {
  color: var(--text-on-dark);
  background: rgba(255, 255, 255, 0.1);
}

.search-hint {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.68rem;
  background: var(--search-hint-bg);
  color: var(--search-hint-color);
  padding: 1px 5px;
  border-radius: 4px;
  pointer-events: none;
}

/* Right header cluster */
.header-right {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: 20px;
  font-size: 0.83rem;
  font-weight: 600;
  padding: 0 14px;
  height: 34px;
  transition: background var(--transition), box-shadow var(--transition);
  white-space: nowrap;
}

.btn-primary {
  background: var(--brand-primary);
  color: var(--brand-white);
}

  .btn-primary:hover {
    background: var(--brand-primary-dark);
    box-shadow: 0 2px 8px rgba(0,110,182,.35);
  }

.btn-secondary {
  background: var(--bg-card);
  color: var(--text-primary);
  border: 1.5px solid var(--border-color);
}

  .btn-secondary:hover {
    background: var(--nav-hover-bg);
    border-color: var(--text-secondary);
  }

.icon-btn {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--icon-btn-color);
  transition: background var(--transition), color var(--transition);
  flex-shrink: 0;
}

  .icon-btn:hover {
    background: var(--icon-btn-hover-bg);
    color: var(--icon-btn-hover-color);
  }

/* Header always has a dark background, so icon buttons in it stay light regardless of theme. */
.app-header .icon-btn {
    color: #cccccc;
}

    .app-header .icon-btn:hover {
        background: rgba(255, 255, 255, 0.08);
        color: var(--brand-white);
    }

.icon-btn--sm {
  width: 28px;
  height: 28px;
}

.icon-btn--danger {
  color: var(--icon-btn-danger-color);
}

  .icon-btn--danger:hover {
    background: var(--icon-btn-danger-hover-bg);
    color: var(--icon-btn-danger-color);
  }

.badge {
  position: absolute;
  top: 4px;
  right: 4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  background: var(--badge-solid-bg);
  color: var(--badge-solid-text);
  font-size: 0.62rem;
  font-weight: 700;
  border-radius: 99px;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  border: 1.5px solid var(--bg-header);
}

/* User avatar / dropdown */
.user-menu-wrapper {
  position: relative;
}

.user-avatar-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  border-radius: 20px;
  padding: 3px 10px 3px 3px;
  color: var(--text-on-dark);
  transition: background var(--transition);
}

  .user-avatar-btn:hover {
    background: rgba(255,255,255,.08);
  }

.avatar-circle {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--brand-primary);
  color: var(--brand-white);
  font-size: 0.72rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  letter-spacing: 0.03em;
}

.avatar-circle--lg {
  width: 40px;
  height: 40px;
  font-size: 0.9rem;
}

.avatar-name {
  font-size: 0.82rem;
  font-weight: 500;
}

.chevron {
  transition: transform var(--transition);
}

.user-avatar-btn[aria-expanded="true"] .chevron {
  transform: rotate(180deg);
}

.user-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 220px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition);
  z-index: 2000;
}

  .user-dropdown.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }

.dropdown-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
}

.dropdown-user-name {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-primary);
}

.dropdown-user-email {
  font-size: 0.75rem;
  color: var(--text-secondary);
  margin-top: 1px;
}

.dropdown-divider {
  border: none;
  border-top: 1px solid var(--border-color);
  margin: 0;
}

.dropdown-menu-list {
  padding: 4px 0;
}

.dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 8px 1rem;
  font-size: 0.84rem;
  color: var(--text-primary);
  transition: background var(--transition);
}

  .dropdown-item:hover {
    background: var(--nav-hover-bg);
  }

.dropdown-item--danger {
  color: var(--dropdown-danger-color);
}

  .dropdown-item--danger:hover {
    background: var(--clr-critical-bg);
    color: var(--clr-critical-text);
  }

.dark-theme .dropdown-item--danger:hover {
  background: var(--clr-critical-bg);
  color: var(--clr-critical-text);
}

/* ════════════════════════════════════════════════════════════
   SIDEBAR
   ════════════════════════════════════════════════════════════ */
/* Wrapper keeps sidebar + tab sticky together */
.sidebar-wrap {
  display: flex;
  flex-shrink: 0;
  align-items: flex-start;
  position: sticky;
  top: var(--header-height);
  height: calc(100vh - var(--header-height));
  z-index: 100;
  /* On short windows the nav is taller than the sidebar box. The aside
     scrolls it internally, but Chromium still adds the sticky wrap's inner
     overflow to the PAGE's scrollable area — a phantom window scrollbar with
     nothing but empty space below every height-pinned page (e.g. the
     document editor). clip stops the leak; nothing renders outside the wrap
     (the aside clips its own scrolling and the collapse button sits inside). */
  overflow: clip;
}

.sidebar {
  width: var(--sidebar-width);
  flex-shrink: 0;
  background: var(--bg-sidebar);
  border-right: 1px solid var(--border-color);
  overflow-y: auto;
  overflow-x: hidden;
  height: 100%;
  transition: width var(--transition-slow);
  display: flex;
  flex-direction: column;
}

  /* Scrollbar for sidebar */
  .sidebar::-webkit-scrollbar {
    width: 4px;
  }

  .sidebar::-webkit-scrollbar-thumb {
    background: var(--border-color);
    border-radius: 2px;
  }

.sidebar-nav {
  padding: 0.5rem 0 1.5rem;
}

/* Sidebar collapse tab — floats on the right edge of the sidebar */
.sidebar-collapse-btn {
  position: sticky;
  top: 0.75rem;
  align-self: flex-start;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 40px;
  margin-left: -1px;
  background: var(--bg-page);
  border: 1px solid var(--border-color);
  border-left: none;
  border-radius: 0 8px 8px 0;
  color: var(--text-tertiary);
  box-shadow: 3px 0 8px rgba(0,0,0,.08);
  transition: background var(--transition), color var(--transition), box-shadow var(--transition);
  z-index: 1;
}

  .sidebar-collapse-btn:hover {
    background: var(--brand-primary);
    color: var(--brand-white);
    box-shadow: 3px 0 12px rgba(0,110,182,.3);
  }

/* Nav lists */
.nav-list {
  padding: 0 0.5rem;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 7px 10px;
  border-radius: var(--border-radius-sm);
  font-size: 0.84rem;
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
  overflow: hidden;
}

  .nav-item:hover {
    background: var(--nav-hover-bg);
    color: var(--text-primary);
  }

  .nav-item.active {
    background: var(--nav-active-bg);
    color: var(--nav-active-text);
    font-weight: 600;
  }

/* Nav icon / label */
.nav-icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

  .nav-icon svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
  }

.nav-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity var(--transition-slow), max-width var(--transition-slow);
}

/* Nav groups — bubble style */
.nav-group {
  margin: 0.45rem 0.5rem 0;
  background: var(--nav-group-bg);
  border: 1px solid var(--nav-group-border);
  border-radius: var(--border-radius);
  overflow: hidden;
  padding-bottom: 0.3rem;
}

/* Hide admin-only nav groups when impersonating a non-admin */
.nav-group.is-impersonate-hidden {
  display: none;
}

.nav-group-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 8px 10px;
  border-radius: 0;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
  overflow: hidden;
  color: var(--text-secondary);
  background: var(--nav-group-header-bg);
  border-bottom: 1px solid var(--nav-group-border);
  transition: background var(--transition), color var(--transition);
}

  .nav-group-header:hover {
    background: var(--brand-primary);
    color: var(--brand-white);
  }

  .nav-group-header .nav-icon {
    font-size: 0.9rem;
  }

.group-chevron {
  margin-left: auto;
  flex-shrink: 0;
  transition: transform var(--transition);
}

.nav-group-header[aria-expanded="false"] .group-chevron {
  transform: rotate(-90deg);
}

.nav-group-items {
  overflow: hidden;
  max-height: 400px;
  transition: max-height var(--transition-slow), opacity var(--transition-slow);
  opacity: 1;
}

  /* Top-level groups (e.g. Admin) can hold several nested sub-groups
     (People, Content, System). When those are expanded their combined
     height exceeds the leaf cap, so give the outer container enough room
     that the last sub-group isn't clipped by overflow: hidden. */
  .nav-group:not(.nav-group--sub) > .nav-group-items {
    max-height: 1500px;
  }

  .nav-group > .nav-group-items.is-collapsed {
    max-height: 0;
    opacity: 0;
  }

/* ── Nested sub-groups (level 2 inside Admin etc.) ──────── */
.nav-group--sub {
  border-bottom: none;
}

  .nav-group--sub > .nav-group-header {
    background: transparent;
    color: var(--text-tertiary);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    border-bottom: none;
    padding: 6px 10px 6px 18px;
  }

  .nav-group--sub > .nav-group-header:hover {
    background: var(--nav-hover-bg);
    color: var(--text-primary);
  }

  .nav-group--sub > .nav-group-items .nav-item {
    padding-left: 28px;
  }

  .sidebar.is-collapsed .nav-group--sub > .nav-group-header {
    padding: 6px 8px;
  }

  .sidebar.is-collapsed .nav-group--sub > .nav-group-items .nav-item {
    padding-left: 8px;
  }

/* ── Collapsed desktop sidebar ─────────────────────────── */
.sidebar.is-collapsed {
  width: var(--sidebar-collapsed-width);
}

  .sidebar.is-collapsed .nav-label,
  .sidebar.is-collapsed .nav-group-header .nav-label,
  .sidebar.is-collapsed .group-chevron,
  .sidebar.is-collapsed .header-dept {
    opacity: 0;
    max-width: 0;
    pointer-events: none;
  }

  .sidebar.is-collapsed .nav-group {
    margin: 0.3rem 0.25rem 0;
    border-radius: var(--border-radius-sm);
    padding-bottom: 0.15rem;
  }

  .sidebar.is-collapsed .nav-group-header {
    justify-content: center;
    border-bottom: none;
    padding: 8px;
    gap: 0;
  }

  .sidebar.is-collapsed .group-chevron {
    margin-left: 0;
  }

  .sidebar.is-collapsed .nav-group-header .nav-icon,
  .sidebar.is-collapsed .nav-item .nav-icon {
    width: 16px;
    height: 16px;
  }

  .sidebar.is-collapsed .nav-group-items {
    padding-left: 0;
    padding-right: 0;
  }

  .sidebar.is-collapsed .nav-list:not(.nav-group-items) {
    padding: 0.3rem 0.25rem 0;
  }

  .sidebar.is-collapsed ~ .sidebar-collapse-btn svg {
    transform: rotate(180deg);
  }

  .sidebar.is-collapsed .nav-item {
    justify-content: center;
    padding: 8px;
    gap: 0;
  }

/* Sidebar overlay (mobile) */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  z-index: 90;
  transition: opacity var(--transition);
}

  .sidebar-overlay.is-visible {
    display: block;
  }

/* ════════════════════════════════════════════════════════════
   MAIN CONTENT
   ════════════════════════════════════════════════════════════ */
.main-content {
  flex: 1;
  min-width: 0;
  /*padding: 0rem 1.5rem 2rem;*/
  position: relative;
}

/* ── Fullscreen toggle button ── */
.fullscreen-btn {
  position: sticky;
  top: calc(var(--header-height) + 0.5rem);
  float: right;
  z-index: 11;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition), background var(--transition), color var(--transition);
}

.main-content:hover .fullscreen-btn,
.fullscreen-btn:focus-visible {
  opacity: 1;
}

.fullscreen-btn:hover {
  background: var(--border-color);
  color: var(--text-primary);
}

/* Icon toggle for fullscreen button */
.fullscreen-icon--exit { display: none; }
.fullscreen-icon--enter { display: block; }

/* ── Fullscreen state ── */
.is-fullscreen .app-header,
.is-fullscreen .sidebar-wrap,
.is-fullscreen .sidebar-overlay,
.is-fullscreen .impersonation-banner {
  display: none !important;
}

.is-fullscreen .layout-shell {
  padding-top: 0;
}

.is-fullscreen .main-content {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: var(--bg-page);
  overflow-y: auto;
  padding-top: 1rem;
}

.is-fullscreen .fullscreen-btn {
  top: 0.5rem;
  opacity: 0;
}

/* Presentation mode owns its own exit control in the same top-right corner, so the
   floating chrome toggle would sit under it and fight for the same click. Hidden here
   rather than for .is-fullscreen generally: the document reader view uses that class
   too, and there the floating button is the affordance for getting the chrome back. */
.is-presenting .fullscreen-btn {
  display: none !important;
}

.is-fullscreen .main-content:hover .fullscreen-btn,
.is-fullscreen .fullscreen-btn:focus-visible {
  opacity: 1;
}

.is-fullscreen .fullscreen-icon--enter { display: none; }
.is-fullscreen .fullscreen-icon--exit { display: block; }

.is-fullscreen .page-header {
  top: 0;
}

/* ── Presentation shell ──
   Used by any surface projected on a screen (training-module preview and a learner's
   tracked instance today). Deliberately global rather than scoped: two components share
   it, and a projected layout that drifts between them is exactly the bug this prevents.
   It sits OUTSIDE .page-wrap on purpose — that wrapper's 900px cap would waste most of a
   projector. Entered via window.sePortalPresentation, which pairs real browser fullscreen
   with the .is-fullscreen chrome hiding above. */
.tm-present {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  background: var(--bg-page);
}

.tm-present__exit {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 1;
  /* Faded until wanted — the control belongs to the presenter, not the room. */
  opacity: 0.35;
  transition: opacity 0.15s ease;
}

.tm-present__exit:hover,
.tm-present__exit:focus-visible {
  opacity: 1;
}

.tm-present-btn {
  align-self: flex-start;
  margin-top: 0.5rem;
}

/* Breadcrumb */
.breadcrumb-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.25rem;
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.78rem;
  color: var(--text-tertiary);
}

.breadcrumb-item a:hover {
  color: var(--brand-primary);
}

.breadcrumb-item + .breadcrumb-item::before {
  content: '/';
  margin-right: 0.3rem;
  color: var(--border-color);
}

.breadcrumb-item--active {
  color: var(--text-secondary);
  font-weight: 500;
}

.page-date {
  font-size: 0.78rem;
  color: var(--text-tertiary);
}

.page-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 1.25rem;
  letter-spacing: -0.02em;
}

/* ─── Hero section ──────────────────────────────────────────── */
.hero-section {
  background: var(--bg-hero);
  border-radius: var(--border-radius-lg);
  padding: 1.75rem 2rem;
  margin-bottom: 1.5rem;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  box-shadow: var(--shadow-md);
  position: relative;
  overflow: hidden;
}

  /* Subtle decorative circles */
  .hero-section::before,
  .hero-section::after {
    content: '';
    position: absolute;
    border-radius: 50%;
    background: rgba(255,255,255,.06);
    pointer-events: none;
  }

  .hero-section::before {
    width: 260px;
    height: 260px;
    top: -80px;
    right: 120px;
  }

  .hero-section::after {
    width: 180px;
    height: 180px;
    bottom: -60px;
    right: 30px;
  }

.hero-text {
  position: relative;
  z-index: 1;
}

.hero-headline {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--brand-white);
  letter-spacing: -0.02em;
  margin-bottom: 0.25rem;
}

.hero-sub {
  font-size: 0.88rem;
  color: rgba(255,255,255,.8);
}

.quick-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  position: relative;
  z-index: 1;
}

.quick-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  background: rgba(255,255,255,.15);
  border: 1px solid rgba(255,255,255,.25);
  border-radius: 20px;
  color: var(--brand-white);
  font-size: 0.8rem;
  font-weight: 500;
  backdrop-filter: blur(4px);
  transition: background var(--transition), box-shadow var(--transition);
}

  .quick-action-btn:hover {
    background: rgba(255,255,255,.25);
    box-shadow: 0 2px 8px rgba(0,0,0,.2);
  }

.qa-icon {
  font-size: 1rem;
}

/* ─── Hero Daily variant (check-in + standup) ───────────────── */
.hero-section--daily {
  display: grid;
  grid-template-columns: 1fr 1.65fr;
  align-items: start;
  gap: 1.25rem;
  padding: 1.5rem;
}

.hero-card {
  background: rgba(255,255,255,.13);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.22);
  border-radius: var(--border-radius);
  padding: 1.1rem 1.25rem;
  position: relative;
  z-index: 1;
}

.hero-card__header {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  margin-bottom: 0.9rem;
}

.hero-card__icon {
  font-size: 1.4rem;
  line-height: 1;
  margin-top: 0.1rem;
  flex-shrink: 0;
}

.hero-card__title {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--brand-white);
  margin: 0 0 0.2rem;
  letter-spacing: -0.01em;
}

.hero-card__sub {
  font-size: 0.72rem;
  color: rgba(255,255,255,.65);
  margin: 0;
}

.hero-card__prompt {
  font-size: 0.8rem;
  color: rgba(255,255,255,.8);
  margin-bottom: 0.7rem;
}

/* Check-in buttons inside hero */
.hero-card--checkin .checkin-btn {
  background: rgba(255,255,255,.12);
  border-color: rgba(255,255,255,.22);
  color: rgba(255,255,255,.85);
}

  .hero-card--checkin .checkin-btn:hover {
    background: rgba(255,255,255,.22);
    border-color: rgba(255,255,255,.45);
    color: var(--brand-white);
  }

.hero-card--checkin .checkin-btn--active {
  background: rgba(255,255,255,.92);
  border-color: var(--brand-white);
  color: var(--brand-primary);
  box-shadow: 0 0 0 3px rgba(255,255,255,.25);
}

.hero-card--checkin .checkin-confirmed {
  background: rgba(255,255,255,.12);
  border-color: rgba(255,255,255,.25);
  color: var(--brand-white);
}

/* Scrum fields inside hero */
.hero-card--scrum .badge-status--info {
  background: rgba(255,255,255,.15);
  color: rgba(255,255,255,.85);
  border-color: rgba(255,255,255,.2);
}

.hero-card--scrum .badge-status--success {
  background: rgba(134,239,172,.2);
  color: var(--clr-success-border);
  border-color: rgba(134,239,172,.35);
}

.hero-card--scrum .scrum-field {
  margin-bottom: 0.6rem;
}

.hero-card--scrum .scrum-label {
  color: rgba(255,255,255,.75);
}

.hero-card--scrum .scrum-q-num {
  background: rgba(255,255,255,.2);
  color: var(--brand-white);
}

.hero-card--scrum .scrum-textarea {
  background: rgba(255,255,255,.1);
  border-color: rgba(255,255,255,.18);
  color: var(--brand-white);
}

  .hero-card--scrum .scrum-textarea::placeholder {
    color: rgba(255,255,255,.4);
  }

  .hero-card--scrum .scrum-textarea:focus {
    border-color: rgba(255,255,255,.55);
    box-shadow: 0 0 0 3px rgba(255,255,255,.12);
  }

.hero-card--scrum .scrum-no-blocker-btn {
  background: rgba(255,255,255,.1);
  border-color: rgba(255,255,255,.18);
  color: rgba(255,255,255,.65);
}

  .hero-card--scrum .scrum-no-blocker-btn:hover {
    background: rgba(255,255,255,.2);
    color: var(--brand-white);
    border-color: rgba(255,255,255,.35);
  }

.hero-card--scrum .scrum-submit-btn {
  background: var(--brand-white);
  color: var(--brand-primary);
  border: 2px solid var(--brand-white);
  font-weight: 700;
}

  .hero-card--scrum .scrum-submit-btn:hover {
    background: rgba(255,255,255,.88);
  }

.hero-card--scrum .scrum-success svg {
  color: var(--clr-success-icon);
}

.hero-card--scrum .scrum-success strong {
  color: var(--clr-success-border);
  font-size: 0.875rem;
}

.hero-card--scrum .scrum-success span {
  color: rgba(255,255,255,.7);
}

.hero-card--scrum .scrum-edit-btn {
  border-color: rgba(255,255,255,.5);
  color: rgba(255,255,255,.85);
}

  .hero-card--scrum .scrum-edit-btn:hover {
    background: rgba(255,255,255,.15);
    color: var(--brand-white);
  }

/* ─── Content body (2-col) ───────────────────────────────────── */
.content-body {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 1.25rem;
  align-items: start;
}

/* ── Section title ─────────────────────────────────────────── */
.section-title {
  font-size: 0.88rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
  margin-bottom: 0.75rem;
}

/* ── Module grid ───────────────────────────────────────────── */
.module-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.75rem;
}

/* Removed: an orphaned `.module-card` + companion classes (.module-card-icon,
   .module-card-name, .module-card-desc) that styled a small icon/name/desc
   chooser card. Zero remaining consumers in the codebase, and the name
   collided with the new dialog-card pattern earlier in this file. */

/* ════════════════════════════════════════════════════════════
   PANELS (Aside)
   ════════════════════════════════════════════════════════════ */
.side-panels {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.panel {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border-color);
}

.panel-title {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.panel-link {
  font-size: 0.75rem;
  color: var(--brand-primary);
  font-weight: 500;
}

  .panel-link:hover {
    text-decoration: underline;
  }

.panel-body {
  padding: 0.5rem 0;
}

/* ─── Notices ─────────────────────────────────────────────── */
.notice-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.65rem 1rem;
  border-left: 3px solid transparent;
  transition: background var(--transition);
}

  .notice-item + .notice-item {
    border-top: 1px solid var(--border-color);
  }

  .notice-item:hover {
    background: var(--bg-page);
  }

.notice-critical {
  border-left-color: var(--notice-critical-accent);
}

.notice-warning {
  border-left-color: var(--notice-warning-accent);
}

.notice-info {
  border-left-color: var(--brand-primary);
}

.notice-severity {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 9999px;
  white-space: nowrap;
  flex-shrink: 0;
  line-height: 1.6;
}

.notice-critical .notice-severity {
  background: var(--clr-critical-bg);
  color: var(--clr-critical-text);
  border: 1px solid var(--clr-critical-border);
}

.notice-warning .notice-severity {
  background: var(--clr-warning-bg);
  color: var(--clr-warning-text);
  border: 1px solid var(--clr-warning-border);
}

.notice-info .notice-severity {
  background: var(--clr-info-bg);
  color: var(--clr-info-text);
  border: 1px solid var(--clr-info-border);
}

.notice-content {
  min-width: 0;
}

.notice-title {
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.3;
}

.notice-meta {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  margin-top: 2px;
}

/* ─── My Week ─────────────────────────────────────────────── */
.my-week-item {
  padding: 0.75rem 1rem;
}

  .my-week-item + .my-week-item {
    border-top: 1px solid var(--border-color);
  }

.my-week-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 0.5rem;
}

.my-week-meta {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  font-weight: 400;
}

/* Progress bars */
.progress-bar-track {
  height: 7px;
  background: var(--clr-progress-track);
  border-radius: 99px;
  overflow: hidden;
}

.progress-bar-fill {
  height: 100%;
  background: var(--clr-progress-default);
  border-radius: 99px;
  transition: width 0.6s ease;
}

.progress-bar-fill--warning {
  background: var(--clr-progress-warning);
}

.progress-bar-labels {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
}

.progress-bar-pct {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.progress-bar-sub {
  font-size: 0.72rem;
  color: var(--text-tertiary);
}

/* Inline mini-badges */
.badge-status {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: 99px;
  font-size: 0.7rem;
  font-weight: 600;
}

.badge-status--warning {
  background: var(--clr-warning-bg);
  color: var(--clr-warning-text);
  border: 1px solid var(--clr-warning-border);
}

.badge-status--info {
  background: var(--clr-info-bg);
  color: var(--clr-info-text);
  border: 1px solid var(--clr-info-border);
}

.my-week-body-text {
  font-size: 0.8rem;
  color: var(--text-secondary);
  line-height: 1.5;
}

/* Events list */
.events-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.1rem;
}

.event-item {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.event-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  margin-top: 4px;
}

.event-dot--blue {
  background: var(--event-dot-blue);
}

.event-dot--green {
  background: var(--event-dot-green);
}

.event-dot--purple {
  background: var(--event-dot-purple);
}

.event-name {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-primary);
}

.event-date {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  margin-top: 1px;
}

/* ════════════════════════════════════════════════════════════
   TOAST
   ════════════════════════════════════════════════════════════ */
.toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--toast-bg);
  color: var(--brand-white);
  padding: 10px 20px;
  border-radius: 99px;
  font-size: 0.83rem;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition);
  z-index: 9999;
  white-space: nowrap;
}

  .toast.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }

/* ════════════════════════════════════════════════════════════
   RESPONSIVE
   ════════════════════════════════════════════════════════════ */

/* Medium screens: collapse right panel */
@media (max-width: 1100px) {
  .content-body {
    grid-template-columns: 1fr;
  }

  .side-panels {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 760px) {
  .side-panels {
    grid-template-columns: 1fr;
  }

  .hero-section {
    flex-direction: column;
    align-items: flex-start;
  }

  .hero-section--daily {
    grid-template-columns: 1fr;
  }

  .quick-actions {
    width: 100%;
  }
}

/* Mobile: sidebar becomes drawer */
@media (max-width: 640px) {
  .app-header {
    flex-wrap: wrap;
    height: auto;
    padding: 0.5rem 1rem;
    row-gap: 0.375rem;
  }

  /* Push right cluster to the far right on the first row */
  .header-right {
    margin-left: auto;
  }

  /* Drop search to its own full-width second row */
  .header-center {
    order: 3;
    flex: 0 0 100%;
    padding-bottom: 0.25rem;
  }

  .search-wrapper {
    max-width: 100%;
  }

  .hamburger-btn {
    display: flex;
  }

  .header-dept,
  .header-divider {
    display: none;
  }

  .sidebar-wrap {
    position: static;
  }

  .sidebar {
    position: fixed;
    top: var(--header-height);
    left: 0;
    bottom: 0;
    height: auto;
    transform: translateX(-100%);
    transition: transform var(--transition-slow), box-shadow var(--transition-slow);
    z-index: 200;
    box-shadow: none;
  }

    .sidebar.is-mobile-open {
      transform: translateX(0);
      box-shadow: var(--shadow-lg);
    }

  .sidebar-collapse-btn {
    display: none;
  }

  .main-content {
    padding: 1rem;
    padding-top: 0;
  }

  .module-grid {
    grid-template-columns: 1fr 1fr;
  }

  .search-hint {
    display: none;
  }
}

@media (max-width: 400px) {
  .module-grid {
    grid-template-columns: 1fr;
  }

  .header-app-name {
    font-size: 0.8rem;
  }
}

/* ─── Action-Required Alert Banner ──────────────────────────── */
.alert-banner {
  display: flex;
  align-items: flex-start;
  gap: 0.875rem;
  padding: 1rem 1.25rem;
  border-radius: var(--border-radius);
  margin-bottom: 1rem;
  position: relative;
  box-shadow: var(--shadow-md);
  animation: alertSlideIn 0.35s cubic-bezier(.22,.68,0,1.2) both;
}

@keyframes alertSlideIn {
  from {
    opacity: 0;
    transform: translateY(-12px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Urgent / high-priority variant */
.alert-banner--urgent {
  background: linear-gradient(135deg, var(--alert-urgent-bg-from) 0%, var(--alert-urgent-bg-to) 100%);
  border: 2px solid var(--alert-urgent-border);
  color: var(--alert-urgent-color);
}

  /* Pulsing left accent stripe */
  .alert-banner--urgent::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 6px;
    border-radius: var(--border-radius) 0 0 var(--border-radius);
    background: var(--alert-urgent-accent);
    animation: alertPulse 1.8s ease-in-out infinite;
  }

@keyframes alertPulse {
  0%, 100% {
    opacity: 1;
  }

  50% {
    opacity: 0.45;
  }
}

.alert-banner__icon {
  flex-shrink: 0;
  margin-top: 0.1rem;
  color: var(--alert-urgent-accent);
  filter: drop-shadow(0 0 6px rgba(252,165,165,.6));
}

.alert-banner__body {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.5rem;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.alert-banner__label {
  display: inline-block;
  background: var(--alert-urgent-accent);
  color: var(--alert-urgent-label-color);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 0.15em 0.55em;
  border-radius: 999px;
  vertical-align: middle;
  flex-shrink: 0;
}

.alert-banner__message {
  color: var(--alert-urgent-color);
}

  .alert-banner__message strong {
    color: var(--brand-white);
    font-weight: 700;
  }

.alert-banner__link {
  display: inline-block;
  margin-left: 0.25rem;
  color: var(--brand-white);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity .15s;
}

  .alert-banner__link:hover {
    opacity: 0.75;
  }

.alert-banner__dismiss {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  color: var(--alert-urgent-color);
  transition: background .15s, color .15s;
  margin-top: -2px;
}

  .alert-banner__dismiss:hover {
    background: rgba(255,255,255,.25);
    color: var(--brand-white);
  }

/* Dark-theme adjustments — tokens are overridden in .dark-theme block above */
.dark-theme .alert-banner--urgent {
  background: linear-gradient(135deg, var(--alert-urgent-bg-from) 0%, var(--alert-urgent-bg-to) 100%);
  border-color: var(--alert-urgent-border);
}

.dark-theme select.form-control {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%239ca3af' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}

/* The same fix as .form-control's own --bg-input, restated here because this
   selector is heavier and was still painting selects with --bg-card — the exact
   bug --bg-input exists to prevent, just reintroduced one rule later. Guarded so
   it doesn't out-specify the recessed .form-control:disabled fill: this selector
   is heavier than that one, so an unguarded colour here would leave dark-theme
   selects looking enabled while they aren't. The arrow above is deliberately
   left in both states: the control is still a picker. */
.dark-theme select.form-control:not(:disabled):not([readonly]) {
  background-color: var(--bg-input);
}

.dark-theme select.form-control option {
  background: var(--bg-card);
  color: var(--text-primary);
}

.dark-theme select.form-control option:checked {
  background: var(--brand-primary);
  color: var(--brand-white);
}

/* Date/time input picker icons — inherit text color so they're visible in dark theme.
   The clock icon on input[type="time"] is the same UA control as the calendar icon and
   disappears against a dark field without this. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  filter: none;
}

.dark-theme input[type="date"]::-webkit-calendar-picker-indicator,
.dark-theme input[type="time"]::-webkit-calendar-picker-indicator {
  filter: invert(0.8);
}

/* ─── Work Mode Check-in Panel ──────────────────────────────── */
.checkin-date {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  font-weight: 500;
}

.checkin-prompt {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin-bottom: 0.75rem;
}

.checkin-options {
  display: flex;
  gap: 0.5rem;
}

.checkin-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.65rem 0.4rem;
  border: 2px solid var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-page);
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 500;
  transition: border-color .15s, background .15s, color .15s, box-shadow .15s;
  cursor: pointer;
}

  .checkin-btn:hover {
    border-color: var(--brand-primary);
    background: var(--bg-card);
    color: var(--text-primary);
  }

.checkin-btn__icon {
  font-size: 1.25rem;
}

.checkin-btn__label {
  line-height: 1.2;
}

.checkin-btn--active {
  border-color: var(--brand-primary);
  background: var(--nav-active-bg);
  color: var(--brand-primary);
  box-shadow: 0 0 0 3px rgba(0,110,182,.15);
}

.dark-theme .checkin-btn--active {
  background: rgba(0,110,182,.2);
}

.checkin-confirmed {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--clr-success-icon);
  background: var(--clr-success-bg);
  border: 1px solid var(--clr-success-border);
  border-radius: var(--border-radius-sm);
  padding: 0.45rem 0.65rem;
  animation: alertSlideIn .25s ease both;
}

.dark-theme .checkin-confirmed {
  background: var(--clr-success-bg);
  border-color: var(--clr-success-icon);
}

/* ─── Daily Scrum / Standup Panel ───────────────────────────── */
.panel--scrum .panel-header {
  align-items: center;
}

.scrum-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-bottom: 0.75rem;
}

.scrum-label {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.scrum-q-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--brand-primary);
  color: var(--brand-white);
  font-size: 0.65rem;
  font-weight: 700;
  flex-shrink: 0;
}

.scrum-textarea {
  width: 100%;
  padding: 0.5rem 0.65rem;
  border: 1.5px solid var(--border-color);
  border-radius: var(--border-radius-sm);
  background: var(--bg-page);
  color: var(--text-primary);
  font: inherit;
  font-size: 0.8125rem;
  line-height: 1.5;
  resize: vertical;
  transition: border-color .15s, box-shadow .15s;
}

  .scrum-textarea:focus {
    outline: none;
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 3px rgba(0,110,182,.12);
  }

.dark-theme .scrum-textarea {
  background: var(--bg-card);
  border-color: var(--scrum-textarea-border-dark);
  color: var(--text-primary);
}

.scrum-no-blocker-btn {
  align-self: flex-start;
  margin-top: 0.2rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-tertiary);
  background: var(--bg-page);
  border: 1px solid var(--border-color);
  border-radius: 999px;
  padding: 0.2em 0.7em;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}

  .scrum-no-blocker-btn:hover {
    background: var(--border-color);
    color: var(--text-primary);
    border-color: var(--scrum-btn-hover-border);
  }

.scrum-submit-btn {
  width: 100%;
  justify-content: center;
  margin-top: 0.25rem;
  font-size: 0.875rem;
}

.scrum-success {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem;
  animation: alertSlideIn .3s ease both;
}

  .scrum-success svg {
    color: var(--clr-success-icon);
    flex-shrink: 0;
  }

  .scrum-success div {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    font-size: 0.8125rem;
  }

  .scrum-success strong {
    color: var(--clr-success-text);
    font-size: 0.875rem;
  }

  .scrum-success span {
    color: var(--text-secondary);
  }

.scrum-edit-btn {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--brand-primary);
  background: none;
  border: 1.5px solid var(--brand-primary);
  border-radius: 999px;
  padding: 0.25em 0.75em;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s, color .15s;
}

  .scrum-edit-btn:hover {
    background: var(--brand-primary);
    color: var(--brand-white);
  }

/* success badge variant */
.badge-status--success {
  background: var(--clr-success-bg);
  color: var(--clr-success-text);
  border: 1px solid var(--clr-success-border);
  border-radius: 999px;
  padding: 0.15em 0.6em;
  font-weight: 600;
}

.dark-theme .badge-status--success {
  background: var(--clr-success-bg);
  border-color: var(--clr-success-icon);
  color: var(--clr-success-text);
}

/* ════════════════════════════════════════════════════════════
   UTILITY: Visually Hidden (screen-reader only)
   ════════════════════════════════════════════════════════════ */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ════════════════════════════════════════════════════════════
   BUTTON VARIANTS: Success, Danger & Small
   ════════════════════════════════════════════════════════════ */
.btn-success {
  background: var(--clr-success-icon);
  color: var(--brand-white);
  border: none;
}

.btn-success:hover {
  background: #15803d;
  box-shadow: 0 2px 8px rgba(22, 163, 74, 0.35);
}

.btn-danger {
  background: var(--clr-critical-bg);
  color: var(--brand-white);
  border: none;
}

.btn-danger:hover {
  background: var(--clr-critical-bg, #b91c1c);
}

.btn-sm {
  padding: 0.8rem;
  font-size: 0.75rem;
}

/* Small count chip rendered inside a nav button — e.g. "My drafts (3)".
   Subtle by default; inverts on the active button so it stays legible against
   the brand-primary aria-current background. */
.btn-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.4em;
  padding: 0 0.4em;
  margin-left: 0.4em;
  height: 1.4em;
  border-radius: 999px;
  background: var(--bg-page);
  color: var(--text-secondary);
  font-size: 0.75em;
  font-weight: 600;
  line-height: 1;
}

.btn[aria-current="page"] .btn-count {
  background: rgba(255, 255, 255, 0.25);
  color: var(--brand-white);
}

/* Dashed-outline pill button used to invite adding a new chip/tag/label/etc.
   to a list. Use anywhere a "+ New X" affordance sits below a list of pills.
   align-self + width: fit-content keep it shrink-to-content even inside a
   flex-column parent (e.g. .form-field) which would otherwise stretch it. */
.btn-add-pill {
  display: inline-flex;
  align-self: flex-start;
  width: fit-content;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.5rem;
  padding: 0.25rem 0.625rem;
  border: 1px dashed var(--border-color);
  border-radius: 999px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.8125rem;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}

.btn-add-pill:hover {
  border-color: var(--brand-primary);
  color: var(--brand-primary);
}

/* Chip wrapper + reveal-on-hover edit affordance.
   Wrap any pill/chip in <span class="chip-wrap"> and add a small
   <button class="chip-edit-btn"> sibling — it floats at the top-right
   corner of the chip, hidden until the wrap is hovered/focused. */
.chip-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.chip-edit-btn {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-color);
  border-radius: 999px;
  background: var(--bg-card);
  color: var(--text-tertiary);
  cursor: pointer;
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 0.15s ease, transform 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.chip-wrap:hover .chip-edit-btn,
.chip-wrap:focus-within .chip-edit-btn {
  opacity: 1;
  transform: scale(1);
}

.chip-edit-btn:hover {
  color: var(--brand-primary);
  border-color: var(--brand-primary);
}

/* ════════════════════════════════════════════════════════════
   IMAGE CROP LAYER (collab editor)
   Body-appended by Assets/collab-editor/src/crop.js — the editor root's
   container-type would trap a fixed overlay rendered inside it, and scoped
   component CSS can't reach body-level chrome, so the classes live here.
   z-index sits above the fullscreen editor (10000) and its dialogs (10001).
   ════════════════════════════════════════════════════════════ */
.se-crop-layer {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index: 10002;
  display: flex;
  align-items: center;
  justify-content: center;
}

.se-crop-panel {
  background: var(--bg-card);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-lg);
  padding: 1rem;
  max-width: calc(100vw - 2rem);
}

.se-crop-stage {
  position: relative;
  overflow: hidden;
  margin: 0 auto;
  touch-action: none;
  /* Neutral checker so transparent-PNG edges stay visible while cropping. */
  background:
    conic-gradient(#d0d0d0 0 25%, #f2f2f2 0 50%, #d0d0d0 0 75%, #f2f2f2 0) 0 0 / 16px 16px;
}

.se-crop-img {
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

.se-crop-marquee {
  position: absolute;
  border: 1px solid var(--brand-white);
  outline: 1px dashed var(--brand-primary);
  /* Dims everything outside the marquee; clipped by the stage. */
  box-shadow: 0 0 0 100000px rgba(0, 0, 0, 0.45);
  cursor: move;
}

.se-crop-handle {
  position: absolute;
  width: 12px;
  height: 12px;
  background: var(--brand-primary);
  border: 1px solid var(--brand-white);
  border-radius: 2px;
}

.se-crop-handle--nw { top: -6px; left: -6px; cursor: nwse-resize; }
.se-crop-handle--n  { top: -6px; left: calc(50% - 6px); cursor: ns-resize; }
.se-crop-handle--ne { top: -6px; right: -6px; cursor: nesw-resize; }
.se-crop-handle--e  { top: calc(50% - 6px); right: -6px; cursor: ew-resize; }
.se-crop-handle--se { bottom: -6px; right: -6px; cursor: nwse-resize; }
.se-crop-handle--s  { bottom: -6px; left: calc(50% - 6px); cursor: ns-resize; }
.se-crop-handle--sw { bottom: -6px; left: -6px; cursor: nesw-resize; }
.se-crop-handle--w  { top: calc(50% - 6px); left: -6px; cursor: ew-resize; }

.se-crop-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.se-crop-hint {
  flex: 1 1 auto;
  font-size: 0.8rem;
  color: var(--text-tertiary);
}

/* ════════════════════════════════════════════════════════════
   DIALOG: Shared modal backdrop + panel pattern
   ════════════════════════════════════════════════════════════ */
.dialog-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  /* Modal dialogs cover ALL layout chrome — sidebar (9989), sticky page
     header (9990), and the app header (9995) — but stay below toasts and
     the loading/busy overlays (9999), which must be able to appear over an
     open dialog. The fullscreen editor (10000) uses
     .dialog-backdrop--above-editor (10001) for its own dialogs. */
  z-index: 9997;
  display: flex;
  align-items: center;
  justify-content: center;
}

.dialog-panel {
  background: var(--bg-card);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-lg);
  max-width: calc(100vw - 2rem);
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
}

.dialog-panel--sm {
  width: 480px;
}

.dialog-panel--md {
  width: 560px;
}

.dialog-panel--lg {
  width: 760px;
}

.dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.875rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
}

.dialog__title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}

.dialog__body {
  padding: 1rem 1.25rem 1.25rem;
}

/* ════════════════════════════════════════════════════════════
   PHASE BADGES
   ════════════════════════════════════════════════════════════ */

.phase-badge {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
  background: var(--bg-page);
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
}

.phase-badge--new { background: var(--clr-info-bg, #eff6ff); color: var(--clr-info-text, #2563eb); border-color: var(--clr-info-text, #2563eb); }
.phase-badge--needs-review { background: var(--clr-needs-review-bg); color: var(--clr-needs-review-text); border-color: var(--clr-needs-review-border); }
.phase-badge--active { background: var(--clr-active-bg); color: var(--clr-active-text); border-color: var(--clr-active-border); }
.phase-badge--maintenance { background: var(--clr-warning-bg, #fffbeb); color: var(--clr-warning-text, #d97706); border-color: var(--clr-warning-text, #d97706); }
.phase-badge--retiring { background: var(--clr-critical-bg, #fef2f2); color: var(--clr-critical-text, #dc2626); border-color: var(--clr-critical-text, #dc2626); }
.phase-badge--retired { background: var(--bg-page); color: var(--text-tertiary); border-color: var(--text-tertiary); }
.phase-badge--ignored { background: var(--clr-ignored-bg); color: var(--clr-ignored-text); border-color: var(--clr-ignored-border); }

/* ════════════════════════════════════════════════════════════
   LABEL PILLS
   ════════════════════════════════════════════════════════════ */

.label-pill {
  display: inline-block;
  padding: 0.0625rem 0.375rem;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 500;
  margin-right: 0.25rem;
  background: var(--bg-page);
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
}

/* Color picker input (shared) */
.form-control--color {
  width: 2rem;
  height: 2rem;
  padding: 0.125rem;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-card);
  cursor: pointer;
}

/* ════════════════════════════════════════════════════════════
   AMBIENT GLOW EFFECTS
   Background glow orbs + glass card treatment
   ════════════════════════════════════════════════════════════ */

/* Ambient glow orbs behind main content */
.main-content {
  position: relative;
  overflow: clip;
}

.main-content::before,
.main-content::after {
  content: '';
  position: fixed;
  border-radius: 50%;
  filter: blur(120px);
  pointer-events: none;
  z-index: -1;
}

.main-content::before {
  width: 500px;
  height: 500px;
  top: -5%;
  right: -8%;
  background: var(--glow-primary);
}

.main-content::after {
  width: 400px;
  height: 400px;
  bottom: -5%;
  left: 5%;
  background: var(--glow-accent);
}

/* Glass card treatment for elevated surfaces */
.dark-theme .panel,
.dark-theme .collapsible-section,
.dark-theme .dialog-panel {
  background: var(--glow-card-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-color: var(--glow-card-border);
  box-shadow: var(--glow-card-shadow);
  transition: box-shadow var(--transition), border-color var(--transition);
}

.dark-theme .panel:hover,
.dark-theme .collapsible-section:hover {
  box-shadow: 0 0 24px rgba(0, 110, 182, 0.08), 0 0 48px rgba(0, 110, 182, 0.04);
  border-color: rgba(0, 110, 182, 0.15);
}

/* Subtle glow on the sidebar in dark mode */
.dark-theme .sidebar-wrap {
  box-shadow: none;
}

/* Stronger header glow in dark mode — ::after spreads beneath sidebar */
.dark-theme .app-header {
  box-shadow: 0 1px 4px rgba(0,0,0,.5);
}

/* Header glow — on layout-shell so it covers collapse btn + main content */
.layout-shell {
  background-image: linear-gradient(to bottom, rgba(38, 24, 58, 0.03) 0%, transparent 30px);
  background-repeat: no-repeat;
}

.dark-theme .layout-shell {
  background-image: linear-gradient(to bottom, rgba(80, 80, 131, 0.274) 0%, transparent 100px);
}

/* ════════════════════════════════════════════════════════════
   GLOBAL TREE CONTROL
   Reusable hierarchical-list style with optional expand/collapse
   toggles. Used by the Handbook folder navigator and intended for
   any future nested-list UI (e.g., admin folder editors,
   org-chart-style pickers). All sizing inherits the body font so
   trees match surrounding body text by default.
   ════════════════════════════════════════════════════════════ */

/* Toolbar above a tree — expand-all / collapse-all icon buttons. */
.tree-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.25rem;
  margin-bottom: 0.25rem;
}

.tree {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Nested level — slight indent, no bullet, no extra margin. */
.tree .tree {
  padding-left: 1.25rem;
}

/* Virtual "Archived" tree sits below the real folder tree (approver/admin only).
   A thin top border + a bit of margin separates it visually so it doesn't read
   like another real top-level folder. */
.hb-archived-tree {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border-color);
}

/* Folder-picker chip — one location assignment. Used inside the New Item
   dialog and the Item-edit dialog. The "primary" variant gets a slightly
   stronger border to reinforce the star indicator. */
.hb-folder-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border-color);
  background: var(--bg-page);
  font-size: 0.875rem;
  color: var(--text-primary);
  line-height: 1;
}

.hb-folder-chip--primary {
  border-color: var(--brand-primary);
  background: var(--bg-card);
}

.hb-folder-chip__star {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--text-tertiary);
  font-size: 0.875rem;
  line-height: 1;
}

.hb-folder-chip--primary .hb-folder-chip__star {
  color: var(--brand-primary);
}

.hb-folder-chip__path {
  white-space: nowrap;
}

.hb-folder-chip__remove {
  background: none;
  border: 0;
  padding: 0 0 0 0.15rem;
  cursor: pointer;
  color: var(--text-tertiary);
  display: inline-flex;
  align-items: center;
}

.hb-folder-chip__remove:hover {
  color: var(--clr-critical-text, var(--text-primary));
}

/* "(Proposed)" badge — shown on chips and tree rows for folders that haven't
   been materialized yet. Reuses the same neutral-secondary look as other
   small status tags in the app. */
.hb-proposed-badge {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: var(--bg-page);
  border: 1px solid var(--border-color);
  color: var(--text-secondary);
  line-height: 1.2;
}

.tree-node {
  margin: 0.125rem 0;
}

/* Row that holds a toggle (or spacer) plus the label. */
.tree-row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  border-radius: var(--border-radius);
  padding: 0.125rem 0.25rem;
}

.tree-row:hover { background: var(--bg-page); }

.tree-row--selected,
.tree-row--selected:hover {
  background: var(--brand-primary);
  color: var(--brand-white);
}

.tree-row--selected .tree-row__label,
.tree-row--selected .tree-row__count { color: var(--brand-white); }

/* Square +/- toggle button. Kept on its own class so non-tree
   contexts can reuse it for any expand/collapse affordance. */
.tree-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--text-secondary);
  border-radius: 3px;
  transition: color var(--transition), background var(--transition);
}

.tree-toggle:hover {
  color: var(--text-primary);
  background: var(--nav-hover-bg);
}

.tree-row--selected .tree-toggle { color: var(--brand-white); }

/* Spacer that occupies the same width as a toggle so leaf rows
   stay vertically aligned with parent rows. */
.tree-toggle-spacer {
  display: inline-block;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

/* The clickable label part of a row. <button> styled as text. */
.tree-row__label {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  flex: 1;
  min-width: 0;
  text-align: left;
  color: inherit;
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

.tree-row__label-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Count chip after a folder name — shows item count. */
.tree-row__count {
  color: var(--text-tertiary);
  font-size: 0.85em;
  margin-left: 0.25rem;
  flex-shrink: 0;
}

/* Quick-add "+" button at the end of a tree row. Hidden until the row is
   hovered or focused (or the row itself is selected) so the tree stays
   visually quiet. Click jumps the user into the New Item dialog with the
   folder pre-selected. */
.tree-row__add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin-left: 0.25rem;
  color: var(--text-secondary);
  border-radius: 3px;
  opacity: 0;
  transition: opacity var(--transition), color var(--transition), background var(--transition);
}
.tree-row:hover .tree-row__add,
.tree-row:focus-within .tree-row__add,
.tree-row--selected .tree-row__add {
  opacity: 1;
}
.tree-row__add:hover {
  color: var(--brand-primary);
  background: var(--nav-hover-bg);
}
.tree-row--selected .tree-row__add { color: var(--brand-white); }
.tree-row--selected .tree-row__add:hover { background: rgba(255, 255, 255, 0.15); }

/* ── Team Handbook ────────────────────────────────────────── */
.hb-grid {
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 1.5rem;
}

@media (max-width: 720px) {
  .hb-grid { grid-template-columns: 1fr; }
}

.hb-sidebar {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  padding: 1rem;
  font-size: 0.875rem;
}

.hb-main {
  min-width: 0;
  font-size: 0.875rem;
}

.hb-section-title {
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 1rem 0 0.5rem;
  color: var(--text-secondary);
}

.hb-section-title:first-child { margin-top: 0; }

/* When the section title sits next to the tree toolbar buttons. */
.hb-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.hb-section-head .hb-section-title { margin: 0; }

.hb-empty {
  color: var(--text-secondary);
  padding: 1rem;
  border: 1px dashed var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-card);
}

.hb-tree {
  list-style: none;
  padding-left: 1rem;
  margin: 0;
}

.hb-tree__node { margin: 0.25rem 0; }

.hb-tree__link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  text-decoration: none;
  color: var(--text-primary);
  padding: 0.125rem 0.25rem;
  border-radius: var(--border-radius);
}

.hb-tree__link:hover { background: var(--bg-page); }

/* Roll-up count pill rendered next to each sub-folder name on the folder page.
   Shows the total published items in that branch (direct + descendants) so
   readers can gauge depth before drilling in. Hidden at zero. */
.hb-tree__count {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0 0.4rem;
  font-size: 0.75rem;
  line-height: 1.25rem;
  color: var(--text-secondary);
  background: var(--bg-page);
  border: 1px solid var(--border-color);
  border-radius: 999px;
  min-width: 1.25rem;
  text-align: center;
}

.hb-item-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0;
}

.hb-item-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border-color);
}

.hb-item-row:last-child { border-bottom: none; }

/* Title takes natural width and shrinks-with-ellipsis when the row is narrow.
   It does NOT flex-grow — leaving that job to the .hb-row-spacer immediately
   after the copy-link icon. Result: copy-link stays snug against the title
   text, and the spacer absorbs the rest of the row so the right-cluster
   (meta, badges, actions) aligns in a consistent column across rows. */
.hb-item-title {
  color: var(--text-primary);
  text-decoration: none;
  font-weight: 500;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hb-item-title:hover { text-decoration: underline; }

/* Title rendered as a <button> when the row supports an inline action
   (clicking opens an edit panel, etc.). Strip the default browser button
   chrome so it reads like the anchor variant of .hb-item-title. */
.hb-item-title--clickable {
  background: transparent;
  border: 0;
  padding: 0;
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.hb-item-title--clickable:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
  border-radius: var(--border-radius);
}

/* Empty flex-grow filler that pins everything after it to the right edge.
   Sits between the title's copy-link button and the right-cluster chips. */
.hb-row-spacer {
  flex: 1 1 0;
  min-width: 0;
}

.hb-item-meta {
  color: var(--text-secondary);
  font-size: 0.875rem;
  flex-shrink: 0;
  margin: 0;
}

/* Summary preview inside an item-row — single line with ellipsis. Allowed
   to shrink so badges / actions on the right keep their natural width;
   the title attribute on the span shows the full text on hover. */
.hb-item-row__summary {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 36rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-style: italic;
}

/* Search-results "locations" inline list: shows every folder breadcrumb the
   item lives under, separated by middle dots. Single-line with ellipsis so a
   heavily cross-listed item doesn't break the row layout; the full list shows
   on the native hover tooltip via the parent span's title attribute. */
.hb-item-row__locations {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 36rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.hb-item-row__locations-sep {
  color: var(--text-tertiary);
  margin: 0 0.25rem;
}

/* Folder-path anchors — pick up the surrounding meta color so the list stays
   visually quiet, but reveal themselves as links on hover. */
.hb-item-row__location-link {
  color: inherit;
  text-decoration: none;
}

.hb-item-row__location-link:hover,
.hb-item-row__location-link:focus-visible {
  color: var(--brand-primary);
  text-decoration: underline;
}

/* Em-dash between locations and summary when both render in the same row. */
.hb-item-row__meta-sep {
  color: var(--text-tertiary);
  flex: 0 0 auto;
}

/* Item-detail header: kind icon sits to the left and visually spans both
   the title+badge row and the owner/meta row. Used in /handbook/item/{slug}. */
.hb-item-head {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  min-width: 0;
}

.hb-item-head__icon {
  color: var(--text-secondary);
  flex-shrink: 0;
}

/* Wraps the kind icon plus its content-type pill (e.g., "Microsoft Word") so
   they stack as a single column to the left of the title + meta rows. */
.hb-item-head__icon-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.hb-content-type-pill {
  font-size: 0.7rem;
  font-weight: 600;
  padding: 0.1rem 0.45rem;
  border-radius: 4px;
  border: 1px solid transparent;
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.4;
}

.hb-item-head__text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.hb-item-head__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.hb-item-summary {
  color: var(--text-secondary);
  margin: 0.5rem 0 1rem;
}

.hb-breadcrumb {
  color: var(--text-secondary);
  font-size: 0.875rem;
  margin: 0 0 0.25rem;
}

.hb-breadcrumb a { color: var(--text-secondary); text-decoration: none; }
.hb-breadcrumb a:hover { text-decoration: underline; }

.hb-labels {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin: 0 0 1rem;
}

/* Per-section grouping on the Handbook item page (e.g. Technology). Section
   title nestles up to the chips with a tight gap, and the whole block gets a
   bit of vertical breathing room from neighboring sections. */
.hb-tech-section {
  margin: 0.5rem 0 1rem;
}
.hb-tech-section .hb-section-title {
  margin: 0 0 0.5rem;
}

/* Inline strip of selected tag pills inside the Technology section's
   collapsible header — lets users see their picks without expanding.
   Sits between the section title and the right-aligned chevron. */
.hb-tech-section__chips {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-left: 0.5rem;
  flex: 1 1 auto;
  min-width: 0;
}

.hb-tech-section__empty {
  margin-left: 0.5rem;
  flex: 1 1 auto;
  color: var(--text-tertiary);
  font-size: 0.8125rem;
  font-style: italic;
}

/* Inline "Edit Details" panel on the item page. Uses the shared
   .collapsible-section / .collapsible-section__header / .collapsible-section__body
   classes (same look as /admin/users grouping) so the disclosure styling stays
   consistent across the app. These rules are just the inner-layout bits that
   .collapsible-section__body doesn't cover — the field column gap, max-width
   so labels stay readable, and a vertical margin around the whole block. */
.hb-edit-details {
  margin: 1.25rem 0;
}

/* Single-column stack by default. On wide viewports the body switches to a
   two-column grid: text fields flow down the left column, the locations
   field (containing the folder tree picker) sits in the right column,
   row-spanning so the tree can grow tall without pushing the left-column
   text fields down. The actions row at the bottom spans both columns. */
.hb-edit-details__body {
  display: grid;
  grid-template-columns: 1fr;
  column-gap: 1.25rem;
  row-gap: 0.875rem;
  align-items: start;
}

@media (min-width: 56rem) {
  .hb-edit-details__body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .hb-edit-details__body > .form-field:has(.hb-folder-picker) {
    grid-column: 2;
    /* "1 / -1" spans from the first explicit row to the implicit last row —
       i.e., as many rows as the left column actually has, no more. The
       earlier "1 / span 99" forced 99 implicit rows; combined with the
       0.875rem row-gap between each, that produced ~85rem of phantom empty
       space below the panel. */
    grid-row: 1 / -1;
    align-self: start;
  }
}

.hb-edit-details__body > .hb-edit-details__actions {
  grid-column: 1 / -1;
}

/* Sticky action row inside Edit Details — keeps Save / Revert glued to the
   viewport bottom while the user scrolls through the field list. Lives in
   normal flow with no negative margins so the panel's natural height stays
   honest; sticking only activates when the bar would otherwise scroll out
   of view. */
.hb-edit-details__actions {
  position: sticky;
  bottom: 0;
  background: var(--bg-card);
  padding: 0.75rem 0;
  border-top: 1px solid var(--border-color);
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Inline error rendered inside the sticky bar — keeps the default
   .form-error box look but tightens the margin so the buttons sit
   right below the message without extra whitespace. */
.hb-edit-details__error {
  margin: 0;
}

/* Inline warning banner used when an item is missing something needed to
   submit/publish (e.g., no folder yet). Sits at the top of the page body
   above the action row. Distinct from .form-error which is for form
   submission failures. */
.form-warning {
  background: var(--clr-warning-bg, var(--bg-card));
  border: 1px solid var(--clr-warning-border, var(--border-color));
  color: var(--clr-warning-text, var(--text-primary));
  padding: 0.625rem 0.875rem;
  border-radius: 6px;
  margin: 1rem 0;
  font-size: 0.9rem;
}

/* Page-level error / blocked-access banner. Shows when a page can't render
   its primary content — wrong slug, missing permissions, item archived, etc.
   Use the warning palette since "you don't have access" and "not found" are
   informational, not failure-state. The actions row below gets clear breathing
   room so it doesn't visually fuse with the alert. */
.page-error {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  background: var(--clr-warning-bg, var(--bg-card));
  border: 1px solid var(--clr-warning-border, var(--border-color));
  color: var(--clr-warning-text, var(--text-primary));
  padding: 0.875rem 1rem;
  border-radius: 6px;
  font-size: 0.95rem;
  max-width: 560px;
  margin: 1rem auto;
}

.page-error::before {
  content: "!";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--clr-warning-border, var(--text-secondary));
  color: var(--bg-card);
  font-weight: 700;
  font-size: 0.85rem;
  line-height: 1;
}

.page-error__actions {
  display: flex;
  justify-content: center;
  margin-top: 0.5rem;
}

/* Inline info banner — same shape as .form-warning but in the info palette.
   Used for transient status messages on the item page (e.g., "Opening in
   Word…" auto-launch banner). Generous margin keeps the box from butting
   up against the action row above or other content below. */
.form-info {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  background: var(--clr-info-bg, var(--bg-card));
  border: 1px solid var(--clr-info-border, var(--border-color));
  color: var(--clr-info-text, var(--text-primary));
  padding: 0.625rem 0.875rem;
  border-radius: 6px;
  margin: 1rem 0;
  font-size: 0.9rem;
}

.form-info a {
  color: var(--clr-info-text, var(--brand-primary));
  text-decoration: underline;
}

/* Version-history disclosure section on the item page. Section sits below
   the action buttons. Toggle button reads like a heading; expanded list
   indents each row and uses the existing hb-status-badge variants for
   Current / Working / Approved markers. */
.hb-versions {
  margin: 1.25rem 0;
}

.hb-versions__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.hb-versions__row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.625rem 0.75rem;
  border-top: 1px solid var(--border-color);
}

.hb-versions__row:last-child {
  border-bottom: 1px solid var(--border-color);
}

.hb-versions__num {
  flex-shrink: 0;
  min-width: 2.5rem;
  font-weight: 600;
  color: var(--text-secondary);
  padding-top: 0.125rem;
}

.hb-versions__meta {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.hb-versions__meta > div { line-height: 1.4; }

.hb-versions__notes {
  font-style: italic;
}

.hb-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0;
}

.hb-status-badge {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border-radius: 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  margin-left: 0.5rem;
  border: 1px solid transparent;
}

/* All variants pair *-bg with *-text (and a matching *-border for definition).
   Earlier the rules referenced non-existent *-fg variables and fell back to
   hardcoded light-theme colors, which produced dark-on-dark text in dark mode. */

.hb-status-badge--draft {
  background: var(--bg-page);
  color: var(--text-secondary);
  border-color: var(--border-color);
}

.hb-status-badge--review {
  background: var(--clr-warning-bg);
  color: var(--clr-warning-text);
  border-color: var(--clr-warning-border);
}

.hb-status-badge--published {
  background: var(--clr-success-bg);
  color: var(--clr-success-text);
  border-color: var(--clr-success-border);
}

.hb-status-badge--declined {
  background: var(--clr-critical-bg);
  color: var(--clr-critical-text);
  border-color: var(--clr-critical-border);
}

.hb-status-badge--archived {
  background: var(--bg-page);
  color: var(--text-tertiary, var(--text-secondary));
  border-color: var(--border-color);
}

.hb-presence-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: 1rem;
  background: var(--clr-info-bg);
  color: var(--clr-info-text);
  border: 1px solid var(--clr-info-border);
  font-size: 0.75rem;
  font-weight: 500;
}

.hb-pivot-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.hb-pivot-label {
  color: var(--text-secondary);
  font-size: 0.875rem;
}

.hb-browse-group { margin: 1rem 0; }

.hb-kind-toggle { display: flex; gap: 0.375rem; }

.hb-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  padding: 1rem;
  margin-top: 1rem;
}

/* ════════════════════════════════════════════════════════════
   DRAG-AND-DROP REORDER (ReorderList + wwwroot/js/reorder.js)
   Utility classes shared by any reorderable list. Rows opt in by
   setting draggable="true" and data-reorder-id; the JS helper
   toggles .reorder-dragging on the lifted row and .reorder-over on
   the row the pointer is hovering as a drop target.
   ════════════════════════════════════════════════════════════ */
.reorder-list [draggable="true"] {
  cursor: grab;
}

.reorder-list [draggable="true"]:active {
  cursor: grabbing;
}

.reorder-dragging {
  opacity: 0.5;
}

/* Insertion indicator: a bold bar on the edge the dragged row will land against — top when it
   drops before the hovered row, bottom when it drops after. The bar tracks the cursor's half of
   the row (see reorder.js dropsAfter) so the preview always matches the actual drop position.
   Keep the full selector: reorder rows can also be surfaces with a higher-specificity hover
   shadow (for example collapsible prompt cards), and that shadow must not hide the drop bar. */
.reorder-list [data-reorder-id].reorder-over {
  box-shadow: inset 0 3px 0 0 var(--brand-primary);
}

.reorder-list [data-reorder-id].reorder-over-after {
  box-shadow: inset 0 -3px 0 0 var(--brand-primary);
}

/* The drag handle is a real <button data-reorder-handle> so it is keyboard-focusable
   and screen-reader-announced; arrow keys (and Home/End) move the row (reorder.js).
   Strip the native button chrome so it still reads as a plain grip glyph, and show a
   clear focus ring for keyboard users. */
.reorder-list [data-reorder-handle] {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
}

.reorder-list [data-reorder-handle]:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ════════════════════════════════════════════════════════════
   SHARED TO-DO LIST (MyToDosCard, AdminFollowUpToDosCard, the
   /my/todos page, and ToDoDialog). Dashboard-card chrome comes from
   .dash-card; these classes style the to-do rows and priority pills.
   Add/edit happens in ToDoDialog, so rows are read-only summaries.
   ════════════════════════════════════════════════════════════ */
.todo-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.todo-row {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 0.4rem;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  font-size: 0.8125rem;
  /* Same blue tint as an unread alert row, so to-dos read as "active" against the card
     surface in both themes. */
  background: var(--nav-active-bg);
}

.todo-row__handle {
  flex: 0 0 auto;
  cursor: grab;
  color: var(--text-tertiary);
  user-select: none;
  line-height: 1;
}

.todo-row__handle:active {
  cursor: grabbing;
}

.todo-row__check {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}

/* The clickable summary (title + priority + due) that opens the edit dialog.
   Looks like plain text, not a button. */
.todo-row__open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  color: inherit;
}

.todo-row__title {
  flex: 1 1 6rem;
  min-width: 0;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.todo-row__due-text {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--text-secondary);
}

/* A row plus its (optional) expandable read-only description panel stacked below it. */
.todo-row-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.todo-row__notes {
  flex: 0 0 auto;
}

/* Small "has instructions" indicator inside a row's clickable summary (dashboard card). */
.todo-row__note-ind {
  flex: 0 0 auto;
  color: var(--text-tertiary);
}

.todo-row__notes.is-active {
  color: var(--brand-primary);
}

/* Read-only rendered description (sanitized HTML) shown when a row's notes are expanded.
   Always-white "paper" via .html-editor-surface; this just sizes/indents it under the row. */
.todo-desc {
  margin: 0 0 0 1.75rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  font-size: 0.8125rem;
}

/* Category chip shown on a row when viewing "All" categories. */
.todo-cat-chip {
  flex: 0 0 auto;
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 0.0625rem 0.4rem;
  border-radius: 999px;
  background: var(--bg-page);
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
}

/* Pushes the category picker to the right edge of a card/list header. */
.todo-card-filter {
  margin-left: auto;
}

/* "Click to view more" link under a capped to-do list. */
.dash-card__more {
  display: inline-block;
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--brand-primary);
  text-decoration: none;
}

.dash-card__more:hover {
  text-decoration: underline;
}

/* Completed rows (on /my/todos): muted with a struck-through title. The checkbox
   stays interactive so the item can be reopened. */
.todo-row--done {
  opacity: 0.8;
}

.todo-row--done .todo-row__title {
  text-decoration: line-through;
  color: var(--text-tertiary);
}

.todo-group {
  margin-bottom: 0.75rem;
}

.todo-group__title {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin: 0 0 0.375rem;
}

/* ════════════════════════════════════════════════════════════
   ONE-ON-ONE PAGE (/my/one-on-one) — sections, tracking values,
   discussion lists, progress, and check-ins.
   ════════════════════════════════════════════════════════════ */
.oo-section {
  /* Match the dashboard card pattern: --bg-card-elevated + shadow lifts the card off the page.
     In dark mode --bg-card is nearly identical to --bg-page (cards looked flat); the elevated
     surface is lighter there, and is identical to --bg-card in light mode so that look is kept. */
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  box-shadow: var(--shadow-sm);
  padding: 1rem 1.25rem;
  margin-top: 1rem;
}

/* Header row that pairs a collapsible-section toggle with an action (add / manage) beside it,
   since the action can't live inside the header button. */
.oo-headrow {
  display: flex;
  align-items: center;
}

.oo-headrow .collapsible-section__header {
  flex: 1 1 auto;
  min-width: 0;
}

.oo-headrow__action {
  flex-shrink: 0;
  margin-right: 0.75rem;
}

/* On-campus percent beside the ComplianceBadge in the check-ins header row. Reads as meta text,
   not a third pill: the badge already carries the color, and two pills competing for attention
   made the row look like it had two separate warnings. */
.oo-compliance {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* Handbook drafts & reviews list on the one-on-one page. */
.oo-hb-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.oo-hb-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.65rem;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-inset);
}

.oo-hb-row__main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.oo-hb-row__title {
  font-weight: 600;
  color: var(--text-primary);
}

.oo-section__title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0 0 0.75rem;
}

/* Section header row: title on the left, an action (e.g. "Manage Tracked Items") on the right. */
.oo-section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

.oo-section__header .oo-section__title {
  margin: 0;
}

/* Tracked values — up to 3 columns, dropping to 2 then 1 as the section narrows.
   The max() floor sets the smallest readable cell; the calc(25% + 1px) term caps the
   count at 3 (a 4th track can never fit). Responds to the section's own width, so it
   needs no viewport breakpoints. */
.oo-tracking {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(14rem, calc(25% + 1px)), 1fr));
  gap: 0.6rem;
}

.oo-tracking__row {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-inset);
}

.oo-tracking__label {
  font-weight: 600;
  font-size: 0.8rem;
  color: var(--text-secondary);
}

.oo-tracking__value {
  min-width: 0;
  color: var(--text-primary);
}

.oo-tracking__input {
  width: 100%;
  max-width: 100%;
}

.oo-tracking__check {
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--brand-primary);
}

/* Admin-only at-a-glance indicators per tracked item: label on the left, flag icons on the right. */
.oo-tracking__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
}

.oo-tracking__flags {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
}

.oo-flag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: var(--border-radius-sm);
  border: 1px solid transparent;
}

/* Visible / developer-can-edit: positive, attention-drawing state. */
.oo-flag--on {
  color: var(--clr-info-text);
  background: var(--clr-info-bg);
  border-color: var(--clr-info-border);
}

/* Hidden from developer: quiet, de-emphasized. */
.oo-flag--off {
  color: var(--text-tertiary);
}

/* Read-only for developer: cautionary tone. */
.oo-flag--locked {
  color: var(--clr-warning-text);
  background: var(--clr-warning-bg);
  border-color: var(--clr-warning-border);
}

/* Discussion lists */
.oo-disc__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.oo-disc__header .oo-section__title {
  margin: 0;
}

.oo-disc__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.oo-disc__item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.4rem 0.65rem;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  background: var(--bg-inset);
}

/* The row wraps so the description/notes blocks can claim a full-width line, but a long title
   must not push itself onto its own line: flex-wrap decides from the hypothetical main size,
   which `flex-basis: auto` makes as wide as the un-wrapped text. Zeroing the basis keeps the
   title on the first line beside the checkbox and lets the text wrap inside its own column. */
.oo-disc__item > .oo-disc__content,
.oo-disc__item > .oo-disc__stack {
  flex-basis: 0;
}

/* The checkbox and drag handle act on the item, so they sit on the title's first line rather
   than floating at the vertical centre of a wrapped one. The date and actions stay centred. */
.oo-disc__item > .oo-disc__check,
.oo-disc__item > .oo-disc__handle {
  align-self: flex-start;
}

.oo-disc__item > .oo-disc__check {
  margin-top: 0.15rem;
}

/* Details (description) indicator + expandable rich-text block, full-width below the row. */
.oo-disc__noteind {
  flex: 0 0 auto;
  margin-top: 0.2rem;
  color: var(--text-tertiary);
}

.oo-disc__desc {
  flex: 1 1 100%;
  margin: 0.15rem 0 0;
  padding: 0.5rem 0.65rem;
  border-radius: var(--border-radius);
}

/* What-was-discussed note in the expanded block: the admin edits it inline (saves on blur),
   everyone else reads it. */
.oo-disc__notes-wrap {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-top: 0.15rem;
}

.oo-disc__notes-label {
  font-size: 0.7rem;
  color: var(--text-tertiary);
}

.oo-disc__notes {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-secondary);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Discussed-history note row: note text with the admin's edit affordance beside it. */
.oo-disc__notes-row {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
}

.oo-disc__notes-add {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  align-self: flex-start;
  padding: 0;
  border: 0;
  background: none;
  font-size: 0.75rem;
  color: var(--text-tertiary);
  cursor: pointer;
}

.oo-disc__notes-add:hover {
  color: var(--brand-primary);
}

/* Discussed-history rows: restore checkbox on the left, content over an audit meta line. */
.oo-disc__item--done {
  align-items: flex-start;
  background: var(--bg-page);
  opacity: 0.85;
}

.oo-disc__stack {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  flex: 1 1 auto;
  min-width: 0;
}

.oo-disc__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.85rem;
  font-size: 0.7rem;
  color: var(--text-tertiary);
}

/* Separate the discussed-history block from the admin discussion items above it. */
.oo-history {
  margin-top: 1rem;
}

/* Standard brand checkbox. Use `.check-input` on any <input type="checkbox">
   that should read as part of the UI (brand accent, comfortable hit size).
   `.oo-disc__check` is the original discussion/agenda alias kept for existing markup. */
.check-input,
.oo-disc__check {
  flex: 0 0 auto;
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--brand-primary);
  cursor: pointer;
}

.oo-disc__handle {
  flex: 0 0 auto;
  cursor: grab;
  color: var(--text-tertiary);
  user-select: none;
  line-height: 1.4;
}

.oo-disc__handle:active {
  cursor: grabbing;
}

.oo-disc__content {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

/* Title is a clickable affordance when the item has a rich-text description. */
.oo-disc__content--toggle {
  display: inline-flex;
  align-items: flex-start;
  gap: 0.35rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.oo-disc__content--toggle:hover {
  color: var(--brand-primary);
}

.oo-disc__content--toggle[aria-expanded="true"] .oo-disc__noteind {
  color: var(--brand-primary);
}

.oo-disc__date {
  flex: 0 0 auto;
  font-size: 0.7rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}

.oo-disc__actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  justify-content: flex-end;
}

.oo-disc__dialogactions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
  margin-top: 0.75rem;
}

/* Progress assignments use the same responsive 3→2→1 grid as the tracked-items section. */
.oo-progress {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(14rem, calc(25% + 1px)), 1fr));
  gap: 0.6rem;
}

/* Each editable assignment is grouped under its list title. */
.oo-progress__list {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 0.2rem;
}

/* ════════════════════════════════════════════════════════════
   CAPACITY OVERVIEW (cpo-*) — shared by the team Capacity Overview
   page, the reusable CapacityDetailTable, and the one-on-one
   DeveloperCapacityCard so all three render identically. Global so
   the styles reach the shared components (not scoped to one page).
   ════════════════════════════════════════════════════════════ */
.cpo-header-tools {
  display: flex;
  align-items: center;
  gap: 0.125rem;
  flex-shrink: 0;
}

.cpo-header-action {
  color: var(--text-tertiary);
}

.cpo-header-action:hover {
  color: var(--brand-primary);
}

.cpo-row:hover {
  background: var(--bg-page);
}

.cpo-row--expanded {
  background: var(--bg-page);
}

.cpo-dev-name {
  font-weight: 500;
  white-space: nowrap;
}

.cpo-dev-name__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}

.cpo-dev-name__btn:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
  border-radius: 2px;
}

.cpo-expand-icon {
  transition: transform 0.2s ease;
  color: var(--text-tertiary);
  margin-right: 0.375rem;
  vertical-align: middle;
}

.cpo-expand-icon--open {
  transform: rotate(180deg);
}

.cpo-focus {
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
  padding: 0.125rem 0;
}

.cpo-focus__name {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-primary);
}

.cpo-focus__meta {
  font-size: 0.6875rem;
  color: var(--text-tertiary);
}

.cpo-focus--sprint {
  flex-direction: row;
  align-items: baseline;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.cpo-focus--sprint .cpo-focus__name {
  color: var(--clr-needs-review-text);
}

.cpo-focus--sprint .cpo-focus__meta {
  color: var(--clr-needs-review-text);
}

.cpo-focus--upcoming {
  opacity: 0.75;
}

.cpo-focus--upcoming .cpo-focus__name::before {
  content: "↗ ";
  font-weight: 400;
}

.cpo-allocation {
  font-weight: 600;
  font-size: 0.875rem;
}

.cpo-allocation--over {
  color: var(--clr-over-capacity);
}

.cpo-score-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 60px;
}

.cpo-score {
  font-weight: 600;
  font-size: 0.875rem;
}

.cpo-score--high {
  color: var(--clr-success-text);
}

.cpo-score--mid {
  color: var(--clr-warning-text);
}

.cpo-score--low {
  color: var(--clr-over-capacity);
}

.cpo-score-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--bg-page);
  overflow: hidden;
}

.cpo-score-bar__fill {
  height: 100%;
  border-radius: 2px;
  transition: width 0.3s ease;
}

.cpo-score-bar__fill--high {
  background: var(--clr-success-text);
}

.cpo-score-bar__fill--mid {
  background: var(--clr-warning-text);
}

.cpo-score-bar__fill--low {
  background: var(--clr-over-capacity);
}

.cpo-empty {
  color: var(--text-tertiary);
  font-size: 0.8125rem;
}

.cpo-priority {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
}

.cpo-priority--urgent {
  background: var(--clr-critical-bg);
  color: var(--clr-critical-text);
}

.cpo-priority--high {
  background: var(--clr-warning-bg);
  color: var(--clr-warning-text);
}

.cpo-priority--medium {
  background: var(--clr-info-bg);
  color: var(--clr-info-text);
}

.cpo-priority--low {
  background: var(--bg-page);
  color: var(--text-secondary);
}

.cpo-frequency {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  white-space: nowrap;
}

.cpo-frequency--never {
  background: var(--bg-page);
  color: var(--text-secondary);
}

.cpo-frequency--hardly-ever {
  background: var(--clr-success-bg);
  color: var(--clr-success-text);
}

.cpo-frequency--sometimes {
  background: var(--clr-info-bg);
  color: var(--clr-info-text);
}

.cpo-frequency--often {
  background: var(--clr-warning-bg);
  color: var(--clr-warning-text);
}

.cpo-frequency--very-often {
  background: var(--clr-critical-bg);
  color: var(--clr-critical-text);
}

.cpo-finish-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.cpo-backlog {
  display: inline-block;
  width: fit-content;
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 0.0625rem 0.4rem;
  border-radius: 999px;
}

.cpo-gantt-col {
  min-width: 220px;
}

.cpo-detail-row {
  background: var(--bg-page);
}

.cpo-detail-row td {
  background: var(--bg-inset);
}

.cpo-detail-row:hover td {
  background: var(--bg-inset);
}

.cpo-detail {
  padding: 0.5rem 0.5rem 0.75rem 2rem;
}

.cpo-detail-table {
  width: 100%;
  font-size: 0.8125rem;
  border-collapse: collapse;
}

.cpo-detail-table th {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-tertiary);
  text-align: left;
  padding: 0.25rem 0.5rem;
  border-bottom: 1px solid var(--border-default, rgba(128, 128, 128, 0.15));
}

.cpo-detail-table td {
  padding: 0.3rem 0.5rem;
  color: var(--text-primary);
  font-size: 0.8125rem;
}

.cpo-detail-row--dim {
  opacity: 1;
}

.cpo-detail-row--boundary td {
  border-top: 2px solid var(--brand-primary);
}

.cpo-detail-nowi-header-row td {
  padding: 0.4rem 0.5rem;
  background: var(--bg-inset);
  border-top: 1px solid var(--border-default, rgba(128, 128, 128, 0.15));
}

.cpo-detail-nowi-header-row:hover td {
  background: var(--bg-subsection);
}

.cpo-detail-nowi-count {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.cpo-detail-nowi-breakdown {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  flex-wrap: wrap;
  margin-left: 0.375rem;
}

.cpo-detail-name-row {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}

.cpo-detail-link {
  color: var(--clr-info-text);
  text-decoration: none;
}

.cpo-detail-link:hover {
  text-decoration: underline;
}

.cpo-detail-repo {
  color: var(--text-tertiary);
  transition: color 0.15s ease;
  display: inline-flex;
}

.cpo-detail-repo:hover {
  color: var(--brand-primary);
}

.cpo-detail-subtitle {
  display: flex;
  align-items: baseline;
  gap: 0.375rem;
  font-size: 0.6875rem;
}

.cpo-detail-phase-title {
  color: var(--text-secondary);
  font-weight: 500;
  font-style: italic;
}

.cpo-detail-project {
  color: var(--text-tertiary);
}

.cpo-detail-notes {
  display: block;
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  font-style: italic;
  margin-top: 0.125rem;
}

.cpo-detail-codev {
  font-size: 0.625rem;
  font-weight: 500;
  color: var(--text-secondary);
  background: var(--bg-page);
  border-radius: 999px;
  padding: 0.0625rem 0.375rem;
  white-space: nowrap;
}
