:root {
    /* Apple-like Light Theme */
    --primary: #dc2626; /* Unidan Red */
    --primary-hover: #b91c1c;
    --bg-body: #f5f5f7; /* Classic Apple light gray */
    --surface: #ffffff; /* Clean white cards */
    --surface-hover: #fcfcfc;
    --border: rgba(0, 0, 0, 0.08);
    --text-main: #1d1d1f; /* Apple typography dark */
    --text-muted: #86868b;
    --success: #34c759;
    --error: #ff3b30;
    --danger: #dc2626; /* Destructive-action red — slightly deeper than --error so "delete/reset" buttons read as a different state from general error chrome. */
    --warning: #ffcc00;
    --radius-sm: 8px;
    --radius-md: 14px;
    --radius-lg: 20px;
    --transition: all 0.3s cubic-bezier(0.25, 1, 0.5, 1);
    --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.04);
    --shadow-md: 0 8px 16px rgba(0, 0, 0, 0.06);
    --bg-muted: #f9fafb; /* Subtle muted-surface background for read-only/display rows */

    /* Status palette — semantic state colours for metric tiles, capacity/meter
       bars, performance badges and status chips. Each state has a foreground
       (-text-readable solid), a subtle tint background and a matching border so
       UI can show "good / warning / bad / info / neutral" states consistently
       and theme cleanly in dark mode (remapped under body.dark-mode below).
       Introduced for the Departments redesign; reusable app-wide so future
       pages stop hardcoding #059669 / #fef2f2 / #1e5bc6 / #e5e7eb etc. */
    --stat-good: #059669;    --stat-good-bg: #ecfdf5;    --stat-good-border: #a7f3d0;
    --stat-warn: #d97706;    --stat-warn-bg: #fff7ed;    --stat-warn-border: #fdba74;
    --stat-bad: #dc2626;     --stat-bad-bg: #fef2f2;     --stat-bad-border: #fecaca;
    --stat-info: #1e5bc6;    --stat-info-bg: #eff6ff;    --stat-info-border: #bfdbfe;
    --stat-neutral: #6b7280; --stat-neutral-bg: #f3f4f6; --stat-neutral-border: rgba(0,0,0,0.08);
    --track: #e5e7eb; /* progress / meter bar track */
}

/* Dark Mode */
body.dark-mode {
    --bg-body: #0d1117;
    --surface: #161b22;
    --surface-hover: #1c2129;
    --border: rgba(255, 255, 255, 0.1);
    --text-main: #e6edf3;
    --text-muted: #8b949e;
    --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 8px 16px rgba(0, 0, 0, 0.4);
    --bg-muted: #1e2227; /* Dark-mode equivalent of muted-surface */

    /* Status palette — dark-mode remap. Foregrounds lighten for contrast on the
       dark surface; tints/borders become translucent so they sit on any bg. */
    --stat-good: #34d399;    --stat-good-bg: rgba(16,185,129,0.12);  --stat-good-border: rgba(16,185,129,0.32);
    --stat-warn: #fbbf24;    --stat-warn-bg: rgba(217,119,6,0.14);   --stat-warn-border: rgba(217,119,6,0.34);
    --stat-bad: #f87171;     --stat-bad-bg: rgba(220,38,38,0.14);    --stat-bad-border: rgba(220,38,38,0.34);
    --stat-info: #60a5fa;    --stat-info-bg: rgba(59,130,246,0.14);  --stat-info-border: rgba(59,130,246,0.34);
    --stat-neutral: #9ca3af; --stat-neutral-bg: rgba(255,255,255,0.06); --stat-neutral-border: rgba(255,255,255,0.12);
    --track: rgba(255,255,255,0.13);
}

/* Sidebar */
body.dark-mode .sidebar { background: #0d1117; border-right-color: rgba(255,255,255,0.06); }
body.dark-mode .sidebar.collapsed .nav-section:hover > .nav-section-items {
    background: #161b22;
    border-color: rgba(255,255,255,0.1);
    box-shadow: 0 4px 16px rgba(0,0,0,0.5);
}
body.dark-mode .card { background: var(--surface); }

/* Inputs */
body.dark-mode input, body.dark-mode select, body.dark-mode textarea { background: #0d1117; color: var(--text-main); border-color: rgba(255,255,255,0.12); }
body.dark-mode input:focus, body.dark-mode select:focus, body.dark-mode textarea:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(249,115,22,0.2); }

/* Tables */
body.dark-mode table th { background: #161b22 !important; color: var(--text-muted) !important; }
body.dark-mode table tr { border-bottom-color: rgba(255,255,255,0.06) !important; }
body.dark-mode tr[style*="background: #fafafa"], body.dark-mode tr[style*="background:#fafafa"] { background: #161b22 !important; }

/* Buttons */
body.dark-mode .btn-secondary { background: #21262d; color: var(--text-main); border-color: rgba(255,255,255,0.12); }
body.dark-mode .btn-secondary:hover { background: #30363d; }

/* Nav */
body.dark-mode .nav-item:hover { background: rgba(255,255,255,0.06); }
body.dark-mode .nav-item.active { background: linear-gradient(135deg, #dc2626 0%, #f87171 100%); color: #fff; }

/* Modals */
body.dark-mode .modal-overlay { background: rgba(0,0,0,0.7); }
body.dark-mode .modal { background: var(--surface); }

/* Mobile topbar */
body.dark-mode #mobile-topbar { background: #0d1117; border-bottom-color: rgba(255,255,255,0.06); }

/* Placeholders */
body.dark-mode ::placeholder { color: #484f58; }

/* Leadership announcement card */
body.dark-mode .card[style*="border-left: 4px solid var(--success)"] { background: rgba(52,199,89,0.06) !important; }

/* Dashboard Today's Tasks card header */
body.dark-mode .card-header[style*="#fffdf5"] { background: rgba(217,119,6,0.08) !important; border-bottom-color: rgba(253,230,138,0.15) !important; }
body.dark-mode .card-header[style*="#fffdf5"] .card-title { color: #fbbf24 !important; }

/* All hardcoded #fafafa backgrounds (filter bars, table headers, chat areas, etc.) */
body.dark-mode [style*="background: #fafafa"], body.dark-mode [style*="background:#fafafa"] { background: #161b22 !important; }
body.dark-mode [style*="background: #fdfdfd"], body.dark-mode [style*="background:#fdfdfd"] { background: var(--surface) !important; }
body.dark-mode [style*="background: #f9fafb"], body.dark-mode [style*="background:#f9fafb"] { background: #0d1117 !important; }
body.dark-mode [style*="background: #f0f9ff"], body.dark-mode [style*="background:#f0f9ff"] { background: rgba(59,130,246,0.08) !important; }
body.dark-mode [style*="background: #f0fdf4"], body.dark-mode [style*="background:#f0fdf4"] { background: rgba(16,185,129,0.08) !important; }
body.dark-mode [style*="background: #eff6ff"], body.dark-mode [style*="background:#eff6ff"] { background: rgba(59,130,246,0.06) !important; }
body.dark-mode [style*="background: #ecfdf5"], body.dark-mode [style*="background:#ecfdf5"] { background: rgba(16,185,129,0.1) !important; }
body.dark-mode [style*="background: #fef2f2"], body.dark-mode [style*="background:#fef2f2"] { background: rgba(220,38,38,0.1) !important; }
body.dark-mode [style*="background: #fefce8"], body.dark-mode [style*="background:#fefce8"] { background: rgba(245,158,11,0.08) !important; }
body.dark-mode [style*="background: #fff7ed"], body.dark-mode [style*="background:#fff7ed"] { background: rgba(249,115,22,0.08) !important; }

/* Sub-nav / tab bars */
body.dark-mode .sub-nav-item { color: var(--text-muted); }
body.dark-mode .sub-nav-item.active { color: var(--primary); }

/* Scrollbar */
body.dark-mode ::-webkit-scrollbar { width: 8px; height: 8px; }
body.dark-mode ::-webkit-scrollbar-track { background: #0d1117; }
body.dark-mode ::-webkit-scrollbar-thumb { background: #30363d; border-radius: 4px; }
body.dark-mode ::-webkit-scrollbar-thumb:hover { background: #484f58; }

/* Generic confirm modal */
body.dark-mode .gcm-border { background: var(--surface) !important; }
body.dark-mode .gcm-title { color: var(--text-main) !important; }
body.dark-mode .gcm-message { color: var(--text-muted) !important; }

/* Part editor modal & catalogue items */
body.dark-mode #create-part-modal > .card { background: var(--surface) !important; }
body.dark-mode .part-row:hover { background: #21262d !important; }
body.dark-mode [style*="background: white"], body.dark-mode [style*="background:white"] { background: var(--surface) !important; }
body.dark-mode .sched-top-tab { color: var(--text-muted) !important; }
body.dark-mode [style*="border-bottom: 2px solid var(--border)"] { border-bottom-color: rgba(255,255,255,0.06) !important; }
body.dark-mode [style*="border-left: 2px solid var(--border)"] { border-left-color: rgba(255,255,255,0.06) !important; }
body.dark-mode [style*="border: 1px dashed var(--border)"] { border-color: rgba(255,255,255,0.1) !important; }

/* Content area */
body.dark-mode .content { background: var(--bg-body); }

/* --- Brainstorming hub: dark mode overrides for inline pastel callouts ---
   The brainstorms page uses a lot of hardcoded amber / violet pastel
   backgrounds with dark text. On dark mode the dark text either clashes
   with `var(--text-main)` (white) or the bright pastel bg looks alien
   against the dark page surface. These rules retint the worst offenders. */

/* Amber / yellow callouts (description box, welcome banner, "no posts" empty state, recording warning).
   We retint just the parent — descendants with explicit dark amber text are
   handled by the `color:#92400e` rule below, which also remaps them to a
   readable amber. Keeping the descendant override narrow avoids stomping on
   buttons / badges that nest inside these callouts. */
body.dark-mode [style*="background:#fffbeb"],
body.dark-mode [style*="background: #fffbeb"] {
    background: rgba(217,119,6,0.12) !important;
    color: #fbbf24 !important;
}
body.dark-mode [style*="background:#fef3c7"],
body.dark-mode [style*="background: #fef3c7"] {
    background: rgba(217,119,6,0.18) !important;
    color: #fbbf24 !important;
}

/* Violet callouts (recording panel, no-meetings state, AI hint, mic dashed box) */
body.dark-mode [style*="background:#f5f3ff"],
body.dark-mode [style*="background: #f5f3ff"],
body.dark-mode [style*="background:#faf5ff"],
body.dark-mode [style*="background: #faf5ff"] {
    background: rgba(124,58,237,0.12) !important;
}
body.dark-mode [style*="background:#ede9fe"],
body.dark-mode [style*="background: #ede9fe"] {
    background: rgba(124,58,237,0.22) !important;
    color: #c4b5fd !important;
}

/* Blue file-block preview */
body.dark-mode [style*="background:#f0f7ff"],
body.dark-mode [style*="background: #f0f7ff"] {
    background: rgba(59,130,246,0.12) !important;
}

/* Red recording-active panel */
body.dark-mode [style*="background:#fef2f2"],
body.dark-mode [style*="background: #fef2f2"] {
    background: rgba(220,38,38,0.12) !important;
}

/* Teal to-do list panel (renderBlock + renderPinnedBlockCompact todo bodies)
   — without this override the very light #f0fdfa wash is barely distinguishable
   from the card surface in dark mode, and the dark teal title/progress text
   (#134e4a / #0f766e) disappears against it. */
body.dark-mode [style*="background:#f0fdfa"],
body.dark-mode [style*="background: #f0fdfa"] {
    background: rgba(13,148,136,0.14) !important;
}
/* Teal progress track (behind the fill bar) */
body.dark-mode [style*="background:#ccfbf1"],
body.dark-mode [style*="background: #ccfbf1"] {
    background: rgba(13,148,136,0.25) !important;
}

/* Pink voice-note / audio panel */
body.dark-mode [style*="background:#fdf2f8"],
body.dark-mode [style*="background: #fdf2f8"] {
    background: rgba(190,24,93,0.12) !important;
}

/* Pinned-block warm cream bg (blk.pinned highlight on bb-block) */
body.dark-mode [style*="background:#fffdf4"],
body.dark-mode [style*="background: #fffdf4"] {
    background: rgba(217,119,6,0.08) !important;
}

/* Inline text colours that vanish on a dark surface */
body.dark-mode [style*="color:#92400e"],
body.dark-mode [style*="color: #92400e"] { color: #fbbf24 !important; }
body.dark-mode [style*="color:#5b21b6"],
body.dark-mode [style*="color: #5b21b6"] { color: #c4b5fd !important; }
body.dark-mode [style*="color:#7c3aed"],
body.dark-mode [style*="color: #7c3aed"] { color: #a78bfa !important; }
body.dark-mode [style*="color:#1e5bc6"],
body.dark-mode [style*="color: #1e5bc6"] { color: #60a5fa !important; }
body.dark-mode [style*="color:#7f1d1d"],
body.dark-mode [style*="color: #7f1d1d"] { color: #fca5a5 !important; }
body.dark-mode [style*="color:#dc2626"],
body.dark-mode [style*="color: #dc2626"] { color: #f87171 !important; }
body.dark-mode [style*="color:#9ca3af"],
body.dark-mode [style*="color: #9ca3af"] { color: #6b7280 !important; }
/* Dark teal to-do text (title + progress count) — both versions have
   #134e4a title and #0f766e count; they're near-black on teal so they
   die on the retinted dark-teal panel. */
body.dark-mode [style*="color:#134e4a"],
body.dark-mode [style*="color: #134e4a"] { color: #5eead4 !important; }
body.dark-mode [style*="color:#0f766e"],
body.dark-mode [style*="color: #0f766e"] { color: #5eead4 !important; }
/* Dark pink voice-note label */
body.dark-mode [style*="color:#9d174d"],
body.dark-mode [style*="color: #9d174d"] { color: #f9a8d4 !important; }

/* Pin wall canvas dot grid is too bright on dark mode */
body.dark-mode #bb-pinwall-canvas {
    background-image: radial-gradient(circle, rgba(255,255,255,0.08) 1px, transparent 1px) !important;
}
/* Pin wall empty-state placeholder gray-on-dark is invisible */
body.dark-mode #bb-pinwall div[style*="color:#9ca3af"] { color: #6b7280 !important; }

/* Cover stage placeholder bg */
body.dark-mode #bb-cover-stage { background: #21262d !important; }

/* Cover-overlay pill buttons (Back, Follow, kebab) sit on top of the board
   cover image. The inline style hardcodes a white pill bg with
   `var(--text-main)` text — in dark mode the text flips to white → invisible
   on the white pill. Rather than force dark text (which dies on dark covers),
   we swap the pill to a solid dark-translucent backdrop with white text in
   dark mode. This reads on BOTH light and dark cover artwork.
   `.bb-star-btn` (hub list card follow star) matches the same pattern —
   dark-translucent circle with light star — so it's consistent with the
   board-header look and reads on dark card covers in dark mode. */
body.dark-mode #bb-back,
body.dark-mode #bb-star,
body.dark-mode #bb-menu-toggle,
body.dark-mode .bb-star-btn {
    background: rgba(30,30,30,0.78) !important;
    color: #f5f5f7 !important;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45) !important;
}

/* Kebab-menu dropdown items (#bb-edit-board, #bb-archive, #bb-cover-edit,
   #bb-cover-remove, #bb-link-job, #bb-unlink-job, #bb-delete) live INSIDE
   the #bb-menu panel which already uses `var(--surface)` → flips dark in
   dark mode. Their inline `color:var(--text-main)` already adapts, so no
   override needed. (An earlier revision forced #1d1d1f on these, making
   dark text on the dark dropdown — that's been removed.)
   Exception: #bb-delete hardcodes `color:#b91c1c` inline (dark red) for
   danger-item visual weight. On the dark dropdown surface (#161b22) that
   red is too low-contrast to read, so we bump it to a lighter red in
   dark mode. */
body.dark-mode #bb-menu #bb-delete { color: #f87171 !important; }

/* AI Summary gradient strip — keep the warm vibe but darken the canvas */
body.dark-mode [style*="linear-gradient(135deg,#f0f9ff"] {
    background: linear-gradient(135deg, rgba(59,130,246,0.12) 0%, rgba(217,119,6,0.15) 100%) !important;
}

/* =====================================================================
   Cross-module dark-mode retints — covers inline pastels used by many
   modules (planner, jobs, scheduling, dashboard, people, feedback).
   All use the same [style*="..."] attribute-selector approach as the
   brainstorm-hub retints above so we don't need markup changes.
   ===================================================================== */

/* Pale-pink delete-button bg (#ffeff3 + #ef4444/#ff4d4d/#dc2626 text)
   — used for Delete buttons in jobs cost-centre rows, planner project/
   task rows, chat Delete, scheduling deletes. Inline dark-red text on
   pale pink reads fine in light mode but the pink looks alien on dark
   surfaces and the text loses contrast. Retint to a dark-red tinted
   translucent bg that sits happily on #161b22. */
body.dark-mode [style*="background:#ffeff3"],
body.dark-mode [style*="background: #ffeff3"] {
    background: rgba(239,68,68,0.12) !important;
}
body.dark-mode [style*="color:#ff4d4d"],
body.dark-mode [style*="color: #ff4d4d"] { color: #fca5a5 !important; }
body.dark-mode [style*="color:#ef4444"],
body.dark-mode [style*="color: #ef4444"] { color: #fca5a5 !important; }
body.dark-mode [style*="color:#e00000"],
body.dark-mode [style*="color: #e00000"] { color: #fca5a5 !important; }

/* Pale-red banner / icon-circle bg (#fef2f2) and border (#fecaca / #fca5a5)
   — used by scheduling gantt overdue state, planner overdue prompt,
   QA failure modals, feedback delete buttons, attendance icons. The
   `#fef2f2` rule already exists above (rgba(220,38,38,0.1)); this adds
   the #fecaca panel variant (used for OVERDUE on scheduling gantt). */
body.dark-mode [style*="background:#fecaca"],
body.dark-mode [style*="background: #fecaca"] {
    background: rgba(239,68,68,0.35) !important;
}

/* Pale-gray progress track / chip bg (#e5e7eb and #f3f4f6)
   — used as the empty portion of budget bars (jobs.js, scheduling.js,
   people.js, materials.js), attendance icon circle, planner read-only
   notice, chip backgrounds. On dark mode #e5e7eb almost blends with
   white (nearly invisible) and #f3f4f6 on a dark card reads backwards
   (dark card, even-lighter strip). Retint both to neutral translucent. */
body.dark-mode [style*="background:#e5e7eb"],
body.dark-mode [style*="background: #e5e7eb"] {
    background: rgba(255,255,255,0.08) !important;
}
body.dark-mode [style*="background:#f3f4f6"],
body.dark-mode [style*="background: #f3f4f6"] {
    background: rgba(255,255,255,0.06) !important;
}
/* Gray text on those chip/badge backgrounds (#4b5563, #6b7280) — becomes
   muted on dark. Bump to text-muted-friendly tone. */
body.dark-mode [style*="color:#4b5563"],
body.dark-mode [style*="color: #4b5563"] { color: #9ca3af !important; }

/* Pale-green success panel bg (#dcfce7, #ecfdf5 already handled)
   — used by leave-type Annual chip legend swatches, materials NEW badge
   panels, sop complete circle. */
body.dark-mode [style*="background:#dcfce7"],
body.dark-mode [style*="background: #dcfce7"] {
    background: rgba(16,185,129,0.18) !important;
}

/* Pale-blue info panel bg (#dbeafe, #eff6ff already handled)
   — used by scheduling SOP badge, feedback attach-count icon chip. */
body.dark-mode [style*="background:#dbeafe"],
body.dark-mode [style*="background: #dbeafe"] {
    background: rgba(59,130,246,0.18) !important;
}

/* Pale-violet board-pill bg (#faf5ff) — used by planner project board
   pill, brainstorm meeting-modal board preview, index.html board-selected
   pills. Kept low-opacity so it still reads as "link to board". */
body.dark-mode [style*="background:#faf5ff"],
body.dark-mode [style*="background: #faf5ff"] {
    background: rgba(124,58,237,0.12) !important;
}

/* Amber-yellow warning banner bgs (#fef9c3, #fef3c7 already handled)
   — used for planner/task overdue reason prompt. */
body.dark-mode [style*="background:#fef9c3"],
body.dark-mode [style*="background: #fef9c3"] {
    background: rgba(245,158,11,0.14) !important;
}

/* Pale-green workview log-hours bar (#f0fdf4 already handled as 0.08)
   — keep it. Pale-blue leave-balance preview (#f0f9ff already handled). */

/* Amber hex text (#b45309, #d97706, #c2410c) — these are dark-amber
   label colours used on amber pastel backgrounds (todo list header,
   SOP pause buttons, worker notes). On dark mode the amber text should
   brighten to match the retinted bg. */
body.dark-mode [style*="color:#b45309"],
body.dark-mode [style*="color: #b45309"] { color: #fbbf24 !important; }
body.dark-mode [style*="color:#9a3412"],
body.dark-mode [style*="color: #9a3412"] { color: #fdba74 !important; }
body.dark-mode [style*="color:#991b1b"],
body.dark-mode [style*="color: #991b1b"] { color: #fca5a5 !important; }
body.dark-mode [style*="color:#b91c1c"],
body.dark-mode [style*="color: #b91c1c"] { color: #fca5a5 !important; }
body.dark-mode [style*="color:#1e40af"],
body.dark-mode [style*="color: #1e40af"] { color: #93c5fd !important; }
body.dark-mode [style*="color:#6d28d9"],
body.dark-mode [style*="color: #6d28d9"] { color: #c4b5fd !important; }

/* Dashboard follow-board pill + related white-translucent pills — same
   pattern as brainstorm .bb-star-btn. rgba(255,255,255,0.92) pill with
   hardcoded dark text (#1d1d1f) sits on top of a board cover image; in
   dark mode the surface flips white → light text dies on white. Swap to
   dark-translucent pill with light text, mirroring the .bb-star-btn
   override above. */
body.dark-mode .dash-board-unstar-btn {
    background: rgba(30,30,30,0.78) !important;
    color: #f5f5f7 !important;
    box-shadow: 0 2px 8px rgba(0,0,0,0.45) !important;
}

/* Static CSS-rule backgrounds that have no dark-mode companion ─────────
   These are targeted by class, not inline style, so the attribute-selector
   approach above doesn't reach them. Each needs an explicit override. */

/* Rectification box (#fff5f5 pale pink panel with dark-red border) */
body.dark-mode .rectification-box { background: rgba(239,68,68,0.1); }

/* Timesheet scroll container (#fff) — wraps planner-week-grid */
body.dark-mode .ts-scroll-container { background: var(--surface); }

/* Log entry separator uses rgba(0,0,0,0.05) → invisible on dark mode */
body.dark-mode .log-entry { border-bottom-color: rgba(255,255,255,0.05); }

/* Log-entry info text (#0066cc) is dark blue — bump to brighter blue */
body.dark-mode .log-entry.info { color: #60a5fa; }

/* Dark Mode Toggle */
.dm-toggle {
    display: flex;
    align-items: center;
    cursor: pointer;
    user-select: none;
}
.dm-toggle input { display: none; }
.dm-track {
    position: relative;
    width: 48px;
    height: 26px;
    background: #fef3c7;
    border: 1px solid #fde68a;
    border-radius: 13px;
    transition: all 0.4s;
    display: flex;
    align-items: center;
}
.dm-thumb {
    position: absolute;
    left: 2px;
    width: 22px;
    height: 22px;
    background: #fbbf24;
    border-radius: 50%;
    transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.4s, box-shadow 0.4s;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 0 8px rgba(251,191,36,0.4), 0 1px 3px rgba(0,0,0,0.15);
    z-index: 1;
}
.dm-icon-sun { color: #fff; display: block; }
.dm-icon-moon { color: #1e1b4b; display: none; }
/* Dark mode: night sky track with stars */
.dm-toggle input:checked + .dm-track {
    background-color: #1e3a5f;
    border-color: #2d5a8e;
    background-image:
        radial-gradient(1px 1px at 5px 6px, #fff 50%, transparent 50%),
        radial-gradient(1px 1px at 13px 18px, #fff 50%, transparent 50%),
        radial-gradient(1px 1px at 9px 4px, rgba(255,255,255,0.8) 50%, transparent 50%),
        radial-gradient(1px 1px at 18px 8px, #fff 50%, transparent 50%),
        radial-gradient(1px 1px at 3px 20px, rgba(255,255,255,0.7) 50%, transparent 50%),
        radial-gradient(1px 1px at 21px 15px, rgba(255,255,255,0.85) 50%, transparent 50%),
        radial-gradient(1px 1px at 7px 13px, #fff 50%, transparent 50%),
        radial-gradient(1px 1px at 16px 3px, rgba(255,255,255,0.75) 50%, transparent 50%),
        radial-gradient(1px 1px at 2px 11px, rgba(255,255,255,0.65) 50%, transparent 50%),
        radial-gradient(1px 1px at 11px 22px, #fff 50%, transparent 50%);
}
.dm-toggle input:checked + .dm-track .dm-thumb {
    transform: translateX(22px);
    background: #e0e7ff;
    box-shadow: 0 0 10px rgba(224,231,255,0.6), 0 1px 3px rgba(0,0,0,0.2);
}
.dm-toggle input:checked + .dm-track .dm-icon-sun { display: none; }
.dm-toggle input:checked + .dm-track .dm-icon-moon { display: block; }
.sidebar.collapsed .dm-toggle { display: none; }

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
    background-color: var(--bg-body);
    color: var(--text-main);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Layout */
.app-container {
    display: flex;
    height: 100vh;
    width: 100vw;
    overflow: hidden;
}

/* Sidebar */
.sidebar {
    width: 260px;
    background: var(--surface);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    padding: 1.5rem;
    z-index: 10;
}

.logo-container {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 2.5rem;
}

.logo {
    max-width: 160px;
    height: auto;
}

/* Theme-aware logo: show black in light mode, white in dark mode */
.logo-themed .logo-white { display: none; }
.logo-themed .logo-black { display: inline-block; }
body.dark-mode .logo-themed .logo-black { display: none; }
body.dark-mode .logo-themed .logo-white { display: inline-block; }

.nav-menu {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    /* Let the nav list flex to fill remaining sidebar height and scroll
       when permissions reveal more items than fit. min-height: 0 is needed
       because flex children default to min-height: auto which would ignore
       overflow. .sidebar-bottom keeps margin-top:auto so it stays pinned. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    /* Small negative margin so the scrollbar sits flush with sidebar padding
       rather than creating a visible gutter. */
    margin-right: -0.5rem;
    padding-right: 0.5rem;
    /* Thin scrollbar (Firefox + WebKit). Matches the muted aesthetic used
       by .feedback-modal-scroll — no new theme invented. */
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 0, 0, 0.18) transparent;
}
.nav-menu::-webkit-scrollbar {
    width: 6px;
}
.nav-menu::-webkit-scrollbar-track {
    background: transparent;
}
.nav-menu::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.18);
    border-radius: 999px;
}
.nav-menu::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 0, 0, 0.32);
}
body.dark-mode .nav-menu {
    scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
}
body.dark-mode .nav-menu::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.18);
}
body.dark-mode .nav-menu::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, 0.32);
}
/* Collapsed sidebar: flyout submenus escape the sidebar via overflow:visible
   on the sidebar itself. The scrolling nav-menu would clip those flyouts,
   so in collapsed state we disable overflow and let content stack (the
   icon-only layout is short enough to never overflow in practice). */
.sidebar.collapsed .nav-menu {
    overflow: visible;
    margin-right: 0;
    padding-right: 0;
}

.nav-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.6rem 0.9rem;
    color: var(--text-main);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.92rem;
    letter-spacing: -0.005em;
    border-radius: 10px;
    transition: background 0.25s ease, color 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease;
    overflow: hidden;
    /* In the scrollable .nav-menu flex column, children would otherwise
       flex-shrink to fit and visibly compress the pinned Dashboard /
       Task Planner rows when every section is expanded. Lock natural
       height so the scroll container is the only thing that gives. */
    flex-shrink: 0;
}

.nav-item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 20%;
    bottom: 20%;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: #ef4444;
    opacity: 0;
    transform: scaleY(0.4);
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.nav-item .icon {
    transition: transform 0.25s ease, color 0.25s ease;
    flex-shrink: 0;
}

.nav-item:hover {
    background: rgba(0, 0, 0, 0.04);
    transform: translateX(2px);
}

.nav-item:hover .icon {
    color: #ef4444;
    transform: scale(1.08);
}

.nav-item.active {
    background: linear-gradient(135deg, #dc2626 0%, #f87171 100%);
    color: #fff;
    box-shadow: 0 6px 16px -6px rgba(220, 38, 38, 0.55), inset 0 1px 0 rgba(255,255,255,0.15);
    transform: translateX(0);
}

.nav-item.active::before {
    opacity: 0;
}

.nav-item.active .icon {
    color: #fff;
    transform: scale(1.05);
}

body.dark-mode .nav-item:hover {
    background: rgba(255, 255, 255, 0.06);
}

body.dark-mode .nav-item.active {
    box-shadow: 0 6px 18px -6px rgba(220, 38, 38, 0.7), inset 0 1px 0 rgba(255,255,255,0.12);
}

.icon {
    width: 17px;
    height: 17px;
}

.nav-dept-separator {
    height: 1px;
    background: linear-gradient(to right, transparent, var(--border) 20%, var(--border) 80%, transparent);
    margin: 0.65rem 0.5rem;
    opacity: 0.8;
    border: none;
}

/* --- Collapsible Sidebar Sections --- */
.nav-section {
    margin-top: 0.15rem;
    /* Same reason as .nav-item: keep natural height so the .nav-menu scroll
       container absorbs overflow instead of flex-compressing the section
       headers + their items. */
    flex-shrink: 0;
}
.nav-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem 0.25rem;
    cursor: pointer;
    user-select: none;
    border-top: 1px solid var(--border);
}
.nav-section-label {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    font-weight: 700;
    line-height: 1;
}
.nav-section-chevron {
    color: var(--text-muted);
    flex-shrink: 0;
    transition: transform 0.2s ease;
    transform: rotate(90deg); /* expanded state: pointing down */
}
.nav-section.collapsed .nav-section-chevron {
    transform: rotate(0deg); /* collapsed state: pointing right */
}
.nav-section-items {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    pointer-events: none;
}
.nav-section.expanded > .nav-section-items {
    max-height: 500px;
    opacity: 1;
    pointer-events: auto;
    transition: max-height 0.25s ease, opacity 0.2s ease;
}
.nav-section.collapsed .nav-section-items {
    max-height: 0;
    opacity: 0;
    pointer-events: none;
    transition: max-height 0.25s ease, opacity 0.2s ease;
}

/* Bottom pinned separator */
.nav-bottom-separator {
    height: 1px;
    background: linear-gradient(to right, transparent, var(--border) 20%, var(--border) 80%, transparent);
    margin: 0.25rem 0.5rem 0.5rem;
    opacity: 0.8;
}

/* Collapsed sidebar: hide section labels + chevrons, keep items icon-only */
.sidebar.collapsed .nav-section-header {
    justify-content: center;
    padding: 0.5rem 0 0.15rem;
    border-top-color: var(--border);
}
.sidebar.collapsed .nav-section-label {
    display: none;
}
.sidebar.collapsed .nav-section-chevron {
    display: none;
}
.sidebar.collapsed .nav-bottom-separator {
    margin: 0.25rem 0.15rem 0.35rem;
}

/* Mobile open: restore section headers to expanded layout */
.sidebar.open .nav-section-header,
.sidebar.open.collapsed .nav-section-header {
    justify-content: space-between !important;
    padding: 0.75rem 1rem 0.25rem !important;
}
.sidebar.open .nav-section-label,
.sidebar.open.collapsed .nav-section-label {
    display: inline !important;
}
.sidebar.open .nav-section-chevron,
.sidebar.open.collapsed .nav-section-chevron {
    display: inline !important;
}
.sidebar.open .nav-section.expanded > .nav-section-items,
.sidebar.open.collapsed .nav-section.expanded > .nav-section-items {
    max-height: 500px !important;
    opacity: 1 !important;
    pointer-events: auto !important;
    gap: 0.2rem !important;
}
.sidebar.open .nav-section-items,
.sidebar.open.collapsed .nav-section-items {
    gap: 0.2rem !important;
}

/* --- Section Header Icons --- */
.nav-section-icon {
    width: 16px;
    height: 16px;
    color: var(--text-muted);
    flex-shrink: 0;
}
.nav-section-header {
    gap: 0.4rem;
    position: relative;
}

/* Notification dot on a section header. Set by _refreshSectionNotificationDots()
   in app.js — which toggles .has-notifications on the section whenever any
   child .nav-badge is visible. The dot only shows when the user can't see
   the item-level badges: either the section is collapsed (items hidden) or
   the whole sidebar is in icon-only collapsed mode (items hidden behind a
   hover flyout). Expanded section + expanded sidebar = item badges are
   already visible, so the section-level dot would be redundant. */
.nav-section.has-notifications > .nav-section-header::after {
    content: '';
    position: absolute;
    top: 0.55rem;
    right: 0.55rem;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    box-shadow: 0 0 0 2px var(--surface);
    display: none;
}
.nav-section.has-notifications.collapsed > .nav-section-header::after {
    display: block;
}
.sidebar.collapsed .nav-section.has-notifications > .nav-section-header::after {
    display: block;
    top: 0.25rem;
    right: 0.25rem;
}
/* Mobile open sidebar uses its own expanded layout and force-shows section
   items — hide the section dot in that mode so it doesn't double up with
   the individual item badges below. */
.sidebar.open .nav-section.expanded > .nav-section-header::after,
.sidebar.open.collapsed .nav-section.expanded > .nav-section-header::after {
    display: none !important;
}
/* In expanded mode, icon sits left of label, push chevron to far right */
.nav-section-header .nav-section-label {
    flex: 1;
}
/* In collapsed sidebar, center the icon */
.sidebar.collapsed .nav-section-icon {
    width: 18px;
    height: 18px;
}

/* --- Collapsed Sidebar: Hover Flyout Menus --- */
/* Make sections position-relative so flyout can anchor */
.sidebar.collapsed .nav-section {
    position: relative;
}
/* Force-hide ALL section items in collapsed sidebar — only flyout hover shows them */
.sidebar.collapsed .nav-section > .nav-section-items {
    display: none !important;
}
/* On hover, show items as a flyout panel to the right */
.sidebar.collapsed .nav-section:hover > .nav-section-items {
    display: flex !important;
    position: absolute;
    left: 100%;
    top: 0;
    max-height: none;
    opacity: 1;
    pointer-events: auto;
    overflow: visible;
    /* Card styling */
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    padding: 0.35rem 0.5rem 0.5rem;
    min-width: 180px;
    z-index: 1000;
    /* Smooth entrance */
    transition: none;
    margin-left: 4px;
}
/* Flyout label header via ::before pseudo-element */
.sidebar.collapsed .nav-section:hover > .nav-section-items::before {
    content: attr(data-label);
    display: block;
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    font-weight: 700;
    padding: 0.3rem 0.5rem 0.35rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.25rem;
}
/* Show full labels for nav items inside flyout */
.sidebar.collapsed .nav-section:hover .nav-section-items .nav-text {
    display: inline !important;
}
.sidebar.collapsed .nav-section:hover .nav-section-items .nav-item {
    justify-content: flex-start;
    padding: 0.5rem 0.75rem;
}
/* Restore the hover indicator bar inside flyout */
.sidebar.collapsed .nav-section:hover .nav-section-items .nav-item::before {
    display: block;
}
/* Bridge gap between header and flyout so mouse can travel without losing hover */
.sidebar.collapsed .nav-section:hover > .nav-section-items::after {
    content: "";
    position: absolute;
    left: -12px;
    top: 0;
    width: 12px;
    height: 100%;
}
/* Highlight section icon on hover */
.sidebar.collapsed .nav-section:hover > .nav-section-header .nav-section-icon {
    color: var(--primary);
}

/* --- Mobile / tablet open: suppress flyout, restore inline --- */
.sidebar.open .nav-section-items,
.sidebar.open.collapsed .nav-section-items {
    position: static !important;
    left: auto !important;
    min-width: 0 !important;
    box-shadow: none !important;
    border: none !important;
    border-radius: 0 !important;
    padding: 0 !important;
    margin-left: 0 !important;
    background: transparent !important;
    z-index: auto !important;
}
.sidebar.open .nav-section-items::before,
.sidebar.open.collapsed .nav-section-items::before {
    display: none !important;
}
.sidebar.open .nav-section-items::after,
.sidebar.open.collapsed .nav-section-items::after {
    display: none !important;
}
/* Hide section icons in mobile open drawer to keep it clean */
.sidebar.open .nav-section-icon,
.sidebar.open.collapsed .nav-section-icon {
    display: none !important;
}

/* Jobs cards grid — desktop default */
.jobs-cards-grid {
    grid-template-columns: repeat(4, 1fr);
}

/* Main Content */
.main-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    padding: 2.5rem 3rem;
    background-color: var(--bg-body);
    contain: layout;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 2rem;
}

.page-title {
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.page-subtitle {
    color: var(--text-muted);
    font-size: 1rem;
    margin-top: 0.25rem;
}

/* ─── Department tool-launcher tiles ───────────────────────────────────────
   Shared by the Drafting / Workshop / Sales hub landings. A clean surface
   card that matches `.card`, with a thin coloured top stripe per tool (set
   via the inline `--tile-accent` custom property) so each tile keeps a
   glanceable identity without the old full-bleed gradients. Dark mode comes
   for free — everything reads from the shared design tokens. */
.tool-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    min-height: 150px;
    padding: 1.35rem 1.25rem 1.25rem;
    text-align: left;
    font-family: inherit;
    color: var(--text-main);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.tool-tile::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--tile-accent, var(--primary));
}
.tool-tile:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--tile-accent, var(--primary));
}
.tool-tile:focus-visible {
    outline: 2px solid var(--tile-accent, var(--primary));
    outline-offset: 2px;
}
.tool-tile-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}
.tool-tile-icon {
    flex-shrink: 0;
    display: inline-flex;
    color: var(--tile-accent, var(--primary));
}
.tool-tile-icon svg {
    width: 26px;
    height: 26px;
}
.tool-tile-title {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-main);
}
.tool-tile-desc {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.5;
    color: var(--text-muted);
}

/* ─── Part Number Generator (Drafting tool) ────────────────────────────────
   Chat-style assistant + the "brace" breakdown legend. Built from the shared
   surface/border/text tokens so it matches the rest of the site and gets dark
   mode for free. The .png-breakdown block is reused by the always-on
   convention legend on the page and by the generated-number result panel. */
.png-chat {
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    max-height: 340px;
    overflow-y: auto;
}
.png-msg {
    max-width: 82%;
    padding: 0.55rem 0.85rem;
    border-radius: 12px;
    font-size: 0.86rem;
    line-height: 1.45;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.png-msg-bot {
    align-self: flex-start;
    background: var(--bg-body);
    border: 1px solid var(--border);
    color: var(--text-main);
    border-bottom-left-radius: 4px;
}
.png-msg-user {
    align-self: flex-end;
    background: var(--primary);
    color: #fff;
    border-bottom-right-radius: 4px;
}
.png-msg-typing { color: var(--text-muted); font-style: italic; }

.png-input-bar {
    display: flex;
    gap: 0.6rem;
    padding: 0.85rem 1.25rem;
    border-top: 1px solid var(--border);
    background: var(--surface);
}
.png-input-bar input {
    flex: 1;
    min-width: 0;
    padding: 0.55rem 0.85rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 0.88rem;
    font-family: inherit;
    background: var(--surface);
    color: var(--text-main);
}
.png-input-bar input:focus { outline: none; border-color: var(--primary); }

.png-result {
    padding: 1.1rem 1.25rem;
    border-top: 1px solid var(--border);
    background: var(--bg-body);
}
.png-result-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}
.png-result-kind {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}
.png-result-number {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 1.35rem;
    font-weight: 800;
    color: var(--primary);
    word-break: break-all;
}
.png-result-rev { font-size: 0.85rem; font-weight: 600; color: var(--text-muted); }
.png-result-sub { font-size: 0.76rem; color: var(--text-muted); margin-top: 0.2rem; }

.png-breakdown { display: flex; flex-direction: column; gap: 0.75rem; }
.png-seg-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}
.png-seg-chip {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text-main);
}
.png-seg-chip-rev { color: var(--text-muted); font-weight: 600; }
.png-seg-dash { color: var(--text-muted); font-weight: 700; padding: 0 0.1rem; }

.png-legend { display: flex; flex-direction: column; gap: 0.3rem; }
.png-leg-row {
    display: grid;
    grid-template-columns: 132px 14px 1fr;
    align-items: baseline;
    gap: 0.5rem;
    font-size: 0.82rem;
}
.png-leg-code {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-weight: 700;
    color: var(--primary);
    text-align: right;
    word-break: break-all;
}
.png-leg-brace { color: var(--text-muted); font-size: 1.15rem; line-height: 1; }
.png-leg-text { color: var(--text-muted); }
.png-leg-text strong { color: var(--text-main); font-weight: 600; }

/* The always-on convention legend rendered as a centred showcase ("How a
   UNIDAN number is built"). Scoped to .png-convention so the compact result
   panel that reuses .png-breakdown is left untouched. */
.png-convention { text-align: center; padding: 1.85rem 1.5rem; }
.png-convention-title {
    margin: 0 0 1.4rem;
    font-size: 1.45rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--text-main);
}
.png-convention .png-breakdown { gap: 1.4rem; align-items: center; }
.png-convention .png-seg-row { justify-content: center; gap: 0.25rem; }
.png-convention .png-seg-chip { padding: 0.45rem 0.8rem; font-size: 1.05rem; }
.png-convention .png-seg-chip-rev { font-size: 0.95rem; }
.png-convention .png-seg-dash { font-size: 1.15rem; }
.png-convention .png-legend {
    width: fit-content;
    max-width: 100%;
    margin: 0 auto;
    text-align: left;
    gap: 0.45rem;
}
.png-convention .png-leg-row { font-size: 0.9rem; }

/* UNIBOT-branded chat header — makes it obvious you're talking to UNIBOT
   (purple is UNIBOT's accent across the app). */
.png-chat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.8rem 1.25rem;
    border-bottom: 1px solid var(--border);
}
.png-bot-id { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }
.png-bot-avatar {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    background: linear-gradient(135deg, #a855f7 0%, #7c3aed 100%);
}
.png-bot-avatar svg { width: 19px; height: 19px; }
.png-bot-name {
    display: block;
    font-weight: 800;
    font-size: 0.95rem;
    letter-spacing: 0.02em;
    color: #a855f7;
    line-height: 1.15;
}
.png-bot-role { display: block; font-size: 0.72rem; color: var(--text-muted); }

/* Tappable answer-suggestion chips under a UNIBOT question. */
.png-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; align-self: flex-start; max-width: 100%; }
.png-chip {
    padding: 0.35rem 0.7rem;
    border: 1px solid var(--primary);
    border-radius: 999px;
    background: var(--surface);
    color: var(--primary);
    font-size: 0.8rem;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}
.png-chip:hover { background: var(--primary); color: #fff; }

/* Suggested house-style description shown on the generated result. */
.png-result-name { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.35rem; }
.png-result-name strong { color: var(--text-main); }

/* "Similar parts already exist" duplicate-guard panel. */
.png-similar {
    margin-top: 1rem;
    padding: 0.75rem 0.9rem;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.35);
    border-radius: 8px;
}
.png-similar-head { font-size: 0.8rem; font-weight: 600; color: #d97706; margin-bottom: 0.5rem; }
.png-similar-row {
    display: flex;
    gap: 0.6rem;
    font-size: 0.8rem;
    padding: 0.25rem 0;
    border-top: 1px solid rgba(245, 158, 11, 0.2);
}
.png-similar-row:first-of-type { border-top: none; }
.png-similar-no {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-weight: 700;
    color: var(--primary);
    flex-shrink: 0;
}
.png-similar-name { color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 600px) {
    .png-leg-row { grid-template-columns: 90px 12px 1fr; }
}

/* ─── Drafting Estimator ──────────────────────────────────────────────────
   AI drafting-hours estimate result, rendered into the shared .png-result slot
   below the UNIBOT chat (#drafting-estimator-result). .png-result already
   supplies the panel padding / top border / background; these de-* classes
   only style the estimate content inside it. */
.de-headline {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    padding-bottom: 1.1rem;
    margin-bottom: 1.1rem;
    border-bottom: 1px solid var(--border);
}
.de-hours-big { display: flex; align-items: baseline; gap: 0.3rem; }
.de-hours-num { font-size: 2.6rem; font-weight: 800; line-height: 1; color: var(--primary); }
.de-hours-unit { font-size: 1.1rem; font-weight: 700; color: var(--text-muted); }
.de-headline-meta { display: flex; flex-direction: column; gap: 0.4rem; }
.de-range { font-size: 0.9rem; color: var(--text-muted); }
.de-conf {
    display: inline-block;
    width: fit-content;
    padding: 0.18rem 0.6rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: capitalize;
    letter-spacing: 0.02em;
}
.de-conf-high { background: rgba(16, 185, 129, 0.14); color: #059669; border: 1px solid rgba(16, 185, 129, 0.4); }
.de-conf-medium { background: rgba(245, 158, 11, 0.14); color: #d97706; border: 1px solid rgba(245, 158, 11, 0.4); }
.de-conf-low { background: rgba(239, 68, 68, 0.12); color: #dc2626; border: 1px solid rgba(239, 68, 68, 0.4); }

.de-block { margin-top: 1.1rem; }
.de-block:first-of-type { margin-top: 0; }
.de-block-label {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 0.4rem;
}
.de-archetype { font-size: 0.9rem; color: var(--text-main); }
.de-assumptions { margin: 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: 0.25rem; }
.de-assumptions li { font-size: 0.85rem; color: var(--text-main); }
.de-reasoning { margin: 0; font-size: 0.88rem; line-height: 1.5; color: var(--text-main); }

.de-money-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 0.6rem;
}
.de-money-cell {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.6rem 0.75rem;
    background: var(--bg-body);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.de-money-k { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.de-money-v { font-size: 1.05rem; font-weight: 700; color: var(--text-main); }
.de-money-profit { color: #059669; }
.de-price-range { margin-top: 0.7rem; font-size: 0.82rem; color: var(--text-muted); }
.de-price-range strong { color: var(--text-main); }

.de-range-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.de-range-table th {
    text-align: left;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    font-weight: 700;
    padding: 0.3rem 0.5rem;
    border-bottom: 1px solid var(--border);
}
.de-range-table td { padding: 0.4rem 0.5rem; border-bottom: 1px solid var(--border); color: var(--text-main); }
.de-range-table tr:last-child td { border-bottom: none; }
.de-range-table .de-row-likely td { font-weight: 700; }
.de-range-table .de-row-likely td:first-child { color: var(--primary); }

.de-disclaimer { margin: 1.25rem 0 0; font-size: 0.76rem; color: var(--text-muted); font-style: italic; }

/* Views */
.view {
    display: none;
    animation: fadeIn 0.4s ease forwards;
    contain: layout style;
}

.view.active {
    display: block;
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Cards */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    box-shadow: var(--shadow-sm);
}

.card-header {
    margin-bottom: 1.5rem;
}

.card-title {
    font-size: 1.25rem;
    font-weight: 600;
}

.card-subtitle {
    color: var(--text-muted);
    font-size: 0.9rem;
    margin-top: 0.5rem;
}

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.6rem 1.25rem;
    border-radius: var(--radius-sm);
    font-weight: 600;
    font-size: 0.95rem;
    cursor: pointer;
    transition: var(--transition);
    border: none;
    font-family: inherit;
}

button:focus:not(:focus-visible),
a:focus:not(:focus-visible),
select:focus:not(:focus-visible),
.btn:focus:not(:focus-visible) {
    outline: none;
}

button:focus-visible,
a:focus-visible,
.btn:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-primary {
    background: var(--primary);
    color: white;
}

.btn-primary:not(:disabled):hover {
    background: var(--primary-hover);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(220, 38, 38, 0.3);
}

.btn-secondary {
    background: rgba(0, 0, 0, 0.05);
    color: var(--text-main);
    border: 1px solid rgba(0,0,0,0.05);
}

.btn-secondary:not(:disabled):hover {
    background: rgba(0, 0, 0, 0.08);
}

/* Dashboard Specifics */
.departments-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}

.dept-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    cursor: pointer;
    transition: var(--transition);
    box-shadow: var(--shadow-sm);
}

.dept-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 16px rgba(0,0,0,0.06);
    border-color: var(--primary);
}

.dept-card .icon {
    width: 32px;
    height: 32px;
    color: var(--primary);
}

.dept-card span {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-main);
}

/* ── Materials Hub landing — richer module cards ──────────────────────────
   Replaces the plain centred .dept-card tiles for the Materials hub only.
   Self-contained .mh-* classes so the dashboard's .dept-card consumers stay
   untouched. Single auto-fit grid per group → all tiles are the same width
   (the old hub hard-coded 1fr 1fr / 1fr 1fr 1fr per row, giving uneven rows).
   The .mh-stat count line is filled live by renderMaterialsHubCounts(); it
   stays hidden while empty so cards look complete before/without numbers. */
/* Each group is a subtly-tinted boxed panel (.mh-sec) so the three groups read
   as clearly separated zones; the color-mix tint sits darker than the page in
   light mode and lighter in dark mode, so the surface cards always pop forward. */
.mh-sec {
    background: color-mix(in srgb, var(--text-muted) 6%, transparent);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 1.3rem 1.4rem 1.45rem;
    margin-bottom: 1.4rem;
}
.mh-sec:last-child { margin-bottom: 0; }
.mh-section {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0 0 1rem;
}
.mh-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
    gap: 1rem;
}
.mh-card {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 1.4rem 1.5rem;
    cursor: pointer;
    transition: var(--transition);
}
.mh-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 22px rgba(0,0,0,0.08);
    border-color: var(--primary);
}
.mh-chip {
    width: 54px;
    height: 54px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    flex-shrink: 0;
}
.mh-chip svg { width: 27px; height: 27px; }
.mh-body { min-width: 0; flex: 1; }
.mh-title { font-size: 1.05rem; font-weight: 600; color: var(--text-main); line-height: 1.2; }
.mh-desc { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.25rem; line-height: 1.35; }
.mh-stat { font-size: 0.82rem; color: var(--text-muted); margin-top: 0.7rem; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.mh-stat:empty { display: none; }
.mh-pill { display: inline-flex; align-items: center; gap: 0.3rem; font-weight: 600; }
.mh-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.mh-sep { color: var(--border); }

.action-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-body);
}

.action-info h3 {
    font-size: 1rem;
    font-weight: 600;
}

.action-info p {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-top: 0.25rem;
}

/* Logging Console */
.log-card .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.console-body {
    padding: 0 !important;
    background: #fdfdfd; /* Light console body to match Apple-style surfaces */
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    border-top: 1px solid var(--border);
}
body.dark-mode .console-body { background: #0b0f14; } /* Deeper console dark for hacker aesthetic */

.console {
    height: 250px;
    overflow-y: auto;
    padding: 1rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.85rem;
}

.log-entry {
    margin-bottom: 0.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid rgba(0,0,0,0.05);
}

.log-entry:last-child {
    border-bottom: none;
    margin-bottom: 0;
}

.log-entry.info { color: #0066cc; }
.log-entry.success { color: var(--success); }
.log-entry.error { color: var(--error); }
.log-entry.warn { color: var(--warning); }
.log-time {
    color: var(--text-muted);
    margin-right: 0.5rem;
}

/* Forms */
.form-section {
    margin-bottom: 2rem;
    padding-bottom: 2rem;
    border-bottom: 1px solid var(--border);
}

.form-section:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}

.section-title {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: 1rem;
}

.form-group {
    margin-bottom: 1.25rem;
}

label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 500;
    font-size: 0.9rem;
}

input {
    width: 100%;
    padding: 0.75rem 1rem;
    background: var(--bg-body);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-main);
    font-family: inherit;
    font-size: 0.95rem;
    transition: var(--transition);
}

input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.15);
}

input[type="checkbox"], input[type="radio"] {
    width: auto;
    padding: 0;
    margin: 0;
    cursor: pointer;
    background: transparent;
    border: none;
    box-shadow: none;
}

input[type="checkbox"]:focus, input[type="radio"]:focus {
    box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.15);
}

.help-text {
    display: block;
    margin-top: 0.4rem;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.form-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 2rem;
}

/* Upload Zone */
.upload-zone {
    border: 2px dashed rgba(0, 0, 0, 0.15);
    border-radius: var(--radius-md);
    padding: 3rem 2rem;
    text-align: center;
    background: var(--bg-body);
    cursor: pointer;
    transition: var(--transition);
}

.upload-zone:hover, .upload-zone.highlight {
    border-color: var(--primary);
    background: rgba(249, 115, 22, 0.03);
}

.upload-status {
    font-size: 0.95rem;
    font-weight: 500;
}

.mb-2 { margin-bottom: 0.5rem; }
.spin { animation: spin 1s linear infinite; }

@keyframes spin {
    to { transform: rotate(360deg); }
}
@keyframes toast-in {
    from { transform: translateY(1rem); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

/* ─── Global Save Indicator ────────────────────────────────────────────── */
/* Thin top-of-viewport progress bar that only appears for saves taking
   longer than ~500ms. The inner fill uses an indeterminate sliding-gradient
   animation so users see motion without us needing real progress data. */
.global-save-progress-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 10002;
    pointer-events: none;
    overflow: hidden;
    background: transparent;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.global-save-progress-bar.is-active {
    opacity: 1;
}
.global-save-progress-bar-fill {
    position: absolute;
    top: 0;
    left: -40%;
    width: 40%;
    height: 100%;
    background: linear-gradient(90deg, transparent 0%, var(--primary) 30%, var(--primary) 70%, transparent 100%);
    animation: global-save-progress-slide 1.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
    border-radius: 2px;
}
@keyframes global-save-progress-slide {
    0%   { left: -40%; }
    100% { left: 100%; }
}

/* Centered "Loading scheduling…" overlay — paired with the top progress
   bar for the Scheduling Hub. Appears together with the bar (same 250ms
   threshold, same ref-count) but is far more visible. Card design with
   spinner + label; pointer-events:none so it doesn't block clicks. */
.sched-hub-load-overlay {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 10001;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.sched-hub-load-overlay.is-active {
    opacity: 1;
}
.sched-hub-load-card {
    background: var(--surface, #fff);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1rem 1.5rem;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
    display: flex;
    align-items: center;
    gap: 0.85rem;
}
.sched-hub-load-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: sched-hub-load-spin 0.8s linear infinite;
    flex-shrink: 0;
}
.sched-hub-load-text {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-main);
    white-space: nowrap;
}
@keyframes sched-hub-load-spin {
    to { transform: rotate(360deg); }
}

/* Flex / Anchored toggle in the task modal's Scheduling section. Two-button
   pill with a sliding "thumb" behind whichever side is active. Springy
   cubic-bezier on transform so the slide overshoots slightly — gives it a
   tactile feel without being silly. The icon on the active side scales +
   tilts; the inactive side fades. The thumb's background tints amber when
   anchored is active so the colour also signals state, not just position. */
.ptask-anchor-toggle {
    position: relative;
    display: inline-flex;
    background: var(--bg-muted, #f3f4f6);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 4px;
    overflow: hidden;
    isolation: isolate;
    user-select: none;
    -webkit-user-select: none;
}
.ptask-anchor-toggle-thumb {
    position: absolute;
    z-index: 1;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: calc(50% - 4px);
    background: var(--surface, #ffffff);
    border-radius: 10px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.10), 0 0 0 1px rgba(0,0,0,0.04);
    transition:
        transform 0.42s cubic-bezier(0.34, 1.56, 0.64, 1),
        background 0.3s ease,
        box-shadow 0.3s ease;
}
.ptask-anchor-toggle[data-state="anchored"] .ptask-anchor-toggle-thumb {
    transform: translateX(100%);
    background: linear-gradient(135deg, #fff5e0 0%, #ffe5b4 100%);
    box-shadow: 0 2px 8px rgba(247, 169, 0, 0.25), 0 0 0 1px rgba(247, 169, 0, 0.15);
}
.ptask-anchor-toggle-btn {
    position: relative;
    z-index: 2;
    flex: 1;
    min-width: 110px;
    /* 0.6rem vertical padding pushes the wrapper to ~44.5px to fully match
       the surrounding date / select input heights (which render at ~44.5px
       from 0.7rem padding + 1.4 line-height on 0.9rem text). Earlier 0.5rem
       was ~1-2px short. Same horizontal padding as before. */
    padding: 0.6rem 0.85rem;
    background: transparent;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    color: var(--text-muted);
    transition: color 0.25s ease, opacity 0.25s ease;
    font-family: inherit;
    opacity: 0.65;
}
.ptask-anchor-toggle-btn[aria-pressed="true"] {
    color: var(--text-main);
    opacity: 1;
}
.ptask-anchor-toggle-icon {
    font-size: 1.05rem;
    line-height: 1;
    display: inline-block;
    transition: transform 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.ptask-anchor-toggle-btn[aria-pressed="true"] .ptask-anchor-toggle-icon {
    transform: scale(1.18) rotate(-6deg);
}
.ptask-anchor-toggle-btn[data-state="flex"][aria-pressed="true"] .ptask-anchor-toggle-icon {
    /* Wave bobs the other way so the two states feel distinct. */
    transform: scale(1.18) rotate(6deg);
}
.ptask-anchor-toggle-label {
    font-size: 0.82rem;
    font-weight: 700;
    line-height: 1;
}
.ptask-anchor-toggle-btn:focus-visible {
    outline: 2px solid var(--primary, #dc2626);
    outline-offset: 2px;
    border-radius: 10px;
}
body.dark-mode .ptask-anchor-toggle-thumb {
    background: var(--surface-elevated, #2a2a2a);
}
body.dark-mode .ptask-anchor-toggle[data-state="anchored"] .ptask-anchor-toggle-thumb {
    background: linear-gradient(135deg, #3a2f1a 0%, #4a3a20 100%);
}

/* Estimated Time dropdown — toned down to match the surrounding date inputs.
   Plain native select; the modal-wide rule rounds it to 12px and the
   inline style on the element handles padding/border/font. The previous
   gradient + clock icon + custom chevron pulled too much attention away
   from the Flex/Anchored toggle, which is the only "hero" control in this
   row. Markup is now just <div><select></select></div> — no wrapper
   class needed. */

/* "Today" quick-pick button next to the workdate input. Soft translucent
   purple — sits quietly next to the date input instead of competing with
   it. Padding matches the date input's 0.7rem so the two stay flush. */
.ptask-today-btn {
    position: relative;
    padding: 0.7rem 1rem;
    background: rgba(100, 116, 139, 0.10);
    color: #475569;
    border: 1px solid rgba(100, 116, 139, 0.22);
    border-radius: 12px;
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition:
        transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1),
        background 0.2s ease,
        border-color 0.2s ease;
}
.ptask-today-btn:hover {
    background: rgba(100, 116, 139, 0.18);
    border-color: rgba(100, 116, 139, 0.38);
    transform: translateY(-1px);
}
.ptask-today-btn:active {
    transform: translateY(0) scale(0.97);
    background: rgba(100, 116, 139, 0.16);
    transition: transform 0.08s ease, background 0.1s ease;
}
.ptask-today-btn:focus-visible {
    outline: 2px solid rgba(100, 116, 139, 0.55);
    outline-offset: 2px;
}
body.dark-mode .ptask-today-btn {
    background: rgba(148, 163, 184, 0.14);
    color: #cbd5e1;
    border-color: rgba(148, 163, 184, 0.28);
}
body.dark-mode .ptask-today-btn:hover {
    background: rgba(148, 163, 184, 0.22);
    border-color: rgba(148, 163, 184, 0.42);
}

/* Round all the form controls inside the planner task modal so they match
   the Estimated Time wrapper (12px) + Schedule type pill (14px). Inputs/
   selects/textareas use 12px to match the Estimated Time wrapper; the
   modal's footer buttons get 12px so save/cancel feel consistent. The
   per-element inline `border-radius: 4px` styles on the existing fields
   are overridden because this rule is more specific (#planner-task-modal
   prefix beats inline only when matched via attribute, but for inline
   styles we need !important). Using !important here is contained to this
   one section and necessary because the existing markup uses inline
   styles for the inputs. */
#planner-task-modal input[type="text"],
#planner-task-modal input[type="number"],
#planner-task-modal input[type="date"],
#planner-task-modal input[type="email"],
#planner-task-modal input[type="search"],
#planner-task-modal select,
#planner-task-modal textarea {
    border-radius: 12px !important;
}
#planner-task-modal .btn {
    border-radius: 12px !important;
}
/* Notes editor wrapper — match too. */
#planner-task-modal .ptask-notes-rich-wrap {
    border-radius: 12px;
}

/* "BLOCKED" banner injected into a flagged anchor's timeline block. Sits
   at the top of the block, full-width, with the BLOCKED label on the left
   and an admin-only Resolve button on the right. Pointer-events stay
   active so the Resolve button is clickable through the block's drag /
   click delegators. */
.pdr-tl-block .pdr-blocked-banner {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    padding: 3px 6px;
    background: linear-gradient(90deg, rgba(192, 57, 43, 0.95) 0%, rgba(220, 38, 38, 0.92) 100%);
    color: #fff;
    z-index: 5;
    border-top-left-radius: inherit;
    border-top-right-radius: inherit;
    font-size: 10px;
    line-height: 1;
}
.pdr-blocked-banner-label {
    font-weight: 800;
    letter-spacing: 0.05em;
}
.pdr-resolve-anchor-btn {
    background: rgba(255, 255, 255, 0.95);
    color: #b91c1c;
    border: none;
    border-radius: 4px;
    padding: 2px 8px;
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.12s ease;
}
.pdr-resolve-anchor-btn:hover {
    background: #fff;
    transform: scale(1.04);
}
.pdr-resolve-anchor-btn:active {
    transform: scale(0.96);
}

/* "Unscheduled" badge in the Your Tasks list — flagged on rows where the
   task has no workDate or no startTime, so it won't appear on the day rail
   / week timeline. Muted slate look + dashed border to suggest "needs
   attention" without screaming. Hidden on completed tasks (the row renderer
   guards). */
.planner-unscheduled-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    background: #f1f5f9;
    color: #475569;
    border: 1px dashed #94a3b8;
    border-radius: 12px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: middle;
    white-space: nowrap;
    cursor: help;
}
body.dark-mode .planner-unscheduled-badge {
    background: #1e293b;
    color: #cbd5e1;
    border-color: #64748b;
}

/* "Untracked" badge in the Your Tasks list — task carries no schedule slot and
   no time tracking; it's completed manually from the status dropdown. Mirrors
   the Unscheduled badge shape but a soft indigo/violet accent (distinct from
   the slate "Unscheduled" look) so the two read as different states. */
.planner-untracked-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    background: #eef2ff;
    color: #4338ca;
    border: 1px solid #c7d2fe;
    border-radius: 12px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: middle;
    white-space: nowrap;
    cursor: help;
}
body.dark-mode .planner-untracked-badge {
    background: #1e1b4b;
    color: #c7d2fe;
    border-color: #4338ca;
}

/* "No job" badge in the Your Tasks list — task detached from any job/cost
   centre (the No-job advanced tool). Neutral slate so it reads distinctly from
   the indigo Untracked badge when a task carries both. */
.planner-nojob-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    background: #f1f5f9;
    color: #475569;
    border: 1px solid #cbd5e1;
    border-radius: 12px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: middle;
    white-space: nowrap;
    cursor: help;
}
body.dark-mode .planner-nojob-badge {
    background: #1e293b;
    color: #cbd5e1;
    border-color: #475569;
}

/* "Blocked" badge in the Your Tasks list — flagged on rows where an
   anchored task has been flagged "Cannot do" but not yet resolved. Strong
   red look to match the BLOCKED stripe on the timeline block. */
.planner-blocked-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    background: #fef2f2;
    color: #b91c1c;
    border: 1px solid #fca5a5;
    border-radius: 12px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    vertical-align: middle;
    white-space: nowrap;
    cursor: help;
}
body.dark-mode .planner-blocked-badge {
    background: #450a0a;
    color: #fca5a5;
    border-color: #b91c1c;
}

/* Swap modal progress bar — same indeterminate sliding-gradient pattern as
   the global save bar, scoped inside the modal. Sits above the action-button
   row. Hidden via display:none until the JS toggles `is-active`. */
.swap-modal-progress {
    position: relative;
    height: 3px;
    background: var(--border, #e5e7eb);
    border-radius: 2px;
    overflow: hidden;
    margin-bottom: 0.6rem;
    display: none;
}
.swap-modal-progress.is-active {
    display: block;
}
.swap-modal-progress-fill {
    position: absolute;
    top: 0;
    left: -40%;
    width: 40%;
    height: 100%;
    background: linear-gradient(90deg, transparent 0%, var(--primary) 30%, var(--primary) 70%, transparent 100%);
    animation: global-save-progress-slide 1.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
    border-radius: 2px;
}

/* Pill that floats above the UNIBOT + chat FABs (bottom-right) and shows
   "Saving…", "Saved ✓", or a short error message. Positioned with its own
   fixed coordinates — not stacked with the locks.js concurrent-edit toasts
   — so it stays easy to spot. Uses semantic colors from the theme palette
   so it works in dark mode. */
.save-feedback-pill {
    position: fixed;
    /* Aligned with the chat FAB column so the pill sits directly above it
       and clears the 52px right rail + quick-links bar. The rail hides at
       <=860px (HIDE_BREAKPOINT_PX in dashboardRightRail.js) and the FAB
       snaps back to right:30px — match that breakpoint below. */
    right: 90px;
    bottom: 130px;            /* chat FAB is bottom:40px + 70px tall → clear */
    z-index: 10003;           /* above toast-container (10001) + FABs (9998) */
    display: none;
    align-items: center;
    gap: 0.6rem;
    padding: 0.75rem 1.25rem;
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-main);
    font-size: 1rem;
    font-weight: 600;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
    border: 1px solid var(--border);
    pointer-events: auto;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.2s ease, transform 0.2s ease;
    max-width: 420px;
}
.save-feedback-pill.is-visible {
    display: inline-flex;
    opacity: 1;
    transform: translateY(0);
}
.save-feedback-pill-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    flex: 0 0 12px;
}
/* Below the right-rail breakpoint the rail is hidden and the chat FAB
   snaps back to right:30px — follow it so the pill stays column-aligned. */
@media (max-width: 860px) {
    .save-feedback-pill {
        right: 30px;
    }
}
/* Phones: tighten padding and trim the right offset. */
@media (max-width: 640px) {
    .save-feedback-pill {
        right: 16px;
        bottom: 120px;
        font-size: 0.95rem;
        padding: 0.65rem 1.1rem;
    }
}
.save-feedback-pill-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.save-feedback-pill.is-saving .save-feedback-pill-dot {
    background: var(--primary);
    animation: save-pill-pulse 1.1s ease-in-out infinite;
}
.save-feedback-pill.is-saved {
    background: rgba(52, 199, 89, 0.12);
    border-color: rgba(52, 199, 89, 0.35);
    color: #1b7c3f;
}
body.dark-mode .save-feedback-pill.is-saved {
    background: rgba(52, 199, 89, 0.18);
    color: #6ee7a0;
}
.save-feedback-pill.is-saved .save-feedback-pill-dot {
    background: var(--success);
}
.save-feedback-pill.is-error {
    background: rgba(255, 59, 48, 0.12);
    border-color: rgba(255, 59, 48, 0.4);
    color: #b91c1c;
}
body.dark-mode .save-feedback-pill.is-error {
    background: rgba(255, 59, 48, 0.2);
    color: #fca5a5;
}
.save-feedback-pill.is-error .save-feedback-pill-dot {
    background: var(--error);
}
@keyframes save-pill-pulse {
    0%, 100% { transform: scale(1);   opacity: 1;   }
    50%      { transform: scale(0.7); opacity: 0.5; }
}

/* Modal Overlay & Modal */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    /* 10000 keeps every modal above the chat + UNIBOT FAB cluster, which
       sits at z-index 9998 (FABs themselves) and 9999 (#btn-fab-collapse).
       Was 9999 — tied with the collapse button, and DOM-order had the
       FABs winning, so the chevron stayed coloured behind any modal
       that didn't override z-index inline. */
    z-index: 10000;
    padding: 1rem;
}

.modal {
    background: var(--surface);
    border-radius: var(--radius-md);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
    max-height: 90vh;
    overflow-y: auto;
    padding: 1.5rem;
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--border);
}

.modal-header h2 {
    font-size: 1.15rem;
    font-weight: 600;
    margin: 0;
}

.btn-close-modal {
    background: none;
    border: none;
    font-size: 1.5rem;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0.25rem;
    line-height: 1;
    transition: color 0.2s;
}

.btn-close-modal:hover {
    color: var(--text-main);
}

/* Old horizontal mobile sidebar removed — now uses slide-in drawer via later media query */

/* Workshop ISO Stepper */
.stepper-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 1.5rem;
    padding: 1.5rem;
    background: var(--bg-body);
    border-radius: var(--radius-sm);
}

.step-indicator {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-muted);
    transition: var(--transition);
}

.step-indicator.active {
    color: var(--primary);
}

.step-indicator.completed {
    color: var(--success);
}

.step-line {
    flex: 1;
    height: 2px;
    background: var(--border);
    margin: 0 1rem;
    position: relative;
    border-radius: 2px;
}

.step-line.completed {
    background: var(--primary);
}

.pb-0 {
    padding-bottom: 0 !important;
}

.icon-sm {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.btn-demo {
    background: rgba(138, 43, 226, 0.1);
    color: #6a0dad;
    border-color: rgba(138, 43, 226, 0.2);
}

.btn-demo:hover {
    background: rgba(138, 43, 226, 0.15);
}

/* QA Tracker Table */
.qa-table tr {
    border-bottom: 1px solid var(--border);
    transition: background 0.2s;
}

.qa-table tr:hover {
    background: rgba(0,0,0,0.015);
}

.qa-table td {
    padding: 1.25rem 1.5rem;
    vertical-align: top;
}

.qa-select {
    width: 100%;
    padding: 0.5rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--surface);
    font-size: 0.85rem;
    font-family: inherit;
    color: var(--text-main);
}

.tag {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
}

.tag-pass { background: rgba(52, 199, 89, 0.1); color: var(--success); }
.tag-fail { background: rgba(255, 59, 48, 0.1); color: var(--error); border: 1px solid rgba(255,59,48,0.2); }
.tag-na { background: rgba(0,0,0,0.05); color: var(--text-muted); }

.tag-minor { background: rgba(255, 204, 0, 0.15); color: #d4a000; }
.tag-major { background: rgba(249, 115, 22, 0.15); color: var(--primary); }
.tag-critical { background: var(--error); color: white; box-shadow: 0 2px 8px rgba(255,59,48,0.3); animation: pulse-critical 2s infinite; }

@keyframes pulse-critical {
    0% { opacity: 1; }
    50% { opacity: 0.8; }
    100% { opacity: 1; }
}

.rectification-box {
    background: #fff5f5;
    border-left: 3px solid var(--error);
    padding: 0.75rem;
    margin-top: 0.5rem;
    border-radius: 0 4px 4px 0;
    font-size: 0.85rem;
}

/* Timesheet Grid */
.ts-scroll-container {
    flex: 1;
    overflow-y: auto;
    overflow-x: auto;
    background: #fff;
    min-height: 500px;
    border-radius: 0 0 var(--radius-md) var(--radius-md);
}

/* --- Internal Chat System — moved to /chat-redesign.css --- */


/* --- Mobile Responsiveness & Sidebar Collapsibility --- */
.disabled-module {
    display: none !important;
}

/* Collapsed Sidebar on Desktop */
.sidebar {
    transition: width 0.18s ease;
    will-change: width;
}
.sidebar.collapsed {
    width: 76px;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    overflow-x: visible;
    overflow-y: visible;
}
.sidebar.collapsed .nav-text {
    display: none;
}
.sidebar.collapsed .sidebar-signed-in-prefix {
    display: none;
}
.sidebar.collapsed .nav-item {
    justify-content: center;
    padding: 0.75rem 0;
}
.sidebar.collapsed .nav-item:hover {
    transform: none;
}
.sidebar.collapsed .nav-item::before {
    display: none;
}
.sidebar.collapsed .sidebar-bottom {
    padding: 10px 5px !important;
}
.sidebar.collapsed #btn-logout {
    padding: 0.5rem 0;
}
.sidebar.collapsed #sidebar-hamburger-wrap {
    justify-content: center;
    width: 100%;
}
.sidebar.collapsed #desktop-menu-btn {
    width: 100%;
    justify-content: center;
    padding: 0.75rem 0;
}
.sidebar.collapsed #btn-logout .nav-text {
    display: none;
}
.sidebar.collapsed #btn-logout .logout-icon {
    display: block !important;
}
.sidebar.collapsed .nav-dept-separator {
    margin: 0.35rem 0.25rem;
}

/* Collapsed-sidebar hover tooltips for top-level and bottom-pinned items.
   Sections already have their own flyout menu that shows child items (see
   the `.nav-section:hover > .nav-section-items` block earlier); this rule
   adds an equivalent right-side label for the pinned items that live
   OUTSIDE a section — Dashboard, Task Planner (top), and Alerts, Admin
   Tools, Bug Report, Logout (bottom). Reads the `title` attribute via
   attr() so the visible label stays in lockstep with the native tooltip.
   Target direct children only so nav items INSIDE .nav-section-items (the
   flyout) don't double up with their own tooltip. */
.sidebar.collapsed .nav-menu > .nav-item,
.sidebar.collapsed .sidebar-bottom > .nav-item,
.sidebar.collapsed .sidebar-bottom > #btn-logout {
    position: relative;
    /* Base .nav-item has overflow:hidden (for the ::before hover sweep).
       That clips the tooltip ::after we attach below since it's positioned
       outside the item's box — unclip it specifically for items that get a
       tooltip. */
    overflow: visible;
}
.sidebar.collapsed .nav-menu > .nav-item::after,
.sidebar.collapsed .sidebar-bottom > .nav-item::after,
.sidebar.collapsed .sidebar-bottom > #btn-logout::after {
    /* Match the `.nav-section:hover > .nav-section-items` flyout card: same
       surface, same 8px radius, same shadow, same `left: 100%; margin-left:
       4px` anchor, same instant entrance (transition: none). Difference is
       this one carries a single label via attr(title) instead of a list of
       nav children, so no uppercase header strip. Pointer-events:none keeps
       it purely informational — not clickable, doesn't block the icon. */
    content: attr(title);
    display: none;
    position: absolute;
    left: 100%;
    margin-left: 4px;
    top: 50%;
    transform: translateY(-50%);
    background: var(--surface);
    color: var(--text-main);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.5rem 0.85rem;
    font-size: 0.92rem;
    font-weight: 500;
    letter-spacing: -0.005em;
    white-space: nowrap;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    pointer-events: none;
    z-index: 1000;
}
.sidebar.collapsed .nav-menu > .nav-item:hover::after,
.sidebar.collapsed .sidebar-bottom > .nav-item:hover::after,
.sidebar.collapsed .sidebar-bottom > #btn-logout:hover::after {
    display: block;
}
/* Mobile hamburger-open state (.sidebar.open / .sidebar.open.collapsed)
   already shows the full text labels — suppress the hover tooltip so it
   doesn't stack on top of the visible label. */
.sidebar.open .nav-menu > .nav-item::after,
.sidebar.open .sidebar-bottom > .nav-item::after,
.sidebar.open .sidebar-bottom > #btn-logout::after,
.sidebar.open.collapsed .nav-menu > .nav-item::after,
.sidebar.open.collapsed .sidebar-bottom > .nav-item::after,
.sidebar.open.collapsed .sidebar-bottom > #btn-logout::after {
    display: none !important;
}

/* People Hub mobile nav toggle — hidden on desktop */
.people-nav-toggle {
    display: none;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.6rem 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-main);
    font-size: 0.9rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    margin-bottom: 0.5rem;
    transition: background 0.15s;
}
.people-nav-toggle:hover,
.people-nav-toggle:focus {
    background: var(--surface-hover);
    outline: none;
}
.people-nav-chevron {
    transition: transform 0.2s;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

@media (max-width: 768px) {
    #mobile-topbar {
        display: flex !important;
    }
    .sidebar {
        position: fixed;
        left: -280px;
        top: 0;
        height: 100vh;
        width: 280px !important;
        flex-direction: column !important;
        transition: left 0.3s ease;
        box-shadow: var(--shadow-md);
        padding: calc(1.5rem + env(safe-area-inset-top, 20px)) 1.5rem 1.5rem 1.5rem !important;
        overflow-x: hidden;
        overflow-y: auto;
        z-index: 1001;
    }
    /* Hide logo on phones */
    .sidebar .logo-container { display: none !important; }
    /* Hide desktop hamburger — use top bar instead */
    #sidebar-hamburger-wrap { display: none !important; }
    /* Force full expanded layout when open (override collapsed class) */
    .sidebar.open,
    .sidebar.open.collapsed {
        left: 0;
        width: 280px !important;
    }
    .sidebar.open .nav-text,
    .sidebar.open.collapsed .nav-text { display: inline !important; }
    .sidebar.open .sidebar-signed-in-prefix,
    .sidebar.open.collapsed .sidebar-signed-in-prefix { display: inline !important; }
    .sidebar.open .nav-item,
    .sidebar.open.collapsed .nav-item { justify-content: flex-start !important; padding: 0.75rem 1rem !important; flex-direction: row !important; }
    .sidebar.open .nav-menu,
    .sidebar.open.collapsed .nav-menu { flex-direction: column !important; }
    /* On mobile the sidebar itself scrolls (see .sidebar rule above with
       overflow-y:auto), so don't create a nested scroll region on .nav-menu. */
    .sidebar .nav-menu {
        overflow: visible;
        flex: 0 0 auto;
        min-height: auto;
        margin-right: 0;
        padding-right: 0;
    }
    .sidebar.open .sidebar-bottom,
    .sidebar.open.collapsed .sidebar-bottom { padding: 10px 20px !important; }
    .sidebar.open #btn-logout .nav-text,
    .sidebar.open.collapsed #btn-logout .nav-text { display: inline !important; }
    .sidebar.open #btn-logout .logout-icon,
    .sidebar.open.collapsed #btn-logout .logout-icon { display: none !important; }
    .sidebar.open #btn-logout,
    .sidebar.open.collapsed #btn-logout { justify-content: center !important; padding: 0.5rem !important; }

    .main-content {
        padding-top: calc(60px + env(safe-area-inset-top, 20px));
        padding-left: 0.75rem;
        padding-right: 0.75rem;
        padding-bottom: 1rem;
        width: 100%;
        max-width: 100vw;
        overflow-x: hidden;
    }
    /* Prevent anything from overflowing horizontally */
    .content, .view, .card {
        max-width: 100%;
        overflow-x: hidden;
    }
    /* Allow tables to scroll horizontally inside cards */
    .card table, table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }
    /* Stack tables and layout grids */
    .jobs-cards-grid {
        grid-template-columns: 1fr 1fr !important;
        gap: 0.65rem !important;
        width: 100% !important;
        max-width: 100% !important;
    }
    .jobs-cards-grid > .card,
    .jobs-cards-grid > div {
        min-width: 0 !important;
        overflow: hidden !important;
        word-break: break-word;
    }
    /* Job cards — hide stage labels on small screens, keep bar */
    .jobs-cards-grid > .card [style*="gap:0.3rem"],
    .jobs-cards-grid > div [style*="gap:0.3rem"] {
        display: none !important;
    }
    .departments-grid {
        grid-template-columns: 1fr 1fr !important;
    }
    /* Live Production Overview header — stack on mobile */
    #view-dashboard .header {
        flex-direction: column !important;
        align-items: flex-start !important;
        gap: 0.5rem !important;
        text-align: center;
    }
    #view-dashboard .header > div {
        width: 100%;
        text-align: center;
    }
    #view-dashboard .header > button,
    #view-dashboard .header > .btn {
        width: 100%;
        justify-content: center;
    }
    /* Job cards — wider, more square on mobile */
    .jobs-cards-grid > .card {
        padding: 0.85rem !important;
    }
    .jobs-cards-grid > .card h3 {
        font-size: 0.85rem !important;
    }
    .jobs-cards-grid > .card p {
        font-size: 0.72rem !important;
    }
    /* Edit announcement — small icon bottom-right on mobile */
    #btn-edit-announcement {
        position: absolute !important;
        top: auto !important;
        bottom: 0.5rem !important;
        right: 0.5rem !important;
        width: 30px !important;
        height: 30px !important;
        padding: 0 !important;
        font-size: 0 !important;
        border-radius: 50% !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        min-height: 0 !important;
        opacity: 0.6;
    }
    #btn-edit-announcement::before {
        content: '';
        display: block;
        width: 14px;
        height: 14px;
        background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z'/%3E%3C/svg%3E");
        background-size: contain;
        background-repeat: no-repeat;
    }
    #view-dashboard .card [style*="padding-right: 6rem"] {
        padding-right: 0 !important;
    }
    /* --- People Hub / My Workspace mobile (sidebar collapses on top) --- */
    #view-people > div,
    #view-my-workspace > div {
        flex-direction: column !important;
    }
    #view-people > div > div:first-child,
    #view-my-workspace > div > div:first-child {
        width: 100% !important;
        min-width: 0 !important;
        border-right: none !important;
        border-bottom: 1px solid var(--border);
        padding-right: 0 !important;
        margin-bottom: 0.75rem;
        padding-bottom: 0 !important;
    }
    #view-people > div > div:last-child,
    #view-my-workspace > div > div:last-child {
        padding-left: 0 !important;
    }

    /* Hide the desktop h2 title on mobile */
    .people-sidebar > h2 { display: none !important; }

    /* Show the mobile dropdown toggle */
    .people-nav-toggle {
        display: flex !important;
    }

    /* Hide nav items by default, show when open */
    .people-sidebar .sub-nav-item {
        display: none !important;
        padding: 0.6rem 1rem !important;
        margin-bottom: 0.25rem !important;
    }
    .people-sidebar.nav-open .sub-nav-item {
        display: flex !important;
    }

    /* Rotate chevron when open */
    .people-sidebar.nav-open .people-nav-chevron {
        transform: rotate(180deg);
    }

    /* Content sections: reduce padding */
    #whos-here-landing-hub,
    #personal-landing-hub,
    #customers-landing-hub,
    #suppliers-landing-hub,
    #employees-landing-hub,
    #team-calendar-landing-hub {
        padding-right: 0 !important;
    }

    /* People Hub headers: stack vertically */
    #customers-list-view > div:first-child,
    #suppliers-list-view > div:first-child,
    #employees-list-view > div:first-child {
        flex-direction: column !important;
        align-items: flex-start !important;
        gap: 0.5rem !important;
    }
    #customers-list-view > div:first-child > div:last-child,
    #suppliers-list-view > div:first-child > div:last-child,
    #employees-list-view > div:first-child > div:last-child {
        width: 100%;
        flex-wrap: wrap;
    }
    #customers-list-view > div:first-child > div:last-child > button,
    #suppliers-list-view > div:first-child > div:last-child > button,
    #employees-list-view > div:first-child > div:last-child > button {
        flex: 1;
        min-width: 0;
        font-size: 0.8rem !important;
        padding: 0.5rem 0.75rem !important;
        white-space: nowrap;
    }

    /* People Hub headings smaller on mobile */
    #customers-landing-hub h2,
    #suppliers-landing-hub h2,
    #employees-landing-hub h2,
    #personal-landing-hub h2,
    #whos-here-landing-hub h2,
    #team-calendar-landing-hub h2 {
        font-size: 1.2rem !important;
    }

    /* Profile views: form grids single column */
    #customer-profile-view .card [style*="grid-template-columns"],
    #supplier-profile-view .card [style*="grid-template-columns"],
    #employee-profile-view .card [style*="grid-template-columns"] {
        grid-template-columns: 1fr !important;
    }

    /* Profile tab buttons: scroll horizontally */
    #customer-profile-view > div:nth-child(2),
    #supplier-profile-view > div:nth-child(2),
    #employee-profile-view > div:nth-child(2) {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .customer-tab-btn, .supplier-tab-btn, .employee-tab-btn {
        font-size: 0.8rem !important;
        padding: 0.5rem 0.8rem !important;
        white-space: nowrap;
    }

    /* Who's Here grid: fewer columns */
    #whos-here-grid {
        grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)) !important;
        gap: 0.5rem !important;
    }

    /* Team Calendar: scroll */
    #tc-calendar {
        overflow-x: auto !important;
        -webkit-overflow-scrolling: touch;
    }
    .modal {
        width: 95% !important;
        padding: 1rem !important;
        margin: 0.5rem;
        max-height: 90vh;
        overflow-y: auto;
    }
    /* Page headers: stack vertically */
    .page-title { font-size: 1.3rem; }
    .page-subtitle { font-size: 0.8rem; }
    /* Scheduling hub: single column on phone */
    #sched-dept-grid {
        grid-template-columns: 1fr 1fr !important;
    }
    #sched-charts-section [style*="grid-template-columns"] {
        grid-template-columns: 1fr !important;
    }
}

/* ===== Device-Aware Scaling ===== */

/* --- Mobile Phones --- */
body.device-mobile {
    font-size: 14px;
}
body.device-mobile .main-content {
    padding: calc(60px + env(safe-area-inset-top, 20px)) 0.75rem 1rem 0.75rem;
}
body.device-mobile #mobile-topbar {
    display: flex !important;
}
body.device-mobile #sidebar-hamburger-wrap {
    display: none !important;
}
body.device-mobile .page-title {
    font-size: 1.4rem;
}
body.device-mobile .page-subtitle {
    font-size: 0.85rem;
}
body.device-mobile .card {
    padding: 1rem;
    margin-bottom: 1rem;
}
body.device-mobile .departments-grid {
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}
body.device-mobile .dept-card {
    padding: 1rem;
}
body.device-mobile .dept-card .icon {
    width: 24px;
    height: 24px;
}
body.device-mobile .dept-card span {
    font-size: 0.85rem;
}
body.device-mobile .btn {
    padding: 0.5rem 1rem;
    font-size: 0.85rem;
}
body.device-mobile .console {
    height: 180px;
    font-size: 0.75rem;
}
body.device-mobile .modal {
    width: 95% !important;
    max-width: none;
    padding: 1rem !important;
}
body.device-mobile .header {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
}
/* Dashboard: center text, full-width button */
body.device-mobile #view-dashboard .header {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.5rem;
}
body.device-mobile #view-dashboard .header > div {
    width: 100%;
    text-align: center;
}
body.device-mobile #view-dashboard .header .page-title {
    font-size: 1.2rem;
}
body.device-mobile #view-dashboard .header .page-subtitle {
    font-size: 0.78rem;
}
body.device-mobile #view-dashboard .header > button {
    width: 100%;
    justify-content: center;
}
/* Job cards: full width, compact square-ish */
body.device-mobile .jobs-cards-grid {
    grid-template-columns: 1fr 1fr !important;
    gap: 0.65rem !important;
    width: 100% !important;
    max-width: 100% !important;
}
body.device-mobile .jobs-cards-grid > .card,
body.device-mobile .jobs-cards-grid > div {
    padding: 0.85rem !important;
    min-width: 0 !important;
    overflow: hidden !important;
    word-break: break-word;
}
body.device-mobile .jobs-cards-grid > .card h3,
body.device-mobile .jobs-cards-grid > div h3 {
    font-size: 0.85rem !important;
}
body.device-mobile .jobs-cards-grid > .card p,
body.device-mobile .jobs-cards-grid > div p {
    font-size: 0.72rem !important;
}
/* Announcement card: small icon bottom-right on mobile */
body.device-mobile #btn-edit-announcement {
    position: absolute !important;
    top: auto !important;
    bottom: 0.5rem !important;
    right: 0.5rem !important;
    width: 30px !important;
    height: 30px !important;
    padding: 0 !important;
    font-size: 0 !important;
    border-radius: 50% !important;
    min-height: 0 !important;
    opacity: 0.6;
}
body.device-mobile #view-dashboard .card [style*="padding-right: 6rem"] {
    padding-right: 0 !important;
}

/* Mobile landscape: give more horizontal room */
body.device-mobile.orient-landscape .main-content {
    padding: 0.75rem 1.5rem;
}
body.device-mobile.orient-landscape .departments-grid {
    grid-template-columns: repeat(3, 1fr);
}

/* --- Tablets --- */
body.device-tablet {
    font-size: 15px;
}
body.device-tablet .main-content {
    padding: 1.5rem 2rem;
}
body.device-tablet .page-title {
    font-size: 1.7rem;
}
body.device-tablet .card {
    padding: 1.25rem;
}
body.device-tablet .departments-grid {
    grid-template-columns: repeat(3, 1fr);
}
body.device-tablet .modal {
    width: 80% !important;
    max-width: 600px;
}
body.device-tablet .sidebar {
    width: 220px;
}
body.device-tablet .sidebar.collapsed {
    width: 64px;
}

/* Tablet portrait: stack sidebar like mobile */
body.device-tablet.orient-portrait #mobile-topbar {
    display: flex !important;
}
body.device-tablet.orient-portrait #sidebar-hamburger-wrap {
    display: none !important;
}
body.device-tablet.orient-portrait .main-content {
    padding-top: 60px;
}
body.device-tablet.orient-portrait .sidebar {
    position: fixed;
    left: -280px;
    top: 0;
    height: 100vh;
    width: 280px !important;
    transition: left 0.3s ease;
    z-index: 1001;
    overflow-y: auto;
}
body.device-tablet.orient-portrait .sidebar.open {
    left: 0;
}
body.device-tablet.orient-portrait .sidebar.open ~ #sidebar-backdrop {
    display: block !important;
}
/* Tablet: larger touch targets */
body.device-tablet .btn {
    min-height: 40px;
    padding: 0.55rem 1rem;
}
body.device-tablet .nav-item {
    padding: 0.85rem 1rem;
}
/* Tablet: scheduling hub 3-col instead of 4 to fit iPad */
body.device-tablet #sched-dept-grid {
    grid-template-columns: repeat(3, 1fr) !important;
}
/* Tablet portrait: scheduling hub 2-col */
body.device-tablet.orient-portrait #sched-dept-grid {
    grid-template-columns: repeat(2, 1fr) !important;
}
body.device-tablet.orient-portrait .departments-grid {
    grid-template-columns: repeat(2, 1fr) !important;
}

/* Tablet: workshop floor plan should fit portrait width. The scroll wrapper
   still lets it pan on very narrow screens, but we avoid it for iPad. */
body.device-tablet .wf-floor {
    min-width: 0;
}
body.device-tablet.orient-portrait .wf-floor {
    min-width: 700px;
}

/* PWA safe area insets */
@supports (padding: env(safe-area-inset-top)) {
    .sidebar {
        padding-top: calc(10px + env(safe-area-inset-top));
    }
    .main-content {
        padding-bottom: calc(1rem + env(safe-area-inset-bottom));
    }
}

/* --- Desktop (defaults, with minor touch-ups) --- */
body.device-desktop {
    font-size: 16px;
}
body.device-desktop .departments-grid {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}


/* ───────────────────────────────────────────────────────────────────
   Template builder & SOP runner — iPad / touch device overrides
   ─────────────────────────────────────────────────────────────────── */

/* #4/#5 — Step & page action buttons need to meet Apple's 44px tap target */
.tpl-step-move,
.tpl-step-delete,
.tpl-step-duplicate,
.tpl-page-move,
.tpl-page-del {
    min-width: 36px;
    min-height: 36px;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
}
@media (pointer: coarse) {
    .tpl-step-move,
    .tpl-step-delete,
    .tpl-step-duplicate {
        min-width: 44px;
        min-height: 44px;
        padding: 0.45rem 0.7rem !important;
        font-size: 0.78rem !important;
    }
    .tpl-page-move,
    .tpl-page-del {
        min-width: 40px;
        min-height: 40px;
        padding: 0.4rem 0.45rem !important;
        font-size: 0.85rem !important;
    }
    /* #5 — All inputs in the template builder & SOP runner need ≥16px
       to prevent iOS Safari's auto-zoom on focus. */
    .tpl-step-card input,
    .tpl-step-card select,
    .tpl-step-card textarea,
    #tpl-page-content input,
    #tpl-page-content select,
    #tpl-page-content textarea,
    #tpl-tab-timings input,
    #tpl-tab-timings select,
    #task-sop-modal input,
    #task-sop-modal select,
    #task-sop-modal textarea {
        font-size: 16px !important;
    }
    /* #6 — SOP modal close button bigger for finger taps */
    #task-sop-modal #sop-run-close {
        min-width: 44px;
        min-height: 44px;
        font-size: 2rem !important;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    /* Step drag handle should look tappable, not just grab-cursor */
    .tpl-step-drag {
        min-width: 32px;
        min-height: 44px;
        display: inline-flex !important;
        align-items: center;
        justify-content: center;
    }
}

/* Template search dropdown */
.sched-tpl-option:hover { background: var(--surface-hover, #f0f7ff); }
.sched-tpl-option:last-child { border-bottom: none !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   SALES HUB
   ════════════��═══════════════════════════��══════════════════════════════════ */

/* Stats Row */
.sales-stats-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.sales-stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1.25rem;
}
.sales-stat-label {
    font-size: 0.8rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 0.35rem;
}
.sales-stat-value {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--text-main);
}

/* View Toggle */
.sales-view-btn {
    padding: 0.5rem 0.75rem;
    background: var(--surface);
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    transition: background 0.15s, color 0.15s;
}
.sales-view-btn:hover { background: var(--surface-hover); color: var(--text-main); }
.sales-view-btn.active { background: var(--primary); color: white; }

/* Pipeline (Kanban) */
.sales-pipeline {
    display: flex;
    gap: 0.75rem;
    overflow-x: auto;
    padding-bottom: 1rem;
    min-height: 300px;
}
.sales-pipeline-col {
    flex: 1;
    min-width: 220px;
    max-width: 320px;
    display: flex;
    flex-direction: column;
}
.sales-pipeline-header {
    padding: 0.75rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px 8px 0 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.sales-pipeline-title {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--text-main);
}
.sales-pipeline-count {
    font-size: 0.75rem;
    color: var(--text-muted);
}
.sales-pipeline-cards {
    flex: 1;
    background: var(--bg-body);
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    padding: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-height: 100px;
    transition: background 0.15s;
}
.sales-pipeline-cards.drag-over {
    background: var(--surface-hover);
    outline: 2px dashed var(--primary);
    outline-offset: -2px;
}
.sales-pipeline-empty {
    text-align: center;
    padding: 2rem 0.5rem;
    color: var(--text-muted);
    font-size: 0.85rem;
}
.sales-pipeline-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.75rem;
    cursor: pointer;
    transition: box-shadow 0.15s, transform 0.15s;
}
.sales-pipeline-card:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
    transform: translateY(-1px);
}
.sales-pipeline-card.dragging {
    opacity: 0.5;
    transform: rotate(2deg);
}
.sales-card-company {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--text-main);
    margin-bottom: 0.2rem;
}
.sales-card-contact {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 0.35rem;
}
.sales-card-value {
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--primary);
    margin-bottom: 0.35rem;
}
.sales-card-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin-bottom: 0.25rem;
}
.sales-card-assigned {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-top: 0.25rem;
}

/* Tags */
.sales-tag {
    display: inline-block;
    padding: 0.15rem 0.45rem;
    border-radius: 4px;
    font-size: 0.7rem;
    font-weight: 500;
    background: var(--surface-hover);
    color: var(--text-muted);
}
.sales-tag-overdue {
    background: #fef2f2;
    color: var(--error);
}
.dark-mode .sales-tag-overdue {
    background: rgba(239, 68, 68, 0.15);
    color: #fca5a5; /* Brighter red so text reads against tinted red bg in dark mode */
}

/* SOP test-drive banner (scheduling.js) — tone down oversaturated solid green in dark mode. */
body.dark-mode [style*="background:#059669"] {
    background: rgba(5, 150, 105, 0.25) !important;
    color: #6ee7b7 !important;
}
.sales-tag-upcoming {
    background: #f0f9ff;
    color: #0369a1;
}
.dark-mode .sales-tag-upcoming {
    background: rgba(14, 165, 233, 0.15);
    color: #38bdf8;
}

/* Status Badge */
.sales-status-badge {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Closed Cards */
.sales-closed-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.75rem 1rem;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 180px;
    transition: box-shadow 0.15s;
}
.sales-closed-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }

/* Detail View */
.sales-detail-grid {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.sales-detail-label {
    font-size: 0.85rem;
    color: var(--text-muted);
    margin-right: 0.5rem;
}

/* Pipeline Stage Buttons */
.sales-status-pipeline {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}
.sales-stage-btn {
    padding: 0.4rem 0.8rem;
    border: 2px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text-main);
    font-size: 0.82rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    font-family: inherit;
}
.sales-stage-btn:hover {
    background: var(--surface-hover);
}

/* Follow-up Items */
.sales-followup-item {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    margin-bottom: 0.5rem;
    transition: background 0.15s;
}
.sales-followup-item:hover { background: var(--surface-hover); }
.sales-followup-item.completed { opacity: 0.6; }
.sales-followup-item.completed .sales-fu-title { text-decoration: line-through; }
.sales-followup-item.overdue { border-left: 3px solid var(--error); }
.sales-fu-complete {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    margin-top: 0.1rem;
    flex-shrink: 0;
}
.sales-fu-content { flex: 1; min-width: 0; }
.sales-fu-title { font-weight: 500; font-size: 0.9rem; color: var(--text-main); }
.sales-fu-meta { font-size: 0.8rem; color: var(--text-muted); margin-top: 0.15rem; }
.sales-fu-notes { font-size: 0.82rem; color: var(--text-muted); margin-top: 0.35rem; line-height: 1.4; }

/* Modal */
.sales-modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.4);
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    box-sizing: border-box;
    opacity: 0;
    transition: opacity 0.2s;
}
.sales-modal-overlay.visible { opacity: 1; }
.sales-modal {
    background: var(--surface);
    border-radius: 12px;
    width: 100%;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 20px 60px rgba(0,0,0,0.2);
    transform: translateY(20px);
    transition: transform 0.2s;
}
.sales-modal-overlay.visible .sales-modal { transform: translateY(0); }
.sales-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1.25rem 1.5rem;
    border-bottom: 1px solid var(--border);
}
.sales-modal-close {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--text-muted);
    padding: 0;
    line-height: 1;
}
.sales-modal-close:hover { color: var(--text-main); }
.sales-modal-body { padding: 1.5rem; }
.sales-modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--border);
}

/* Form Elements */
.sales-label {
    display: block;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--text-muted);
    margin-bottom: 0.3rem;
}
.sales-input {
    width: 100%;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.9rem;
    font-family: inherit;
    box-sizing: border-box;
    background: var(--surface);
    color: var(--text-main);
}
.sales-input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 2px rgba(30, 91, 198, 0.15);
}

/* List View Row Hover */
.sales-list-row:hover { background: var(--surface-hover); }

/* Customer Profile — Linked Lead Card */
.sales-linked-lead-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1rem 1.25rem;
    cursor: pointer;
    transition: box-shadow 0.15s, border-color 0.15s;
}
.sales-linked-lead-card:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
    border-color: var(--primary);
}

/* Responsive */
@media (max-width: 768px) {
    .sales-pipeline {
        flex-direction: column;
    }
    .sales-pipeline-col {
        max-width: 100%;
    }
    .sales-stats-row {
        grid-template-columns: 1fr 1fr;
    }
}

/* ─── Workshop Floor ────────────────────────────────────────────────────── */
.wf-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}
.wf-header-actions {
    display: flex;
    gap: 0.5rem;
}

.wf-count {
    display: inline-block;
    background: var(--primary);
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    margin-left: 0.4rem;
    min-width: 1.25rem;
    text-align: center;
}

.wf-legend {
    display: flex;
    gap: 0.8rem;
    flex-wrap: wrap;
    font-size: 0.75rem;
    color: var(--text-muted);
}
.wf-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
.wf-legend-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    display: inline-block;
}

/* Arrivals lane */
.wf-arrivals-card { margin-top: 0; }
.wf-arrivals {
    display: flex;
    gap: 0.6rem;
    overflow-x: auto;
    padding: 0.6rem;
    min-height: 110px;
    background: var(--bg-body);
    border: 2px dashed var(--border);
    border-radius: var(--radius-sm, 8px);
    transition: background 0.15s, border-color 0.15s;
}
.wf-arrivals.wf-drop-hover {
    background: rgba(249, 115, 22, 0.08);
    border-color: var(--primary);
}
.wf-empty-lane {
    color: var(--text-muted);
    font-size: 0.85rem;
    padding: 1.5rem;
    text-align: center;
    width: 100%;
}

/* Floor plan container */
.wf-floor-wrap {
    width: 100%;
    overflow-x: auto;
}
.wf-floor {
    position: relative;
    width: 100%;
    min-width: 900px;
    aspect-ratio: 3 / 2;
    background:
        repeating-linear-gradient(45deg,
            rgba(0,0,0,0.03) 0 10px,
            transparent 10px 20px),
        var(--bg-body);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 8px);
}

/* Bays */
.wf-bay {
    position: absolute;
    border: 2px solid rgba(0,0,0,0.35);
    border-radius: 4px;
    padding: 4px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 3px;
    transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
    box-sizing: border-box;
}
.wf-bay.wf-drop-hover {
    box-shadow: 0 0 0 3px var(--primary) inset;
    filter: brightness(1.05);
}

.wf-bay-truck     { background: #fef3c7; border-color: #eab308; }
.wf-bay-assembly  { background: #bfdbfe; border-color: #2563eb; }
.wf-bay-pallet    { background: #bbf7d0; border-color: #16a34a; }
.wf-bay-workshop  { background: #111827; border-color: #000000; }
.wf-bay-wash      { background: #fecaca; border-color: #dc2626; }

.wf-bay-label {
    font-size: 0.68rem;
    font-weight: 700;
    color: #1f2937;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.wf-bay-trucks {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
    overflow: hidden;
    flex: 1;
}

/* Truck card — full size (in arrivals lane) */
.wf-truck {
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 4px solid var(--primary);
    border-radius: 6px;
    padding: 0.5rem 0.6rem;
    min-width: 160px;
    max-width: 200px;
    font-size: 0.78rem;
    cursor: grab;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
    flex-shrink: 0;
    transition: transform 0.08s, box-shadow 0.15s;
}
.wf-truck:hover {
    box-shadow: 0 3px 10px rgba(0,0,0,0.1);
    transform: translateY(-1px);
}
.wf-truck.wf-dragging {
    opacity: 0.4;
    cursor: grabbing;
}
.wf-truck-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.2rem;
}
.wf-truck-rego {
    font-weight: 700;
    color: var(--text-main);
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wf-truck-status {
    font-size: 0.62rem;
    font-weight: 700;
    color: #fff;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    white-space: nowrap;
    flex-shrink: 0;
}
.wf-truck-customer {
    color: var(--text-main);
    font-size: 0.78rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wf-truck-job {
    color: var(--text-muted);
    font-size: 0.7rem;
    margin-top: 0.15rem;
}
.wf-truck-meta {
    color: var(--text-muted);
    font-size: 0.68rem;
    margin-top: 0.2rem;
}

/* Compact truck inside a bay */
.wf-bay .wf-truck {
    min-width: 0;
    max-width: 100%;
    width: 100%;
    padding: 3px 5px;
    font-size: 0.68rem;
    border-radius: 3px;
}
.wf-bay .wf-truck-rego { font-size: 0.72rem; }
.wf-bay .wf-truck-status,
.wf-bay .wf-truck-customer,
.wf-bay .wf-truck-job,
.wf-bay .wf-truck-meta { display: none; }

/* Form fields inside the modal */
.wf-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    font-size: 0.82rem;
    color: var(--text-main);
}
.wf-field > span {
    font-weight: 600;
    color: var(--text-muted);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.wf-field input,
.wf-field select,
.wf-field textarea {
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text-main);
    font: inherit;
    font-size: 0.88rem;
}
.wf-field textarea { resize: vertical; min-height: 60px; }
.wf-field input:focus,
.wf-field select:focus,
.wf-field textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.18);
}

/* Generic helpers used by the modal */
.btn-danger {
    background: var(--error, #dc2626);
    color: #fff;
    border: none;
    padding: 0.55rem 1.1rem;
    border-radius: 6px;
    font-weight: 600;
    cursor: pointer;
    font-size: 0.88rem;
}
.btn-danger:hover { filter: brightness(0.92); }

/* Dark mode tweaks — keep bay colors readable */
body.dark-mode .wf-bay-label { color: #0f172a; }
body.dark-mode .wf-floor {
    background:
        repeating-linear-gradient(45deg,
            rgba(255,255,255,0.03) 0 10px,
            transparent 10px 20px),
        var(--bg-body);
}

@media (max-width: 768px) {
    .wf-floor { min-width: 700px; }
}

/* ── Employee tab textarea sizing ───────────────────────────────────────
   The global `input` rule sets width:100% but textareas have no default
   style, so without an inline width they render at browser default
   (~200px). That made the medical-conditions / PPE / H&S notes boxes
   feel tiny. Mirror the input styling + vertical resize + larger
   min-height for free-form text. Scoped to the employees landing hub
   so other pages with their own textarea rules aren't affected.
   ──────────────────────────────────────────────────────────────────── */
#employees-landing-hub textarea {
    width: 100%;
    padding: 0.75rem 1rem;
    background: var(--bg-body);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-main);
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.45;
    resize: vertical;
    min-height: 110px;
    box-sizing: border-box;
    transition: var(--transition);
}
#employees-landing-hub textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.15);
}

/* ── Employee tab responsive ────────────────────────────────────────────
   Most of the employee profile pages use inline 2-, 3- and 6-column
   grids via `style="display:grid;grid-template-columns:..."`. On narrow
   screens (phone / iPad portrait) those grids would squeeze inputs so
   tightly that labels get cropped and number fields lose their spinners.
   Collapse them here with attribute selectors — no markup changes
   required. The 70px Day column in the work-schedule row is intentional
   and doesn't need collapsing (70px + 2 compact time inputs fits 320px).
   ──────────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
    #employees-landing-hub [style*="grid-template-columns: 1fr 1fr;"],
    #employees-landing-hub [style*="grid-template-columns: 1fr 1fr 1fr"],
    #employees-landing-hub [style*="grid-template-columns: 2fr 1fr 1fr"] {
        grid-template-columns: 1fr !important;
    }
    /* Leave record form: 6-col grid -> 2-col to avoid squishing */
    #employee-tab-leave [style*="grid-template-columns: 140px 120px 120px 80px 1fr auto"] {
        grid-template-columns: 1fr 1fr !important;
        gap: 0.6rem 0.75rem !important;
    }
    #employee-tab-leave [style*="grid-template-columns: 140px 120px 120px 80px 1fr auto"] > button {
        grid-column: 1 / -1;
    }
    /* List-view header row — let the "+ Add Employee" button wrap under
       the heading instead of crushing the heading text. */
    #employees-list-view > div:first-child {
        flex-wrap: wrap;
        gap: 0.75rem;
    }
    /* Employee profile tab bar — scroll horizontally instead of wrapping
       so each tab stays full-size and readable. */
    #employee-profile-view > div:nth-child(2) {
        flex-wrap: nowrap !important;
        overflow-x: auto;
    }
    #employee-profile-view .employee-tab-btn {
        flex-shrink: 0;
    }
}

/* Feedback modal — custom scrollbar that sits cleanly inside the rounded card */
.feedback-modal-scroll {
    scrollbar-width: thin;
    scrollbar-color: rgba(0,0,0,0.22) transparent;
    scrollbar-gutter: stable;
}
.feedback-modal-scroll::-webkit-scrollbar {
    width: 8px;
}
.feedback-modal-scroll::-webkit-scrollbar-track {
    background: transparent;
    margin: 8px 0;
}
.feedback-modal-scroll::-webkit-scrollbar-thumb {
    background: rgba(0,0,0,0.22);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.feedback-modal-scroll::-webkit-scrollbar-thumb:hover {
    background: rgba(0,0,0,0.38);
    background-clip: padding-box;
    border: 2px solid transparent;
}
body.dark-mode .feedback-modal-scroll {
    scrollbar-color: rgba(255,255,255,0.22) transparent;
}
body.dark-mode .feedback-modal-scroll::-webkit-scrollbar-thumb {
    background: rgba(255,255,255,0.22);
    background-clip: padding-box;
}
body.dark-mode .feedback-modal-scroll::-webkit-scrollbar-thumb:hover {
    background: rgba(255,255,255,0.38);
    background-clip: padding-box;
}

/* ────────────────────────────────────────────────────────────────────
   MACHINING STOCK — responsive layout (iPad / mobile)
   ──────────────────────────────────────────────────────────────────── */

/* iPad portrait + narrow desktops: collapse the outer 2-column Details grid */
@media (max-width: 900px) {
    .ms-details-grid {
        grid-template-columns: 1fr !important;
    }
}

/* Phone: stack paired form fields, allow item rows to scroll horizontally */
@media (max-width: 768px) {
    .ms-pair-grid {
        grid-template-columns: 1fr !important;
    }
    .ms-item-add-row {
        grid-template-columns: 1fr !important;
        gap: 0.75rem !important;
    }
    .ms-item-add-row > button {
        justify-self: stretch;
        width: 100%;
    }
    /* Financials + stock-adjust rows keep their grid but scroll inside the card */
    #mach-stock-items-financials,
    #mach-stock-items-stock {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .ms-item-row {
        min-width: 620px;
    }
    .ms-stock-adjust-row {
        min-width: 560px;
    }
    /* List-view header: wrap the "+ Add Material" button under the title */
    #mach-stock-list-view > div:first-child {
        flex-wrap: wrap;
        gap: 0.75rem;
    }
    #mach-stock-list-view > div:first-child > button {
        width: 100%;
    }
    /* Profile-view heading row: wrap Back + title on tiny screens */
    #mach-stock-profile-view > div:first-of-type {
        flex-wrap: wrap;
    }
    /* Profile tab bar: horizontal scroll if it gets too narrow */
    #mach-stock-profile-view > div:nth-of-type(2) {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        white-space: nowrap;
    }
    #mach-stock-profile-view .mach-stock-profile-tab {
        flex-shrink: 0;
    }
    /* Footer Delete/Save row — let them sit side-by-side on phones without squashing */
    #ms-tab-details > div:last-child {
        flex-wrap: wrap;
        gap: 0.75rem;
    }
}

/* ─── Info-icon tooltip ────────────────────────────────────────────────────
 * Small ⓘ badge next to a label with a CSS-only pseudo-element tooltip.
 * Shows on :hover AND :focus so mobile taps reveal it (span is tabindex=0).
 * Consumed via utils.js infoTip(text) — copy lives in the calling module.
 */
.info-tip {
    display: inline-block;
    width: 14px;
    height: 14px;
    line-height: 14px;
    font-size: 12px;
    text-align: center;
    color: var(--text-muted);
    cursor: help;
    margin-left: 4px;
    vertical-align: middle;
    user-select: none;
    position: relative;
    transition: color 0.15s ease;
}
.info-tip:hover,
.info-tip:focus {
    color: var(--primary);
    outline: none;
}
/* position: fixed lets the tooltip escape any overflow:auto/hidden ancestor
   (e.g. table-scroll wrappers like `<div style="overflow-x:auto;">` around
   labour-entries / rates / scheduling tables). Anchor coords are written into
   --tip-top / --tip-left by the delegated JS handler in modules/utils.js
   on mouseover/focusin. */
.info-tip::after {
    content: attr(data-tip);
    position: fixed;
    top: var(--tip-top, -9999px);
    left: var(--tip-left, -9999px);
    transform: translate(-50%, calc(-100% + 4px));
    width: max-content;
    max-width: 260px;
    padding: 8px 10px;
    background: var(--text-main);
    color: var(--bg-body);
    border-radius: 6px;
    font-size: 12px;
    line-height: 1.45;
    font-weight: normal;
    text-align: left;
    white-space: normal;
    word-wrap: break-word;
    box-shadow: var(--shadow-md);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 10000;
}
.info-tip::before {
    content: '';
    position: fixed;
    top: var(--tip-arrow-top, -9999px);
    left: var(--tip-left, -9999px);
    transform: translate(-50%, calc(-100% + 4px));
    border: 6px solid transparent;
    border-top-color: var(--text-main);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 10000;
}
.info-tip:hover::after,
.info-tip:focus::after,
.info-tip:hover::before,
.info-tip:focus::before {
    opacity: 1;
    transform: translate(-50%, -100%);
}

/* ─── Rates view (modules/rates.js) ───────────────────────────────────────
   Machine cost / timing editor. Active cards get a coloured accent strip on
   the left keyed off the machine category; WIP cards get a muted dashed
   treatment so active vs not-yet-built is obvious at a glance. No new
   colour palette — every hue is an rgba() fade of an existing token. */
.rates-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 1.25rem;
}
@media (max-width: 1000px) {
    .rates-grid { grid-template-columns: 1fr; }
}
.rates-card {
    position: relative;
    padding: 1.5rem;
    transition: var(--transition);
}
/* Hover-lift only on editable (unlocked) active cards — locked cards stay
   static so they read as non-interactive. */
.rates-card--active:not(.rates-card--locked):hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}
/* Locked rate cards — read-only view mode or no edit permission. Whole card
   dimmed + not-allowed cursor on the inputs so it's obvious you must click
   "Edit rates" first. The --locked class is dropped once an editable user
   enters edit mode, restoring full opacity and the normal text cursor. */
.rates-card--locked {
    opacity: 0.6;
}
.rates-card--locked input {
    cursor: not-allowed;
}
.rates-card__accent {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
    background: var(--text-muted);
}
.rates-card__head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.75rem;
    border-bottom: 1px solid var(--border);
    padding-bottom: 0.75rem;
    margin-bottom: 1rem;
}
.rates-card__title {
    font-size: 0.98rem;
    font-weight: 600;
    color: var(--text-main);
    margin: 0;
    line-height: 1.3;
}
.rates-chip {
    display: inline-block;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    white-space: nowrap;
    border: 1px solid var(--border);
    background: var(--bg-body);
    color: var(--text-muted);
}
/* Category-keyed chip tints — rgba fades of the existing semantic tokens */
.rates-chip--laser      { background: rgba(220,38,38,0.10); color: #b91c1c; border-color: rgba(220,38,38,0.25); }
.rates-chip--folding    { background: rgba(255,204,0,0.18); color: #8a6d00; border-color: rgba(255,204,0,0.45); }
.rates-chip--finishing  { background: rgba(52,199,89,0.12); color: #1f7a3a; border-color: rgba(52,199,89,0.30); }
.rates-chip--machining  { background: rgba(0,102,204,0.10); color: #0b4a8f; border-color: rgba(0,102,204,0.25); }
.rates-chip--cutting    { background: rgba(134,134,139,0.15); color: var(--text-main); border-color: var(--border); }
.rates-chip--welding    { background: rgba(249,115,22,0.12); color: #b45309; border-color: rgba(249,115,22,0.30); }
.rates-chip--printing   { background: rgba(139,92,246,0.12); color: #6d28d9; border-color: rgba(139,92,246,0.30); }
.rates-chip--labour     { background: rgba(13,148,136,0.12); color: #0f766e; border-color: rgba(13,148,136,0.30); }
body.dark-mode .rates-chip--laser      { color: #fca5a5; }
body.dark-mode .rates-chip--folding    { color: #fde68a; }
body.dark-mode .rates-chip--finishing  { color: #86efac; }
body.dark-mode .rates-chip--machining  { color: #93c5fd; }
body.dark-mode .rates-chip--welding    { color: #fdba74; }
body.dark-mode .rates-chip--printing   { color: #c4b5fd; }
body.dark-mode .rates-chip--labour     { color: #5eead4; }

.rates-group {
    margin-bottom: 1.1rem;
}
.rates-group__label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 0.6rem;
}
.rates-cost-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}
@media (max-width: 520px) {
    .rates-cost-row { grid-template-columns: 1fr; }
}
.rates-field { margin: 0; }
.rates-field > label {
    font-size: 0.82rem;
    color: var(--text-muted);
    font-weight: 500;
    margin-bottom: 0.35rem;
}
.rates-input-wrap {
    position: relative;
}
.rates-input-wrap > input { padding-right: 3.25rem; }
.rates-input-wrap__suffix {
    position: absolute;
    right: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.75rem;
    color: var(--text-muted);
    pointer-events: none;
    background: transparent;
}
.rates-helper {
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-top: 0.3rem;
    min-height: 1em;
}
.rates-timing-scope {
    display: inline-block;
    font-size: 0.66rem;
    font-weight: 500;
    padding: 0.08rem 0.45rem;
    border-radius: 999px;
    background: var(--bg-body);
    color: var(--text-muted);
    border: 1px solid var(--border);
    margin-left: 0.4rem;
    vertical-align: middle;
}
.rates-timing-row { margin-bottom: 0.85rem; }
.rates-timing-row > label {
    font-size: 0.82rem;
    color: var(--text-main);
    font-weight: 500;
}
.rates-details {
    margin-top: 0.9rem;
    border-top: 1px dashed var(--border);
    padding-top: 0.75rem;
}
.rates-details > summary {
    cursor: pointer;
    font-size: 0.82rem;
    color: var(--text-muted);
    user-select: none;
    font-weight: 500;
    list-style: none;
}
.rates-details > summary::-webkit-details-marker { display: none; }
.rates-details > summary::before {
    content: '▸';
    display: inline-block;
    margin-right: 0.4rem;
    transition: transform 0.15s;
    font-size: 0.7rem;
}
.rates-details[open] > summary::before { transform: rotate(90deg); }
.rates-details__body { margin-top: 0.75rem; }
.rates-formula {
    margin: 0.6rem 0 0 0;
    padding: 0.75rem 0.9rem;
    background: var(--bg-body);
    border-radius: var(--radius-sm);
    font-size: 0.72rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--text-muted);
    white-space: pre-wrap;
    line-height: 1.45;
    border: none;
}

/* WIP card — muted, dashed, no interactive affordance */
.rates-card--wip {
    opacity: 0.7;
    border-style: dashed;
    box-shadow: none;
    background: var(--bg-body);
}
.rates-card--wip .rates-card__head { border-bottom: none; margin-bottom: 0.6rem; padding-bottom: 0; }
.rates-wip-body {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 5rem;
    color: var(--text-muted);
    font-size: 0.85rem;
    font-style: italic;
}
.rates-wip-badge {
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    background: transparent;
    border: 1px dashed var(--text-muted);
    color: var(--text-muted);
    white-space: nowrap;
}

/* ── Secondary & finishing rates — vertical card; one row per finishing op ── */
.rates-sec-intro {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin: 0 0 0.4rem;
    line-height: 1.5;
}
.rates-sec-grid {
    display: flex;
    flex-direction: column;
}
.rates-sec-tile {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 0.85rem 0;
    border-top: 1px solid var(--border);
}
.rates-sec-tile:first-child { border-top: none; }
.rates-sec-tile:last-child { padding-bottom: 0; }
.rates-sec-tile__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}
.rates-sec-tile__name {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text-main);
}
.rates-sec-tile__icon {
    width: 28px; height: 28px;
    flex: 0 0 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 7px;
    background: var(--surface-hover);
    color: var(--text-muted);
}
.rates-sec-tile__icon svg { width: 15px; height: 15px; }
.rates-sec-tag {
    font-size: 0.58rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.15rem 0.45rem;
    border-radius: 999px;
    white-space: nowrap;
    border: 1px solid var(--border);
}
.rates-sec-tag--outsourced { background: rgba(0,102,204,0.10); color: #0b4a8f; border-color: rgba(0,102,204,0.22); }
.rates-sec-tag--labour     { background: rgba(13,148,136,0.12); color: #0f766e; border-color: rgba(13,148,136,0.28); }
body.dark-mode .rates-sec-tag--outsourced { color: #93c5fd; }
body.dark-mode .rates-sec-tag--labour     { color: #5eead4; }
.rates-sec-tile__fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 0.5rem 0.75rem;
}
.rates-sec-tile__fields .rates-field > label { font-size: 0.74rem; margin-bottom: 0.25rem; }

/* Sticky-ish save bar in the page header */
.rates-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}
.rates-header__title { font-size: 1.5rem; color: var(--text-main); margin: 0 0 0.4rem 0; font-weight: 600; }
.rates-header__subtitle { color: var(--text-muted); margin: 0; font-size: 0.9rem; max-width: 56ch; }
.rates-header__actions {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.rates-updated {
    font-size: 0.76rem;
    color: var(--text-muted);
    font-style: italic;
    text-align: right;
    max-width: 22ch;
    line-height: 1.35;
}
.rates-save-btn {
    padding: 0.6rem 1.3rem;
}
.rates-save-btn.is-clean {
    background: rgba(0,0,0,0.05);
    color: var(--text-muted);
    border: 1px solid var(--border);
    cursor: default;
    box-shadow: none;
}
.rates-save-btn.is-clean:hover { transform: none; box-shadow: none; background: rgba(0,0,0,0.05); }
body.dark-mode .rates-save-btn.is-clean { background: rgba(255,255,255,0.05); }

/* ============================================================
   New: attendance + bonus
   Task 7.2 Step 3 — My Bonus card styles (Personal tab)
   Task 8.2 Step 3 — People Hub > Attendance reporting styles
   ============================================================ */

/* --- Task 7.2 Step 3: Bonus card --- */
.bonus-card { padding: 1.5rem; margin-bottom: 1.5rem; }
.bonus-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; }
.bonus-card-header h3 { margin: 0; font-size: 1rem; }
.bonus-subtitle { color: var(--text-muted); font-size: 0.85rem; margin: 0 0 1rem; }
.bonus-pill { padding: 0.25rem 0.75rem; border-radius: 999px; font-size: 0.8rem; font-weight: 600; }
.bonus-pill-eligible { background: var(--success-bg, #d1fae5); color: var(--success, #065f46); }
.bonus-pill-at-risk { background: var(--warn-bg, #fef3c7); color: var(--warn, #92400e); }
.bonus-pill-ineligible { background: var(--danger-bg, #fee2e2); color: var(--danger, #991b1b); }
.bonus-rules { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.75rem 0; }
.bonus-rule-row { display: grid; grid-template-columns: auto 1fr auto; gap: 0.6rem; align-items: center;
    padding: 0.5rem 0.75rem; border-radius: 6px; background: var(--bg-subtle, #f9fafb); }
.bonus-rule-row.rule-ok .bonus-rule-icon { color: var(--success, #065f46); }
.bonus-rule-row.rule-fail .bonus-rule-icon { color: var(--danger, #991b1b); }
.bonus-rule-icon { font-weight: 700; font-size: 1.1rem; }
.bonus-rule-label { font-weight: 500; }
.bonus-rule-detail { color: var(--text-muted); font-size: 0.85rem; }
.bonus-help { margin: 0.5rem 0 0; font-size: 0.85rem; }
.bonus-help a { color: var(--primary); }
@media (max-width: 640px) {
    .bonus-rule-row { grid-template-columns: auto 1fr; }
    .bonus-rule-detail { grid-column: 1 / -1; padding-left: 1.7rem; }
}

/* --- Task 8.2 Step 3: Attendance reporting (KPI + data table) --- */
#attendance-landing-hub .view-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; flex-wrap: wrap; gap: 1rem; }
#attendance-landing-hub .view-header h2 { margin: 0; }
.quarter-picker { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
.quarter-picker label { display: flex; gap: 0.5rem; align-items: center; font-size: 0.85rem; color: var(--text-muted); }
.quarter-picker select {
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--card-bg, var(--bg-main));
    color: var(--text-main);
    font-family: inherit;
    font-size: 0.88rem;
    cursor: pointer;
}
.quarter-picker select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.18);
}
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 1rem; }
.kpi-tile { background: var(--bg-subtle, #f9fafb); padding: 1rem; border-radius: 8px; display: flex; flex-direction: column; }
.kpi-value { font-size: 1.6rem; font-weight: 700; }
.kpi-label { font-size: 0.8rem; color: var(--text-muted); }
.data-table { width: 100%; border-collapse: collapse; }
.data-table th, .data-table td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
.data-table tr.row-fail { background: var(--danger-bg-subtle, #fef2f2); }
.data-table tr.row-ok { background: transparent; }
.absence-reclassify { margin-right: 0.5rem; }
.att-overview { display: flex; flex-direction: column; gap: 1rem; }
.att-quarter-header { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.att-quarter-progress { flex: 1; min-width: 280px; height: 22px; background: var(--bg-subtle, #e5e7eb); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; position: relative; box-shadow: inset 0 1px 2px rgba(0,0,0,0.08); }
.att-quarter-progress-fill { height: 100%; background: linear-gradient(90deg, var(--primary), var(--primary-dark, #1e40af)); transition: width 0.4s ease; display: flex; align-items: center; justify-content: flex-end; padding-right: 0.5rem; color: #fff; font-size: 0.75rem; font-weight: 700; white-space: nowrap; box-shadow: 0 1px 2px rgba(0,0,0,0.15); }
.att-quarter-progress-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-muted); font-size: 0.75rem; font-weight: 600; pointer-events: none; }
.att-two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1rem; }
.att-panel { padding: 1rem 1.25rem; }
.att-panel h4 { margin: 0 0 0.75rem 0; font-size: 0.85rem; text-transform: uppercase; color: var(--text-muted); letter-spacing: 0.03em; display: flex; align-items: center; gap: 0.5rem; }
.att-count { display: inline-block; min-width: 1.4rem; padding: 0.1rem 0.5rem; background: var(--primary); color: #fff; border-radius: 999px; font-size: 0.7rem; font-weight: 700; text-align: center; letter-spacing: 0; }
.att-count:empty, .att-count:has-text("0") { background: var(--bg-subtle, #e5e7eb); color: var(--text-muted); }
.att-flags { display: flex; flex-direction: column; gap: 1rem; }
.att-history-picker { display: flex; align-items: center; gap: 0.75rem; padding: 1rem; background: var(--bg-subtle, #f9fafb); border: 1px solid var(--border); border-radius: 8px; flex-wrap: wrap; }
.att-history-picker label { font-weight: 600; font-size: 0.85rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.att-history-picker select { flex: 1; min-width: 240px; padding: 0.6rem 0.75rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card-bg, var(--bg-main)); color: var(--text-main); font-size: 0.95rem; font-family: inherit; cursor: pointer; }
.att-history-picker select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.18); }

/* HR pending-count badge on the People Hub sidebar nav button */
.nav-item { position: relative; }
.nav-badge {
    position: absolute;
    top: 0.35rem;
    right: 0.35rem;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.35rem;
    background: #ef4444;
    color: #fff;
    border: 2px solid var(--sidebar-bg, #ffffff);
    border-radius: 999px;
    font-size: 0.65rem;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
    pointer-events: none;
}

/* ───────────────────────────────────────────── */
/* Mobile Dashboard (/m)                         */
/* ───────────────────────────────────────────── */

body.is-mobile-dashboard,
#view-mobile-dashboard {
  --uni-red: #dc2626;
  --uni-red-hover: #b91c1c;
  --uni-red-soft: rgba(220, 38, 38, 0.08);

  --md-bg: #f5f5f7;
  --md-bg-elev: #ffffff;
  --md-bg-sunk: #efeff1;
  --md-border: rgba(16, 16, 20, 0.08);
  --md-border-strong: rgba(16, 16, 20, 0.14);
  --md-text: #17171a;
  --md-text-muted: #6b7280;
  --md-text-subtle: #9ca3af;

  --md-ok: #10b981;
  --md-warn: #f59e0b;
  --md-err: #ef4444;

  --md-radius-card: 16px;
  --md-radius-tile: 14px;
  --md-tap: 56px;

  --md-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --md-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

body.is-mobile-dashboard .sidebar { display: none; }
body.is-mobile-dashboard #mobile-topbar { display: none !important; }
body.is-mobile-dashboard #sidebar-backdrop { display: none !important; }

/* Ancestors have `contain: layout` (main-content l.950, .view l.976).
   `contain: layout` turns the element into the containing block for fixed
   descendants — which would trap #view-mobile-dashboard { position: fixed }
   inside .main-content's padded content box instead of the viewport. Null it
   out on this route so the fixed positioning actually reaches the viewport. */
body.is-mobile-dashboard .main-content,
body.is-mobile-dashboard .content {
    contain: none;
    padding: 0 !important;
    overflow: visible;
}
body.is-mobile-dashboard .view {
    contain: none;
    animation: none;
    overflow: visible;
    max-width: none;
}

#view-mobile-dashboard.view.active {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset: 0;
    z-index: 1000;
    animation: none; /* global .view fadeIn breaks fixed positioning */
    overflow: hidden;
}

#view-mobile-dashboard,
#view-mobile-dashboard * { box-sizing: border-box; }

body.is-mobile-dashboard {
  margin: 0;
  padding: 0;
  font-family: var(--md-font);
  color: var(--md-text);
  -webkit-font-smoothing: antialiased;
  background: #e8e8ea;
  min-height: 100vh;
}

#view-mobile-dashboard button { font-family: inherit; }

.md-app {
  height: 100%; width: 100%;
  display: flex; flex-direction: column;
  background: var(--md-bg);
  position: relative; overflow: hidden;
}

.md-top {
  display: flex; align-items: center; gap: 10px;
  padding: max(14px, env(safe-area-inset-top, 0)) 16px 12px;
  flex: 0 0 auto;
}
.md-top .md-hamburger {
  width: 44px; height: 44px; border-radius: 12px;
  background: var(--md-bg-elev); border: 1px solid var(--md-border);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--md-text);
  padding: 0;
}
.md-top .md-hamburger:active { background: var(--md-bg-sunk); }
.md-top .md-greet-wrap {
  flex: 1; min-width: 0;
}
.md-top .md-greet {
  font-size: 18px; font-weight: 800; letter-spacing: -0.015em; line-height: 1.1;
  color: var(--md-text);
}
.md-top .md-date {
  font-size: 11.5px; font-weight: 600; color: var(--md-text-muted);
  margin-top: 2px;
}
.md-top .md-bell {
  position: relative;
  width: 44px; height: 44px; border-radius: 12px;
  background: var(--md-bg-elev); border: 1px solid var(--md-border);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--md-text);
  padding: 0;
}
.md-top .md-bell .dot {
  position: absolute; top: 9px; right: 9px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--uni-red);
  border: 2px solid var(--md-bg-elev);
}

.md-body {
  flex: 1 1 auto; min-height: 0; /* allow flex shrink so overflow-y actually scrolls */
  overflow-y: auto; overflow-x: hidden;
  padding: 4px 16px calc(140px + env(safe-area-inset-bottom, 0));
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.md-body::-webkit-scrollbar { width: 4px; }
.md-body::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 2px; }

.md-ann {
  position: relative;
  border-radius: 18px;
  background: linear-gradient(155deg, #18181b 0%, #27272a 60%, #3f3f46 100%);
  color: white;
  padding: 18px 18px 16px;
  margin-bottom: 16px;
  overflow: hidden;
  box-shadow: 0 12px 28px -14px rgba(0,0,0,0.55);
  cursor: pointer;
}
.md-ann::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(80% 60% at 100% 0%, rgba(220,38,38,0.35) 0%, transparent 55%),
    radial-gradient(60% 40% at 0% 100%, rgba(255,255,255,0.06) 0%, transparent 60%);
}
.md-ann-label {
  position: relative;
  font-size: 10px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: rgba(255,255,255,0.65);
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 8px;
}
.md-ann-label .pin { color: #fbbf24; }
.md-ann h3 {
  position: relative;
  margin: 0 0 6px; font-size: 17px; font-weight: 800;
  letter-spacing: -0.015em; line-height: 1.25;
  text-wrap: balance;
}
.md-ann p {
  position: relative;
  margin: 0 0 12px; font-size: 13px; line-height: 1.45;
  color: rgba(255,255,255,0.75);
}
.md-ann-meta {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  font-size: 11px; color: rgba(255,255,255,0.6); font-weight: 600;
}
.md-ann-meta .who { display: inline-flex; align-items: center; gap: 7px; }
.md-ann-meta .who .av {
  width: 20px; height: 20px; border-radius: 50%;
  background: linear-gradient(135deg, #dc2626, #f97316);
  font-size: 9.5px; font-weight: 800; color: white;
  display: inline-flex; align-items: center; justify-content: center;
}
.md-ann-dots {
  display: flex; gap: 4px;
}
.md-ann-dots span {
  width: 5px; height: 5px; border-radius: 50%;
  background: rgba(255,255,255,0.25);
}
.md-ann-dots span.on { background: white; width: 16px; border-radius: 3px; }

.md-clock {
  display: flex; align-items: center; gap: 14px;
  padding: 18px;
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: var(--md-radius-card);
  margin-bottom: 14px;
  cursor: pointer;
  position: relative; overflow: hidden;
  transition: transform 120ms, box-shadow 120ms;
}
.md-clock:active { transform: scale(0.99); }
.md-clock.on {
  background: linear-gradient(135deg, #065f46 0%, #059669 100%);
  border-color: rgba(16,185,129,0.4);
  color: white;
}
.md-clock .md-clock-ico {
  width: 48px; height: 48px; border-radius: 14px;
  background: var(--md-bg-sunk);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--md-text);
  flex-shrink: 0;
}
.md-clock.on .md-clock-ico {
  background: rgba(255,255,255,0.2);
  color: white;
}
.md-clock .md-clock-ico .pulse {
  width: 8px; height: 8px; border-radius: 50%;
  background: white;
  animation: mdPulse 1.5s ease-in-out infinite;
}
@keyframes mdPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(1.4); }
}
.md-clock .md-clock-body { flex: 1; min-width: 0; }
.md-clock .md-clock-label {
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--md-text-muted);
}
.md-clock.on .md-clock-label { color: rgba(255,255,255,0.7); }
.md-clock .md-clock-title {
  font-size: 17px; font-weight: 800;
  letter-spacing: -0.015em; margin-top: 2px;
}
.md-clock .md-clock-sub {
  font-size: 12px; color: var(--md-text-muted); margin-top: 2px;
}
.md-clock.on .md-clock-sub { color: rgba(255,255,255,0.8); }
.md-clock .md-clock-arrow {
  color: var(--md-text-subtle);
  flex-shrink: 0;
}
.md-clock.on .md-clock-arrow { color: rgba(255,255,255,0.6); }

.md-sec-head {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 16px 4px 10px;
}
.md-sec-head h2 {
  margin: 0; font-size: 15px; font-weight: 800;
  letter-spacing: -0.015em; color: var(--md-text);
}
.md-sec-head .md-sec-action {
  font-size: 12.5px; font-weight: 700;
  color: var(--uni-red); text-decoration: none;
  padding: 4px 2px;
}
.md-sec-head .n {
  font-size: 11px; font-weight: 800;
  padding: 2px 7px; border-radius: 999px;
  background: var(--md-bg-sunk); color: var(--md-text-muted);
  margin-left: 7px;
  font-feature-settings: "tnum";
}

.md-todos {
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: var(--md-radius-card);
  overflow: hidden;
}
.md-todo {
  display: grid;
  grid-template-columns: 30px 1fr auto;
  gap: 12px; align-items: center;
  padding: 14px 16px;
  border-bottom: 1px solid var(--md-border);
  cursor: pointer;
  min-height: var(--md-tap);
}
.md-todo:last-child { border-bottom: none; }
.md-todo:active { background: var(--md-bg-sunk); }

.md-check {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid var(--md-border-strong);
  background: var(--md-bg-elev);
  display: inline-flex; align-items: center; justify-content: center;
  color: transparent;
  flex-shrink: 0;
  transition: background 150ms, border-color 150ms, color 150ms;
}
.md-todo.done .md-check {
  background: var(--uni-red); border-color: var(--uni-red); color: white;
}
.md-todo-body { min-width: 0; }
.md-todo-title {
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em;
  line-height: 1.3; color: var(--md-text);
  text-wrap: pretty;
}
.md-todo.done .md-todo-title {
  text-decoration: line-through; color: var(--md-text-subtle);
}
.md-todo-sub {
  display: flex; gap: 7px; align-items: center;
  font-size: 11.5px; color: var(--md-text-muted); margin-top: 3px;
  font-weight: 500;
}
.md-todo-sub .prio {
  width: 7px; height: 7px; border-radius: 50%;
}
.md-todo-sub .prio.p1 { background: var(--md-err); }
.md-todo-sub .prio.p2 { background: var(--md-warn); }
.md-todo-sub .prio.p3 { background: var(--md-text-subtle); }
.md-todo-sub .jn {
  font-family: var(--md-font-mono); font-size: 10.5px;
  padding: 1px 6px; background: var(--md-bg-sunk);
  border-radius: 4px; color: var(--md-text-muted);
}
.md-todo-chevron { color: var(--md-text-subtle); flex-shrink: 0; }

.md-cal-strip {
  display: grid; grid-template-columns: repeat(7, 1fr);
  gap: 6px; margin-bottom: 10px;
  padding: 0 2px;
}
.md-cal-day {
  text-align: center;
  padding: 9px 0 10px;
  border-radius: 12px;
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.md-cal-day.today {
  background: var(--uni-red); border-color: var(--uni-red); color: white;
}
.md-cal-day .dn {
  font-size: 9.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--md-text-muted);
}
.md-cal-day.today .dn { color: rgba(255,255,255,0.85); }
.md-cal-day .d {
  font-size: 15px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--md-text);
  font-feature-settings: "tnum";
}
.md-cal-day.today .d { color: white; }
.md-cal-day .dot {
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--uni-red);
}
.md-cal-day.today .dot { background: white; }

.md-cal-events {
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: var(--md-radius-card);
  overflow: hidden;
}
.md-cal-event {
  display: grid;
  grid-template-columns: 54px 1fr auto;
  gap: 14px; align-items: center;
  padding: 12px 14px 12px 12px;
  border-bottom: 1px solid var(--md-border);
  min-height: var(--md-tap);
  cursor: pointer;
}
.md-cal-event:last-child { border-bottom: none; }
.md-cal-event .time {
  text-align: center;
  font-family: var(--md-font-mono);
  padding: 6px 4px;
  border-radius: 10px;
  background: var(--md-bg-sunk);
}
.md-cal-event .time .h {
  font-size: 14px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--md-text); display: block; line-height: 1;
  font-feature-settings: "tnum";
}
.md-cal-event .time .ampm {
  font-size: 9.5px; font-weight: 700;
  color: var(--md-text-muted); letter-spacing: 0.04em;
  margin-top: 3px; display: block;
}
.md-cal-event .md-cal-body { min-width: 0; }
.md-cal-event .md-cal-title {
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em;
  line-height: 1.25; color: var(--md-text);
}
.md-cal-event .md-cal-meta {
  font-size: 11.5px; color: var(--md-text-muted); font-weight: 500;
  margin-top: 3px;
}
.md-cal-event .tag {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  padding: 4px 8px; border-radius: 999px;
}
.md-cal-event .tag.meeting { background: rgba(59,130,246,0.12); color: #1d4ed8; }
.md-cal-event .tag.shift { background: rgba(16,185,129,0.12); color: #047857; }
.md-cal-event .tag.deadline { background: rgba(220,38,38,0.1); color: var(--uni-red); }

.md-boards {
  display: grid; gap: 10px;
}
.md-board {
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: var(--md-radius-card);
  padding: 14px;
  cursor: pointer;
  position: relative;
  min-height: var(--md-tap);
}
.md-board:active { background: var(--md-bg-sunk); }
.md-board-title {
  font-size: 14.5px; font-weight: 700; letter-spacing: -0.01em;
  line-height: 1.25; color: var(--md-text);
  margin-bottom: 8px; padding-right: 32px;
  text-wrap: pretty;
}
.md-board-meta {
  display: flex; align-items: center; gap: 10px;
  font-size: 11.5px; color: var(--md-text-muted); font-weight: 500;
}
.md-board-meta .avs { display: flex; }
.md-board-meta .avs .av {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--md-bg-sunk); border: 2px solid var(--md-bg-elev);
  font-size: 9.5px; font-weight: 800; color: var(--md-text);
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: -6px;
}
.md-board-meta .avs .av:first-child { margin-left: 0; }
.md-board-meta .dot { color: var(--md-text-subtle); }
.md-board-count {
  position: absolute; top: 14px; right: 14px;
  background: var(--uni-red-soft); color: var(--uni-red);
  font-size: 11px; font-weight: 800;
  padding: 3px 8px; border-radius: 999px;
  font-feature-settings: "tnum";
}

.md-tiles {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.md-tile {
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: var(--md-radius-tile);
  padding: 16px 10px 14px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  cursor: pointer;
  min-height: 92px;
}
.md-tile:active { background: var(--md-bg-sunk); }
.md-tile-ico {
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--md-bg-sunk);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--md-text);
}
.md-tile-label {
  font-size: 11.5px; font-weight: 600; color: var(--md-text);
  text-align: center; line-height: 1.15;
  letter-spacing: -0.005em;
  text-wrap: balance;
}

.md-desktop-cta {
  margin-top: 24px;
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: var(--md-radius-card);
  padding: 16px;
  display: grid; gap: 12px;
}
.md-desktop-cta .md-warn {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 12px; color: var(--md-text-muted); line-height: 1.4;
  padding: 10px 12px;
  background: rgba(245,158,11,0.08);
  border: 1px solid rgba(245,158,11,0.2);
  border-radius: 10px;
}
.md-desktop-cta .md-warn svg {
  flex-shrink: 0; color: var(--md-warn); margin-top: 1px;
}
.md-desktop-cta .md-warn b { color: var(--md-text); font-weight: 700; }
.md-desktop-cta .md-desktop-btn {
  background: var(--md-text); color: var(--md-bg-elev);
  border: none;
  font-family: inherit; font-size: 14px; font-weight: 700;
  letter-spacing: -0.01em;
  padding: 14px 16px;
  border-radius: 12px;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  cursor: pointer;
  min-height: var(--md-tap);
}
.md-desktop-cta .md-desktop-btn:active { opacity: 0.9; }

.md-menu-scrim {
  position: absolute; inset: 0; z-index: 30;
  background: rgba(0,0,0,0.4);
  opacity: 0; pointer-events: none;
  transition: opacity 200ms;
}
.md-menu-scrim.open { opacity: 1; pointer-events: auto; }

.md-menu {
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 82%; max-width: 320px;
  background: var(--md-bg-elev);
  z-index: 31;
  transform: translateX(-100%);
  transition: transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
  display: flex; flex-direction: column;
  box-shadow: 0 25px 60px -20px rgba(0,0,0,0.4);
}
.md-menu.open { transform: translateX(0); }
.md-menu-head {
  padding: 48px 20px 20px;
  background: var(--uni-red);
  color: white;
}
.md-menu-head .av {
  width: 52px; height: 52px; border-radius: 50%;
  background: rgba(255,255,255,0.2);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 18px; font-weight: 800; color: white;
  margin-bottom: 10px;
}
.md-menu-head .name {
  font-size: 17px; font-weight: 800; letter-spacing: -0.015em;
}
.md-menu-head .role {
  font-size: 12.5px; color: rgba(255,255,255,0.8); margin-top: 2px;
  font-weight: 500;
}
.md-menu-items { flex: 1; padding: 8px 0; overflow-y: auto; }
.md-menu-item {
  display: grid; grid-template-columns: 36px 1fr auto; gap: 10px; align-items: center;
  padding: 13px 20px;
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em;
  color: var(--md-text);
  cursor: pointer;
  min-height: 52px;
}
.md-menu-item:active { background: var(--md-bg-sunk); }
.md-menu-item svg { color: var(--md-text-muted); }
.md-menu-item .md-badge {
  background: var(--uni-red); color: white;
  font-size: 11px; font-weight: 800;
  padding: 2px 7px; border-radius: 999px;
  min-width: 20px; text-align: center;
}
.md-menu-divider {
  height: 1px; background: var(--md-border); margin: 8px 20px;
}
.md-menu-foot {
  padding: 12px 20px 28px;
  border-top: 1px solid var(--md-border);
}
.md-menu-foot .logout {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 14px;
  background: var(--md-bg-sunk);
  border: 1px solid var(--md-border);
  border-radius: 12px;
  font-family: inherit; font-size: 14px; font-weight: 700;
  color: var(--uni-red); cursor: pointer;
  min-height: var(--md-tap);
}

.md-sheet-scrim {
  position: absolute; inset: 0; z-index: 30;
  background: rgba(0,0,0,0.4);
  opacity: 0; pointer-events: none;
  transition: opacity 200ms;
}
.md-sheet-scrim.open { opacity: 1; pointer-events: auto; }
.md-sheet {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--md-bg-elev);
  border-radius: 24px 24px 0 0;
  z-index: 31;
  transform: translateY(100%);
  transition: transform 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
  max-height: 75%;
  display: flex; flex-direction: column;
}
.md-sheet.open { transform: translateY(0); }
.md-sheet .handle {
  width: 36px; height: 4px; border-radius: 2px;
  background: var(--md-border-strong);
  margin: 10px auto 0;
}
.md-sheet .md-sheet-head {
  padding: 16px 20px 12px;
  display: flex; align-items: baseline; justify-content: space-between;
  border-bottom: 1px solid var(--md-border);
}
.md-sheet .md-sheet-head h3 {
  margin: 0; font-size: 17px; font-weight: 800; letter-spacing: -0.015em;
}
.md-sheet .md-sheet-head .clear {
  color: var(--uni-red); font-size: 13px; font-weight: 700;
  background: none; border: none; cursor: pointer;
}
.md-sheet .md-sheet-list { overflow-y: auto; flex: 1; }
.md-alert {
  display: grid; grid-template-columns: 36px 1fr auto; gap: 12px; align-items: flex-start;
  padding: 14px 20px;
  border-bottom: 1px solid var(--md-border);
  cursor: pointer;
}
.md-alert .ac {
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--md-bg-sunk);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.md-alert.err .ac { background: rgba(239,68,68,0.12); color: var(--md-err); }
.md-alert.warn .ac { background: rgba(245,158,11,0.12); color: var(--md-warn); }
.md-alert.info .ac { background: rgba(59,130,246,0.12); color: #2563eb; }
.md-alert-body { min-width: 0; }
.md-alert-title {
  font-size: 13.5px; font-weight: 700; letter-spacing: -0.01em;
  line-height: 1.25; color: var(--md-text); text-wrap: pretty;
}
.md-alert-sub {
  font-size: 12px; color: var(--md-text-muted); line-height: 1.4;
  margin-top: 3px; text-wrap: pretty;
}
.md-alert-time {
  font-size: 11px; color: var(--md-text-subtle); font-weight: 600;
  font-feature-settings: "tnum";
  flex-shrink: 0;
}

/* ───────────────────────────────────────────── */
/* Persistent mobile nav (floating hamburger on  */
/* every route at phone widths, except /m which  */
/* has its own topbar hamburger)                 */
/* ───────────────────────────────────────────── */

#mobile-nav-root {
    font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
#mobile-nav-root[hidden] { display: none !important; }
body.is-mobile-dashboard #mobile-nav-root,
body.mobile-nav-hidden #mobile-nav-root { display: none !important; }
/* iPads use the standard desktop layout now (device.js no longer returns
   'tablet'), so the phone FAB must never appear on them. mobileNav.js's
   [hidden] gate handles this in JS; pin it in CSS too so a sub-901px tablet
   can't flash the FAB before the body class is applied. */
body.device-desktop #mobile-nav-root,
body.device-tablet #mobile-nav-root { display: none !important; }

@media (min-width: 901px) {
    #mobile-nav-root { display: none !important; }
}

/* iPad mini / 9.7" portrait (≤768px) are classed device-desktop now (device.js),
   but the width-based mobile shell in the `@media (max-width: 768px)` block would
   still off-canvas their sidebar and show the mobile topbar. Re-dock the sidebar
   and drop the topbar so these small iPads get the standard layout like every
   other iPad. Scoped to ≤768px so normal desktop sidebar-collapse is untouched;
   phones (device-mobile) keep their shell. */
@media (max-width: 768px) {
    body.device-desktop #mobile-topbar { display: none !important; }
    body.device-desktop .sidebar {
        position: static;
        left: auto;
        top: auto;
        height: auto;
        width: 260px !important;
        box-shadow: none;
        z-index: 10;
    }
}

/* When our mobile-nav FAB is active, hide the desktop sidebar's topbar
   hamburger so there aren't two hamburgers competing for the same slot,
   and shift the topbar's content right so the logo doesn't sit under our
   44px FAB. The `body.mobile-nav-hidden` exclusion means a user who
   explicitly chose "Open full desktop dashboard" gets the real desktop
   chrome back. */
@media (max-width: 900px) {
    body:not(.is-mobile-dashboard):not(.mobile-nav-hidden) #mobile-menu-btn { display: none !important; }
    body:not(.is-mobile-dashboard):not(.mobile-nav-hidden) #mobile-topbar {
        padding-left: calc(68px + env(safe-area-inset-left, 0px)) !important;
    }
    /* Show the escape-hatch pill whenever the user has opted into desktop mode. */
    body.mobile-nav-hidden #btn-switch-to-mobile { display: inline-flex !important; }
}

/* Read alerts in the mobile bottom-sheet — dimmed so new unread rows pop. */
#view-mobile-dashboard .md-alert.md-alert-read { opacity: 0.5; }
#view-mobile-dashboard .md-alert.md-alert-read .md-alert-title { font-weight: 500; }

#mobile-nav-root .mn-fab {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 4px);
    left: calc(12px + env(safe-area-inset-left, 0px));
    width: 44px; height: 44px;
    border-radius: 12px;
    background: #ffffff;
    border: 1px solid rgba(16, 16, 20, 0.08);
    color: #17171a;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 6px 18px -6px rgba(0, 0, 0, 0.28), 0 2px 6px rgba(0, 0, 0, 0.08);
    cursor: pointer;
    padding: 0;
    z-index: 9999;
    transition: background-color 120ms;
}
#mobile-nav-root .mn-fab:active { background: #efeff1; }

#mobile-nav-root .mn-scrim {
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.4);
    opacity: 0; pointer-events: none;
    transition: opacity 200ms;
    z-index: 9998;
}
#mobile-nav-root.is-open .mn-scrim { opacity: 1; pointer-events: auto; }

#mobile-nav-root .mn-panel {
    position: fixed; top: 0; bottom: 0; left: 0;
    width: 82%; max-width: 320px;
    background: #ffffff;
    z-index: 10000;
    transform: translateX(-100%);
    transition: transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1);
    display: flex; flex-direction: column;
    box-shadow: 0 25px 60px -20px rgba(0, 0, 0, 0.4);
    color: #17171a;
}
#mobile-nav-root.is-open .mn-panel { transform: translateX(0); }

#mobile-nav-root .mn-head {
    padding: calc(28px + env(safe-area-inset-top, 0px)) 20px 20px;
    background: #dc2626;
    color: #ffffff;
}
#mobile-nav-root .mn-av {
    width: 52px; height: 52px; border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 18px; font-weight: 800; color: #ffffff;
    margin-bottom: 10px;
}
#mobile-nav-root .mn-name {
    font-size: 17px; font-weight: 800; letter-spacing: -0.015em;
}
#mobile-nav-root .mn-role {
    font-size: 12.5px; color: rgba(255, 255, 255, 0.8);
    margin-top: 2px; font-weight: 500;
}

#mobile-nav-root .mn-items {
    flex: 1;
    padding: 8px 0;
    overflow-y: auto;
}
#mobile-nav-root .mn-item {
    display: grid;
    grid-template-columns: 36px 1fr;
    gap: 10px;
    align-items: center;
    width: 100%;
    padding: 13px 20px;
    min-height: 52px;
    background: transparent;
    border: 0;
    cursor: pointer;
    font: inherit;
    font-size: 14.5px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: #17171a;
    text-align: left;
}
#mobile-nav-root .mn-item:active { background: #efeff1; }
#mobile-nav-root .mn-item-ico {
    display: inline-flex; align-items: center; justify-content: center;
    color: #6b7280;
    width: 36px;
}

#mobile-nav-root .mn-foot {
    padding: 12px 20px calc(20px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid rgba(16, 16, 20, 0.08);
}
#mobile-nav-root .mn-logout {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    width: 100%; padding: 14px;
    background: #efeff1;
    border: 1px solid rgba(16, 16, 20, 0.08);
    border-radius: 12px;
    font: inherit;
    font-size: 14px; font-weight: 700;
    color: #dc2626;
    cursor: pointer;
    min-height: 48px;
}

/* ============================================================
   Mobile Task Planner (variant B · "Now Hub")
   Ported from .planning/Mobile task planner/ERP/planner_b_full_styles.css.
   Every selector is scoped under `body.is-mobile-planner` so these rules
   never leak to the desktop /planner view. The design's `.pv-phone /
   .pv-screen / .pv-app / .pv-status / .pv-notch` faux-iOS frame is
   intentionally not ported. The design's own `bf-bot-fab` (UniBot mini)
   is also not ported — the real `#unibot-chip` self-injects on every page.
   ============================================================ */

/* CSS variables shared with the mobile dashboard. Re-declared on the
   mobile-planner body class so the `--md-*` lookups inside the .bf-*
   rules resolve regardless of nesting. */
body.is-mobile-planner,
#view-mobile-planner {
  --uni-red: #dc2626;
  --uni-red-hover: #b91c1c;
  --uni-red-soft: rgba(220, 38, 38, 0.08);

  --md-bg: #f5f5f7;
  --md-bg-elev: #ffffff;
  --md-bg-sunk: #efeff1;
  --md-border: rgba(16, 16, 20, 0.08);
  --md-border-strong: rgba(16, 16, 20, 0.14);
  --md-text: #17171a;
  --md-text-muted: #6b7280;
  --md-text-subtle: #9ca3af;

  --md-ok: #10b981;
  --md-warn: #f59e0b;
  --md-err: #ef4444;

  --md-radius-card: 16px;
  --md-radius-tile: 14px;
  --md-tap: 56px;

  --md-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --md-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Mirror the mobile-dashboard's overlay treatment: ancestors with
   `contain: layout` would trap our fixed-positioned view inside
   .main-content. Null those out so the planner fills the viewport. */
body.is-mobile-planner .sidebar { display: none; }
body.is-mobile-planner #mobile-topbar { display: none !important; }
body.is-mobile-planner #sidebar-backdrop { display: none !important; }
body.is-mobile-planner #mobile-nav-root { display: none !important; }

body.is-mobile-planner .main-content,
body.is-mobile-planner .content {
    contain: none;
    padding: 0 !important;
    overflow: visible;
}
body.is-mobile-planner .view {
    contain: none;
    animation: none;
    overflow: visible;
    max-width: none;
}

#view-mobile-planner.view.active {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset: 0;
    z-index: 1000;
    animation: none;
    overflow: hidden;
}

#view-mobile-planner,
#view-mobile-planner * { box-sizing: border-box; }

body.is-mobile-planner {
  margin: 0;
  padding: 0;
  font-family: var(--md-font);
  color: var(--md-text);
  -webkit-font-smoothing: antialiased;
  background: #e8e8ea;
  min-height: 100vh;
}

#view-mobile-planner button { font-family: inherit; }

/* Inner app shell */
body.is-mobile-planner .bf-app {
  height: 100%; width: 100%;
  display: flex; flex-direction: column;
  background: var(--md-bg);
  position: relative; overflow: hidden;
}

/* Topbar — reuses the mobile-dashboard `.md-top` skeleton; the bf-top
   modifier is just so future tweaks don't bleed into /m. */
body.is-mobile-planner .md-top {
  display: flex; align-items: center; gap: 10px;
  padding: max(14px, env(safe-area-inset-top, 0)) 16px 12px;
  flex: 0 0 auto;
}
body.is-mobile-planner .md-top .md-hamburger,
body.is-mobile-planner .md-top .md-bell {
  width: 44px; height: 44px; border-radius: 12px;
  background: var(--md-bg-elev); border: 1px solid var(--md-border);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--md-text);
  padding: 0;
}
body.is-mobile-planner .md-top .md-greet-wrap { flex: 1; min-width: 0; }
body.is-mobile-planner .md-top .md-greet {
  font-size: 18px; font-weight: 800; letter-spacing: -0.015em; line-height: 1.1;
  color: var(--md-text);
}
body.is-mobile-planner .md-top .md-date {
  font-size: 11.5px; font-weight: 600; color: var(--md-text-muted);
  margin-top: 2px;
}

/* Body scroll */
body.is-mobile-planner .md-body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  padding: 4px 0 calc(140px + env(safe-area-inset-bottom, 0));
  -webkit-overflow-scrolling: touch;
}
body.is-mobile-planner .bf-body { padding-bottom: 100px; }

body.is-mobile-planner .bf-loading {
    padding: 1rem 16px;
    color: var(--md-text-muted);
    font-size: 0.85rem;
    text-align: center;
}

/* ===================== Now hub card =====================
   Shared between mobile (`mobilePlanner.js`) and desktop (`planner.js`).
   Both surfaces render `<div class="bf-now [bf-now-meeting]">` so a
   visual change here propagates to both. The mobile-specific outer
   margin (positions the card under the topbar) stays scoped to mobile;
   desktop slots the bf-now into `#planner-now-card` directly. */
.bf-now {
  background: linear-gradient(135deg, #065f46 0%, #047857 50%, #059669 100%);
  border-radius: 22px;
  padding: 20px;
  color: white;
  position: relative;
  overflow: hidden;
  /* Neutral drop-shadow only — earlier versions used a green-tinted
     shadow which read as a green halo/border on the right edge of the
     desktop card. Plain shadow keeps depth without colour bleed. */
  box-shadow: 0 12px 28px -14px rgba(0,0,0,0.25);
}
body.is-mobile-planner .bf-now { margin: 6px 16px 14px; }
/* Blue Now Card — shown when the user is currently inside a meeting
   OR a meeting is starting within the 5-min nudge window. Same blue
   palette as the day-rail meeting rows so the visual language stays
   consistent. Overrides the green task gradient above. Shadow stays
   neutral (no blue halo). */
.bf-now.bf-now-meeting {
  background: linear-gradient(135deg, #1e3a8a 0%, #1d4ed8 50%, #2563eb 100%);
}
.bf-now.bf-now-meeting .bf-now-actions button.primary { color: #1d4ed8; }
.bf-now::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(70% 50% at 100% 0%, rgba(255,255,255,0.18) 0%, transparent 60%);
  pointer-events: none;
}
.bf-now-eye {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: rgba(255,255,255,0.9);
  margin-bottom: 12px;
}
.bf-now-eye .live {
  width: 8px; height: 8px; border-radius: 50%;
  background: white;
  animation: mdPulse 1.5s ease-in-out infinite;
}
.bf-now-title {
  position: relative;
  margin: 0 0 12px;
  font-size: 21px; font-weight: 800;
  letter-spacing: -0.02em; line-height: 1.2;
  text-wrap: balance;
}
.bf-now-meta {
  position: relative;
  display: flex; gap: 6px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.bf-now-meta .chip {
  font-size: 10.5px; font-weight: 700;
  padding: 4px 9px;
  background: rgba(255,255,255,0.18);
  border-radius: 999px;
  color: white;
  display: inline-flex; align-items: center; gap: 5px;
}
.bf-now-meta .chip .ps { width: 7px; height: 7px; border-radius: 2px; }
.bf-now-meta .chip.timer {
  font-family: var(--md-font-mono);
  font-feature-settings: "tnum";
  background: rgba(255,255,255,0.28);
}
.bf-now-clock {
  position: relative;
  font-family: var(--md-font-mono);
  font-feature-settings: "tnum";
  font-size: 36px; font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 14px;
  line-height: 1;
}
/* Flex (not grid) so 2 buttons on mobile + 3 buttons on desktop both
   distribute width evenly. Wraps on narrow widths. */
.bf-now-actions {
  position: relative;
  display: flex; flex-wrap: wrap;
  gap: 8px;
}
.bf-now-actions button {
  flex: 1; min-width: 0;
  height: 44px;
  padding: 0 12px;
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,0.3);
  background: rgba(255,255,255,0.15);
  color: white;
  font-size: 13.5px; font-weight: 700;
  letter-spacing: -0.005em;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer;
  font-family: inherit;
  box-shadow: 0 1px 3px rgba(0,0,0,0.18), inset 0 1px 0 rgba(255,255,255,0.18);
}
.bf-now-actions button.primary {
  background: white; color: #047857;
  border-color: white;
}
.bf-now-actions button:active { transform: scale(0.97); }

/* Desktop-specific tuning — fits inside the right-column "Now" slot
   with smaller header-less padding and a tighter type scale. */
body:not(.is-mobile-planner) #planner-now-card .bf-now { border-radius: 14px; padding: 14px 16px; }
body:not(.is-mobile-planner) #planner-now-card .bf-now-title { font-size: 1rem; margin: 0 0 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body:not(.is-mobile-planner) #planner-now-card .bf-now-clock { font-size: 1.5rem; margin-bottom: 10px; }
body:not(.is-mobile-planner) #planner-now-card .bf-now-eye { margin-bottom: 8px; }
body:not(.is-mobile-planner) #planner-now-card .bf-now-actions button { height: 36px; font-size: 0.78rem; }

/* Empty state — single full-width button */
.bf-now-empty .bf-now-actions { flex-direction: column; }
.bf-now-empty .bf-now-actions button { flex: 0 0 auto; width: 100%; }

/* ===================== Overdue strip ===================== */
body.is-mobile-planner .bf-overdue {
  margin: 0 16px 14px;
  background: rgba(239,68,68,0.05);
  border: 1px solid rgba(239,68,68,0.25);
  border-radius: 16px;
  overflow: hidden;
}
body.is-mobile-planner .bf-overdue-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px dashed rgba(239,68,68,0.25);
}
body.is-mobile-planner .bf-overdue-eye {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 10.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: #dc2626;
}
body.is-mobile-planner .bf-overdue-eye .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: #dc2626;
  animation: mdPulse 1.5s ease-in-out infinite;
}
body.is-mobile-planner .bf-overdue-head .n {
  font-size: 11px; font-weight: 800;
  background: #dc2626; color: white;
  padding: 2px 8px; border-radius: 999px;
  font-feature-settings: "tnum";
}
body.is-mobile-planner .bf-overdue-list { display: grid; }
body.is-mobile-planner .bf-overdue-row {
  display: grid;
  /* first column widened from 24px to 44px for the new pill-shaped check
     affordance. The whole row used to be tappable; now only the pill on the
     left fires the complete action — `cursor:default` on the wrapper makes
     that explicit. */
  grid-template-columns: 44px 1fr auto;
  gap: 10px; align-items: center;
  padding: 8px 14px;
  border-top: 1px solid rgba(239,68,68,0.15);
}
body.is-mobile-planner .bf-overdue-row:first-child { border-top: none; }
body.is-mobile-planner .bf-overdue-check {
  /* Pill-shaped tap target so the row's "complete" affordance is obvious.
     Empty button + "Done" label reads as a button; check icon only fades
     in on press as a "yes, this completes it" hint. Red-tinted because
     overdue rows live in the overdue strip. */
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px;
  width: 44px; min-height: 44px;
  border-radius: 14px;
  border: 1.5px solid rgba(220,38,38,0.5);
  background: white;
  color: #dc2626;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
  flex-shrink: 0;
  transition: background 120ms, color 120ms, transform 120ms;
}
body.is-mobile-planner .bf-overdue-check svg { display: none; }
body.is-mobile-planner .bf-overdue-check:active {
  background: rgba(220,38,38,0.12);
  border-color: #dc2626;
  transform: scale(0.95);
}
body.is-mobile-planner .bf-overdue-check:active svg { display: block; }
body.is-mobile-planner .bf-overdue-check .bf-check-hint {
  font-size: 8.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: #dc2626;
  line-height: 1;
}
body.is-mobile-planner .bf-overdue-body { min-width: 0; }
body.is-mobile-planner .bf-overdue-title {
  font-size: 13.5px; font-weight: 600;
  color: var(--md-text); line-height: 1.3;
  letter-spacing: -0.005em;
}
body.is-mobile-planner .bf-overdue-meta {
  display: flex; gap: 6px; align-items: center;
  font-size: 10.5px; color: var(--md-text-muted);
  margin-top: 3px; font-weight: 500;
}
body.is-mobile-planner .bf-overdue-meta .proj-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; font-weight: 700;
  padding: 1px 6px; border-radius: 999px;
  background: white;
  border: 1px solid var(--md-border);
  color: var(--md-text);
}
body.is-mobile-planner .bf-overdue-meta .proj-chip .ps { width: 6px; height: 6px; border-radius: 2px; }
body.is-mobile-planner .bf-overdue-meta .pv-pdot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--md-text-subtle);
}
body.is-mobile-planner .bf-overdue-meta .pv-pdot.p1 { background: #dc2626; }
body.is-mobile-planner .bf-overdue-meta .pv-pdot.p2 { background: #f59e0b; }
body.is-mobile-planner .bf-overdue-meta .pv-pdot.p3 { background: var(--md-text-subtle); }

body.is-mobile-planner .bf-overdue-tag {
  font-family: var(--md-font-mono);
  font-size: 10px; font-weight: 700;
  color: #dc2626;
  background: white;
  padding: 3px 8px; border-radius: 999px;
  border: 1px solid rgba(239,68,68,0.3);
  font-feature-settings: "tnum";
}

/* ===================== Filter pills ===================== */
body.is-mobile-planner .bf-pills {
  display: flex; gap: 6px;
  padding: 4px 16px 14px;
  overflow-x: auto;
  scrollbar-width: none;
}
body.is-mobile-planner .bf-pills::-webkit-scrollbar { display: none; }
body.is-mobile-planner .bf-pill {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 12px;
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: 999px;
  font-size: 12.5px; font-weight: 700;
  color: var(--md-text-muted);
  font-family: inherit;
  cursor: pointer;
}
body.is-mobile-planner .bf-pill .ic { display: inline-flex; align-items: center; }
body.is-mobile-planner .bf-pill .n {
  font-size: 11px; font-weight: 800;
  padding: 1px 7px; border-radius: 999px;
  background: var(--md-bg-sunk);
  color: var(--md-text-muted);
  font-feature-settings: "tnum";
}
body.is-mobile-planner .bf-pill.on {
  background: var(--md-text);
  border-color: var(--md-text);
  color: white;
}
body.is-mobile-planner .bf-pill.on .n {
  background: rgba(255,255,255,0.22);
  color: white;
}

/* ===================== Day section ===================== */
body.is-mobile-planner .bf-day { margin: 0 16px; }
body.is-mobile-planner .bf-day-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 10px;
}
body.is-mobile-planner .bf-day-head-title {
  font-size: 13px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--md-text);
}
body.is-mobile-planner .bf-day-head-sub {
  font-size: 11px; font-weight: 600;
  color: var(--md-text-muted);
  font-feature-settings: "tnum";
}

body.is-mobile-planner .bf-rail {
  position: relative;
  display: grid;
  gap: 10px;
  padding: 4px 0 8px;
}
body.is-mobile-planner .bf-rail::before {
  content: "";
  position: absolute;
  left: 50px; top: 4px; bottom: 8px;
  width: 2px;
  background: linear-gradient(to bottom, transparent 0%, var(--md-border) 8px, var(--md-border) calc(100% - 8px), transparent 100%);
  border-radius: 1px;
}

body.is-mobile-planner .bf-item {
  position: relative;
  display: grid;
  grid-template-columns: 50px 1fr;
  gap: 12px;
  align-items: stretch;
}
body.is-mobile-planner .bf-rail-col {
  display: flex; flex-direction: column; align-items: center;
  padding-top: 10px;
  position: relative;
}
body.is-mobile-planner .bf-time {
  display: flex; flex-direction: column; align-items: center;
  background: var(--md-bg-elev);
  border: 1.5px solid var(--md-border);
  border-radius: 10px;
  padding: 5px 0;
  width: 48px;
  font-family: var(--md-font-mono);
  font-feature-settings: "tnum";
  position: relative;
  z-index: 2;
}
body.is-mobile-planner .bf-time .h {
  font-size: 12.5px; font-weight: 700;
  color: var(--md-text); line-height: 1;
}
body.is-mobile-planner .bf-time .dur {
  font-size: 9px; font-weight: 700;
  color: var(--md-text-muted);
  margin-top: 3px;
  text-transform: uppercase;
}
body.is-mobile-planner .bf-time.bell {
  background: rgba(245,158,11,0.1);
  border-color: rgba(245,158,11,0.4);
  color: #b45309;
  padding: 7px 0;
}
body.is-mobile-planner .bf-time.bell .ic {
  display: inline-flex; align-items: center; justify-content: center;
  color: #b45309;
  margin-bottom: 3px;
}
body.is-mobile-planner .bf-time.bell .h { color: #b45309; font-size: 11px; }

body.is-mobile-planner .bf-item.past .bf-time { opacity: 0.55; }
body.is-mobile-planner .bf-item.past .bf-card { opacity: 0.65; }
body.is-mobile-planner .bf-item.now .bf-time {
  background: var(--uni-red); border-color: var(--uni-red);
}
body.is-mobile-planner .bf-item.now .bf-time .h,
body.is-mobile-planner .bf-item.now .bf-time .dur { color: white; }
body.is-mobile-planner .bf-item.now .bf-time .dur { color: rgba(255,255,255,0.85); }

/* ===================== Task card ===================== */
body.is-mobile-planner .bf-task .bf-card {
  display: grid;
  /* third column widened to fit the 48px "Done?" pill that replaced the
     original 24px circle. Body column (1fr) absorbs the difference. */
  grid-template-columns: 4px 1fr 56px;
  background: var(--md-bg-elev);
  border: 1px solid var(--md-border);
  border-radius: 14px;
  overflow: hidden;
  cursor: pointer;
  align-items: stretch;
}
body.is-mobile-planner .bf-task .bf-card:active { background: var(--md-bg-sunk); }
body.is-mobile-planner .bf-task.now .bf-card {
  border-color: var(--uni-red);
  box-shadow: 0 8px 22px -10px rgba(220,38,38,0.4);
}
/* Completed-today task row — visually dim the whole thing so it reads as
   "log entry, not action item". Strikethrough on the title alone wasn't
   enough; the project bar + chips were still loud. Combination: 0.55
   opacity drops the visual weight, grey-toned card background, drained
   project bar (saturate 0.3 + opacity), and strikethrough title. */
body.is-mobile-planner .bf-task.done {
  opacity: 0.55;
}
body.is-mobile-planner .bf-task.done .bf-card {
  background: var(--md-bg-sunk);
  border-color: rgba(0,0,0,0.06);
  box-shadow: none;
}
body.is-mobile-planner .bf-task.done .bf-card-bar {
  filter: saturate(0.25);
  opacity: 0.5;
}
body.is-mobile-planner .bf-task.done .bf-card-title {
  text-decoration: line-through;
  color: var(--md-text-subtle);
}
body.is-mobile-planner .bf-task.done .bf-card-eye .proj-chip,
body.is-mobile-planner .bf-task.done .bf-card-eye .prio {
  filter: grayscale(0.7);
  opacity: 0.7;
}
body.is-mobile-planner .bf-card-bar { width: 4px; }
body.is-mobile-planner .bf-card-body {
  padding: 10px 12px 12px;
  min-width: 0;
}
body.is-mobile-planner .bf-card-eye {
  display: flex; align-items: center; gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
body.is-mobile-planner .bf-card-eye .kind {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--md-text-muted);
}
body.is-mobile-planner .bf-card-eye .kind.mtg { color: #2563eb; }
body.is-mobile-planner .bf-card-eye .kind .ic { display: inline-flex; }
body.is-mobile-planner .bf-card-eye .proj-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; font-weight: 700;
  padding: 1px 7px; border-radius: 999px;
  background: var(--md-bg-sunk);
  color: var(--md-text);
}
body.is-mobile-planner .bf-card-eye .proj-chip .ps { width: 6px; height: 6px; border-radius: 2px; }
body.is-mobile-planner .bf-card-eye .prio {
  font-size: 10px; font-weight: 800;
  padding: 1px 6px; border-radius: 4px;
  background: var(--md-bg-sunk);
  color: var(--md-text-muted);
}
body.is-mobile-planner .bf-card-eye .prio.p1 { background: rgba(220,38,38,0.1); color: #dc2626; }
body.is-mobile-planner .bf-card-eye .prio.p2 { background: rgba(245,158,11,0.12); color: #b45309; }
body.is-mobile-planner .bf-chunk-pill {
  font-family: monospace;
  font-size: 10px; font-weight: 800;
  padding: 1px 6px; border-radius: 4px;
  background: #e0e7ff; color: #4338ca;
  margin-left: auto;
}

body.is-mobile-planner .bf-card-title {
  font-size: 14px; font-weight: 600;
  color: var(--md-text); line-height: 1.3;
  letter-spacing: -0.005em;
  text-wrap: pretty;
}
body.is-mobile-planner .bf-card-running {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 8px;
  font-size: 10.5px; font-weight: 700;
  color: var(--uni-red);
  background: rgba(220,38,38,0.08);
  padding: 3px 8px; border-radius: 999px;
  font-family: var(--md-font-mono);
  font-feature-settings: "tnum";
}
body.is-mobile-planner .bf-card-running .live {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--uni-red);
  animation: mdPulse 1.5s ease-in-out infinite;
}
/* Done button — two visually-distinct states so the user instantly knows
   whether they're looking at an action ("Mark done") or a status ("Done").
     PENDING: neutral grey card-style pill with no check icon shown until
              press. Reads as "button, click me".
     COMPLETED (.on): solid green pill with white check + "Done" label.
              Reads as "status badge, this is finished".
   The shape (pill, 48x44) is the same so the row layout doesn't shift on
   toggle, only the colour scheme.  */
body.is-mobile-planner .bf-check {
  align-self: center;
  margin-right: 8px;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px;
  width: 48px; min-height: 44px;
  border-radius: 14px;
  border: 1.5px solid var(--md-border-strong, rgba(16,16,20,0.18));
  background: white;
  color: var(--md-text-muted, #6b7280);
  cursor: pointer;
  flex-shrink: 0;
  font-family: inherit;
  padding: 0;
  transition: background 120ms, color 120ms, transform 120ms, border-color 120ms;
}
/* Pending state intentionally hides the check icon — empty pill + label
   reads as "click to do this" rather than "check this off". A subtle
   green icon shows on press as a hint. */
body.is-mobile-planner .bf-check svg { display: none; }
body.is-mobile-planner .bf-check .bf-check-hint {
  font-size: 8.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--md-text-muted, #6b7280);
  line-height: 1;
}
body.is-mobile-planner .bf-check:active {
  background: rgba(16,185,129,0.14);
  border-color: var(--md-ok, #10b981);
  color: var(--md-ok, #10b981);
  transform: scale(0.95);
}
body.is-mobile-planner .bf-check:active svg { display: block; color: var(--md-ok, #10b981); }
body.is-mobile-planner .bf-check:active .bf-check-hint { color: var(--md-ok, #10b981); }

/* Completed state — solid green, white check ALWAYS visible, "Done"
   label. Distinct enough from pending that a glance tells you the
   status without parsing the text. */
body.is-mobile-planner .bf-check.on {
  background: var(--md-ok, #10b981);
  border-color: var(--md-ok, #10b981);
  color: white;
}
body.is-mobile-planner .bf-check.on svg { display: block; }
body.is-mobile-planner .bf-check.on .bf-check-hint { color: white; }

/* ===================== Meeting card ===================== */
body.is-mobile-planner .bf-meeting .bf-card.mtg {
  background: linear-gradient(180deg, rgba(37,99,235,0.05) 0%, rgba(37,99,235,0.02) 100%);
  border: 1px solid rgba(37,99,235,0.25);
  border-radius: 14px;
  overflow: hidden;
  cursor: pointer;
  position: relative;
}
body.is-mobile-planner .bf-meeting .bf-card.mtg::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 4px;
  background: #2563eb;
}
body.is-mobile-planner .bf-meeting .bf-card.mtg:active { background: rgba(37,99,235,0.08); }
body.is-mobile-planner .bf-meeting.now .bf-card.mtg {
  border-color: #2563eb;
  box-shadow: 0 8px 22px -10px rgba(37,99,235,0.4);
}
body.is-mobile-planner .bf-meeting .bf-card-body { padding: 10px 12px 12px 14px; }

body.is-mobile-planner .bf-mtg-row {
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px;
  font-size: 11.5px; color: #1d4ed8;
  font-weight: 600;
}
body.is-mobile-planner .bf-mtg-where {
  display: inline-flex; align-items: center; gap: 5px;
}
body.is-mobile-planner .bf-mtg-where svg { color: #2563eb; }

body.is-mobile-planner .bf-mtg-foot {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 10px;
  gap: 8px;
}
body.is-mobile-planner .bf-avatars {
  display: flex; align-items: center;
}
body.is-mobile-planner .bf-avatars .av {
  width: 24px; height: 24px; border-radius: 50%;
  background: #dbeafe;
  border: 1.5px solid white;
  margin-left: -6px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 9.5px; font-weight: 800;
  color: #1d4ed8;
  font-family: var(--md-font-mono);
}
body.is-mobile-planner .bf-avatars .av:first-child { margin-left: 0; }
body.is-mobile-planner .bf-avatars .av.you {
  background: var(--md-text); color: white;
}
body.is-mobile-planner .bf-avatars .av.plus {
  background: white; color: #1d4ed8;
  border-color: #bfdbfe;
}
body.is-mobile-planner .bf-join {
  display: inline-flex; align-items: center; gap: 4px;
  height: 30px;
  padding: 0 12px;
  border-radius: 999px;
  background: #2563eb;
  color: white;
  border: none;
  font-size: 12px; font-weight: 700;
  font-family: inherit;
  cursor: pointer;
}
body.is-mobile-planner .bf-join.ghost {
  background: white;
  color: #1d4ed8;
  border: 1px solid rgba(37,99,235,0.3);
}
body.is-mobile-planner .bf-join:active { transform: scale(0.97); }

/* ===================== Reminder row ===================== */
body.is-mobile-planner .bf-reminder .bf-rmd {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px; align-items: center;
  background: rgba(245,158,11,0.06);
  border: 1px dashed rgba(245,158,11,0.45);
  border-radius: 14px;
  padding: 10px 12px;
  margin-top: 6px;
}
body.is-mobile-planner .bf-reminder.dismissed .bf-rmd {
  opacity: 0.5;
  background: var(--md-bg-sunk);
  border-style: solid;
  border-color: var(--md-border);
}
body.is-mobile-planner .bf-reminder.dismissed .bf-rmd-title { text-decoration: line-through; color: var(--md-text-subtle); }
body.is-mobile-planner .bf-rmd-body { min-width: 0; }
body.is-mobile-planner .bf-rmd-eye {
  display: flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: #b45309;
  margin-bottom: 4px;
}
body.is-mobile-planner .bf-rmd-recur,
body.is-mobile-planner .bf-rmd-personal {
  font-size: 9.5px; font-weight: 700;
  padding: 1px 6px; border-radius: 999px;
  background: rgba(245,158,11,0.18);
  color: #b45309;
  text-transform: none; letter-spacing: 0;
}
body.is-mobile-planner .bf-rmd-personal {
  background: rgba(124,58,237,0.12);
  color: #6d28d9;
}
body.is-mobile-planner .bf-rmd-title {
  font-size: 13.5px; font-weight: 600;
  color: var(--md-text); line-height: 1.3;
  letter-spacing: -0.005em;
}
body.is-mobile-planner .bf-rmd-actions {
  display: flex; gap: 6px;
  flex-shrink: 0;
}
body.is-mobile-planner .bf-rmd-actions button {
  height: 30px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 11.5px; font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  border: 1px solid var(--md-border);
  background: white;
  color: var(--md-text);
}
body.is-mobile-planner .bf-rmd-done {
  background: #b45309 !important;
  color: white !important;
  border-color: #b45309 !important;
  display: inline-flex; align-items: center; gap: 4px;
}
body.is-mobile-planner .bf-rmd-done.on {
  background: var(--md-ok) !important;
  border-color: var(--md-ok) !important;
}

/* ===================== Now marker ===================== */
body.is-mobile-planner .bf-nowmark {
  display: grid;
  grid-template-columns: 50px 1fr;
  gap: 12px;
  align-items: center;
  margin: 4px 0;
  position: relative;
  z-index: 3;
}
body.is-mobile-planner .bf-nowmark-rail {
  display: flex; align-items: center; justify-content: center;
  position: relative;
}
body.is-mobile-planner .bf-nowmark-rail .dot {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--uni-red);
  border: 3px solid var(--md-bg);
  box-shadow: 0 0 0 2px var(--uni-red);
}
body.is-mobile-planner .bf-nowmark-time {
  font-family: var(--md-font-mono);
  font-size: 11px; font-weight: 800;
  color: var(--uni-red);
  font-feature-settings: "tnum";
  text-transform: uppercase; letter-spacing: 0.05em;
  position: relative;
  display: flex; align-items: center; gap: 8px;
}
body.is-mobile-planner .bf-nowmark-time::after {
  content: "";
  flex: 1;
  height: 2px;
  background: linear-gradient(to right, var(--uni-red) 0%, transparent 100%);
}

/* ===================== FAB ===================== */
/* The design's `bf-bot-fab` (UniBot mini) is intentionally not ported — the
   real `#unibot-chip` self-injects in unibot.js. Place our `+` FAB at right:18px
   so the chip (right:110px on mobile) and our FAB don't overlap. */
/* + FAB sits bottom-left to clear the UNIBOT chip + chat-widget FAB on the
   right. Sized 70x70 to match #unibot-chip and #btn-floating-chat-toggle so
   the three controls feel like a coordinated set. The chat/UNIBOT live in
   <body> at z-index 9998; this FAB is inside #view-mobile-planner (z-index
   1000) so it can't out-z-index them — moving it to the left side avoids
   the stacking-context fight entirely. */
body.is-mobile-planner .bf-fab-wrap {
  position: fixed;
  left: calc(30px + env(safe-area-inset-left, 0px));
  bottom: calc(40px + env(safe-area-inset-bottom, 0px));
  z-index: 1100;
}
body.is-mobile-planner .bf-fab-wrap .pv-fab {
  position: relative;
  right: auto; bottom: auto;
  width: 70px; height: 70px;
  border-radius: 50%;
  background: var(--uni-red);
  color: white;
  border: none;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 15px rgba(0,0,0,0.3);
  cursor: pointer;
  font-family: inherit;
  transition: transform 200ms cubic-bezier(.4,1.4,.6,1);
}
body.is-mobile-planner .bf-fab-wrap .pv-fab:active { transform: scale(0.95); }
body.is-mobile-planner .bf-fab.pv-fab.open {
  transform: rotate(45deg);
  background: #1a1a1f;
  box-shadow: 0 12px 24px -8px rgba(0,0,0,0.45);
}
body.is-mobile-planner .bf-fab-menu {
  position: absolute;
  left: 0; bottom: 80px;
  display: flex; flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  animation: bfFabIn 180ms ease-out;
}
@keyframes bfFabIn {
  from { opacity: 0; transform: translateY(8px) scale(0.95); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
body.is-mobile-planner .bf-fab-menu-item {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 14px 10px 12px;
  background: white;
  border: 1px solid var(--md-border);
  border-radius: 999px;
  font-family: inherit;
  font-size: 13px; font-weight: 700;
  color: var(--md-text);
  cursor: pointer;
  box-shadow: 0 8px 20px -8px rgba(0,0,0,0.25);
  white-space: nowrap;
}
body.is-mobile-planner .bf-fab-menu-item:active { transform: scale(0.96); }
body.is-mobile-planner .bf-fab-menu-item .ic {
  width: 28px; height: 28px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--md-bg-sunk);
  color: var(--md-text);
}
body.is-mobile-planner .bf-fab-menu-item.task .ic     { background: rgba(220,38,38,0.12); color: #dc2626; }
body.is-mobile-planner .bf-fab-menu-item.meeting .ic  { background: rgba(37,99,235,0.12); color: #2563eb; }
body.is-mobile-planner .bf-fab-menu-item.reminder .ic { background: rgba(245,158,11,0.18); color: #b45309; }

body.is-mobile-planner .bf-fab-scrim {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.04);
  z-index: 1099;
  cursor: pointer;
}

/* Hide the floating UNIBOT chip + chat-widget FAB + the planner + FAB
   while a desktop create-modal is open over the mobile planner. They
   live in <body> at z-index 9998 (chip + chat) and would otherwise float
   over the modal on a phone-width viewport. The body class is set by
   _bridgeDesktopModalToMobileReload before opening the modal and cleared
   on close (or 5-min fallback). */
body.is-mobile-planner-modal-open #unibot-chip,
body.is-mobile-planner-modal-open #unibot-panel,
body.is-mobile-planner-modal-open #btn-floating-chat-toggle,
body.is-mobile-planner-modal-open #fabs-backdrop,
body.is-mobile-planner-modal-open .bf-fab-wrap {
  display: none !important;
}

/* Desktop — grey out the floating UNIBOT chip + chat FAB while the planner
   task-edit modal is open. They sit at the same z-index as the modal and
   would otherwise be distracting / accidentally clickable through the
   modal backdrop. The body class is toggled by openTaskModal /
   closeTaskModal in planner.js. */
body.is-task-modal-open #unibot-chip,
body.is-task-modal-open #btn-floating-chat-toggle,
body.is-task-modal-open #fabs-backdrop {
  opacity: 0.35 !important;
  filter: grayscale(0.6);
  pointer-events: none !important;
  transition: opacity 0.2s ease, filter 0.2s ease;
}

/* Mobile-only meeting modal layout fixes. Gated on
   `body.is-mobile-planner-modal-open` rather than a viewport media query
   because the body class is set by mobilePlanner.js's bridge ONLY for
   phone-launched modals — so we know we're on a mobile shell regardless
   of orientation/landscape width.
   Desktop's 3-column Date / Start Time / Duration row collapses to
   `Date | Date` on row 1 and `Time | Duration` on row 2 so the native
   widgets stop overlapping. Each individual cell is also forced
   min-width:0 so the native time picker can shrink instead of overflowing
   onto its sibling. */
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid {
  display: grid !important;
  grid-template-columns: 1fr 1fr !important;
  grid-template-areas:
    "date date"
    "time duration" !important;
  gap: 0.75rem !important;
}
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid > .form-group {
  min-width: 0 !important;
}
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid > .form-group:nth-child(1) { grid-area: date; }
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid > .form-group:nth-child(2) { grid-area: time; }
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid > .form-group:nth-child(3) { grid-area: duration; }
/* Native form controls stretch to fill their cell without overflowing it. */
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid input,
body.is-mobile-planner-modal-open #meeting-modal .mtg-datetime-grid select {
  width: 100% !important;
  min-width: 0 !important;
  max-width: 100% !important;
  box-sizing: border-box !important;
}
/* Tighter card padding on phones so the form has more usable width. */
body.is-mobile-planner-modal-open #meeting-modal > .card {
  padding: 1.25rem !important;
}
/* Same treatment for the task modal's 3-column Priority / Status / Due Date
   grid — same overflow problem on phones. The grid is the only inline
   `1fr 1fr 1fr` div inside `<form id="ptask-form">`, and the planner-task
   modal is `#planner-task-modal`. Use the attribute selector since this
   grid wasn't tagged with a class. */
body.is-mobile-planner-modal-open #planner-task-modal form > div[style*="1fr 1fr 1fr"] {
  grid-template-columns: 1fr 1fr !important;
  gap: 0.75rem !important;
}
body.is-mobile-planner-modal-open #planner-task-modal form > div[style*="1fr 1fr 1fr"] > .form-group {
  min-width: 0 !important;
}
body.is-mobile-planner-modal-open #planner-task-modal form > div[style*="1fr 1fr 1fr"] input,
body.is-mobile-planner-modal-open #planner-task-modal form > div[style*="1fr 1fr 1fr"] select {
  width: 100% !important;
  min-width: 0 !important;
  max-width: 100% !important;
  box-sizing: border-box !important;
}
body.is-mobile-planner-modal-open #planner-task-modal > .card {
  padding: 1.25rem !important;
}

/* ===================== End of day ===================== */
body.is-mobile-planner .bf-end {
  display: flex; align-items: center; gap: 8px;
  margin: 18px 16px 8px;
}
body.is-mobile-planner .bf-end-line {
  flex: 1; height: 1px;
  background: var(--md-border);
}
body.is-mobile-planner .bf-end-text {
  font-size: 10.5px; font-weight: 700;
  color: var(--md-text-subtle);
  text-transform: uppercase; letter-spacing: 0.08em;
  font-feature-settings: "tnum";
}

/* ========================================================================
   Desktop Planner day rail — #planner-day-rail-body .pdr-*
   Mirrors the mobile rail's visual language but the selectors intentionally
   do NOT depend on body.is-mobile-planner — this is the desktop variant.
   The rail card sits in a 2fr column (~700px on 1440), so the time gutter is
   widened to 70px and cards run edge-to-edge with the body grid.
   ======================================================================== */
.planner-day-rail-body { padding: 0.85rem 1rem 1rem; }
.planner-day-rail-body .pdr-empty {
  color: var(--text-muted); font-size: 0.85rem;
  padding: 1.25rem 0.25rem;
  text-align: center;
}
.planner-day-rail-body .pdr-rail {
  position: relative;
  display: grid;
  gap: 10px;
  padding: 4px 0 8px;
}
.planner-day-rail-body .pdr-rail::before {
  content: "";
  position: absolute;
  left: 70px; top: 4px; bottom: 8px;
  width: 2px;
  background: linear-gradient(to bottom, transparent 0%, var(--border) 8px, var(--border) calc(100% - 8px), transparent 100%);
  border-radius: 1px;
}

.planner-day-rail-body .pdr-item {
  position: relative;
  display: grid;
  grid-template-columns: 70px 1fr;
  gap: 14px;
  align-items: stretch;
}
.planner-day-rail-body .pdr-rail-col {
  display: flex; flex-direction: column; align-items: center;
  padding-top: 10px;
  position: relative;
}
.planner-day-rail-body .pdr-time {
  display: flex; flex-direction: column; align-items: center;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 10px;
  padding: 5px 0;
  width: 64px;
  font-family: monospace;
  font-feature-settings: "tnum";
  position: relative;
  z-index: 2;
}
.planner-day-rail-body .pdr-time .h {
  font-size: 13px; font-weight: 700;
  color: var(--text-main); line-height: 1;
}
.planner-day-rail-body .pdr-time .dur {
  font-size: 9.5px; font-weight: 700;
  color: var(--text-muted);
  margin-top: 3px;
  text-transform: uppercase;
}
.planner-day-rail-body .pdr-time.bell {
  background: rgba(245,158,11,0.1);
  border-color: rgba(245,158,11,0.4);
  color: #b45309;
  padding: 7px 0;
}
.planner-day-rail-body .pdr-time.bell .ic {
  display: inline-flex; align-items: center; justify-content: center;
  color: #b45309;
  margin-bottom: 3px;
  font-size: 13px;
}
.planner-day-rail-body .pdr-time.bell .h { color: #b45309; font-size: 11.5px; }

.planner-day-rail-body .pdr-item.past .pdr-time { opacity: 0.55; }
.planner-day-rail-body .pdr-item.past .pdr-card,
.planner-day-rail-body .pdr-item.past .pdr-rmd { opacity: 0.7; }
/* When a row is BOTH past AND done, the .pdr-task.done rule already drops
   the whole row to opacity 0.55. Stacking the .past 0.7 inner-opacity on
   top makes completed-today tasks look much fainter than their pending
   neighbours that just sat past their slot — confusing because completion
   should look uniform regardless of where the task lands in the day. Reset
   the inner opacity to 1 so .done becomes the single source of dimming. */
.planner-day-rail-body .pdr-item.past.pdr-task.done .pdr-card,
.planner-day-rail-body .pdr-item.past.pdr-task.done .pdr-time { opacity: 1; }
.planner-day-rail-body .pdr-item.past.pdr-reminder.dismissed .pdr-rmd,
.planner-day-rail-body .pdr-item.past.pdr-reminder.dismissed .pdr-time { opacity: 1; }
.planner-day-rail-body .pdr-item.now .pdr-time {
  background: #10b981; border-color: #10b981;
}
.planner-day-rail-body .pdr-item.now .pdr-time .h,
.planner-day-rail-body .pdr-item.now .pdr-time .dur { color: #fff; }
.planner-day-rail-body .pdr-item.now .pdr-time .dur { color: rgba(255,255,255,0.9); }

/* ===================== Task card (desktop rail) ===================== */
.planner-day-rail-body .pdr-task .pdr-card {
  display: grid;
  grid-template-columns: 4px 1fr;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  align-items: stretch;
  transition: background 120ms, border-color 120ms, box-shadow 120ms;
}
.planner-day-rail-body .pdr-task .pdr-card:hover { background: var(--surface-hover); }
.planner-day-rail-body .pdr-task.now .pdr-card {
  border-color: #10b981;
  box-shadow: 0 6px 18px -10px rgba(16,185,129,0.5);
}
/* Completed-today task in the desktop day rail — same visual treatment
   as the mobile (.bf-task.done): drop opacity to 0.55, drain the project
   bar, greyscale the chips/priority, sunk background. Reads as "log
   entry, not actionable" at a glance. */
.planner-day-rail-body .pdr-task.done {
  opacity: 0.55;
}
.planner-day-rail-body .pdr-task.done .pdr-card {
  background: var(--surface-hover);
  border-color: rgba(0,0,0,0.06);
  box-shadow: none;
}
.planner-day-rail-body .pdr-task.done .pdr-card-bar {
  filter: saturate(0.25);
  opacity: 0.5;
}
.planner-day-rail-body .pdr-task.done .pdr-card-title {
  text-decoration: line-through;
  color: var(--text-muted);
}
.planner-day-rail-body .pdr-task.done .pdr-card-eye .proj-chip,
.planner-day-rail-body .pdr-task.done .pdr-card-eye .prio {
  filter: grayscale(0.7);
  opacity: 0.7;
}
.planner-day-rail-body .pdr-card-bar { width: 4px; }
.planner-day-rail-body .pdr-card-body {
  padding: 10px 14px 12px;
  min-width: 0;
}
.planner-day-rail-body .pdr-card-eye {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.planner-day-rail-body .pdr-card-eye .kind {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted);
}
.planner-day-rail-body .pdr-card-eye .kind.mtg { color: #2563eb; }
.planner-day-rail-body .pdr-card-eye .proj-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10.5px; font-weight: 700;
  padding: 1px 8px; border-radius: 999px;
  background: var(--surface-hover);
  color: var(--text-main);
  max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.planner-day-rail-body .pdr-card-eye .proj-chip .ps {
  width: 7px; height: 7px; border-radius: 2px; flex-shrink: 0;
}
.planner-day-rail-body .pdr-card-eye .prio {
  font-size: 10px; font-weight: 800;
  padding: 1px 6px; border-radius: 4px;
  background: var(--surface-hover);
  color: var(--text-muted);
}
.planner-day-rail-body .pdr-card-eye .prio.p1 { background: rgba(220,38,38,0.1); color: #dc2626; }
.planner-day-rail-body .pdr-card-eye .prio.p2 { background: rgba(245,158,11,0.12); color: #b45309; }
.planner-day-rail-body .pdr-card-title {
  font-size: 14px; font-weight: 600;
  color: var(--text-main); line-height: 1.3;
}
.planner-day-rail-body .pdr-running {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10.5px; font-weight: 700;
  color: #10b981;
  background: rgba(16,185,129,0.08);
  padding: 2px 7px; border-radius: 999px;
  font-family: monospace;
}
.planner-day-rail-body .pdr-running .live {
  width: 6px; height: 6px; border-radius: 50%;
  background: #10b981;
  animation: pulse 1.5s ease-in-out infinite;
}

/* ===================== Meeting card (desktop rail) ===================== */
.planner-day-rail-body .pdr-meeting .pdr-card.pdr-mtg {
  background: linear-gradient(180deg, rgba(37,99,235,0.05) 0%, rgba(37,99,235,0.02) 100%);
  border: 1px solid rgba(37,99,235,0.25);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  position: relative;
  transition: background 120ms, border-color 120ms;
}
.planner-day-rail-body .pdr-meeting .pdr-card.pdr-mtg::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 4px;
  background: #2563eb;
}
.planner-day-rail-body .pdr-meeting .pdr-card.pdr-mtg:hover { background: rgba(37,99,235,0.07); }
.planner-day-rail-body .pdr-meeting.now .pdr-card.pdr-mtg {
  border-color: #2563eb;
  box-shadow: 0 6px 18px -10px rgba(37,99,235,0.5);
}
.planner-day-rail-body .pdr-meeting .pdr-card-body { padding: 10px 14px 12px 18px; }
.planner-day-rail-body .pdr-mtg-where {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 6px;
  font-size: 11.5px; color: #1d4ed8; font-weight: 600;
}
.planner-day-rail-body .pdr-mtg-foot {
  display: flex; align-items: center; justify-content: flex-start;
  margin-top: 10px;
}
.planner-day-rail-body .pdr-avatars {
  display: flex; align-items: center;
}
.planner-day-rail-body .pdr-avatars .av {
  width: 24px; height: 24px; border-radius: 50%;
  background: #dbeafe;
  border: 1.5px solid var(--surface);
  margin-left: -6px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 9.5px; font-weight: 800;
  color: #1d4ed8;
  font-family: monospace;
}
.planner-day-rail-body .pdr-avatars .av:first-child { margin-left: 0; }
.planner-day-rail-body .pdr-avatars .av.you {
  background: var(--text-main); color: #fff;
}
.planner-day-rail-body .pdr-avatars .av.plus {
  background: var(--surface); color: #1d4ed8;
  border-color: #bfdbfe;
}

/* ===================== Reminder row (desktop rail) ===================== */
.planner-day-rail-body .pdr-reminder .pdr-rmd {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px; align-items: center;
  background: rgba(245,158,11,0.06);
  border: 1px dashed rgba(245,158,11,0.45);
  border-radius: 10px;
  padding: 10px 14px;
}
.planner-day-rail-body .pdr-reminder.dismissed .pdr-rmd {
  opacity: 0.55;
  background: var(--surface-hover);
  border-style: solid;
  border-color: var(--border);
}
.planner-day-rail-body .pdr-reminder.dismissed .pdr-rmd-title {
  text-decoration: line-through;
  color: var(--text-muted);
}
.planner-day-rail-body .pdr-rmd-body { min-width: 0; }
.planner-day-rail-body .pdr-rmd-eye {
  display: flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.07em;
  color: #b45309;
  margin-bottom: 4px;
}
.planner-day-rail-body .pdr-rmd-recur {
  font-size: 9.5px; font-weight: 700;
  padding: 1px 6px; border-radius: 999px;
  background: rgba(245,158,11,0.18);
  color: #b45309;
  text-transform: none; letter-spacing: 0;
}
.planner-day-rail-body .pdr-rmd-title {
  font-size: 13.5px; font-weight: 600;
  color: var(--text-main); line-height: 1.3;
}
.planner-day-rail-body .pdr-rmd-actions {
  display: flex; gap: 6px;
  flex-shrink: 0;
}
.planner-day-rail-body .pdr-rmd-ack {
  height: 28px;
  padding: 0 12px;
  border-radius: 999px;
  font-size: 11.5px; font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  border: 1px solid #b45309;
  background: #b45309;
  color: #fff;
}
.planner-day-rail-body .pdr-rmd-ack:hover { background: #92400e; border-color: #92400e; }
.planner-day-rail-body .pdr-rmd-done.on {
  color: #10b981;
  font-size: 14px; font-weight: 800;
}

/* ===================== Now marker (desktop rail) ===================== */
.planner-day-rail-body .pdr-nowmark {
  display: grid;
  grid-template-columns: 70px 1fr;
  gap: 14px;
  align-items: center;
  margin: 4px 0;
  position: relative;
  z-index: 3;
}
.planner-day-rail-body .pdr-nowmark-rail {
  display: flex; align-items: center; justify-content: center;
}
.planner-day-rail-body .pdr-nowmark-rail .dot {
  width: 12px; height: 12px; border-radius: 50%;
  background: #ef4444;
  border: 3px solid var(--surface);
  box-shadow: 0 0 0 2px #ef4444;
}
.planner-day-rail-body .pdr-nowmark-time {
  font-family: monospace;
  font-size: 11.5px; font-weight: 800;
  color: #ef4444;
  font-feature-settings: "tnum";
  text-transform: uppercase; letter-spacing: 0.05em;
  display: flex; align-items: center; gap: 8px;
}
.planner-day-rail-body .pdr-nowmark-time::after {
  content: "";
  flex: 1;
  height: 2px;
  background: linear-gradient(to right, #ef4444 0%, transparent 100%);
}

/* ===================== Timeline view (desktop day rail) =====================
   Time-proportional version of the rail: hour gutter on the left, items
   absolutely positioned by their `time`/`dur`. Block height = duration ×
   PDR_PX_PER_HOUR (60px/hr), clamped to PDR_MIN_BLOCK_PX (36px) so 15-min
   tasks stay clickable. */
.pdr-tl-bookend {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; margin: 4px 0;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: 8px;
  font-size: 0.78rem; font-weight: 700; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.pdr-tl-clockon  { border-left: 3px solid #10b981; }
.pdr-tl-clockoff { border-left: 3px solid #6b7280; }
.pdr-tl-bookend-icon { color: #6b7280; font-size: 0.7rem; }
.pdr-tl-clockon  .pdr-tl-bookend-icon { color: #10b981; }
.pdr-tl-bookend-label { flex: 1; color: var(--text-main); }
.pdr-tl-bookend-time {
  font-family: monospace; font-size: 0.85rem; color: var(--text-main);
}

.pdr-tl {
  position: relative;
  margin: 4px 0;
}
.pdr-tl::before {
  content: "";
  position: absolute;
  left: 56px; top: 0; bottom: 0;
  width: 2px;
  background: var(--border);
  border-radius: 1px;
}

/* Track sits to the right of the hour gutter; items are absolutely
   positioned inside it with percentage left/width so multi-lane clusters
   split evenly. z-index lifts the whole track above the hour/quarter
   gridlines so no dotted ticks show through block bodies. */
.pdr-tl-track {
  position: absolute;
  left: 64px; right: 8px; top: 0;
  z-index: 2;
}

/* Hour labels in the left gutter. Dashed gridline spans the full width as
   a faint guide; the label has the surface background so it punches
   through cleanly. */
.pdr-tl-hour {
  position: absolute;
  left: 0; right: 0;
  height: 0;
  pointer-events: none;
  border-top: 1px solid rgba(0,0,0,0.1);
  z-index: 0;
}
/* 15-min sub-grid — full-width so a nested label can punch through with
   its surface background (mirrors the hour-line/-label layering). */
.pdr-tl-quarter {
  position: absolute;
  left: 0; right: 0;
  height: 0;
  pointer-events: none;
  border-top: 1px dotted rgba(0,0,0,0.05);
  z-index: 0;
}
.pdr-tl-half {
  border-top: 1px dashed rgba(0,0,0,0.12);
}
.pdr-tl-half-label {
  position: absolute;
  /* Same gutter column as hour labels — same left/width/text-align so they
     line up vertically below each hour. Smaller font + faded colour marks
     them as sub-labels rather than competing labels. */
  left: 0; top: -6px;
  width: 50px;
  text-align: right;
  font-family: monospace;
  font-size: 9px; font-weight: 600;
  color: rgba(0,0,0,0.35);
  background: var(--surface);
  padding: 0 6px 0 0;
}
/* Week view shrinks both gutter labels — keep half-hour in lockstep. */
.pdr-wv-col .pdr-tl-half-label {
  width: 36px;
  padding: 0 4px 0 0;
}
.pdr-tl-hour-label {
  position: absolute;
  left: 0; top: -8px;
  width: 50px;
  text-align: right;
  font-family: monospace;
  font-size: 11px; font-weight: 700;
  color: var(--text-muted);
  background: var(--surface);
  padding: 0 6px 0 0;
}

.pdr-tl-block {
  position: absolute;
  /* left/width set inline based on lane assignment */
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 8px;
  display: flex; gap: 6px; align-items: stretch;
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow 0.12s, transform 0.12s;
  z-index: 1;
  box-sizing: border-box;
}
.pdr-tl-compact {
  justify-content: center;
}
.pdr-tl-compact .pdr-tl-title {
  font-size: 0.78rem;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  white-space: nowrap;
}
.pdr-tl-compact .live-dot {
  display: inline-block; width: 7px; height: 7px;
  background: #10b981; border-radius: 50%;
  margin-right: 4px; vertical-align: middle;
  animation: pdr-live 1.2s ease-in-out infinite;
}
@keyframes pdr-live {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 1; }
}
.pdr-tl-block:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  transform: translateY(-1px);
  z-index: 3;
}
/* Drag-to-reschedule (week views only) — see planner.js
   `_ensurePlannerDragDelegation`. Source element fades while in flight; the
   target rail gets a dashed outline so the user can see exactly which day
   they're about to drop on. */
.planner-drag-source { opacity: 0.4; }
.pdr-tl.planner-drop-active {
  outline: 2px dashed var(--primary, #2563eb);
  outline-offset: -2px;
  background: rgba(37, 99, 235, 0.04);
}
/* Week-pagination drop zones — visible only while a task is being dragged.
   Position is set inline by `_positionDragZonesOverGrid` in planner.js so
   the zones sit flush with the visible week-grid's bounding rect (left and
   right edges, full grid height) rather than the viewport edges. Hovering
   INTO a zone fires the visible week-nav button (Prev / Next) once per
   entry — leave + re-enter to fire again. See `_onDragZoneEnter` / Leave
   in planner.js. */
.planner-drag-zone {
  position: fixed;          /* JS sets top/left/width/height inline */
  z-index: 9997;            /* below modals (10000+) and FABs (9998), above content */
  display: none;
  align-items: center;
  justify-content: center;
  background: #dbeafe;       /* solid pale blue — opaque so day columns don't show through */
  border: 2px dashed #2563eb;
  color: var(--primary, #2563eb);
  font-weight: 700;
  font-size: 0.78rem;
  text-align: center;
  user-select: none;
  pointer-events: auto;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
  padding: 0.6rem 0.4rem;
  line-height: 1.3;
  transition: background 0.12s, border-color 0.12s;
}
body.dark-mode .planner-drag-zone {
  background: #1e2a4a;       /* dark navy — opaque counterpart for dark mode */
  border-color: #3b6dd9;
  color: #a8c4f0;
}
body.is-dragging-task .planner-drag-zone {
  display: flex;
}
.planner-drag-zone.is-armed {
  background: #93c5fd;       /* stronger solid blue while armed */
}
body.dark-mode .planner-drag-zone.is-armed {
  background: #3b6dd9;
  color: #fff;
}
/* Snap-line indicator that follows the cursor during drag, locked to the
   nearest 15-min boundary, with a small label so the user can see the exact
   start time before releasing. */
.planner-drop-indicator {
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  background: #2563eb;
  pointer-events: none;
  z-index: 5;
  box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.25);
}
.planner-drop-indicator-label {
  position: absolute;
  top: -10px;
  left: 4px;
  background: #2563eb;
  color: #fff;
  font-size: 0.62rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 3px;
  font-family: monospace;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.pdr-tl-block.past { opacity: 0.55; }
/* Strikethrough title on past blocks so it's obvious they're history,
   not still on the agenda. Mirrors the .done treatment but lighter
   (still uses the original colour, just with a line-through). */
.pdr-tl-block.past .pdr-tl-title {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(0,0,0,0.5);
}
/* Overdue = past + task + not completed + not running. Stays in its slot
   (Owen 2026-04-28: no auto-bump) but yells for attention so the user
   knows to reschedule. Overrides .past muting + strikethrough so the
   block reads as "needs action" instead of "done with". */
.pdr-tl-block.overdue {
  opacity: 1;
  background: rgba(220, 38, 38, 0.10);
  box-shadow: 0 0 0 2px #dc2626 inset, 0 0 10px rgba(220, 38, 38, 0.35);
  animation: pdrOverduePulse 2.4s ease-in-out infinite;
}
.pdr-tl-block.overdue .pdr-tl-title {
  text-decoration: none;
  color: #b91c1c;
  font-weight: 700;
}
.pdr-tl-block.overdue::after {
  content: "OVERDUE";
  position: absolute;
  top: 3px;
  right: 4px;
  background: #dc2626;
  color: #fff;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  padding: 1px 5px;
  border-radius: 3px;
  z-index: 2;
  pointer-events: none;
}
@keyframes pdrOverduePulse {
  0%, 100% { box-shadow: 0 0 0 2px #dc2626 inset, 0 0 8px rgba(220, 38, 38, 0.30); }
  50%      { box-shadow: 0 0 0 2px #dc2626 inset, 0 0 16px rgba(220, 38, 38, 0.55); }
}
.pdr-tl-block.now {
  box-shadow: 0 0 0 2px #10b981 inset, 0 4px 18px rgba(16,185,129,0.25);
  z-index: 3;
  animation: pdr-now-pulse 2.4s ease-in-out infinite;
}
@keyframes pdr-now-pulse {
  0%, 100% { box-shadow: 0 0 0 2px #10b981 inset, 0 4px 18px rgba(16,185,129,0.25); }
  50%      { box-shadow: 0 0 0 2px #10b981 inset, 0 4px 22px rgba(16,185,129,0.45); }
}
/* Done state — strong green tint + green left border + strikethrough so
   it reads "complete" at a glance without overpowering the day. Wins over
   per-kind tints because of higher specificity inside this rule block.
   Layered over the surface so gridlines don't bleed through the tint. */
.pdr-tl-block.done {
  background: linear-gradient(rgba(16,185,129,0.08), rgba(16,185,129,0.08)), var(--surface);
  border-color: rgba(16,185,129,0.35);
  border-left: 4px solid #10b981;
  opacity: 0.85;
}
.pdr-tl-block.done .pdr-tl-title {
  text-decoration: line-through;
  color: var(--text-muted);
}
.pdr-tl-block.done .pdr-tl-bar { display: none; }

.pdr-tl-bar {
  width: 4px; flex-shrink: 0;
  border-radius: 2px;
  align-self: stretch;
}
.pdr-tl-body {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.pdr-tl-head {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 0.65rem; line-height: 1.1;
}
/* Chip styles broadened from `.pdr-tl-head .kind` etc. to the whole block
   so the compact single-line variant (which inlines kind/proj-chip/prio
   into .pdr-tl-title rather than .pdr-tl-head) picks up the same paint.
   Without this the "Meeting" pill renders as plain text on short blocks. */
.pdr-tl-block .kind {
  font-size: 0.6rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  background: #4338ca; color: #fff;
  padding: 2px 7px; border-radius: 3px;
  vertical-align: middle;
}
.pdr-tl-block .kind.mtg { background: #2563eb; color: #fff; }
.pdr-tl-block .kind.rmd { background: #f59e0b; color: #fff; }
.pdr-tl-block .kind.brk { background: #b45309; color: #fff; }
.pdr-tl-block .proj-chip {
  display: inline-flex; align-items: center; gap: 3px;
  font-weight: 700; color: var(--text-main);
  vertical-align: middle;
}
.pdr-tl-block .proj-chip .ps {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
}
.pdr-tl-block .prio {
  font-weight: 700; padding: 1px 5px; border-radius: 3px; font-size: 0.55rem;
  vertical-align: middle;
}
.pdr-tl-block .prio.p1 { background: rgba(220,38,38,0.1); color: #dc2626; }
.pdr-tl-block .prio.p2 { background: rgba(245,158,11,0.12); color: #b45309; }
.pdr-tl-block .prio.p3 { background: rgba(99,102,241,0.1); color: #4338ca; }
.pdr-tl-block .prio.p4 { background: rgba(107,114,128,0.1); color: #6b7280; }
.pdr-tl-title {
  font-size: 0.85rem; font-weight: 700;
  color: var(--text-main);
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.pdr-tl-where {
  font-size: 0.7rem; color: var(--text-muted);
}
.pdr-tl-avatars {
  margin-top: 4px;
}
.pdr-tl-rmd-actions {
  margin-top: 4px;
}
.pdr-tl-done-pill {
  background: rgba(16,185,129,0.12); color: #059669;
  font-size: 0.6rem; font-weight: 700;
  padding: 1px 6px; border-radius: 3px;
}
.pdr-tl-chunk-pill {
  background: #e0e7ff; color: #4338ca;
  font-family: monospace;
  font-size: 0.6rem; font-weight: 700;
  padding: 1px 6px; border-radius: 3px;
  margin-left: auto;
}
.pdr-tl-compact .pdr-tl-chunk-pill {
  margin-left: 6px;
}
.pdr-tl-cont-pill {
  background: #fef3c7; color: #92400e;
  font-size: 0.6rem; font-weight: 700;
  padding: 1px 6px; border-radius: 3px;
  margin-right: 4px;
}
.pdr-tl-rem-pill {
  background: #f3e8ff; color: #7e22ce;
  font-size: 0.6rem; font-weight: 700;
  padding: 1px 6px; border-radius: 3px;
  margin-right: 4px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.pdr-tl-spillover {
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.75rem;
  background: #fef3c7;
  border: 1px dashed #f59e0b;
  border-radius: 4px;
  font-size: 0.78rem;
  color: #92400e;
  font-weight: 600;
}
/* Week-view capacity pill in the day header */
.pdr-wv-cap {
  font-size: 0.65rem; font-weight: 700;
  color: #4338ca;
  background: #eef2ff;
  padding: 1px 6px; border-radius: 10px;
  font-family: monospace;
}
.pdr-wv-cap.over {
  color: #b91c1c;
  background: #fee2e2;
}
.pdr-wv-col-overflow {
  grid-column: 1 / -1;
  margin: 8px;
  padding: 10px 14px;
  background: #fef3c7;
  border: 1px solid #fde68a;
  border-radius: 8px;
  font-size: 0.85rem;
  color: #92400e;
}

/* Per-kind tints — coloured left borders + tinted background so the
   user can read "what kind is this?" at a glance without parsing the
   text label. Tasks keep the project colour on .pdr-tl-bar (the inner
   strip) so the tile background can stay neutral white. */
/* Per-kind tints layered over an opaque surface — so the dotted hour /
   half-hour gridlines stop showing through the block bodies. */
.pdr-tl-task {
  background: linear-gradient(rgba(99,102,241,0.07), rgba(99,102,241,0.07)), var(--surface);
  border-color: rgba(99,102,241,0.3);
}
.pdr-tl-meeting {
  background: linear-gradient(rgba(37,99,235,0.10), rgba(37,99,235,0.10)), var(--surface);
  border: 1px solid rgba(37,99,235,0.35);
  border-left: 4px solid #2563eb;
}
.pdr-tl-reminder {
  background: linear-gradient(rgba(245,158,11,0.10), rgba(245,158,11,0.10)), var(--surface);
  border: 1px solid rgba(245,158,11,0.4);
  border-left: 4px solid #f59e0b;
}
.pdr-tl-break {
  background: repeating-linear-gradient(
    135deg,
    #fffbeb 0px, #fffbeb 8px,
    #fef3c7 8px, #fef3c7 12px
  );
  border: 1px dashed #f59e0b;
  border-left: 4px dashed #f59e0b;
  cursor: default;
  /* Breaks render at their true height (15-min morning break ≈ 15-22 px),
     so the body needs to fit in a single short line without the default
     4px padding pushing the text out of the box. */
  padding: 0 8px;
  align-items: center;
}
.pdr-tl-break:hover { transform: none; box-shadow: none; }
.pdr-tl-job-pill {
  display: inline-block;
  font-family: monospace;
  font-weight: 700;
  font-size: 0.65rem;
  padding: 1px 6px;
  border-radius: 3px;
  background: rgba(30,91,198,0.1);
  color: var(--primary);
  vertical-align: middle;
}
.pdr-tl-break .pdr-tl-title {
  font-size: 0.72rem;
  line-height: 1.1;
  white-space: nowrap;
  -webkit-line-clamp: 1;
  line-clamp: 1;
}

/* Now marker — horizontal red line spanning the full timeline width.
   When the current time is outside clock-on/clock-off, the marker pins
   to the bottom (after-hours) or top (before-hours) edge with a slight
   different label so the user knows the day is over / not started. */
.pdr-tl-nowmark {
  position: absolute;
  left: 0; right: 8px;
  height: 0;
  border-top: 2px solid #ef4444;
  z-index: 4;
  pointer-events: none;
}
.pdr-tl-nowmark::after {
  content: "";
  position: absolute;
  right: 0; top: -5px;
  width: 8px; height: 8px;
  background: #ef4444; border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(239,68,68,0.25);
}
.pdr-tl-nowmark-label {
  position: absolute;
  left: 0; top: -10px;
  font-family: monospace;
  font-size: 11px; font-weight: 700;
  color: #ef4444;
  background: var(--surface);
  padding: 0 6px 0 0;
}
.pdr-tl-nowmark-after {
  border-top-style: dashed;
}
.pdr-tl-nowmark-after .pdr-tl-nowmark-label {
  color: #b45309;
  background: #fef3c7;
  border: 1px solid #fde68a;
  border-radius: 3px;
  padding: 1px 6px;
  top: -12px;
}
.pdr-tl-nowmark-after::after { background: #b45309; box-shadow: 0 0 0 3px rgba(180,83,9,0.2); }
.pdr-tl-nowmark-before {
  border-top-style: dashed;
}
.pdr-tl-nowmark-before .pdr-tl-nowmark-label {
  color: #6b7280;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 1px 6px;
  top: 4px;
}
.pdr-tl-nowmark-before::after { background: #6b7280; box-shadow: 0 0 0 3px rgba(107,114,128,0.2); }

/* Reminder marker — fixed orange twin of the now line; pinned at the
   reminder's time, name as label. z-index 3 sits below the red now
   line's 4 so when a reminder and "now" coincide the now line wins. */
.pdr-tl-rmdmark {
  position: absolute;
  left: 0; right: 8px;
  height: 0;
  border-top: 2px solid #f59e0b;
  z-index: 3;
  pointer-events: none;
}
.pdr-tl-rmdmark::after {
  content: "";
  position: absolute;
  right: 0; top: -5px;
  width: 8px; height: 8px;
  background: #f59e0b; border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(245,158,11,0.25);
}
.pdr-tl-rmdmark-label {
  position: absolute;
  left: 0; top: -10px;
  max-width: calc(100% - 24px);
  font-family: monospace;
  font-size: 11px; font-weight: 700;
  color: #f59e0b;
  background: var(--surface);
  padding: 0 6px 0 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ===================== Week View (7-column timeline) =====================
   Reuses every .pdr-tl-* style from the day rail; each column hosts its
   own .pdr-tl with shared bounds (clock-on / clock-off). The grid scrolls
   horizontally if the columns get too narrow on smaller monitors. */
.pdr-wv-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(220px, 1fr));
  gap: 10px;
  padding: 10px;
  background: var(--surface-hover);
  overflow-x: auto;
}
/* Null containment + overflow on the planner week card chain so HTML5
   drag-and-drop's drop targeting works. The .view ancestor sets
   `contain: layout style` which traps drop events on the long task
   columns; per-person Weekly Views work because their host containers
   sit inline without these constraints. */
#view-planner #planner-week-card,
#view-planner #planner-week-grid,
#view-planner .pdr-wv-grid { contain: none; }
.pdr-wv-col {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0 0 4px;
  min-width: 0;
  display: flex; flex-direction: column;
}
.pdr-wv-col.is-today {
  border-color: #10b981;
  box-shadow: 0 0 0 1px rgba(16,185,129,0.25);
}
.pdr-wv-day-head {
  display: flex; align-items: baseline; gap: 6px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-hover);
  border-radius: 8px 8px 0 0;
}
.pdr-wv-col.is-today .pdr-wv-day-head {
  background: rgba(16,185,129,0.08);
}
.pdr-wv-day-name {
  font-weight: 800;
  font-size: 0.85rem;
  color: var(--text-main);
}
.pdr-wv-col.is-today .pdr-wv-day-name { color: #059669; }
.pdr-wv-day-date {
  font-size: 0.72rem;
  color: var(--text-muted);
  font-family: monospace;
}
.pdr-wv-day-count {
  margin-left: auto;
  font-size: 0.65rem; font-weight: 700;
  color: #4338ca;
  background: #e0e7ff;
  padding: 1px 6px; border-radius: 10px;
  min-width: 18px; text-align: center;
}
.pdr-wv-day-count:empty { display: none; }
.pdr-wv-empty {
  padding: 1.5rem 0.5rem;
  text-align: center;
  font-size: 0.78rem;
  color: var(--text-muted);
}
/* Inside a week column, the timeline shrinks: hour labels need to stay
   readable, but the track gets narrower. Compact mode triggers earlier. */
.pdr-wv-col .pdr-tl::before { left: 38px; }
.pdr-wv-col .pdr-tl-track { left: 46px; right: 4px; }
.pdr-wv-col .pdr-tl-hour-label {
  font-size: 10px;
  width: 36px;
  padding-right: 4px;
}
.pdr-wv-col .pdr-tl-bookend {
  margin: 4px 6px;
  padding: 5px 8px;
  font-size: 0.65rem;
  letter-spacing: 0.03em;
}
.pdr-wv-col .pdr-tl-bookend-icon { font-size: 0.6rem; }
.pdr-wv-col .pdr-tl-bookend-time { font-size: 0.72rem; }
.pdr-wv-col .pdr-tl-block {
  padding: 3px 6px;
  gap: 4px;
}
.pdr-wv-col .pdr-tl-head {
  font-size: 0.55rem;
  gap: 4px;
}
.pdr-wv-col .pdr-tl-head .kind { font-size: 0.5rem; padding: 1px 4px; }
.pdr-wv-col .pdr-tl-head .prio { font-size: 0.5rem; padding: 1px 4px; }
.pdr-wv-col .pdr-tl-title { font-size: 0.72rem; }
.pdr-wv-col .pdr-tl-where, .pdr-wv-col .pdr-tl-avatars { display: none; }

/* Roomy mode — block tall enough to host bigger type comfortably.
   Smaller blocks keep the compact/default sizes so they still fit. */
.pdr-tl-block.roomy .pdr-tl-title {
  font-size: 1rem;
  -webkit-line-clamp: 3;
  line-clamp: 3;
}
.pdr-tl-block.roomy .pdr-tl-head { font-size: 0.72rem; }
.pdr-tl-block.roomy .pdr-tl-head .kind { font-size: 0.65rem; padding: 2px 8px; }
.pdr-tl-block.roomy .pdr-tl-head .prio { font-size: 0.6rem; padding: 2px 6px; }
.pdr-tl-block.roomy .pdr-tl-where { font-size: 0.78rem; }
.pdr-wv-col .pdr-tl-block.roomy .pdr-tl-title { font-size: 0.88rem; }
.pdr-wv-col .pdr-tl-block.roomy .pdr-tl-head { font-size: 0.65rem; }
.pdr-wv-col .pdr-tl-block.roomy .pdr-tl-head .kind { font-size: 0.58rem; padding: 1px 5px; }
.pdr-wv-col .pdr-tl-block.roomy .pdr-tl-head .prio { font-size: 0.58rem; padding: 1px 5px; }

/* ─── P2.9 — Current-session pill ──────────────────────────────────────────
   Shown below the dashboard hero while the user is clocked in. Hidden
   when clocked out (JS removes the inner HTML and sets display:none).
   The pill is inline-flex so it only takes as much horizontal space as
   it needs and doesn't push other content down when short. */
#dash-session-pill {
    margin-bottom: 0.6rem;
}
.session-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.75rem;
    border-radius: 999px;
    background: #eff6ff;
    border: 1px solid #bfdbfe;
    font-size: 0.82rem;
    color: #1d4ed8;
    position: relative;
}
.session-pill__label {
    font-weight: 600;
    white-space: nowrap;
}
/* [▼] dropdown trigger — sits inline in the pill */
.session-pill__cc-btn {
    background: none;
    border: none;
    padding: 0 0.15rem;
    cursor: pointer;
    color: #1d4ed8;
    font-size: 0.7rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    border-radius: 4px;
    transition: background 0.15s;
}
.session-pill__cc-btn:hover {
    background: rgba(29, 78, 216, 0.12);
}
/* Floating CC picker dropdown */
.session-pill__dropdown {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 800;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    min-width: 200px;
    max-width: 320px;
    overflow: hidden;
}
.session-pill__cc-option {
    display: block;
    width: 100%;
    padding: 0.5rem 0.85rem;
    text-align: left;
    background: none;
    border: none;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    font-size: 0.85rem;
    color: var(--text-main);
    font-family: inherit;
    transition: background 0.12s;
}
.session-pill__cc-option:last-child {
    border-bottom: none;
}
.session-pill__cc-option:hover {
    background: var(--surface-hover);
}
.session-pill__cc-option--active {
    font-weight: 700;
    color: var(--primary, #3b82f6);
}

/* Dark-mode retint for the session pill */
body.dark-mode .session-pill {
    background: rgba(59, 130, 246, 0.12);
    border-color: rgba(59, 130, 246, 0.25);
    color: #93c5fd;
}
body.dark-mode .session-pill__cc-btn {
    color: #93c5fd;
}
body.dark-mode .session-pill__cc-btn:hover {
    background: rgba(147, 197, 253, 0.12);
}

/* ─── P2.11 — Forgot-to-sign-out banner ────────────────────────────────────
   Non-blocking amber informational strip shown below the hero immediately
   after a sign-in where the nightly sweep auto-closed yesterday's session.
   Dismissable via ×. Banner is always full-width so it reads clearly on
   narrow viewports — staff on phones should see it without zooming. */
.dash-forgot-banner {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.65rem 0.9rem;
    margin-bottom: 0.6rem;
    border-radius: 8px;
    background: #fef3c7;
    border: 1px solid #fde68a;
    color: #92400e;
    font-size: 0.85rem;
    line-height: 1.45;
}
.dash-forgot-banner__icon {
    flex-shrink: 0;
    margin-top: 0.05rem;
    color: #d97706;
}
.dash-forgot-banner__text {
    flex: 1;
    min-width: 0;
}
.dash-forgot-banner__close {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.1rem;
    line-height: 1;
    color: #92400e;
    padding: 0 0.1rem;
    flex-shrink: 0;
    opacity: 0.6;
    transition: opacity 0.15s;
}
.dash-forgot-banner__close:hover {
    opacity: 1;
}

/* Dark-mode retint for the forgot banner */
body.dark-mode .dash-forgot-banner {
    background: rgba(217, 119, 6, 0.12);
    border-color: rgba(217, 119, 6, 0.3);
    color: #fcd34d;
}
body.dark-mode .dash-forgot-banner__icon {
    color: #fbbf24;
}
body.dark-mode .dash-forgot-banner__close {
    color: #fcd34d;
}

/* ─── People Hub → Hours subtab (hoursPanel.js) ────────────────────────────
   Manager-facing labour dashboard. Four panels: live state strip, today
   totals table, weekly heatmap, and a date-range filter bar. Heatmap cell
   colour encodes % on jobs (red < 50, amber 50–75, green > 75).
*/
.hours-panel {
    padding-bottom: 2rem;
}
.hours-panel__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1rem;
}
.hours-panel__filterbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding-bottom: 1rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}
.hours-panel__filterbtn {
    padding: 0.45rem 0.95rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--text-main);
    cursor: pointer;
    font-family: inherit;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.hours-panel__filterbtn:hover {
    background: var(--surface-hover);
}
.hours-panel__filterbtn--active {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
}
.hours-panel__custom-range {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: 0.25rem;
}
.hours-panel__custom-range label {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8rem;
    color: var(--text-muted);
}
.hours-panel__custom-range input[type="date"] {
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    font-family: inherit;
    font-size: 0.82rem;
    background: var(--surface);
    color: var(--text-main);
}
.hours-panel__asof {
    margin-left: auto;
    font-size: 0.78rem;
    color: var(--text-muted);
    font-style: italic;
}
.hours-panel__section-title {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin: 0 0 0.5rem 0;
}
.hours-panel__loading,
.hours-panel__empty,
.hours-panel__notice {
    padding: 1.25rem 1rem;
    color: var(--text-muted);
    font-size: 0.85rem;
    text-align: center;
    background: var(--surface);
    border: 1px dashed var(--border);
    border-radius: 6px;
}
.hours-panel__notice {
    background: rgba(217, 119, 6, 0.08);
    border-style: solid;
    border-color: rgba(217, 119, 6, 0.3);
    color: #92400e;
}
.hours-panel__live,
.hours-panel__totals,
.hours-panel__heatmap {
    margin-bottom: 1.75rem;
}

/* Live state strip — pill per user. */
.hours-live__strip {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}
.hours-live__pill {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 180px;
    padding: 0.6rem 0.9rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 4px solid var(--primary);
    border-radius: 6px;
    font-size: 0.8rem;
}
.hours-live__pill--job {
    border-left-color: #2563eb;
}
.hours-live__pill--overhead {
    border-left-color: #6b7280;
}
.hours-live__pill-name {
    font-weight: 700;
    font-size: 0.88rem;
    color: var(--text-main);
}
.hours-live__pill-target {
    color: var(--text-muted);
    font-size: 0.78rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 240px;
}
.hours-live__pill-cc {
    color: var(--text-muted);
    font-style: italic;
}
.hours-live__pill-time {
    font-family: monospace;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--primary);
}

/* Today totals table — sortable, click-row drills to weekly view. */
.hours-totals__tablewrap {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow-x: auto;
}
.hours-totals__table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
    font-size: 0.85rem;
}
.hours-totals__table th {
    padding: 0.7rem 1rem;
    background: var(--surface-hover);
    border-bottom: 2px solid var(--border);
    font-size: 0.72rem;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--text-muted);
    letter-spacing: 0.04em;
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.hours-totals__table th:hover {
    color: var(--text-main);
}
.hours-totals__th--active {
    color: var(--primary) !important;
}
.hours-totals__table td {
    padding: 0.65rem 1rem;
    border-bottom: 1px solid var(--border);
    color: var(--text-main);
}
.hours-totals__pct {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 700;
    min-width: 48px;
    text-align: center;
}
.hours-totals__pct--red {
    background: rgba(220, 38, 38, 0.12);
    color: #b91c1c;
}
.hours-totals__pct--amber {
    background: rgba(217, 119, 6, 0.12);
    color: #92400e;
}
.hours-totals__pct--green {
    background: rgba(16, 185, 129, 0.14);
    color: #047857;
}

/* Weekly heatmap — Mon–Sun × user grid. */
.hours-heatmap__legend {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 0.55rem;
    font-size: 0.72rem;
    color: var(--text-muted);
}
.hours-heatmap__legend > span {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}
.hours-heatmap__legend .hours-heatmap__cell {
    display: inline-block;
    width: 16px;
    height: 16px;
    padding: 0;
    border-radius: 3px;
    border: 1px solid var(--border);
}
.hours-heatmap__tablewrap {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow-x: auto;
}
.hours-heatmap__table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 4px;
    padding: 0.5rem;
    font-size: 0.78rem;
}
.hours-heatmap__th-user,
.hours-heatmap__th-day {
    padding: 0.35rem 0.6rem;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.7rem;
    text-transform: uppercase;
    font-weight: 700;
    text-align: center;
    letter-spacing: 0.04em;
}
.hours-heatmap__th-user {
    text-align: left;
}
.hours-heatmap__td-user {
    padding: 0.45rem 0.6rem;
    color: var(--text-main);
    font-weight: 600;
    background: transparent;
    white-space: nowrap;
}
.hours-heatmap__cell {
    width: 56px;
    height: 32px;
    text-align: center;
    border-radius: 4px;
    font-size: 0.74rem;
    font-weight: 700;
    color: #fff;
    padding: 0;
    background: #e5e7eb;
}
.hours-heatmap__cell--red {
    background: #ef4444;
}
.hours-heatmap__cell--amber {
    background: #f59e0b;
}
.hours-heatmap__cell--green {
    background: #10b981;
}
.hours-heatmap__cell--empty {
    background: var(--bg-body);
    color: var(--text-muted);
    border: 1px dashed var(--border);
}

/* Dark-mode retint for the hours panel. */
body.dark-mode .hours-panel__notice {
    background: rgba(217, 119, 6, 0.14);
    color: #fcd34d;
    border-color: rgba(217, 119, 6, 0.3);
}
body.dark-mode .hours-panel__loading,
body.dark-mode .hours-panel__empty {
    background: var(--surface);
}
body.dark-mode .hours-totals__pct--red {
    background: rgba(220, 38, 38, 0.22);
    color: #fca5a5;
}
body.dark-mode .hours-totals__pct--amber {
    background: rgba(217, 119, 6, 0.22);
    color: #fcd34d;
}
body.dark-mode .hours-totals__pct--green {
    background: rgba(16, 185, 129, 0.22);
    color: #6ee7b7;
}
body.dark-mode .hours-heatmap__cell {
    background: #374151;
}
body.dark-mode .hours-heatmap__cell--empty {
    background: transparent;
}

/* ─── cc_needs_review badge (P5.11) ───────────────────────────────────────
   Yellow "review CC" pill rendered next to a task title whenever the task
   was backfilled by scripts/backfill_tasks_cc.py. Click → opens that task's
   editor so the user can pick the right CC; saving the task clears the flag.
*/
.cc-review-badge {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0.1rem 0.45rem;
    background: #fef9c3;
    color: #92400e;
    border: 1px solid #fde68a;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    cursor: pointer;
    vertical-align: middle;
    line-height: 1.3;
}
.cc-review-badge:hover {
    background: #fde68a;
}
body.dark-mode .cc-review-badge {
    background: rgba(217, 119, 6, 0.2);
    color: #fcd34d;
    border-color: rgba(217, 119, 6, 0.4);
}

/* ─── Weekly Timesheet (weeklyTimesheet.js — P4 frontend) ──────────────────
   Mon–Sun grid with coloured session blocks. Sessions outside the 06:00–22:00
   window get pushed into "<06:00" / ">22:00" overflow strips at the top and
   bottom of each day column so they stay visible without forcing a 24-row
   grid. _PX_PER_MIN = 2 (in JS) keeps the 16h window at ~1920px tall — roomy
   enough to read CC names on 5-minute blocks.

   The grid uses CSS Grid: 8 columns (1 time-axis + 7 days) and 2 rows (header
   + body). The body row is a positioned context for absolutely-placed blocks.
*/
.wts-panel {
    padding-bottom: 2rem;
}
.wts-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1rem;
}
.wts-title {
    font-size: 1.5rem;
    color: var(--text-main);
    margin: 0 0 0.35rem 0;
}
.wts-subtitle {
    color: var(--text-muted);
    margin: 0;
    font-size: 0.9rem;
}
.wts-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.wts-toolbar .btn {
    padding: 0.4rem 0.85rem;
    font-size: 0.85rem;
}
.wts-week-input {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.85rem;
    background: var(--surface);
    color: var(--text-main);
    font-family: inherit;
}
.wts-userpicker-wrap {
    display: inline-flex;
    align-items: center;
    margin-left: 0.5rem;
}
.wts-userpicker-label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}
.wts-userpicker-label select {
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.85rem;
    background: var(--surface);
    color: var(--text-main);
    font-family: inherit;
}
.wts-legend {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
    font-size: 0.82rem;
    color: var(--text-muted);
}
.wts-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.wts-legend-swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 3px;
    vertical-align: middle;
}
.wts-legend-swatch--job {
    background: #3b82f6;
}
.wts-legend-swatch--overhead {
    background: #94a3b8;
}
.wts-legend-meta {
    margin-left: auto;
    font-weight: 600;
    color: var(--text-main);
}
.wts-loading,
.wts-notice {
    padding: 2rem;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.9rem;
    background: var(--surface);
    border: 1px dashed var(--border);
    border-radius: 8px;
}
.wts-notice {
    color: var(--warning, #b45309);
    background: rgba(245, 158, 11, 0.06);
    border-color: rgba(245, 158, 11, 0.3);
}
.wts-gridwrap {
    overflow: visible;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
}
.wts-grid {
    display: grid;
    grid-template-columns: 70px repeat(7, minmax(140px, 1fr));
    grid-template-rows: auto 1fr;
    min-width: 1080px;
    background: var(--surface);
}
.wts-grid__corner {
    grid-row: 1;
    grid-column: 1;
    background: var(--surface-hover);
    border-bottom: 1px solid var(--border);
    border-right: 1px solid var(--border);
}
.wts-grid__dayhead {
    grid-row: 1;
    background: var(--surface-hover);
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--border);
    border-right: 1px solid var(--border);
    text-align: center;
}
.wts-grid__dayhead--today {
    background: rgba(59, 130, 246, 0.08);
}
.wts-grid__dayhead-wk {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.wts-grid__dayhead-date {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-main);
    margin-top: 0.1rem;
}
.wts-grid__timeaxis {
    grid-row: 2;
    grid-column: 1;
    position: relative;
    background: var(--surface-hover);
    border-right: 1px solid var(--border);
    /* Matches the day column height: 16h × 60min × 1px/min = 960px. */
    min-height: 960px;
}
.wts-grid__hour {
    position: absolute;
    left: 0;
    right: 0;
    padding-right: 0.5rem;
    text-align: right;
    font-size: 0.7rem;
    color: var(--text-muted);
    font-weight: 600;
    line-height: 1;
    transform: translateY(-50%);
}
.wts-grid__half {
    position: absolute;
    left: 0;
    right: 0;
    padding-right: 0.5rem;
    text-align: right;
    font-size: 0.58rem;
    color: var(--text-muted);
    font-weight: 500;
    opacity: 0.65;
    line-height: 1;
    transform: translateY(-50%);
}
.wts-grid__daycol {
    grid-row: 2;
    border-right: 1px solid var(--border);
    background: var(--surface);
}
.wts-grid__col {
    position: relative;
    background: var(--surface);
}
.wts-grid__col--today {
    background: rgba(59, 130, 246, 0.05);
}
.wts-grid__col--weekend {
    background: rgba(148, 163, 184, 0.06);
}
.wts-grid__band {
    position: absolute;
    left: 0;
    right: 0;
    pointer-events: none;
    z-index: 0;
}
.wts-grid__band--alt {
    background: rgba(148, 163, 184, 0.04);
}
.wts-grid__band--lunch {
    background: rgba(245, 158, 11, 0.06);
    border-top: 1px dashed rgba(245, 158, 11, 0.35);
    border-bottom: 1px dashed rgba(245, 158, 11, 0.35);
}
/* Lunch lock — sealed Mon–Thu 12:00–12:30 band that no work block may
   occupy. z-index sits above blocks (.wts-block @ 2) so the overlay
   masks any legacy session that overlaps the lunch window. */
.wts-grid__lunch-lock {
    position: absolute;
    left: 4px;
    right: 4px;
    border-radius: 4px;
    background-color: rgba(245, 158, 11, 0.18);
    background-image: repeating-linear-gradient(
        135deg,
        rgba(120, 53, 15, 0.12) 0,
        rgba(120, 53, 15, 0.12) 6px,
        transparent 6px,
        transparent 12px
    );
    border: 1px dashed rgba(180, 83, 9, 0.55);
    color: rgba(120, 53, 15, 0.85);
    cursor: not-allowed;
    pointer-events: auto;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    font-size: 0.78rem;
    font-weight: 600;
    user-select: none;
    overflow: hidden;
}
.wts-grid__lunch-lock-icon {
    font-size: 0.95rem;
    line-height: 1;
}
.wts-grid__lunch-lock-label {
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
body.dark-mode .wts-grid__lunch-lock {
    background-color: rgba(245, 158, 11, 0.14);
    background-image: repeating-linear-gradient(
        135deg,
        rgba(254, 215, 170, 0.12) 0,
        rgba(254, 215, 170, 0.12) 6px,
        transparent 6px,
        transparent 12px
    );
    border-color: rgba(251, 191, 36, 0.55);
    color: rgba(254, 215, 170, 0.95);
}
.wts-grid__hourline {
    /* Solid, prominent hour rule — the most visible of the three. */
    position: absolute;
    left: 0;
    right: 0;
    height: 2px;
    background: rgba(71, 85, 105, 0.55);
    pointer-events: none;
    z-index: 0;
}
.wts-grid__halfline {
    /* Highlighted mid-hour anchor — full-width dashed line, less heavy
       than the hour rule but still clearly visible. */
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    border-top: 2px dashed rgba(100, 116, 139, 0.5);
    pointer-events: none;
    z-index: 0;
}
.wts-grid__quarterline {
    /* :15 / :45 ticks — partial-width so the 15-min grid is legible
       without competing with the hour + half-hour anchors. */
    position: absolute;
    left: 25%;
    right: 25%;
    height: 1px;
    background: rgba(100, 116, 139, 0.45);
    pointer-events: none;
    z-index: 0;
}
body.dark-mode .wts-grid__hourline {
    background: rgba(203, 213, 225, 0.4);
}
body.dark-mode .wts-grid__halfline {
    border-top-color: rgba(203, 213, 225, 0.32);
}
body.dark-mode .wts-grid__quarterline {
    background: rgba(203, 213, 225, 0.28);
}
.wts-grid__hitarea {
    position: absolute;
    inset: 0;
    cursor: copy;
    z-index: 1;
}
.wts-grid__hitarea:hover {
    background: rgba(59, 130, 246, 0.04);
}
.wts-block {
    position: absolute;
    left: 4px;
    right: 4px;
    border-radius: 4px;
    padding: 4px 26px 4px 8px;
    font-size: 0.78rem;
    color: #fff;
    cursor: grab;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
    transition: filter 0.15s ease, box-shadow 0.15s ease;
    z-index: 2;
    user-select: none;
}
.wts-block:active {
    cursor: grabbing;
}
.wts-block__resize {
    position: absolute;
    left: 0;
    right: 0;
    height: 6px;
    cursor: ns-resize;
    z-index: 3;
}
.wts-block__resize--top {
    top: 0;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
}
.wts-block__resize--bottom {
    bottom: 0;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
}
.wts-block__resize:hover {
    background: rgba(255, 255, 255, 0.25);
}
.wts-block:hover {
    filter: brightness(1.08);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}
.wts-block:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 1px;
}
.wts-block--job {
    background: #3b82f6;
}
.wts-block--overhead {
    background: #94a3b8;
}
/* Public-holiday closure block — teal palette mirrors the planner's
   `.so-band-holiday` stripe so the eye links the two surfaces ("this is the
   workshop closure that shows in your weekly view"). Diagonal-stripe
   background lets it read distinctly from a solid job/overhead block even
   at small sizes. */
.wts-block--public-holiday {
    background: #14b8a6;
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0.10) 0,
        rgba(255, 255, 255, 0.10) 6px,
        transparent 6px,
        transparent 12px
    );
}
/* Auto-seeded (synthetic, no DB row yet) public_holiday block — same teal
   palette but a dashed border + slightly lower opacity so the eye reads
   "ghost / unsaved" before a manager edits it into a real row. */
.wts-block--synthetic {
    opacity: 0.85;
    border: 1px dashed rgba(255, 255, 255, 0.5);
}
/* Split-job block — its single time slice is shared across ≥2 jobs and is
   drawn as N stacked, labelled segments (see _renderSplitSegments). Zero the
   block padding so the segment layer (position:absolute; inset:0) fills the
   whole rounded rectangle edge-to-edge; the ⓘ history button and resize
   handles keep their own higher z-index and float above the segments. The
   per-segment background colours are set inline so the JS owns the primary
   vs extras shading ramp. */
.wts-block--split {
    padding: 0;
    background: #3b82f6;
}
.wts-block__title {
    font-weight: 700;
    line-height: 1.15;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.wts-block__sub {
    font-size: 0.7rem;
    opacity: 0.9;
    margin-top: 1px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.wts-block__info {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 20px;
    height: 20px;
    border: none;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    border-radius: 999px;
    font-size: 0.85rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Above the split-segment layer (z-index:1) and resize handles (3) so
       the history button stays visible + clickable on a segmented block. */
    z-index: 4;
}
.wts-block__info:hover {
    background: rgba(255, 255, 255, 0.32);
}
/* ─── Modals (edit / create) ─────────────────────────────────────────── */
.wts-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
    padding: 1rem;
}
.wts-modal {
    background: var(--surface);
    border-radius: 10px;
    width: 460px;
    max-width: 95vw;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
}
.wts-modal__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
}
.wts-modal__head h3 {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--text-main);
}
.wts-modal__close {
    background: none;
    border: none;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
}
.wts-modal__body {
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.wts-form-row {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.wts-form-row label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
}
.wts-form-row input,
.wts-form-row select,
.wts-form-row textarea {
    width: 100%;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.88rem;
    background: var(--surface);
    color: var(--text-main);
    font-family: inherit;
    box-sizing: border-box;
}
.wts-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}
.wts-edit-error {
    background: rgba(220, 38, 38, 0.08);
    color: var(--error, #dc2626);
    border: 1px solid rgba(220, 38, 38, 0.3);
    border-radius: 6px;
    padding: 0.5rem 0.75rem;
    font-size: 0.82rem;
}
.wts-modal__foot {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
    margin-top: 0.25rem;
    padding-bottom: 0;
}
.wts-modal__spacer {
    flex: 1;
}
.wts-modal__readonly {
    flex: 1;
    color: var(--text-muted);
    font-size: 0.82rem;
    font-style: italic;
}
.btn.btn-danger {
    background: var(--error, #dc2626);
    color: #fff;
    border: 1px solid var(--error, #dc2626);
}
.btn.btn-danger:hover {
    filter: brightness(0.92);
}

/* ─── Audit history popover ──────────────────────────────────────────── */
.wts-popover {
    position: absolute;
    z-index: 10000;
    width: 320px;
    max-width: 92vw;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
    overflow: hidden;
}
.wts-popover__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.6rem 0.85rem;
    border-bottom: 1px solid var(--border);
    background: var(--surface-hover);
    color: var(--text-main);
    font-size: 0.85rem;
}
.wts-popover__close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
}
.wts-popover__body {
    padding: 0.65rem 0.85rem;
    font-size: 0.82rem;
    color: var(--text-main);
    max-height: 280px;
    overflow-y: auto;
}
.wts-popover__list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.wts-popover__row {
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--border);
}
.wts-popover__row:last-child {
    border-bottom: none;
}
.wts-popover__when {
    font-weight: 600;
    color: var(--text-muted);
}
.wts-popover__action {
    color: var(--primary, #3b82f6);
    font-weight: 600;
}
.wts-popover__who {
    font-weight: 600;
}
.wts-popover__summary {
    margin-top: 0.25rem;
    color: var(--text-muted);
    font-size: 0.78rem;
    white-space: pre-wrap;
}

/* ─── labourTracking session-backed badge + history link (4.16) ───────── */
.labour-session-badge {
    display: inline-block;
    margin-left: 0.3rem;
    padding: 0.05rem 0.35rem;
    background: rgba(34, 197, 94, 0.1);
    color: #15803d;
    border-radius: 3px;
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    vertical-align: middle;
}
body.dark-mode .labour-session-badge {
    background: rgba(34, 197, 94, 0.18);
    color: #4ade80;
}
.labour-history-link {
    color: var(--primary, #3b82f6);
    font-size: 0.72rem;
    text-decoration: underline;
    cursor: pointer;
    margin-left: 0.25rem;
}

/* ─── Dark mode tweaks ─────────────────────────────────────────────────── */
body.dark-mode .wts-block__info {
    background: rgba(0, 0, 0, 0.25);
}
body.dark-mode .wts-block__info:hover {
    background: rgba(0, 0, 0, 0.4);
}
body.dark-mode .wts-grid__dayhead--today {
    background: rgba(59, 130, 246, 0.18);
}

/* ─── Phase 1 dynamic-scheduling visual cues ────────────────────────────── */
/* Layer on top of `.pdr-tl-block` (the existing task block class root). The
   modifier classes are applied in `_pdrTlBlockHtml` based on packer outputs
   (`_atRisk`, `_spilledFrom`) and task fields (`anchored`, `pauseMode`).   */
.pdr-tl-block.pdr-anchored {
    border-left-width: 3px;
    border-left-style: solid;
    border-left-color: var(--accent, #f7a900);
    /* Opaque pale-amber wash — no rgba alpha, so the underlying timeline
       grid lines don't bleed through. Dark-mode counterpart below. */
    background-color: #fff5e0;
}
body.dark-mode .pdr-tl-block.pdr-anchored {
    background-color: #2c2417;
}
.pdr-tl-block.pdr-anchored::before {
    content: "\2693";  /* anchor glyph */
    position: absolute;
    bottom: 4px;
    right: 6px;
    font-size: 22px;
    color: var(--accent, #f7a900);
    opacity: 0.95;
    line-height: 1;
    z-index: 2;            /* above the background tint */
    pointer-events: none;  /* don't swallow clicks meant for the block */
    /* Note: the bottom-right segment-text badge (.pdr-split-segment::after)
       sits in the same corner, but anchored tasks are NEVER split (see
       comment at the .pdr-split-segment block above + planner.js
       _pdrTlBlockHtml ~L4347), so this anchor and that badge are mutually
       exclusive and cannot collide in real-world renders. */
}
/* Flex blocks get a subtle diagonal stripe overlay so non-flex (anchored,
   regular) tasks are immediately distinguishable at a glance. The 4% white
   stripes layer on top of whatever status-based background colour the task
   already has. */
.pdr-tl-block.pdr-flex {
    background-image: repeating-linear-gradient(
        135deg,
        transparent 0px,
        transparent 10px,
        rgba(0, 0, 0, 0.06) 10px,
        rgba(0, 0, 0, 0.06) 12px
    );
}
/* Flex blocks get italic / muted predicted-time text so the user can see
   at a glance that the time is a projection, not a fixed commitment. The
   selectors target both the explicit time labels (if a future render adds
   one) and the existing `.pdr-tl-head` so today's blocks visibly differ
   from anchored ones — the head meta strip ("Task | Project | P3") goes
   slightly muted to convey "this start time is a prediction". */
.pdr-tl-block.pdr-flex .pdr-tl-time,
.pdr-tl-block.pdr-flex .pdr-tl-when {
    font-style: italic;
    opacity: 0.75;
}
.pdr-tl-block.pdr-flex .pdr-tl-head {
    opacity: 0.85;
    font-style: italic;
}
/* Anchor whose predicted start sits later than the cursor — earlier flex
   tasks have overflowed onto its slot. Anchor stays pinned; warning border
   surfaces the conflict for the manager / user. */
.pdr-tl-block.pdr-at-risk {
    border-color: #c0392b;
    box-shadow: 0 0 0 1px #c0392b inset;
}
/* Spilled blocks (EOD overflow) — dashed border so the user can see the
   block landed on a different date because something earlier ran long. */
.pdr-tl-block.pdr-spilled {
    border-style: dashed;
}
/* Break-mode active: dashed accent border + small pause glyph. Distinct
   from regular pause (which gets no special styling — the schedule still
   ticks). Phase 1 hardcodes the break windows used by the packer; Stage 4
   moves them into a config module. */
.pdr-tl-block.pdr-break-active {
    border: 2px dashed var(--accent, #f7a900);
    background-image: linear-gradient(135deg,
        rgba(247, 169, 0, 0.10) 0%,
        rgba(247, 169, 0, 0.02) 100%);
}
.pdr-tl-block.pdr-break-active::after {
    content: "\2759\2759";  /* Unicode pause: two heavy vertical bars */
    position: absolute;
    bottom: 4px;
    right: 6px;
    font-size: 9px;
    color: var(--accent, #f7a900);
    opacity: 0.85;
    letter-spacing: -1px;
    z-index: 2;
}

/* ─── Phase 1 auto-split visual cues (Stage 5A — Task 20) ─────────────────── */
/* When a flex task is broken into multiple segments (around breaks AND/OR
   across day boundaries), each segment is its own .pdr-tl-block carrying
   `pdr-split-segment` plus exactly one of pdr-segment-first /
   pdr-segment-middle / pdr-segment-last. The dashed boundaries on segment
   edges that adjoin a break or day boundary visually convey "this is one
   task in multiple parts." Anchored tasks are never split, so these rules
   only ever fire on flex tasks.                                            */
.pdr-tl-block.pdr-split-segment.pdr-segment-first {
    border-bottom-style: dashed;
    border-bottom-color: var(--accent, #f7a900);
}
.pdr-tl-block.pdr-split-segment.pdr-segment-middle {
    border-top-style: dashed;
    border-bottom-style: dashed;
    border-top-color: var(--accent, #f7a900);
    border-bottom-color: var(--accent, #f7a900);
}
.pdr-tl-block.pdr-split-segment.pdr-segment-last {
    border-top-style: dashed;
    border-top-color: var(--accent, #f7a900);
}
.pdr-tl-block.pdr-split-segment::after {
    /* Small "X of Y" badge in the bottom-right of each segment to indicate
       continuation. Reads from data-segment-info set by _pdrTlBlockHtml.    */
    content: attr(data-segment-info);
    position: absolute;
    bottom: 2px;
    right: 4px;
    font-size: 9px;
    opacity: 0.6;
    pointer-events: none;
}

/* Stage 5C: original-predicted-end dashed line inside stretched overdue blocks.
   Rendered when the worker is past actualStart + estimatedHours and the block
   has grown to wall-clock-now. Pairs with the red overdue styling. Pointer-
   events:none so it doesn't intercept clicks on the underlying block. */
.pdr-tl-block .pdr-original-finish-line {
    position: absolute;
    left: 0;
    right: 0;
    height: 0;
    border-top: 3px dashed #dc2626;     /* full saturation, thicker */
    pointer-events: none;
    z-index: 4;                         /* above ::after badge */
}
/* Inline label sits above the dashed line, right-aligned, on a high-contrast
   chip so it's readable on any block colour (red overdue blocks included).
   Always visible — the hover-tooltip alone was easy to miss. */
.pdr-tl-block .pdr-original-finish-label {
    position: absolute;
    bottom: 1px;                         /* sits ABOVE the dashed line */
    right: 4px;
    background: #ffffff;
    color: #dc2626;
    border: 1px solid #dc2626;
    border-radius: 3px;
    padding: 1px 5px;
    font-size: 10px;
    font-weight: 700;
    line-height: 1.1;
    white-space: nowrap;
    pointer-events: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
/* Dark mode: invert the chip so the red border + text stay readable. */
body.dark-mode .pdr-tl-block .pdr-original-finish-label {
    background: #1a1a1a;
    color: #f87171;
    border-color: #f87171;
}

/* Pause bands inside timeline blocks. Render the wall-clock spans where a
   running task was paused (pauseMode='pause' only — break-mode splits the
   chunk so it's already represented as a separate bar). z-index:-1 keeps
   the band above the block's surface but below the title/content (which
   are non-positioned flex children). */
.pdr-tl-block .pdr-tl-pause-band {
    position: absolute;
    left: 0;
    right: 0;
    background-color: rgba(251, 191, 36, 0.35);
    border-top: 1px solid #d97706;
    border-bottom: 1px solid #d97706;
    pointer-events: none;
    z-index: -1;
    box-sizing: border-box;
    min-height: 4px;
}
.pdr-tl-block .pdr-tl-pause-band--live {
    background-image: repeating-linear-gradient(
        45deg,
        rgba(251, 191, 36, 0.35) 0,
        rgba(251, 191, 36, 0.35) 6px,
        rgba(251, 191, 36, 0.55) 6px,
        rgba(251, 191, 36, 0.55) 12px
    );
}
body.dark-mode .pdr-tl-block .pdr-tl-pause-band {
    background-color: rgba(251, 191, 36, 0.22);
    border-color: #f59e0b;
}

/* Past-due flag — task's predicted end falls past its dueDate. Strong red
   border. The warning glyph itself is rendered inline in the head row by
   _pdrTlTaskBody (right after the priority pill) so it sits next to the
   other chips instead of floating absolute. */
.pdr-tl-block.pdr-past-due {
    box-shadow: 0 0 0 2px #c0392b inset;
}
.pdr-tl-head .pdr-tl-caution {
    color: #c0392b;
    font-size: 14px;
    font-weight: bold;
    line-height: 1;
}

/* ─── Phase 1 dynamic-task-scheduling: break overstay modal ──────────────
   Fired by taskTimer.js's 30-second sweep when wall clock exceeds
   break_end + 5 min for any task in pauseMode='break'. Inline styles on
   the modal cover positioning and chrome; these rules are minimal cleanup
   for the textarea + container so the popup matches the rest of the
   modal-overlay family. */
.break-overstay-modal {
    max-width: 420px;
}
.break-overstay-modal textarea {
    width: 100%;
    min-height: 70px;
    padding: 6px;
    margin: 8px 0;
    box-sizing: border-box;
    font-family: inherit;
    font-size: 13px;
}

/* ─── Department Backlog Categories ─────────────────────────────────────
   Per-section folder chrome inside #planner-dept-body. Tokens map to the
   project's existing CSS vars: spec calls for `--surface-subtle` / `--accent`
   which don't exist here, so we substitute `--bg-muted` (the canonical
   "subtle" surface) and `--primary` (Unidan Red, the de-facto accent).
   `.is-drop-target` lights up while a draggable task hovers a section.
   `.planner-dept-row.is-dragging` fades the original card while it's being
   carried. `.dept-cat-rename-input` swaps in for the header span during
   inline rename.

   The body becomes a responsive 3/2/1-column grid only when at least one
   `.dept-cat-section` is present — the `:has()` guard keeps the legacy flat
   fallback (department with zero categories, see `renderDeptView()` early
   return at planner.js ~7540) rendering as a vertical stack of task rows.
   `min-width: 0` on the section is required so long task titles don't blow
   out the grid track. The existing inline padding on #planner-dept-body
   stays (set in index.html); we only add the grid display + columns + gap
   here, so the flat fallback's padding is unaffected. */
#planner-dept-body:has(.dept-cat-section) {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.6rem;
}
@media (min-width: 901px) and (max-width: 1300px) {
    #planner-dept-body:has(.dept-cat-section) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
    #planner-dept-body:has(.dept-cat-section) { grid-template-columns: minmax(0, 1fr); }
}
.dept-cat-section { border: 1px solid var(--border); border-radius: 6px; background: var(--bg-muted); min-width: 0; }
.dept-cat-section.is-drop-target { outline: 2px dashed var(--primary); outline-offset: -2px; }
.dept-cat-header { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.7rem; cursor: pointer; user-select: none; }
.dept-cat-header .dept-cat-name { font-weight: 600; font-size: 0.88rem; }
.dept-cat-header .dept-cat-count { font-size: 0.7rem; color: var(--text-muted); background: rgba(107,114,128,0.1); border-radius: 10px; padding: 0.05rem 0.45rem; font-weight: 700; }
.dept-cat-body { padding: 0.1rem 0.1rem 0.3rem; }
.dept-cat-body.collapsed { display: none; }
.dept-cat-empty { text-align: center; color: var(--text-muted); font-size: 0.78rem; padding: 0.75rem; font-style: italic; }
.planner-dept-row.is-dragging { opacity: 0.45; }
.dept-cat-rename-input { font: inherit; padding: 0.15rem 0.3rem; border: 1px solid var(--primary); border-radius: 3px; background: var(--surface); color: var(--text-main); }

/* ───────────────────────────────────────────────────────────────────────
   Add/Edit Task modal — wide two-column layout (v2).
   Markup lives at index.html ~6331-6527 (#planner-task-modal).
   The .ptask-* prefix avoids collisions with the global .form-group styles
   and the v1 inline-style sized version we replaced. Element IDs are
   preserved so planner.js continues to read/write them unchanged.
   ─────────────────────────────────────────────────────────────────────── */
.ptask-card {
    width: 95vw;
    max-width: 1500px;
    padding: 0.7rem 1.8rem 0.7rem;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
    /* Owen 2026-05-27: bigger modal for the 80%-default-zoom view — a
       min-height so it fills the screen instead of collapsing to its content,
       and a higher cap before it scrolls. */
    min-height: 85vh;
    max-height: 99vh;
    overflow-y: auto;
    box-sizing: border-box;
}
/* Thin, rounded scrollbar that sits inside the card's rounded corners — the
   card is itself the scroll container (max-height + overflow-y above), so the
   browser's default square gutter scrollbar overshot the rounded top/bottom
   corners. Mirrors .feedback-modal-scroll: the transparent track + 8px top/
   bottom margin keep the thumb off the corners, and the inset rounded thumb
   (2px transparent border via background-clip) floats clear of the edge. */
.ptask-card { scrollbar-width: thin; scrollbar-color: rgba(0,0,0,0.22) transparent; }
.ptask-card::-webkit-scrollbar { width: 8px; }
.ptask-card::-webkit-scrollbar-track { background: transparent; margin: 8px 0; }
.ptask-card::-webkit-scrollbar-thumb {
    background: rgba(0,0,0,0.22);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.ptask-card::-webkit-scrollbar-thumb:hover {
    background: rgba(0,0,0,0.38);
    background-clip: padding-box;
    border: 2px solid transparent;
}
body.dark-mode .ptask-card { scrollbar-color: rgba(255,255,255,0.22) transparent; }
body.dark-mode .ptask-card::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.22); }
.ptask-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.5rem;
}
.ptask-title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--text-main);
}
.ptask-close {
    background: transparent;
    border: none;
    font-size: 1.75rem;
    cursor: pointer;
    color: var(--text-muted);
    line-height: 1;
    padding: 0;
}

.ptask-header-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

/* Advanced (expandable) section — sits below Estimated Time in the task modal.
   The toggle header expands #ptask-advanced-panel IN-PLACE (normal document
   flow, so the modal card grows to fit — no popover / no zoom-coordinate math).
   The panel is a plain container meant to hold MORE per-task option blocks than
   just "Split time across jobs" later (one .ptask-adv-block each). */
.ptask-advanced {
    margin-top: 1.1rem;
    border-top: 1px solid var(--border);
    padding-top: 1rem;
}
.ptask-advanced-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: transparent;
    color: var(--text-main);
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 8px);
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.ptask-advanced-toggle:hover {
    background: var(--bg-muted, #f3f4f6);
    border-color: var(--border);
}
/* Open state keeps the toggle visually "pressed" so it reads as the header of
   the panel that's now expanded beneath it. */
.ptask-advanced-toggle.is-open {
    background: var(--bg-muted, #f3f4f6);
    border-color: var(--border);
}
.ptask-advanced-caret {
    display: inline-block;
    font-size: 0.7rem;
    color: var(--text-muted);
    transition: transform 0.15s ease;
}
/* Collapsed shows ▾; expanded flips it to ▴ (rotate the literal ▾ glyph). */
.ptask-advanced-toggle.is-open .ptask-advanced-caret { transform: rotate(180deg); }
.ptask-advanced-toggle-label { line-height: 1; }
.ptask-adv-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.3rem;
    background: #4338ca;
    color: #fff;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1;
}
/* The expanded panel reads as one inset surface holding the option blocks, so
   it's clearly partitioned off from the form fields above it. Subtle muted fill
   + border tie it to the app's section chrome. */
.ptask-advanced-panel {
    margin-top: 0.7rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.85rem;
    background: var(--bg-muted, #f8fafc);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 8px);
}
/* One self-contained option block inside the panel — a COLLAPSIBLE CARD. Stack
   more of these for future Advanced tools; each gets its own clickable head
   (button: caret + title + hint + count) and a collapsible body. The body's
   padding lives here (not on .ptask-adv-block) so the head button can span the
   full card width and read as a clickable header. */
.ptask-adv-block {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 8px);
    background: var(--surface, #fff);
    overflow: hidden;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
/* Lift the card slightly while expanded so the open tool reads as active. */
.ptask-adv-block:has(.ptask-adv-block-head.is-open) {
    border-color: rgba(67,56,202,0.35);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
/* Head is a full-width <button> that toggles the body. Looks like a clickable
   card header — reset the native button chrome and lay caret + text out in a
   row. The caret sits centred against the title line (align-items:center) so it
   doesn't drift up next to the multi-line hint. */
.ptask-adv-block-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    margin: 0;
    padding: 0.8rem 0.85rem;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm, 8px);
    text-align: left;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.12s ease;
}
.ptask-adv-block-head:hover { background: rgba(0,0,0,0.035); }
.ptask-adv-block-head:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: -2px;
}
.ptask-adv-block-caret {
    display: inline-block;
    flex: 0 0 auto;
    font-size: 0.7rem;
    color: var(--text-muted);
    transition: transform 0.15s ease;
}
/* Collapsed shows ▾; expanded flips it to ▴ (rotate the literal ▾ glyph). */
.ptask-adv-block-head.is-open .ptask-adv-block-caret { transform: rotate(180deg); }
.ptask-adv-block-head-text {
    display: block;
    min-width: 0;
}
.ptask-adv-block-title {
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--text-main);
}
/* Per-tool count on the head, e.g. "Split time across jobs · 2". */
.ptask-adv-block-count {
    margin-left: 0.35rem;
    font-size: 0.82rem;
    font-weight: 700;
    color: #4338ca;
}
.ptask-adv-block-hint {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.78rem;
    color: var(--text-muted);
    line-height: 1.4;
}
/* Collapsible body — toggled inline (display:none/block) by planner.js. Pads
   the body but not its top (the head already has bottom padding), and a hairline
   rule separates it from the head so the expanded body reads as a distinct
   region of the card. */
.ptask-adv-block-body {
    padding: 0.75rem 0.85rem 0.85rem;
    border-top: 1px solid var(--border);
}
.ptask-split-rows {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.ptask-split-rows:empty { display: none; }
.ptask-split-add {
    margin-top: 0.7rem;
    width: 100%;
    padding: 0.55rem;
    font-size: 0.85rem;
    font-weight: 600;
    border-style: dashed;
    color: var(--text-muted);
    transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease;
}
.ptask-split-add:hover {
    border-color: var(--primary);
    color: var(--primary);
}

/* "Untracked task" toggle ROW — a single on/off switch, so it's a plain bordered
   row (NOT a collapsible card; cf. the split .ptask-adv-block sibling). It sits
   directly in .ptask-advanced-panel and matches the cards' surface/border so the
   panel reads as one consistent stack. The whole <label> is the click target
   (wraps the checkbox), so the entire row toggles. */
.ptask-untracked-row {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    cursor: pointer;
    padding: 0.8rem 0.85rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 8px);
    background: var(--surface, #fff);
    transition: border-color 0.12s ease, background 0.12s ease;
}
.ptask-untracked-row:hover { background: rgba(0,0,0,0.025); }
.ptask-untracked-check {
    margin: 0.1rem 0 0;
    width: 1.05rem;
    height: 1.05rem;
    flex: 0 0 auto;
    cursor: pointer;
    accent-color: #4338ca;
}
.ptask-untracked-text { display: flex; flex-direction: column; min-width: 0; }
.ptask-untracked-label {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.88rem;
    font-weight: 700;
    color: var(--text-main);
}
/* "ON" pill shown next to the label while the toggle is checked
   (display flipped by _applyUntrackedMode). */
.ptask-untracked-on {
    font-size: 0.62rem;
    font-weight: 800;
    letter-spacing: 0.05em;
    color: #fff;
    background: #4338ca;
    border-radius: 999px;
    padding: 0.1rem 0.4rem;
    line-height: 1.3;
}
.ptask-untracked-desc {
    margin-top: 0.2rem;
    font-size: 0.78rem;
    color: var(--text-muted);
    line-height: 1.4;
}
/* When ON, give the whole row a faint accent tint + border so the active state
   is obvious at a glance. :has() targets the row whose checkbox is checked. */
.ptask-untracked-row:has(.ptask-untracked-check:checked) {
    border-color: rgba(67,56,202,0.4);
    background: rgba(67,56,202,0.05);
}

/* Greyed-out look for scheduling controls (and their labels) while a task is
   in Untracked mode. They are ALSO `.disabled` in the DOM (set by
   _applyUntrackedMode) — this class is the visual half: dim + muted + a
   not-allowed cursor. NOTE: applied per-control on purpose, never to the whole
   scheduling section, because the Untracked toggle itself lives inside that
   section's Advanced panel and must stay interactive. */
.is-untracked-disabled {
    opacity: 0.45;
    color: var(--text-muted) !important;
    cursor: not-allowed;
}
.is-untracked-disabled .ptask-anchor-toggle-btn { cursor: not-allowed; }

body.dark-mode .ptask-advanced-toggle:hover,
body.dark-mode .ptask-advanced-toggle.is-open { background: rgba(255,255,255,0.06); }
body.dark-mode .ptask-advanced-panel { background: rgba(255,255,255,0.03); }
/* Cards + the untracked toggle row read against the dark panel — lift them a
   touch lighter than the panel fill. */
body.dark-mode .ptask-adv-block,
body.dark-mode .ptask-untracked-row { background: rgba(255,255,255,0.05); }
body.dark-mode .ptask-adv-block:has(.ptask-adv-block-head.is-open) { border-color: rgba(165,180,252,0.4); }
body.dark-mode .ptask-adv-block-head:hover { background: rgba(255,255,255,0.06); }
body.dark-mode .ptask-untracked-row:hover { background: rgba(255,255,255,0.07); }
body.dark-mode .ptask-untracked-row:has(.ptask-untracked-check:checked) {
    border-color: rgba(165,180,252,0.5);
    background: rgba(99,102,241,0.14);
}
body.dark-mode .ptask-adv-block-count { color: #a5b4fc; }

/* Split-time-across-jobs rows (inline in the Advanced panel). The primary row
   is reference-only; extra rows carry a job typeahead + a CC <select>. Built
   by planner.js. Rows sit inside the white card body, so they're tinted with
   --bg-muted to read as distinct sub-rows; the primary row is dashed to mark it
   read-only. */
.split-job-row {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.65rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm, 8px);
    background: var(--bg-muted, #f8fafc);
}
.split-job-row--primary {
    border-style: dashed;
}
.split-job-row-badge {
    flex: 0 0 auto;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
    background: rgba(0,0,0,0.05);
    border-radius: 6px;
    padding: 0.25rem 0.45rem;
    margin-top: 0.15rem;
}
.split-job-row-badge--extra { color: #4338ca; background: #eef2ff; }
.split-job-row-main { flex: 1; min-width: 0; }
.split-job-row-job { font-family: monospace; font-weight: 600; font-size: 0.9rem; }
.split-job-row-cc { font-size: 0.8rem; color: var(--text-muted); margin-top: 0.2rem; }
.split-job-row-actions { flex: 0 0 auto; }
.split-job-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    background: transparent;
    border: none;
    border-radius: 6px;
    font-size: 1.3rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0;
    transition: background 0.12s ease, color 0.12s ease;
}
.split-job-remove:hover { color: #dc2626; background: rgba(220,38,38,0.1); }
body.dark-mode .split-job-row { background: rgba(255,255,255,0.04); }
body.dark-mode .split-job-row-badge { background: rgba(255,255,255,0.08); }
body.dark-mode .split-job-row-badge--extra { color: #a5b4fc; background: rgba(99,102,241,0.18); }

/* Your Tasks "Done" tickbox — replaces the old 3-state untracked status
   dropdown (planner.js _untrackedDoneCheckboxHtml). Sits in the status <td> for
   untracked rows only. A compact labelled checkbox styled as a small pill so it
   reads as an intentional control, not a stray form input; the .is-done variant
   greens it to match the completed badge it stands in for. */
.planner-untracked-done {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: rgba(0,0,0,0.03);
    cursor: pointer;
    user-select: none;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.planner-untracked-done:hover { border-color: var(--text-muted); }
.planner-untracked-done-check {
    width: 0.95rem;
    height: 0.95rem;
    margin: 0;
    flex: 0 0 auto;
    cursor: pointer;
    accent-color: var(--success, #16a34a);
}
.planner-untracked-done-label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
    line-height: 1;
}
/* Completed: green pill mirroring the read-only "Completed" status badge. */
.planner-untracked-done.is-done {
    background: #dcfce7;
    border-color: #86efac;
}
.planner-untracked-done.is-done .planner-untracked-done-label { color: #16a34a; }
body.dark-mode .planner-untracked-done { background: rgba(255,255,255,0.05); }
body.dark-mode .planner-untracked-done.is-done {
    background: rgba(34,197,94,0.18);
    border-color: rgba(34,197,94,0.45);
}
body.dark-mode .planner-untracked-done.is-done .planner-untracked-done-label { color: #4ade80; }

/* Two-column body grid: left fields (~1.4fr) + 1px divider + right Notes (~1fr).
   `align-items: stretch` lets the right column stretch so the Notes textarea
   can `flex:1` to the body's full height. */
.ptask-body {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) 1px minmax(0, 1fr);
    gap: 1.6rem;
    align-items: stretch;
}
.ptask-col-left { min-width: 0; }
.ptask-col-right {
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.ptask-divider {
    background: var(--border);
    align-self: stretch;
    width: 1px;
}

/* Section blocks. Sections in the left column are separated by a 1px
   horizontal line; the first section has no top border. The Notes section
   in the right column is full-height (no top border, flex-fills the column).
   The right column's first VISIBLE section also drops its top border — when
   the SOP picker is rendered above Notes, the Notes section becomes a
   non-first section and would otherwise gain an unwanted top rule. We
   target the SOP-section explicitly (it's always first when present) and
   leave .ptask-section-notes alone (it has its own override below). */
.ptask-section {
    padding-top: 0.5rem;
    margin-top: 0.5rem;
    border-top: 1px solid var(--border);
}
.ptask-section:first-child {
    border-top: none;
    margin-top: 0;
    padding-top: 0;
}
.ptask-col-right .ptask-section:first-child {
    border-top: none;
    margin-top: 0;
    padding-top: 0;
}
.ptask-section-label {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin-bottom: 0.6rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.ptask-section-label::before {
    content: '';
    width: 3px;
    height: 14px;
    background: var(--primary);
    border-radius: 2px;
    flex: 0 0 auto;
}
.ptask-section-notes {
    padding-top: 0;
    margin-top: 0;
    border-top: none;
    flex: 1;
    display: flex;
    flex-direction: column;
}
/* Right-column notes wrapper grows to fill available height so the
   rich-text editor can fill it via flex:1. */
.ptask-fg-fill {
    flex: 1;
    display: flex;
    flex-direction: column;
    margin-bottom: 0;
}
/* The shared WYSIWYG editor (window._buildNotesEditor) is mounted into
   #ptask-notes-rich-wrap at modal-open time. The helper produces a single
   bordered outer <div> that contains a toolbar <div> and a contenteditable
   <div>. The editor's own inline styles handle border/background/padding,
   so all we need to do here is make the wrapper + outer div + contenteditable
   all stretch to fill the right column's available height (the same flex:1
   the textarea used to get from .ptask-notes-textarea). */
.ptask-col-right .ptask-section-notes .ptask-notes-rich-wrap {
    flex: 1;
    min-height: 220px;
    display: flex;
}
.ptask-col-right .ptask-section-notes .ptask-notes-rich-wrap > div {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.ptask-col-right .ptask-section-notes .ptask-notes-rich-wrap > div > div[contenteditable] {
    flex: 1;
    min-height: 200px;
}

/* Generic n-column rows used inside the left column sections. */
.ptask-row {
    display: grid;
    gap: 1rem;
}
.ptask-row.ptask-cols-2 { grid-template-columns: 1fr 1fr; }
.ptask-row.ptask-cols-3 { grid-template-columns: 1fr 1fr 1fr; }

/* Priority sits on its own row in the General section. We let it span ~50%
   of the column so the field doesn't stretch awkwardly wide on a 1500px
   modal. The hidden #ptask-status form-group is its sibling but stays
   display:none so it doesn't take a column. */
.ptask-row-priority {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1rem;
}

/* Department + Assignee row — JS toggles style.display between 'grid'
   and 'none'. CSS supplies the 2-col template + gap so the JS toggle
   doesn't have to. */
#ptask-dept-assignee-row.ptask-row-dept-assignee {
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    margin-top: 0.75rem;
}

/* ===== Meeting detail modal — action items + decisions =====
   Reuses ptask-card / ptask-body / ptask-section / ptask-divider so the
   meeting modal sizes and structures identically to the task editor.
   These rules are scoped under #meeting-detail-popup so they don't leak
   to other places. */
#meeting-detail-popup .mtg-ai-list,
#meeting-detail-popup .mtg-dec-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
#meeting-detail-popup .mtg-ai-empty,
#meeting-detail-popup .mtg-dec-empty {
    color: var(--text-muted);
    font-size: 0.85rem;
    font-style: italic;
    padding: 0.4rem 0;
}
#meeting-detail-popup .mtg-ai-item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    background: var(--bg-body);
    border: 1px solid var(--border);
    border-radius: 8px;
}
#meeting-detail-popup .mtg-ai-item.done .mtg-ai-text {
    text-decoration: line-through;
    color: var(--text-muted);
}
#meeting-detail-popup .mtg-ai-check { width: 18px; height: 18px; cursor: pointer; flex-shrink: 0; }
#meeting-detail-popup .mtg-ai-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
#meeting-detail-popup .mtg-ai-text { font-size: 0.88rem; color: var(--text-main); line-height: 1.35; }
#meeting-detail-popup .mtg-ai-meta {
    display: flex; flex-wrap: wrap; gap: 6px;
    font-size: 0.72rem; color: var(--text-muted);
}
#meeting-detail-popup .mtg-ai-meta .mtg-ai-assignee,
#meeting-detail-popup .mtg-ai-meta .mtg-ai-due {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 1px 7px;
    background: rgba(29,78,216,0.10);
    color: #1d4ed8;
    border-radius: 8px;
    font-weight: 600;
}
#meeting-detail-popup .mtg-ai-meta .mtg-ai-due { background: rgba(245,158,11,0.10); color: #b45309; }
#meeting-detail-popup .mtg-ai-delete,
#meeting-detail-popup .mtg-dec-delete {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 4px;
    flex-shrink: 0;
}
#meeting-detail-popup .mtg-ai-delete:hover,
#meeting-detail-popup .mtg-dec-delete:hover { background: rgba(220,38,38,0.10); color: #dc2626; }
#meeting-detail-popup .mtg-ai-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}
#meeting-detail-popup .mtg-ai-promote {
    background: rgba(29,78,216,0.10);
    color: #1d4ed8;
    border: 1px solid rgba(29,78,216,0.30);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 0.72rem;
    font-weight: 700;
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
}
#meeting-detail-popup .mtg-ai-promote:hover {
    background: rgba(29,78,216,0.18);
}
/* → Backlog — sister button to → Make task. Same shape so the row reads
   as "two related actions"; violet hue so the user can tell the holding-
   pattern path apart from the immediate-assign path at a glance, without
   colliding with the green "✓ Task made" success state. */
#meeting-detail-popup .mtg-ai-promote-backlog {
    background: rgba(124,58,237,0.10);
    color: #6d28d9;
    border: 1px solid rgba(124,58,237,0.30);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 0.72rem;
    font-weight: 700;
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
}
#meeting-detail-popup .mtg-ai-promote-backlog:hover {
    background: rgba(124,58,237,0.18);
}
/* ✓ Task made — replaces the promote button once an action item has
   been turned into a real planner task. Green-tinted to signal the
   "task exists" state; click opens the linked task. */
#meeting-detail-popup .mtg-ai-task-made {
    background: rgba(16,185,129,0.10);
    color: #047857;
    border: 1px solid rgba(16,185,129,0.35);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 0.72rem;
    font-weight: 700;
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
}
#meeting-detail-popup .mtg-ai-task-made:hover {
    background: rgba(16,185,129,0.18);
}
#meeting-detail-popup .mtg-dec-item {
    display: flex; align-items: flex-start; gap: 8px;
    padding: 8px 10px;
    background: var(--bg-body);
    border: 1px solid var(--border);
    border-radius: 8px;
}
#meeting-detail-popup .mtg-dec-item::before {
    content: "✓";
    color: #10b981;
    font-weight: 800;
    flex-shrink: 0;
    margin-top: 1px;
}
#meeting-detail-popup .mtg-dec-text {
    flex: 1;
    font-size: 0.88rem;
    color: var(--text-main);
    line-height: 1.4;
    white-space: pre-wrap;
}
#meeting-detail-popup .mtg-add-row {
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    gap: 6px;
    margin-top: 8px;
    align-items: center;
}
#meeting-detail-popup .mtg-add-row.mtg-add-row-decision {
    grid-template-columns: 1fr auto;
}
#meeting-detail-popup .mtg-add-row input,
#meeting-detail-popup .mtg-add-row select {
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.84rem;
    background: var(--surface);
    color: var(--text-main);
}
#meeting-detail-popup .mtg-add-btn {
    padding: 0.45rem 0.85rem;
    border-radius: 6px;
    border: none;
    background: #1d4ed8;
    color: #fff;
    font-weight: 700;
    font-size: 0.82rem;
    cursor: pointer;
}
#meeting-detail-popup .mtg-add-btn:hover { background: #1e40af; }
#meeting-detail-popup .mtg-add-btn:disabled { opacity: 0.5; cursor: not-allowed; }
#meeting-detail-popup .mtg-section-head {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    margin-bottom: 0.6rem;
}
#meeting-detail-popup .mtg-section-head .ptask-section-label { margin-bottom: 0; }
#meeting-detail-popup .mtg-info-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.5rem 1rem;
    font-size: 0.85rem;
}
#meeting-detail-popup .mtg-attendee-chips {
    display: flex; flex-wrap: wrap; gap: 0.35rem;
}
#meeting-detail-popup .mtg-attendee-chip {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.2rem 0.6rem;
    background: rgba(0,0,0,0.05);
    border-radius: 12px;
    font-size: 0.8rem;
    font-weight: 500;
}
#meeting-detail-popup .mtg-attendee-chip.organiser {
    background: rgba(29,78,216,0.15);
    color: #1e40af;
    font-weight: 700;
}

/* Footer — identical to the v1 layout (Delete left, Cancel + Save right). */
.ptask-footer {
    display: flex;
    gap: 0.75rem;
    justify-content: space-between;
    align-items: center;
    margin-top: 0.6rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
}
.ptask-footer-right {
    display: flex;
    gap: 0.75rem;
    margin-left: auto;
}

/* SOP Template picker — sits above Notes in the right column.
   The card appears once a template is selected; the small helper line below
   the dropdown clarifies the Notes-hide behaviour. We deliberately use the
   shared CSS variables (--border / --bg-muted / --primary / --text-muted)
   so the card automatically tracks light/dark theme. */
.ptask-sop-card {
    border: 1px solid var(--border);
    background: var(--bg-muted);
    border-radius: 6px;
    padding: 0.7rem 0.85rem;
    margin-bottom: 0.5rem;
}
.ptask-sop-name {
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--text-main);
    margin-bottom: 0.25rem;
    word-break: break-word;
}
.ptask-sop-summary {
    font-size: 0.78rem;
    color: var(--text-muted);
    line-height: 1.4;
}
.ptask-sop-help {
    font-size: 0.72rem;
    color: var(--text-muted);
    line-height: 1.45;
    margin-top: 0.15rem;
}

/* ── Mobile: collapse the 2-column body into one column. ───────────────
   The vertical divider becomes a horizontal rule (it's a 1px tall block
   when its parent grid no longer constrains its width). The Notes
   textarea stops fighting for column height — it gets a sensible
   single-column min-height instead. */
@media (max-width: 900px) {
    .ptask-card {
        width: 100%;
        padding: 1.25rem 1.1rem 1rem;
    }
    .ptask-body {
        grid-template-columns: 1fr;
        gap: 1rem;
    }
    .ptask-divider {
        width: 100%;
        height: 1px;
    }
    .ptask-row.ptask-cols-3 {
        grid-template-columns: 1fr;
    }
    .ptask-row.ptask-cols-2 {
        grid-template-columns: 1fr;
    }
    .ptask-row-priority {
        grid-template-columns: 1fr;
    }
    #ptask-dept-assignee-row.ptask-row-dept-assignee {
        grid-template-columns: 1fr;
    }
    /* On mobile the right Notes column shouldn't stretch to fill body
       height (there's no body height to fill once columns stack); reset
       the flex so the rich editor sits at its own min-height. */
    .ptask-section-notes {
        flex: 0 0 auto;
    }
    .ptask-col-right .ptask-section-notes .ptask-notes-rich-wrap {
        min-height: 220px;
    }
    .ptask-fg-fill {
        flex: 0 0 auto;
    }
}

/* Phase 2 dynamic-task-scheduling: swap modal classes. Inline-styled markup
   carries most of the layout; classes here exist for the bits that benefit
   from real selectors (target rows, Cannot-do button on the planner). */

.swap-target-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 0.75rem;
    cursor: pointer;
    border-bottom: 1px solid var(--border);
    transition: background 0.1s;
}
.swap-target-row:last-child { border-bottom: none; }
.swap-target-row:hover { background: #f0f7ff; }
.swap-target-row.selected {
    background: #2c3e50;
    color: #fff;
}
.swap-target-row.disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}
.swap-target-row.disabled:hover { background: transparent; }
.swap-target-time {
    font-family: monospace;
    font-size: 0.82rem;
    font-weight: 600;
    min-width: 60px;
}
.swap-target-title {
    flex: 1;
    font-size: 0.88rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.swap-target-anchor-tag {
    font-size: 0.7rem;
    padding: 1px 5px;
    background: rgba(247, 169, 0, 0.18);
    border: 1px solid rgba(247, 169, 0, 0.6);
    border-radius: 3px;
    color: #b97f00;
}
.swap-target-day-header {
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    padding: 0.45rem 0.75rem;
    background: var(--surface-hover);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
}

.swap-chip {
    background: #ecf0f1;
    border: 1px solid #bdc3c7;
    border-radius: 16px;
    padding: 0.4rem 0.85rem;
    font-size: 0.82rem;
    font-family: inherit;
    cursor: pointer;
    color: var(--text-main);
}
.swap-chip:hover { background: #dfe6e9; }
.swap-chip.selected {
    background: #2c3e50;
    color: #fff;
    border-color: #2c3e50;
}

/* Phase 2 "Cannot do this" button on flex/anchored task blocks. Compact
   icon-only on small blocks; expanded with label on roomy blocks. Fires
   data-action="cannot-do" through the existing planner click delegation
   (see Task C1 for the wiring). */
.pdr-cannot-do-btn {
    position: absolute;
    top: 4px;
    right: 4px;
    background: rgba(220, 38, 38, 0.85);
    color: #fff;
    border: none;
    border-radius: 4px;
    padding: 1px 6px;
    font-size: 0.7rem;
    line-height: 1.2;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 5;
}
.pdr-tl-block:hover .pdr-cannot-do-btn,
.pdr-tl-block.now .pdr-cannot-do-btn {
    opacity: 1;
}
.pdr-cannot-do-btn:hover { background: rgba(185, 28, 28, 0.95); }

.pdr-tl-block.pdr-cannot-do-flagged {
    opacity: 0.55;
    background-image: repeating-linear-gradient(
        135deg,
        transparent 0,
        transparent 6px,
        rgba(220, 38, 38, 0.12) 6px,
        rgba(220, 38, 38, 0.12) 8px
    );
}
.pdr-tl-block.pdr-cannot-do-flagged::after {
    content: "FLAGGED";
    position: absolute;
    bottom: 4px;
    left: 4px;
    font-size: 0.65rem;
    font-weight: 800;
    color: #b91c1c;
    background: #fee2e2;
    padding: 1px 5px;
    border-radius: 3px;
}

/* ─── Phase 3 Hub Alerts ──────────────────────────────────────────────────── */
.sched-hub3-alerts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 0.75rem;
    align-items: start;
}
.sched-hub3-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.85rem 0.95rem;
    border-left: 4px solid var(--text-muted);
}
.sched-hub3-card.is-warn { border-left-color: #d97706; }
.sched-hub3-card.is-danger { border-left-color: #dc2626; }
.sched-hub3-card.is-info { border-left-color: #1e5bc6; }
.sched-hub3-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    user-select: none;
    gap: 0.5rem;
}
.sched-hub3-card-head h4 {
    margin: 0;
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--text-main);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.sched-hub3-card-count {
    font-size: 0.78rem;
    font-weight: 700;
    background: var(--bg-body);
    color: var(--text-main);
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    border: 1px solid var(--border);
}
.sched-hub3-card-count.is-danger { background: #fef2f2; color: #dc2626; border-color: #fecaca; }
.sched-hub3-card-count.is-warn   { background: #fff7ed; color: #d97706; border-color: #fdba74; }
.sched-hub3-card-count.is-info   { background: #eff6ff; color: #1e5bc6; border-color: #bfdbfe; }
.sched-hub3-card-body {
    margin-top: 0.6rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border);
}
.sched-hub3-card-body[hidden] { display: none; }
.sched-hub3-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0;
    border-bottom: 1px solid #f3f4f6;
    font-size: 0.78rem;
}
.sched-hub3-row:last-child { border-bottom: none; }
.sched-hub3-row-title {
    flex: 1;
    min-width: 0;
    font-weight: 600;
    color: var(--text-main);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sched-hub3-row-meta {
    flex-shrink: 0;
    font-size: 0.7rem;
    color: var(--text-muted);
}
.sched-hub3-row-actions {
    display: flex;
    gap: 0.3rem;
    flex-shrink: 0;
}
.sched-hub3-row-actions button {
    font-size: 0.68rem;
    padding: 0.2rem 0.45rem;
    border-radius: 4px;
    border: 1px solid var(--border);
    background: var(--surface);
    cursor: pointer;
}
.sched-hub3-row-actions button:hover { background: var(--bg-body); }

/* Break-overstay review row — click-to-expand <details>. Collapsed shows the
   worker + reason snippet; open reveals the full reason and the green
   Acknowledge / red Report dispositions. */
.sched-hub3-overstay {
    border-bottom: 1px solid var(--border);
}
.sched-hub3-overstay:last-child { border-bottom: none; }
.sched-hub3-overstay-sum {
    display: flex;
    align-items: flex-start;
    gap: 0.45rem;
    padding: 0.5rem 0.25rem;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.sched-hub3-overstay-sum::-webkit-details-marker { display: none; }
.sched-hub3-overstay-sum:hover { background: var(--bg-body); }
.sched-hub3-overstay-chev {
    flex-shrink: 0;
    color: var(--text-muted);
    font-size: 0.72rem;
    line-height: 1.4;
    transition: transform 0.15s;
}
.sched-hub3-overstay[open] .sched-hub3-overstay-chev { transform: rotate(90deg); }
.sched-hub3-overstay-main { min-width: 0; flex: 1; }
.sched-hub3-overstay-title {
    font-size: 0.78rem;
    font-weight: 600;
    margin-right: 0.35rem;
}
.sched-hub3-overstay-meta {
    display: block;
    font-size: 0.7rem;
    color: var(--text-muted);
    margin-top: 0.1rem;
}
.sched-hub3-overstay-rsnip {
    display: block;
    font-size: 0.72rem;
    color: var(--text-muted);
    font-style: italic;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-top: 0.1rem;
}
.sched-hub3-overstay-body {
    padding: 0.1rem 0.25rem 0.65rem 1.15rem;
}
.sched-hub3-overstay-reason {
    font-size: 0.78rem;
    color: var(--text);
    background: var(--bg-body);
    border-radius: 5px;
    padding: 0.45rem 0.6rem;
    margin-bottom: 0.55rem;
    white-space: pre-wrap;
    word-break: break-word;
}
.sched-hub3-overstay-actions {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}
.sched-hub3-btn-ack,
.sched-hub3-btn-report {
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.32rem 0.7rem;
    border-radius: 4px;
    border: 1px solid transparent;
    color: #fff;
    cursor: pointer;
}
.sched-hub3-btn-ack { background: #059669; }
.sched-hub3-btn-ack:hover { background: #047857; }
.sched-hub3-btn-report { background: #dc2626; }
.sched-hub3-btn-report:hover { background: #b91c1c; }
.sched-hub3-overstay-hint {
    font-size: 0.68rem;
    color: var(--text-muted);
    line-height: 1.5;
}
.sched-hub3-empty {
    font-style: italic;
    font-size: 0.75rem;
    color: var(--text-muted);
    padding: 0.5rem 0;
}
.sched-hub3-chevron {
    transition: transform 0.15s;
    color: var(--text-muted);
    font-size: 0.7rem;
}
.sched-hub3-card.is-open .sched-hub3-chevron { transform: rotate(90deg); }

.sched-hub3-modal {
    position: fixed;
    inset: 0;
    z-index: 5000;
    display: flex;
    align-items: center;
    justify-content: center;
}
.sched-hub3-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
}
.sched-hub3-modal-card {
    position: relative;
    background: var(--surface);
    border-radius: 10px;
    width: min(440px, calc(100vw - 2rem));
    max-height: calc(100vh - 2rem);
    overflow: auto;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
    display: flex;
    flex-direction: column;
}
.sched-hub3-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.85rem 1rem;
    border-bottom: 1px solid var(--border);
}
.sched-hub3-modal-close {
    background: none;
    border: none;
    font-size: 1.4rem;
    color: var(--text-muted);
    cursor: pointer;
    line-height: 1;
}
.sched-hub3-modal-body {
    padding: 1rem;
    flex: 1;
    overflow: auto;
}
.sched-hub3-modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--border);
    background: var(--bg-body);
}

.sched-hub3-pace {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.65rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    border: 1px solid transparent;
}
.sched-hub3-pace.is-on    { background: #ecfdf5; color: #059669; border-color: #a7f3d0; }
.sched-hub3-pace.is-early { background: #eff6ff; color: #1e5bc6; border-color: #bfdbfe; }
.sched-hub3-pace.is-late  { background: #fff7ed; color: #d97706; border-color: #fdba74; }
.sched-hub3-pace-detail {
    font-size: 0.7rem;
    color: var(--text-muted);
    font-weight: 500;
}

.sched-hub3-row-dept {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    border-radius: 4px;
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--bg-body);
    color: var(--text-muted);
    border: 1px solid var(--border);
    white-space: nowrap;
    margin-left: 0.4rem;
    vertical-align: middle;
}

/* ============================================================================
   Scheduling · Departments redesign (grid + detail page).
   Token-driven, dark-mode-clean replacements for the old inline-styled blobs.
   Colour comes from the --stat-* / --track / surface / text / border tokens at
   the top of this file. Per-department brand accent comes from an inline
   `--sd-accent` custom property the JS sets from DEPT_META.color, so the accent
   stays per-dept while everything else themes with the app.
   `sd-` = scheduling-departments (namespaced to dodge the dashboard .dept-card).
   ========================================================================== */

/* ── Shared atoms (consume the status tokens) ───────────────────────────── */
.sd-meter { background: var(--track); border-radius: 999px; height: 6px; overflow: hidden; }
.sd-meter__fill { height: 100%; border-radius: 999px; background: var(--sd-meter, var(--stat-info)); transition: width 0.3s ease; }

.sd-badge {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.15rem 0.5rem; border-radius: 999px;
    font-size: 0.68rem; font-weight: 700; white-space: nowrap;
    background: var(--stat-neutral-bg); color: var(--stat-neutral);
    border: 1px solid var(--stat-neutral-border);
}
.sd-badge.is-good { background: var(--stat-good-bg); color: var(--stat-good); border-color: var(--stat-good-border); }
.sd-badge.is-warn { background: var(--stat-warn-bg); color: var(--stat-warn); border-color: var(--stat-warn-border); }
.sd-badge.is-bad  { background: var(--stat-bad-bg);  color: var(--stat-bad);  border-color: var(--stat-bad-border); }
.sd-badge.is-info { background: var(--stat-info-bg); color: var(--stat-info); border-color: var(--stat-info-border); }

.sd-info {
    flex-shrink: 0; width: 15px; height: 15px; border-radius: 50%;
    background: var(--stat-neutral-bg); color: var(--stat-neutral);
    font-size: 0.6rem; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: help; vertical-align: middle; margin-left: 0.25rem;
}

.sd-stat { text-align: center; background: var(--bg-muted); border-radius: 6px; padding: 0.3rem 0.2rem; }
.sd-stat__val { font-size: 0.95rem; font-weight: 700; line-height: 1.15; color: var(--sd-stat-color, var(--text-main)); }
.sd-stat__lbl { font-size: 0.62rem; color: var(--text-muted); }

/* ── Metric chip (KPI strip in the detail header) ───────────────────────── */
.sd-metric-strip { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.sd-metric {
    flex: 1 1 auto; min-width: 96px;
    background: var(--surface); border: 1px solid var(--border);
    border-top: 3px solid var(--sd-metric-color, var(--stat-neutral));
    border-radius: 8px; padding: 0.55rem 0.7rem;
}
.sd-metric__val { font-size: 1.25rem; font-weight: 800; line-height: 1.05; color: var(--sd-metric-color, var(--text-main)); display: flex; align-items: flex-start; justify-content: space-between; gap: 0.25rem; }
.sd-metric__lbl { font-size: 0.7rem; font-weight: 600; color: var(--text-main); margin-top: 0.1rem; }
.sd-metric__sub { font-size: 0.62rem; color: var(--text-muted); }
/* Row-2 "needs action" tiles — clickable .sd-metric buttons that expand a list below. */
/* Row-2 "needs action" tiles are native <details> that grow open in place —
   the card keeps its width and just grows downward; siblings stay compact at
   the top (align-items:flex-start on the strip). */
.sd-signal { min-width: 190px; }
.sd-signal-sum { display: block; cursor: pointer; list-style: none; }
.sd-signal-sum::-webkit-details-marker { display: none; }
.sd-signal-chev { font-size: 0.7rem; color: var(--text-muted); transition: transform 0.15s ease; }
.sd-signal[open] .sd-signal-chev { transform: rotate(90deg); }
.sd-signal-body { margin-top: 0.6rem; border-top: 1px solid var(--border); padding-top: 0.45rem; }
/* Break-overstay row — Acknowledge / Report always visible on the right. */
.sd-overstay-row { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.5rem 0; border-bottom: 1px solid var(--border); }
.sd-overstay-row:last-child { border-bottom: none; }
.sd-overstay-main { flex: 1; min-width: 0; }
.sd-overstay-title { font-weight: 600; font-size: 0.8rem; color: var(--text-main); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sd-overstay-meta { font-size: 0.7rem; color: var(--text-muted); margin-top: 0.1rem; }
.sd-overstay-reason { font-size: 0.74rem; color: var(--stat-warn); margin-top: 0.2rem; }
.sd-overstay-actions { display: flex; gap: 0.4rem; flex-shrink: 0; }

/* ── Departments grid (the Departments tab) ─────────────────────────────── */
.sd-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1rem; }
.sd-card {
    background: var(--surface); border: 1px solid var(--border);
    border-top: 3px solid var(--sd-accent, var(--primary));
    border-radius: var(--radius-sm); padding: 1.1rem; cursor: pointer;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.sd-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.sd-card__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.6rem; }
.sd-card__name { font-size: 1rem; font-weight: 700; color: var(--text-main); display: flex; align-items: center; gap: 0.4rem; }
.sd-card__stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.35rem; margin-bottom: 0.5rem; }
.sd-card__meta-row { display: flex; justify-content: space-between; font-size: 0.7rem; color: var(--text-muted); margin-bottom: 0.25rem; }
.sd-card__foot { margin-top: 0.65rem; padding-top: 0.65rem; border-top: 1px solid var(--border); font-size: 0.72rem; font-weight: 600; text-align: center; color: var(--sd-accent, var(--primary)); }

/* ── Detail page: summary-first 2-column layout ─────────────────────────── */
.sd-head { display: flex; align-items: center; gap: 0.85rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.sd-head__bar { width: 4px; align-self: stretch; min-height: 38px; border-radius: 999px; background: var(--sd-accent, var(--primary)); }
.sd-head__title { display: flex; align-items: center; gap: 0.5rem; }
.sd-cols { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 1rem; align-items: start; margin-bottom: 1rem; }
@media (max-width: 1024px) { .sd-cols { grid-template-columns: 1fr; } }
.sd-section-title { margin: 0 0 0.65rem; font-size: 0.9rem; font-weight: 700; color: var(--text-main); }

/* ── Team roster (dense rows, left column) ──────────────────────────────── */
.sd-team { display: flex; flex-direction: column; gap: 0.5rem; }
.sd-row { background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--sd-accent, var(--primary)); border-radius: 8px; padding: 0.6rem 0.75rem; }
.sd-row__top { display: flex; align-items: center; gap: 0.6rem; }
.sd-row__avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--sd-accent, var(--primary)); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 0.78rem; font-weight: 700; flex-shrink: 0; }
.sd-row__main { min-width: 0; flex: 1; }
.sd-row__name { font-weight: 700; font-size: 0.85rem; color: var(--text-main); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sd-row__name a { color: inherit; text-decoration: none; border-bottom: 1px dashed transparent; }
.sd-row__name a:hover { border-bottom-color: currentColor; }
.sd-row__sub { font-size: 0.7rem; color: var(--text-muted); }
.sd-row__cap { width: 104px; flex-shrink: 0; }
.sd-row__cap-top { display: flex; justify-content: space-between; font-size: 0.64rem; color: var(--text-muted); margin-bottom: 0.15rem; }
.sd-row__count { text-align: center; flex-shrink: 0; min-width: 32px; }
.sd-row__count-n { font-size: 1rem; font-weight: 700; color: var(--text-main); line-height: 1; }
.sd-row__count-l { font-size: 0.56rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.sd-row__tasks { margin-top: 0.5rem; }
.sd-row__tasks > summary { font-size: 0.72rem; font-weight: 600; cursor: pointer; color: var(--sd-accent, var(--stat-info)); list-style: none; }
.sd-row__tasks > summary::-webkit-details-marker { display: none; }
/* Rotating disclosure chevron — ▸ when closed, points down when open. */
.sd-row__tasks > summary::before { content: '▸'; display: inline-block; margin-right: 0.4rem; font-size: 0.7rem; transition: transform 0.15s ease; }
.sd-row__tasks[open] > summary::before { transform: rotate(90deg); }

/* ── Charts column (right) ──────────────────────────────────────────────── */
.sd-charts { display: flex; flex-direction: column; gap: 0.85rem; }
.sd-chart-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.85rem; }
.sd-chart-card h4 { margin: 0 0 0.5rem; font-size: 0.8rem; font-weight: 700; display: flex; align-items: center; color: var(--text-main); }
.sd-chart-wrap { position: relative; height: 168px; }

/* Analytics 2×2 grid (department detail). Charts sit half-width so they get a
   touch more height than the 168px snapshot wrap. Collapses to 1-col on phones. */
.sd-analytics { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.85rem; margin-bottom: 1.25rem; }
.sd-analytics .sd-chart-wrap { height: 210px; }
@media (max-width: 900px) { .sd-analytics { grid-template-columns: 1fr; } }

/* ── Dept tables (self-contained so .data-table consumers are untouched) ── */
.sd-tasks-card { padding: 0; }
.sd-tasks-card__head { display: flex; justify-content: space-between; align-items: center; padding: 0.85rem 1.1rem; border-bottom: 1px solid var(--border); }
.sd-tasks-card__head h4 { margin: 0; font-size: 0.9rem; font-weight: 700; color: var(--text-main); }
.sd-table { width: 100%; border-collapse: collapse; }
.sd-table thead th { text-align: left; font-size: 0.72rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; padding: 0.55rem 0.75rem; background: var(--bg-muted); border-bottom: 1px solid var(--border); white-space: nowrap; }
.sd-table tbody td { padding: 0.5rem 0.75rem; font-size: 0.8rem; border-bottom: 1px solid var(--border); color: var(--text-main); vertical-align: middle; }
.sd-table tbody tr:last-child td { border-bottom: none; }
.sd-table tbody tr:hover td { background: var(--surface-hover); }
.sd-table .sd-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.72rem; color: var(--text-muted); }

/* SOP rich-text editor + worker-side runner — restore list padding the
 * global `* { padding:0; margin:0 }` reset stripped, so bullets and
 * numbers render inside the box, not under the left border. */
.tpl-step-instructions-rich ul,
.sop-run-step-rich ul {
    list-style: disc outside;
    padding-left: 1.5rem;
    margin: 0.35rem 0;
}
.tpl-step-instructions-rich ol,
.sop-run-step-rich ol {
    list-style: decimal outside;
    padding-left: 1.75rem;
    margin: 0.35rem 0;
}
.tpl-step-instructions-rich li,
.sop-run-step-rich li {
    margin: 0.15rem 0;
}
.tpl-step-instructions-rich p,
.sop-run-step-rich p {
    margin: 0.35rem 0;
}

/* ─── Schedule overrides — modal ─── */
/* Type-radio chip pattern. The four radio buttons in the override modal are
   visually rendered as full-width labels (display:none on the actual <input>).
   Wave 2 JS toggles the .is-selected class on label click. The outline /
   focus state below ensures keyboard users still see the focused option even
   with the input hidden — the focus-within wraps the visible label. */
.override-type-radio {
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.override-type-radio:hover {
    border-color: var(--text-muted);
}
.override-type-radio.is-selected {
    background: rgba(52, 152, 219, 0.12);
    border-color: #3498db;
    color: var(--text-main);
    font-weight: 600;
}
.override-type-radio:focus-within {
    outline: 2px solid #3498db;
    outline-offset: 2px;
}

/* ─── Schedule overrides — timesheet bands ─── */
/* Painted UNDER the labour-session blocks in the weekly timesheet for any
   day that has an active override. Colours mirror the four override types
   surfaced in the manager UI: orange for overtime, blue for shift_change,
   yellow for partial_day, grey diagonal stripes for non_working. The
   .so-band-overtime-delta inset shadow highlights the *added* portion of an
   overtime override (i.e. the chunk beyond baseline end) so the eye can
   distinguish "shift was always 8h, manager extended by 2h" from "shift was
   8h, manager moved it earlier by 1h". pointer-events:none keeps the band
   click-through so the labour-session blocks above stay interactive. */
.so-band-overtime     { background: rgba(243, 156, 18, 0.18); border-left: 3px solid #f39c12; }
.so-band-shift_change { background: rgba(52, 152, 219, 0.18); border-left: 3px solid #3498db; }
.so-band-partial_day  { background: rgba(241, 196, 15, 0.18); border-left: 3px solid #f1c40f; }
.so-band-non_working  { background: repeating-linear-gradient(45deg, transparent, transparent 6px, rgba(127, 140, 141, 0.18) 6px, rgba(127, 140, 141, 0.18) 12px); border-left: 3px solid #7f8c8d; }
/* Public-holiday stripes — same diagonal pattern as non_working but in a
   teal tint so the eye distinguishes a workshop-wide closure ("everyone is
   off") from a per-employee day-off-in-lieu ("Kori only is off"). */
.so-band-holiday      { background: repeating-linear-gradient(45deg, transparent, transparent 6px, rgba(20, 184, 166, 0.20) 6px, rgba(20, 184, 166, 0.20) 12px); border-left: 3px solid #14b8a6; }
.so-band-overtime-delta { box-shadow: inset 0 0 0 2px #f39c12; }
.so-band-overtime,
.so-band-shift_change,
.so-band-partial_day,
.so-band-non_working,
.so-band-holiday {
    border-radius: 3px;
    pointer-events: none;
    z-index: 0;
}
/* Header chip for a public-holiday day in the per-person weekly view. Sits
   in the day-head row alongside the date + count pill so the eye finds the
   closure without scanning the column body. */
.pdr-wv-holiday-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    background: rgba(20, 184, 166, 0.14);
    color: #0f766e;
    border: 1px solid rgba(20, 184, 166, 0.35);
    border-radius: 999px;
    padding: 1px 6px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}
/* Day-rail full-card holiday banner — replaces the "Nothing scheduled
   today" copy when today is a workshop-wide public holiday so the worker
   sees the closure as a deliberate state, not an empty schedule. */
.pdr-holiday-banner {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1.1rem 1.2rem;
    margin: 0.4rem 0;
    border-radius: 12px;
    background: linear-gradient(135deg, rgba(20, 184, 166, 0.12), rgba(20, 184, 166, 0.05));
    border: 1px solid rgba(20, 184, 166, 0.35);
    color: var(--text-main);
}
.pdr-holiday-banner-title {
    font-size: 0.95rem;
    font-weight: 700;
    color: #0f766e;
}
.pdr-holiday-banner-body {
    font-size: 0.82rem;
    color: var(--text-muted);
    line-height: 1.4;
}
/* Inline pill in the weekly timesheet header summarising the week's OT
   total (e.g. "↑ 1h OT authorised this week"). Matches the orange palette
   of .so-band-overtime so the eye traces from pill to band. */
.so-ot-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    background: rgba(243, 156, 18, 0.15);
    color: #c87f0a;
    padding: 0.15rem 0.55rem;
    border-radius: 12px;
    font-size: 0.74rem;
    font-weight: 600;
    margin-left: 0.5rem;
}

/* ───────────────────────────────────────────────────────────────────────
   Edit User modal — wide redesign with panelised permission grid.
   Markup lives at index.html ~4280-4470 (#edit-user-modal). Mirrors the
   .ptask-card layout used by the Task Planner edit modal so admins get
   a familiar two-column form sized for the perm catalogue (17+ keys).
   The .euser-* prefix avoids collisions with the legacy inline-style
   sized modal that existed previously and with the .ptask-* set.
   ─────────────────────────────────────────────────────────────────────── */
.euser-card {
    width: 95vw;
    max-width: 1400px;
    padding: 1.75rem 2rem 1.5rem;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
    position: relative;
    margin: auto 0;
    box-sizing: border-box;
}
.euser-close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    padding: 0;
}
.euser-header { margin-bottom: 1.25rem; }
.euser-header h2 {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--text-main);
    margin: 0 0 0.15rem 0;
}
.euser-header p {
    color: var(--text-muted);
    font-size: 0.9rem;
    margin: 0;
}

/* Two-column upper section. Identity / role on the left, security +
   employee link on the right. Stacks at <900px. */
.euser-top-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1.25rem;
    margin-bottom: 1.25rem;
}
@media (max-width: 900px) {
    .euser-top-grid { grid-template-columns: minmax(0, 1fr); }
}
.euser-top-grid .form-group { margin-bottom: 0; }

/* Section heading above the panel grid. */
.euser-section-heading {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin: 0.5rem 0 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.euser-section-heading::before {
    content: '';
    width: 3px;
    height: 14px;
    background: var(--primary);
    border-radius: 2px;
    flex: 0 0 auto;
}

/* Bordered card per permission category. Auto-fit grid so the panels
   reflow at narrower widths. */
.euser-panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}
.euser-panel {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.euser-panel-page-access {
    /* The Page Access panel is the primary panel — span the full row so
       the 13 view-perms breathe across 3 columns at desktop widths. */
    grid-column: 1 / -1;
    border-color: rgba(220, 38, 38, 0.22);
}
.euser-panel-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.65rem 0.9rem;
    background: var(--surface-hover);
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
}
.euser-panel-title {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text-main);
    flex: 1;
    min-width: 0;
}
.euser-panel-count {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-muted);
    background: rgba(107, 114, 128, 0.1);
    border-radius: 10px;
    padding: 0.1rem 0.55rem;
    white-space: nowrap;
}
.euser-panel-count.is-full {
    background: rgba(52, 199, 89, 0.15);
    color: #15803d;
}
.euser-panel-actions { display: flex; gap: 0.3rem; }
.euser-panel-action {
    background: none;
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 0.7rem;
    padding: 0.2rem 0.55rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-family: inherit;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.euser-panel-action:hover {
    color: var(--primary);
    border-color: var(--primary);
}
.euser-panel-action:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}
.euser-panel-body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.4rem 1rem;
    padding: 0.85rem 0.9rem;
}
.euser-panel-page-access .euser-panel-body {
    /* 3 columns on the Page Access panel where space allows. */
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.euser-perm {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    cursor: pointer;
    padding: 0.2rem 0;
    line-height: 1.3;
}
.euser-perm input[type="checkbox"] { flex-shrink: 0; }
.euser-perm-label {
    flex: 1;
    min-width: 0;
}
.euser-perm input[type="checkbox"]:disabled + .euser-perm-label {
    color: var(--text-muted);
}

/* Sub-sections inside the Edit User modal (Email / Motion / Reset
   testing). Keeps them visually grouped without re-using the legacy
   inline-style block. */
.euser-subsection {
    margin-top: 1.25rem;
}
.euser-subsection-label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}
.euser-subsection-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 1.25rem 1.5rem;
}

/* Footer save bar. */
.euser-footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}
.euser-footer .btn { padding: 0.6rem 1.4rem; }

/* Danger-styled button used by the "Enforce Password Reset" control. */
.btn-danger-outline {
    color: var(--danger, #dc2626);
    border-color: rgba(239, 68, 68, 0.4);
}
.btn-danger-outline:hover {
    background: rgba(239, 68, 68, 0.08);
    border-color: rgba(239, 68, 68, 0.7);
    color: var(--danger, #dc2626);
}

/* ============================================================================
   DESKTOP 80% DENSITY  (added 2026-05-27)
   Staff were manually zooming the browser to 80% because the denser layout
   reads better. This bakes that in for desktop so it's the default for everyone
   without a per-person browser setting.

   Mechanism: CSS `zoom` on <body>. Unlike real browser zoom, CSS zoom does NOT
   re-measure the viewport, so anything sized to fill the viewport (100vh/100vw,
   or position:fixed width/height:100%) would render at 80% and leave an empty
   strip on the right + bottom. The handful of full-screen fillers are therefore
   scaled up by 1/0.8 below so they still fill the screen.

   Scope: desktop only. Phones/tablets are excluded via the body device-classes
   and keep their own responsive sizing — zooming them would shrink an already
   small, touch-first UI and gap their 100vh mobile layouts.

   To revert: delete this whole block. No JS / version changes depend on it.
   ============================================================================ */
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) {
    zoom: 0.8;
}
/* Full-viewport fillers — keep them filling the screen under the zoom so there
   is no empty strip / short modal dimming at the right + bottom edges. */
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) .app-container {
    height: calc(100vh / 0.8);
    width: calc(100vw / 0.8);
}
/* The SOP runner overlay (#task-sop-modal) and its fullscreen image lightbox
   (#sop-image-fullscreen) size themselves from CSS, not inline, so the
   desktop-zoom filler below can scale them to fill the screen. This base rule
   is the un-zoomed default — mobile/tablet (excluded from the filler) keep it.
   Without the filler they render at 80% and the bottom gap dwarfs the top one. */
#task-sop-modal,
#sop-image-fullscreen {
    width: 100%;
    height: 100%;
}
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) .modal-overlay,
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) .sales-modal-overlay,
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #task-sop-modal,
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #sop-image-fullscreen {
    width: calc(100vw / 0.8);
    height: calc(100vh / 0.8);
}
/* Catalogue part & assembly editors (#create-part-modal, #assembly-editor-view)
   size themselves via INLINE styles (backdrop 100%/100%; card 95vw/95vh/
   max-width:1400px), so they aren't caught by the .modal-overlay filler above
   and render at 0.8× on desktop — a dim gap at the right/bottom and a smaller-
   than-needed card. Scale them up to fill the screen here (desktop only).
   !important is needed to beat the inline values; mobile/tablet are excluded by
   the body selector and keep the inline base. */
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #create-part-modal,
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #assembly-editor-view {
    width: calc(100vw / 0.8) !important;
    height: calc(100vh / 0.8) !important;
}
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #create-part-modal > .card,
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #assembly-editor-view > .card {
    width: calc(96vw / 0.8) !important;
    height: calc(95vh / 0.8) !important;
    max-width: calc(1800px / 0.8) !important;
}
/* Wider "Visual"/image column in those editors' Details tab (desktop only).
   The modals are near full-screen on desktop, so give the drawing/3D preview
   more room; the form column (flex:1 / 1fr) takes the rest. Mobile/tablet keep
   the inline 320px / 250px so the narrow layout isn't pushed off-screen.
   Selectors are 2 levels off stable ids that JS already depends on. */
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #part-tab-content-details > div:first-child {
    width: 480px !important;
}
body:not(.device-mobile):not(.device-tablet):not(.is-mobile-dashboard):not(.is-mobile-planner) #asm-tab-details > div:first-child {
    grid-template-columns: 480px 1fr !important;
}
