:root {
  /* Material + Neumorphism hybrid (approved via the Sales-page pilot,
     now rolled out app-wide). Neumorphism needs a MID-TONE base to shade
     both lighter and darker from - the old near-black (#0b0d10) had
     nowhere to go "darker", so the base moved to a lighter charcoal.
     --neu-light/--neu-dark are the two shadow colors used together for
     the soft "carved" dual-shadow look on passive/informational surfaces
     (cards, panels, tables, inputs - see box-shadow rules below).
     --accent is Copper as of the premium login-page redesign (was a vivid
     Material blue before that, and a graphite mid-tone before that) - this
     is the BASELINE brand accent, i.e. what the login page and anyone
     who's never opened My Profile -> Appearance's color picker sees (see
     lib/accentColors.js's DEFAULT_ACCENT and the [data-accent="x"] blocks
     further down, which override these bare values for everyone who HAS
     picked a personal color - blue included, it just isn't free anymore).
     --accent is used as both a solid fill (buttons, active nav, avatars)
     and an inline highlight color (hover states, focus rings, calendar
     "today"), so --accent-text is a dark shade of the same hue for
     contrast against the bright fill, and --accent-dim is a hue-tinted
     (not gray-tinted) dim surface for things like chat "mine" bubbles and
     avatar backgrounds. */
  --bg: #22252a;
  --bg-elevated: #282b31;
  --bg-card: #22252a;
  --border: #34383f;
  --border-soft: #2a2e34;
  --neu-light: #2d3037;
  --neu-dark: #14161a;
  --text: #e8e9ea;
  --text-muted: #9aa0a6;
  --text-faint: #676d75;
  --accent: #d9822f;
  --accent-dim: #3d2a10;
  --accent-text: #402207;
  --silver: #c7ccd3;
  --silver-dim: #7d838c;
  --green: #3ecf6e;
  --amber: #d9822f;
  --red: #f0554d;
  --blue: #4c9eea;
  --radius: 8px;
  --sidebar-w: 256px;
}

/* Light mode - opt-in per user (see My Profile's Appearance setting,
   routes/me.js), applied via a data-theme="light" attribute lib/layout.js
   puts on <html> based on the logged-in user's saved preference. Default
   for everyone who hasn't touched the setting stays dark (no attribute,
   or data-theme="dark", falls through to the :root values above
   unchanged) so existing users see no surprise change.
   --green/--amber/--red/--blue are darkened here (not just left alone)
   because they're used as small badge/banner TEXT sitting on a pale
   low-opacity tint of themselves - the bright, saturated values tuned for
   readability against a near-black page would be too washed-out against
   a light one. The tint backgrounds themselves (hardcoded rgba(...) alpha
   overlays scattered through this file) don't need per-theme overrides -
   alpha-blending the same RGB numbers over a light or dark base both
   still produce a sensible pale tint, only the solid TEXT color needs to
   change. */
[data-theme="light"] {
  --bg: #f4f5f6;
  --bg-elevated: #eceef0;
  --bg-card: #f4f5f6;
  --border: #dfe2e5;
  --border-soft: #e8eaec;
  --neu-light: #ffffff;
  --neu-dark: #d1d4d8;
  --text: #181b1f;
  --text-muted: #565c64;
  --text-faint: #8a9099;
  --accent: #8a5a12;
  --accent-dim: #f5e3c8;
  --accent-text: #ffffff;
  --silver: #565c64;
  --silver-dim: #9299a1;
  --green: #1f7a45;
  --amber: #8a5a12;
  --red: #b8362c;
  --blue: #1f5fa8;
}
[data-theme="light"] .nav-item.active { background: rgba(138,90,18,0.10); }
[data-theme="light"] .cal-today { background: rgba(138,90,18,0.08); }
[data-theme="light"] .cal-open { background: rgba(138,90,18,0.14); }

/* Per-user accent-color picker (My Profile -> Appearance, alongside the
   Dark/Light toggle above - see lib/layout.js's data-accent attribute and
   lib/accentColors.js for the canonical palette/values). "copper" is the
   default (DEFAULT_ACCENT) and needs no override here since :root and
   [data-theme="light"] above already ARE the copper values - see the long
   comment at the top of :root for why copper replaced blue as the
   baseline. Each other color, blue included now, supplies its own
   dark-theme block (plain [data-accent="x"], applies whenever data-theme
   isn't "light") and light-theme block (chained with [data-theme="light"]),
   mirroring the exact accent/accent-dim/accent-text roles the :root
   comment describes. Deliberately does NOT touch --green/--amber/--red/
   --blue - those are semantic status colors (badges, calendar leave, etc),
   independent of the brand accent choice. */
[data-accent="blue"] { --accent: #4c9eea; --accent-dim: #1c3a5e; --accent-text: #0c2c53; }
[data-theme="light"][data-accent="blue"] { --accent: #1f5fa8; --accent-dim: #d7e6f7; --accent-text: #ffffff; }

[data-accent="green"] { --accent: #3ecf6e; --accent-dim: #123a25; --accent-text: #06331c; }
[data-theme="light"][data-accent="green"] { --accent: #1f7a45; --accent-dim: #d7f0e0; --accent-text: #ffffff; }

[data-accent="purple"] { --accent: #a374e0; --accent-dim: #2c1b45; --accent-text: #2a0f4a; }
[data-theme="light"][data-accent="purple"] { --accent: #6b3fa0; --accent-dim: #e8ddf5; --accent-text: #ffffff; }

[data-accent="red"] { --accent: #f0554d; --accent-dim: #3d1614; --accent-text: #47120f; }
[data-theme="light"][data-accent="red"] { --accent: #b8362c; --accent-dim: #fadbd8; --accent-text: #ffffff; }

[data-accent="teal"] { --accent: #35c5c0; --accent-dim: #123634; --accent-text: #073a37; }
[data-theme="light"][data-accent="teal"] { --accent: #147d79; --accent-dim: #d3f0ee; --accent-text: #ffffff; }

/* The swatch picker itself (routes/me.js) - each color renders as a small
   circle button that submits its own POST on click, no JS needed. */
.accent-swatch-row { display: flex; gap: 10px; flex-wrap: wrap; }
.accent-swatch {
  width: 32px; height: 32px; border-radius: 50%; border: 2px solid transparent;
  cursor: pointer; padding: 0; box-shadow: 2px 2px 5px var(--neu-dark), -2px -2px 5px var(--neu-light);
  transition: transform 0.1s ease;
}
.accent-swatch:hover { transform: scale(1.08); }
.accent-swatch.selected { border-color: var(--text); box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--text); }
/* .btn.danger used to be a solid --red fill - harmless normally, but when
   someone's personal accent color (My Profile -> Appearance) is set to
   "red", --accent and --red become the exact same hex value, so a plain
   .btn (e.g. "Confirm Payment Received") and .btn.danger (Cancel/Delete
   Order) rendered as literally identical buttons - the confusing mix of
   colors this comment used to be about no longer applies now that danger
   buttons are outlined instead of filled (see .btn.danger below), which
   stays visually distinct from every accent color, not just red, so this
   light-theme text-color override isn't needed any more. */

* { box-sizing: border-box; }
/* Root font-size anchor. Every font-size elsewhere in this file (and in
   inline styles in the route files) is expressed in rem - a multiple of
   THIS value - instead of its own independent fixed px number. That means
   changing this one line (see the mobile media queries near the bottom,
   which bump it for narrow screens) scales literally every piece of text
   in the whole app together, proportionally, in one place - instead of
   the old approach of hunting down and separately overriding dozens of
   individual classes, which is exactly how several got missed on the
   first mobile pass. Desktop is unaffected: 14px here reproduces the
   exact original pixel sizes everywhere else. */
html { font-size: 14px; }
html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
}
body { font-size: 1rem; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { font-weight: 700; margin: 0; letter-spacing: -0.01em; }
button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }
/* Baseline for any <select> that isn't given a more specific style elsewhere
   (e.g. the calendar page's employee picker) - without this, the browser's
   native white dropdown background combines with our dark-theme's light text
   color to render as white-on-white / unreadable. */
select {
  background: var(--bg-card); border: none; border-radius: 8px;
  padding: 7px 10px; color: var(--text);
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
}

.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w);
  background: var(--bg-elevated);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: fixed; top: 0; bottom: 0; left: 0;
  padding: 18px 14px;
  overflow-y: auto;
  overflow-anchor: none;
}
.brand { display: flex; align-items: center; gap: 8px; padding: 0 8px 18px 8px; flex-shrink: 0; }
.brand-mark {
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.brand-mark svg { width: 100%; height: 100%; display: block; }
.brand-name { font-weight: 800; font-size: 1.0714rem; }
.brand-name .brand-suite { color: var(--silver); }
.brand-name .brand-os { color: var(--accent); }
.brand-sub { font-size: 0.7143rem; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; margin-top: -2px; }

/* Sidebar nav - a grid of icon-on-top app buttons (like a launcher grid)
   instead of the old stacked list of icon+label rows, so each page reads
   as its own tappable tile rather than one item in a dense vertical list.
   Passive/resting tiles get the neumorphic dual-shadow "extrusion"; the
   active tile switches to a flat accent fill (same interactive/passive
   split used everywhere else in the redesign) so it's unmistakable which
   page you're on. */
/* Department page switcher (Home + whatever pages the active department
   owns) - a plain scannable icon+label LIST, not a grid of buttons. A
   page switcher with 6+ items (HR & Admin, for instance) reads better as
   a list than a wall of square tiles - the square app-button treatment
   below is reserved for the account/system row, which always has a
   fixed, small item count. */
.nav-group {
  flex: 1;
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 14px;
}
.nav-item {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1; gap: 5px; padding: 6px 4px; border-radius: 10px; border: none;
  text-align: center; color: var(--text-muted); font-weight: 600; font-size: 0.6786rem; line-height: 1.2;
  background: var(--bg-card); cursor: pointer;
  box-shadow: 3px 3px 7px var(--neu-dark), -3px -3px 7px var(--neu-light);
  transition: box-shadow 0.15s ease, color 0.15s ease, background 0.15s ease, transform 0.1s ease;
}
.nav-item:hover { color: var(--accent); box-shadow: 2px 2px 4px var(--neu-dark), -2px -2px 4px var(--neu-light); transform: translateY(1px); }
.nav-item.active {
  background: var(--accent); color: var(--accent-text);
  box-shadow: 0 2px 6px rgba(217,130,47,0.35), 0 1px 2px rgba(0,0,0,0.2);
}
.nav-icon { width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; opacity: 0.9; }
.nav-icon svg { width: 100%; height: 100%; }
.nav-item.active .nav-icon { opacity: 1; }

.nav-group .nav-item {
  flex-direction: row; align-items: center; justify-content: flex-start;
  aspect-ratio: auto; gap: 12px; padding: 10px 12px; border-radius: 8px;
  text-align: left; font-size: 0.9286rem; font-weight: 600;
  background: none; box-shadow: none; transform: none;
}
.nav-group .nav-item:hover { background: var(--bg-card); color: var(--text); box-shadow: none; transform: none; }
.nav-group .nav-item.active { background: rgba(217, 130, 47, 0.16); color: var(--accent); box-shadow: none; }
.nav-group .nav-item .nav-icon { width: 19px; height: 19px; opacity: 1; }
.nav-bottom {
  border-top: 1px solid var(--border); padding-top: 16px; margin-top: 20px; flex-shrink: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}

.app-version { grid-column: 1 / -1; font-size: 0.7143rem; color: var(--text-faint); padding: 6px 4px 0; text-align: center; }

.main-col { margin-left: var(--sidebar-w); flex: 1; display: flex; flex-direction: column; min-height: 100vh; }

.topbar {
  height: 58px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 14px; padding: 0 22px;
  background: var(--bg); position: sticky; top: 0; z-index: 10;
}
.search-box {
  flex: 1; max-width: 480px; display: flex; align-items: center; gap: 8px;
  background: var(--bg-card); border: none;
  border-radius: 8px; padding: 7px 10px; color: var(--text-faint);
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
}
.search-box input { background: transparent; border: none; outline: none; color: var(--text); width: 100%; }
.kbd { font-size: 0.7143rem; border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; color: var(--text-faint); }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 16px; }
.icon-btn { position: relative; width: 34px; height: 34px; border-radius: 6px; display: flex; align-items: center; justify-content: center; color: var(--text-muted); border: 1px solid transparent; cursor: pointer; background: none; }
.icon-btn:hover { background: var(--bg-card); border-color: var(--border); }
.notif-dot { position: absolute; top: 6px; right: 6px; width: 7px; height: 7px; border-radius: 50%; background: var(--red); }
.avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--accent); color: var(--accent-text); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.8571rem; cursor: pointer; box-shadow: 0 2px 6px rgba(217,130,47,0.35); }

.page { padding: 26px 32px 60px; max-width: 1400px; }
.page-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 22px; gap: 16px; }
.page-title { font-size: 1.5rem; margin-bottom: 4px; }
.page-desc { color: var(--text-muted); font-size: 0.9286rem; max-width: 640px; }
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent); color: var(--accent-text); font-weight: 700;
  border: none; border-radius: 8px; padding: 9px 14px; cursor: pointer; font-size: 0.9286rem;
  white-space: nowrap;
  box-shadow: 0 3px 8px rgba(217,130,47,0.35), 0 1px 2px rgba(0,0,0,0.2);
}
.btn:hover { filter: brightness(1.08); box-shadow: 0 4px 11px rgba(217,130,47,0.42), 0 1px 2px rgba(0,0,0,0.2); }
.btn.secondary {
  background: var(--bg-card); color: var(--text); border: none;
  box-shadow: 4px 4px 8px var(--neu-dark), -4px -4px 8px var(--neu-light);
}
.btn.secondary:hover { box-shadow: 2px 2px 5px var(--neu-dark), -2px -2px 5px var(--neu-light); }
/* Outlined rather than solid-filled, deliberately: a solid .btn.danger
   used to be indistinguishable from a plain .btn whenever someone's
   personal accent color was set to "red" (--accent and --red are the same
   hex in that case - see the removed comment above). An outline never
   collides with a solid-fill primary button, whatever accent is active. */
.btn.danger { background: transparent; color: var(--red); border: 1.5px solid var(--red); box-shadow: none; }
.btn.danger:hover { background: rgba(240, 85, 77, 0.14); filter: none; box-shadow: none; }
.btn.small { padding: 6px 10px; font-size: 0.8571rem; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }

.kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 20px; }
.kpi-card { background: var(--bg-card); border: none; border-radius: var(--radius); padding: 16px; box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light); }
.kpi-label { font-size: 0.7857rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; }
.kpi-value { font-size: 1.8571rem; font-weight: 800; margin-top: 8px; }
.kpi-sub { font-size: 0.8571rem; color: var(--text-faint); margin-top: 4px; }

.dept-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }
.dept-card {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background: var(--bg-card); border: none; border-radius: var(--radius);
  aspect-ratio: 1 / 1; padding: 16px; text-align: center; color: var(--text); text-decoration: none;
  box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light);
  transition: box-shadow 0.15s ease, transform 0.15s ease, color 0.15s ease;
}
.dept-card:hover { color: var(--accent); transform: translateY(-2px); box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light); }
.dept-card-icon { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; color: var(--accent); }
.dept-card-icon svg { width: 100%; height: 100%; }
.dept-card-label { font-weight: 700; font-size: 1rem; }
.dept-card-placeholder { opacity: 0.72; }
.dept-card-badge {
  font-size: 0.7143rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-muted); background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: 100px; padding: 3px 9px;
}

/* Reports-to org tree (routes/hr.js's orgChartPage()) - a simple nested
   indent tree, connecting lines drawn via border-left on each nesting
   level rather than absolutely-positioned connectors. */
.org-tree { margin-top: 8px; }
.org-node-card {
  display: inline-block; background: var(--bg-card); border-radius: var(--radius);
  padding: 10px 14px; margin: 4px 0;
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
}
.org-node-name { font-weight: 700; font-size: 0.9286rem; color: var(--text); }
.org-node-title { font-size: 0.7857rem; color: var(--text-muted); margin-top: 2px; }
.org-children { margin-left: 28px; padding-left: 18px; border-left: 2px solid var(--border); margin-top: 2px; margin-bottom: 4px; }

.subsection-list { margin: 0 0 18px; padding-left: 20px; color: var(--text); font-size: 0.9643rem; line-height: 1.9; }

/* Section headers on the departmental Home dashboard (routes/home.js) -
   one per department the logged-in user has access to, stacked in
   lib/departments.js's fixed order. */
.home-dept-header { display: flex; align-items: center; gap: 10px; margin: 28px 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.home-dept-header:first-child { margin-top: 0; }
.home-dept-header-icon { width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; color: var(--accent); }
.home-dept-header-icon svg { width: 100%; height: 100%; }
.home-dept-header-label { font-size: 1.1429rem; font-weight: 800; color: var(--text); }

.layout-2col { display: grid; grid-template-columns: 1fr 300px; gap: 18px; align-items: start; }
.panel { background: var(--bg-card); border: none; border-radius: var(--radius); padding: 16px; margin-bottom: 14px; box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light); }
.panel-title { font-size: 0.8571rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin-bottom: 10px; }
.quick-actions { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 20px; }
.quick-action { background: var(--bg-card); border: none; border-radius: var(--radius); padding: 12px; text-align: center; font-weight: 700; font-size: 0.8929rem; cursor: pointer; box-shadow: 5px 5px 10px var(--neu-dark), -5px -5px 10px var(--neu-light); transition: box-shadow 0.15s ease, color 0.15s ease, transform 0.1s ease; }
.quick-action:hover { color: var(--accent); box-shadow: 2px 2px 6px var(--neu-dark), -2px -2px 6px var(--neu-light); transform: translateY(1px); }

.table-wrap { background: var(--bg-card); border: none; border-radius: var(--radius); overflow: hidden; box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light); }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; font-size: 0.7857rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); padding: 10px 14px; border-bottom: 1px solid var(--border-soft); background: transparent; }
td { padding: 11px 14px; border-bottom: 1px solid var(--border-soft); font-size: 0.9286rem; }
tr:last-child td { border-bottom: none; }
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: var(--bg-elevated); }
.table-toolbar { display: flex; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--border-soft); align-items: center; }
.table-toolbar input, .table-toolbar select {
  background: var(--bg-card); border: none; border-radius: 8px; padding: 7px 10px; color: var(--text);
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
}
.empty-state { padding: 40px; text-align: center; color: var(--text-faint); }

.badge { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 100px; font-size: 0.8214rem; font-weight: 700; box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
.badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; }
.badge.green { background: rgba(62,207,110,0.12); color: var(--green); }
.badge.green::before { background: var(--green); }
.badge.amber { background: rgba(217,130,47,0.14); color: var(--amber); }
.badge.amber::before { background: var(--amber); }
.badge.red { background: rgba(240,85,77,0.12); color: var(--red); }
.badge.red::before { background: var(--red); }
.badge.blue { background: rgba(76,158,234,0.12); color: var(--blue); }
.badge.blue::before { background: var(--blue); }
.badge.gray { background: rgba(255,255,255,0.06); color: var(--text-muted); }
.badge.gray::before { background: var(--text-faint); }

.list-item { display: flex; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--border-soft); font-size: 0.8929rem; }
.list-item:last-child { border-bottom: none; }
.list-dot { width: 6px; height: 6px; border-radius: 50%; margin-top: 5px; flex-shrink: 0; background: var(--text-faint); }
.list-item .meta { color: var(--text-faint); font-size: 0.7857rem; margin-top: 2px; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.field.full { grid-column: 1 / -1; }
.field label { font-size: 0.8571rem; font-weight: 700; color: var(--text-muted); }
.field input, .field select, .field textarea {
  background: var(--bg-card); border: none; border-radius: 8px;
  padding: 9px 11px; color: var(--text); outline: none;
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
}
table input[type="number"] {
  background: var(--bg-card); border: none; border-radius: 8px;
  padding: 6px 8px; color: var(--text); outline: none;
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
}
.field input:focus, .field select:focus, .field textarea:focus { box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light), 0 0 0 2px var(--accent); }

/* Custom date picker (see public/datepicker.js) - .dp-native is the real
   <input type="date"> that still carries the field's name/value for form
   submission, visually hidden but still in normal layout flow (not
   display:none) so it stays a valid target for scrollIntoView/focus and
   doesn't collapse the .field's height before datepicker.js has run.
   .dp-display is the visible, clickable stand-in that opens the popup. */
.dp-native { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.dp-display { cursor: pointer; }
.dp-display[disabled] { cursor: default; opacity: 0.6; }
.dp-display-invalid { box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light), 0 0 0 2px var(--red) !important; }
.dp-error { display: none; color: var(--red); font-size: 0.7857rem; margin-top: 4px; }
.dp-popup {
  position: absolute; z-index: 120; width: 232px; background: var(--bg-card); border-radius: var(--radius);
  padding: 10px; box-shadow: 8px 8px 18px var(--neu-dark), -8px -8px 18px var(--neu-light), 0 12px 30px rgba(0,0,0,0.3);
}
.dp-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.dp-nav {
  background: none; border: none; color: var(--text); font-size: 1.0714rem; line-height: 1; cursor: pointer;
  padding: 2px 8px; border-radius: 6px;
}
.dp-nav:hover { color: var(--accent); }
.dp-month-label { font-size: 0.8571rem; font-weight: 700; color: var(--text); }
.dp-dow-row { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px; }
.dp-dow { text-align: center; font-size: 0.7143rem; color: var(--text-faint); padding: 2px 0; }
.dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp-day {
  background: none; border: 1px solid transparent; border-radius: 6px; color: var(--text);
  font-size: 0.8214rem; padding: 6px 0; cursor: pointer; text-align: center;
}
.dp-day:hover { background: var(--bg); }
.dp-day-muted { color: var(--text-faint); }
.dp-day-today { border-color: var(--accent); }
.dp-day-selected { background: var(--accent); color: var(--accent-text); font-weight: 700; }
.dp-footer { display: flex; justify-content: space-between; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.dp-footer-btn { background: none; border: none; color: var(--accent); font-size: 0.7857rem; font-weight: 700; cursor: pointer; padding: 2px 4px; }
.dp-footer-btn:hover { text-decoration: underline; }

/* Show/hide password toggle - see passwordFieldHtml()/PASSWORD_TOGGLE_SCRIPT
   in lib/helpers.js. The button sits absolutely inside the same wrapper as
   the input so it doesn't need its own flex/grid slot; padding-right on the
   input keeps typed text from running under it. */
.password-input-wrap { position: relative; }
.password-input-wrap input { width: 100%; padding-right: 38px; }
.password-toggle-btn {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;
  background: none; border: none; color: var(--text-faint); cursor: pointer; padding: 0;
}
.password-toggle-btn:hover { color: var(--accent); }
.field textarea { resize: vertical; min-height: 70px; }
.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: 0.9286rem; font-weight: 500; color: var(--text); padding: 3px 0; }
.checkbox-row input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--accent); }

/* Groups a list of .checkbox-row's by functional area - see
   routes/users.js's departmentCheckboxes(), used on the department grant
   checklists (New/Edit User forms). */
/* Now a checkbox label itself (the group "select all" tick, see
   departmentCheckboxes() in routes/users.js) rather than a plain div, so
   .checkbox-row's flex/gap layout still applies - only the text styling
   below is overridden. */
.checkbox-group-label {
  font-size: 0.7143rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); margin: 12px 0 2px; cursor: pointer;
}
.checkbox-group-label:first-child { margin-top: 0; }
/* Individual department rows are nudged in from the group label above them
   (see departmentCheckboxes() in routes/users.js) so the grouping reads as
   a hierarchy, not just a color/weight change. */
.checkbox-row.dept-row { margin-left: 20px; }
/* One divider after each group's departments, before the next group label -
   skipped after the last group. */
.dept-group-divider { border: none; border-top: 1px solid var(--border); margin: 10px 0 4px; }
.card { background: var(--bg-card); border: none; border-radius: var(--radius); padding: 20px; box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light); }
.card.narrow { max-width: 480px; }

.breadcrumb { font-size: 0.8571rem; color: var(--text-faint); margin-bottom: 10px; }
.breadcrumb a:hover { color: var(--accent); }
.detail-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; gap: 12px; }
.detail-title-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.stat-row { display: flex; gap: 24px; margin-bottom: 4px; }
.stat { }
.stat-label { font-size: 0.7857rem; color: var(--text-muted); text-transform: uppercase; }
.stat-value { font-size: 1.2857rem; font-weight: 800; margin-top: 3px; }
.kv-row { display: flex; justify-content: space-between; padding: 7px 0; border-bottom: 1px solid var(--border-soft); font-size: 0.8929rem; }
.kv-row:last-child { border-bottom: none; }
.kv-row .k { color: var(--text-muted); }

.avatar-thumb { width: 36px; height: 36px; border-radius: 8px; object-fit: cover; display: block; background: var(--bg-elevated); }
.avatar-thumb-empty { border: 1px dashed var(--border); }

.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: radial-gradient(ellipse at top, #16191d 0%, #0b0d10 60%); padding: 24px; }
/* Premium redesign (matches the reference mockup) - the split-panel
   structure from before is unchanged (shellWrap()/loginPage() in
   routes/auth.js still just needs .login-brand + .login-form-panel), but
   the treatment changed: instead of a solid var(--accent) color block on
   the left, both panels now share the same card background (keeps login
   visually consistent with every other card in the app - see the copper
   baseline comment at the top of :root) and the "premium" signal comes
   from a copper glow ring around the whole card plus a soft radial glow
   behind the logo, not a big flat color fill. */
.login-card {
  width: 760px; max-width: 92vw;
  background: var(--bg-card); border: none; border-radius: 20px;
  box-shadow: 10px 10px 24px var(--neu-dark), -10px -10px 24px var(--neu-light),
    0 0 0 1px rgba(217,130,47,0.22), 0 0 54px rgba(217,130,47,0.10);
  display: flex; overflow: hidden; padding: 0;
}
.login-brand {
  width: 300px; flex-shrink: 0; position: relative; overflow: hidden;
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 40px 30px; text-align: center;
}
.login-brand::before {
  content: ''; position: absolute; top: 36%; left: 50%; width: 280px; height: 280px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(217,130,47,0.20) 0%, rgba(217,130,47,0) 70%);
  pointer-events: none;
}
.login-brand > * { position: relative; z-index: 1; }
.login-brand .brand-mark { width: 64px; height: 64px; filter: drop-shadow(0 8px 20px rgba(217,130,47,0.32)); }
.login-brand .brand-name { font-size: 1.5714rem; }
.login-brand-tagline { color: var(--text-muted); font-size: 0.8571rem; line-height: 1.55; margin-top: 14px; max-width: 220px; }
.login-form-panel { flex: 1; min-width: 0; padding: 44px 44px; overflow-y: auto; }
.login-heading { font-size: 1.5714rem; font-weight: 800; margin: 0 0 4px; }
.login-subtitle { color: var(--text-muted); font-size: 0.8929rem; margin: 0 0 22px; }
.error-banner { background: rgba(240,85,77,0.12); border: 1px solid rgba(240,85,77,0.35); color: var(--red); padding: 10px 12px; border-radius: 6px; font-size: 0.8929rem; margin-bottom: 16px; }
.success-banner { background: rgba(62,207,110,0.12); border: 1px solid rgba(62,207,110,0.35); color: var(--green); padding: 10px 12px; border-radius: 6px; font-size: 0.8929rem; margin-bottom: 16px; }
.divider-text { text-align: center; color: var(--text-faint); font-size: 0.7857rem; margin: 16px 0; text-transform: uppercase; letter-spacing: 0.06em; }
.hint { font-size: 0.8214rem; color: var(--text-faint); margin-top: 14px; text-align: center; }

/* "OR" divider with flanking lines, distinct from .divider-text above
   (which is reused as a plain centered link on the forgot-password page -
   giving it flanking lines would look wrong there, hence a separate
   class instead of restyling .divider-text itself). */
.or-divider { display: flex; align-items: center; gap: 12px; margin: 18px 0; color: var(--text-faint); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; }
.or-divider::before, .or-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }

/* Icon-prefixed inputs (Employee ID/Email/Password on login) - a plain
   wrapper around the existing .field markup, not a rework of .field
   itself, so every other form in the app is untouched. */
.field-icon-input { position: relative; }
.field-icon-input .field-icon { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--text-faint); display: flex; pointer-events: none; z-index: 1; }
.field-icon-input input { padding-left: 40px; }
/* Password field variant - spliced onto passwordFieldHtml()'s own
   .password-input-wrap (routes/auth.js) rather than wrapped in
   .field-icon-input, since that wrap is already position:relative and
   already reserves padding-right for the eye-toggle button; this just
   adds the matching left-side padding/icon for the lock glyph. */
.login-password-wrap .field-icon { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--text-faint); display: flex; pointer-events: none; z-index: 1; }
.login-password-wrap input { padding-left: 40px; }

/* Trust note (shield icon + "encrypted in transit" text) - separate from
   .hint since .hint is reused for plain success/notice banners elsewhere
   on this same page and shouldn't turn into a flex icon row everywhere. */
.trust-note { display: flex; align-items: flex-start; gap: 10px; margin-top: 20px; color: var(--text-faint); font-size: 0.8214rem; line-height: 1.5; }
.trust-note svg { flex-shrink: 0; margin-top: 1px; color: var(--accent); }

/* Gradient primary button (Sign In) - layers on top of the base .btn
   class (still supplies padding/radius/font), just swaps the flat
   var(--accent) fill for a warm copper gradient with a stronger glow,
   matching the reference. Used only on the login page for now. */
.btn-gradient {
  background: linear-gradient(135deg, #f0a851 0%, var(--accent) 55%, #a8590f 100%);
  color: #1a0f02; box-shadow: 0 10px 24px rgba(217,130,47,0.38), 0 1px 2px rgba(0,0,0,0.25);
}
.btn-gradient:hover { filter: brightness(1.06); box-shadow: 0 12px 28px rgba(217,130,47,0.46), 0 1px 2px rgba(0,0,0,0.25); }

@media (max-width: 680px) {
  .login-card { flex-direction: column; width: min(420px, 94vw); }
  .login-brand { width: 100%; padding: 28px 20px; }
  .login-brand-tagline { display: none; }
  .login-form-panel { padding: 28px 24px; }
}

.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); display: none; align-items: center; justify-content: center; z-index: 100; }
.modal-overlay.open { display: flex; }
.modal { background: var(--bg-card); border: none; border-radius: 14px; padding: 24px; width: 460px; max-height: 85vh; overflow-y: auto; box-shadow: 10px 10px 24px var(--neu-dark), -10px -10px 24px var(--neu-light), 0 20px 50px rgba(0,0,0,0.35); }
.modal-title { font-size: 1.1429rem; margin-bottom: 16px; }
.close-x { float: right; cursor: pointer; color: var(--text-faint); font-size: 1.2857rem; }

.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.mt-0 { margin-top: 0; }
.flex-between { display: flex; justify-content: space-between; align-items: center; }
.tag-pill { display: inline-block; padding: 2px 8px; border-radius: 100px; background: var(--bg-card); border: none; font-size: 0.7857rem; color: var(--text-muted); box-shadow: inset 1px 1px 3px var(--neu-dark), inset -1px -1px 3px var(--neu-light); }

@media (max-width: 1100px) {
  .kpi-row, .quick-actions { grid-template-columns: repeat(2, 1fr); }
  .layout-2col { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
}

/* ID cards - standard CR80 card size in portrait (54mm x 85.6mm / 2.126in x
   3.370in), same physical size as an RFID/credit card, so this prints or
   exports at real-world size. Colors are hardcoded (not var(--bg-*)) so the
   card looks identical regardless of the app's dark UI theme, and matches
   the printed-on-white-stock look. */
.id-card-sheet { display: flex; gap: 24px; flex-wrap: wrap; align-items: flex-start; }
.id-card {
  width: 2.126in; height: 3.370in; border-radius: 14px; padding: 0.16in 0.17in 0.14in;
  background: #dddddd; border: 1px solid #c6c6c6; box-shadow: 0 4px 14px rgba(0,0,0,0.25);
  display: flex; flex-direction: column; box-sizing: border-box; color: #141414;
  position: relative; overflow: hidden; font-family: inherit;
}

/* ---- Front ---- */
.id-card-photo-wrap { align-self: center; position: relative; z-index: 1; }
.id-card-photo { width: 1.15in; height: 1.15in; object-fit: cover; border: 1.5px solid #141414; display: block; }
.id-card-photo-empty { background: #ececec; }
.id-card-frame { position: relative; z-index: 1; width: 0.76in; height: 0.76in; margin: 0.1in 0 0 0; }
.id-card-corner { position: absolute; width: 11px; height: 11px; }
.id-card-corner.tl { top: 0; left: 0; border-top: 2px solid #141414; border-left: 2px solid #141414; }
.id-card-corner.tr { top: 0; right: 0; border-top: 2px solid #141414; border-right: 2px solid #141414; }
.id-card-corner.bl { bottom: 0; left: 0; border-bottom: 2px solid #141414; border-left: 2px solid #141414; }
.id-card-corner.br { bottom: 0; right: 0; border-bottom: 2px solid #141414; border-right: 2px solid #141414; }
.id-card-qr { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); width: 0.62in; height: 0.62in; background: #fff; padding: 2px; box-sizing: border-box; }
.id-card-front-text { margin-top: 0.1in; position: relative; z-index: 1; }
.id-card-name { font-weight: 800; font-size: 14pt; line-height: 1.15; text-transform: uppercase; border-bottom: 1.5px solid #141414; padding-bottom: 3px; }
.id-card-meta-row { font-size: 6.5pt; margin-top: 3px; line-height: 1.35; text-transform: uppercase; }
.id-card-meta-row b { font-weight: 800; }
.id-card-idno { font-size: 6pt; color: #3a3a3a; margin-top: 4px; text-transform: uppercase; }

/* ---- Back ---- */
.id-card-back-logo { display: block; width: 1.15in; height: auto; margin: 0 auto; }
.id-card-back-field { font-size: 6pt; line-height: 1.4; margin-top: 3px; position: relative; z-index: 1; }
.id-card-back-field b { font-weight: 800; }
.id-card-signature-label { font-size: 6pt; font-weight: 800; margin-top: 8px; position: relative; z-index: 1; }
.id-card-signature-box { border: 1.5px solid #141414; height: 0.42in; margin-top: 3px; position: relative; z-index: 1; box-sizing: border-box; background-repeat: no-repeat; background-position: center; background-size: contain; }
.id-card-signature-caption { font-size: 6pt; text-align: center; margin-top: 3px; position: relative; z-index: 1; }
.id-card-signature-name { font-size: 6.5pt; font-weight: 800; text-align: center; margin-top: 3px; position: relative; z-index: 1; }
.id-card-signature-title { font-size: 5.5pt; color: #3a3a3a; text-align: center; position: relative; z-index: 1; }
.id-card-watermark { position: absolute; right: -0.35in; bottom: 0.5in; width: 1.7in; pointer-events: none; z-index: 0; }
.id-card-back-footer { margin-top: auto; font-size: 6.5pt; font-weight: 800; text-align: center; position: relative; z-index: 1; padding-top: 8px; }

.kiosk-wrap { display: flex; justify-content: center; padding: 30px 0; }
.kiosk-panel { background: var(--bg-card); border: none; border-radius: var(--radius); padding: 40px; text-align: center; width: 100%; max-width: 420px; box-shadow: 8px 8px 18px var(--neu-dark), -8px -8px 18px var(--neu-light); }
.kiosk-icon { font-size: 2.8571rem; }
.kiosk-title { font-size: 1.4286rem; font-weight: 800; margin-top: 8px; }
.kiosk-input { width: 100%; margin-top: 20px; padding: 14px; font-size: 1.1429rem; text-align: center; background: var(--bg-card); border: none; border-radius: 8px; color: var(--text); outline: none; box-shadow: inset 2px 2px 6px var(--neu-dark), inset -2px -2px 6px var(--neu-light); }
.kiosk-input:focus { box-shadow: inset 2px 2px 6px var(--neu-dark), inset -2px -2px 6px var(--neu-light), 0 0 0 2px var(--accent); }
.kiosk-photo { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; border: 2px solid var(--border); background: var(--bg-elevated); margin: 0 auto; display: block; }
.kiosk-name { font-size: 1.2857rem; font-weight: 800; margin-top: 10px; }

/* Touch-friendly sizing for the shared kiosk tablet - much bigger tap
   targets than the desktop app's default .btn, per Apple/Google guidance
   (44px minimum, we go well beyond that for a walk-up-and-tap device). */
.kiosk-panel .btn { width: 100%; padding: 20px; font-size: 1.3571rem; border-radius: 12px; min-height: 60px; justify-content: center; }
.kiosk-panel .btn.secondary { font-size: 1.2143rem; padding: 16px; min-height: 52px; }
#actionArea, #retryArea { margin-top: 18px !important; }
#cancelBtn { margin-top: 14px !important; }
.kiosk-video-wrap { position: relative; width: 100%; max-width: 320px; margin: 0 auto; }
.kiosk-video { width: 100%; border-radius: 10px; background: #000; display: block; transform: scaleX(-1); }
.kiosk-qr-guide { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); width: 62%; aspect-ratio: 1; border: 3px dashed rgba(255,255,255,0.75); border-radius: 14px; pointer-events: none; }

.cal-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; gap: 10px; }
.cal-table { width: 100%; border-collapse: collapse; table-layout: fixed; background: var(--bg-card); border: none; border-radius: var(--radius); overflow: hidden; box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light); }
.cal-table th { padding: 8px 4px; font-size: 0.8214rem; color: var(--text-faint); text-align: center; border-bottom: 1px solid var(--border); font-weight: 600; }
.cal-cell { vertical-align: top; height: 92px; border: 1px solid var(--border-soft); padding: 6px; width: 14.28%; }
.cal-empty { background: var(--bg-elevated); opacity: 0.4; }
.cal-daynum { font-size: 0.8571rem; font-weight: 600; color: var(--text-muted); margin-bottom: 4px; }
.cal-today { background: rgba(217,130,47,0.10); }
.cal-today .cal-daynum { color: var(--accent); }
.cal-weekend { background: var(--bg-elevated); }
.cal-tag { font-size: 0.75rem; padding: 2px 5px; border-radius: 4px; margin-bottom: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-present { background: rgba(62,207,110,0.15); color: var(--green); }
.cal-open { background: rgba(217,130,47,0.16); color: var(--accent); }
.cal-absent { background: rgba(240,85,77,0.15); color: var(--red); }
.cal-leave { background: rgba(76,158,234,0.15); color: var(--blue); }
.cal-holiday { background: rgba(168,109,240,0.16); color: #a86df0; }

@media print {
  .sidebar, .topbar, .page-header, .no-print { display: none !important; }
  body, .app-shell, .main-col, .page { background: #fff !important; }
  .page { padding: 0 !important; }
  .id-card { box-shadow: none; border: 1px solid #ccc; -webkit-print-color-adjust: exact; print-color-adjust: exact; }

  /* Every color in the app is a CSS custom property tuned for whichever
     theme the viewer has on screen (dark by default, see renderShell's
     data-theme) - printed paper is always "light mode" regardless of
     that setting, so dark theme's near-white --text/--border/--bg-card
     values were printing as washed-out, barely-legible light gray on
     white instead of solid black (see the Bill feature in
     routes/orders.js, the first place this got noticed). Force the same
     dark-on-white values light theme already defines (see :root above)
     for every printed page app-wide, not just the Bill. */
  :root {
    --bg: #ffffff; --bg-elevated: #ffffff; --bg-card: #ffffff;
    --border: #dfe2e5; --border-soft: #e8eaec;
    --text: #181b1f; --text-muted: #565c64; --text-faint: #8a9099;
    --silver: #565c64;
  }
  /* .card's neumorphic box-shadow (see the comment above --neu-light /
     --neu-dark near the top of this file) is a screen-only effect built
     around a dark background - on white paper it just prints as a muddy
     gray smudge. A plain, crisp border reads as an actual printed
     document instead. */
  .card { box-shadow: none !important; border: 1px solid var(--border) !important; }
}

/* ---- Encrypted Chat ---- */
.chat-shell { display: flex; height: calc(100vh - 210px); min-height: 420px; border: none; border-radius: var(--radius); overflow: hidden; background: var(--bg-card); box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light); }
.chat-sidebar { width: 280px; flex-shrink: 0; border-right: 1px solid var(--border); display: flex; flex-direction: column; }
.chat-sidebar-header { padding: 14px; border-bottom: 1px solid var(--border-soft); display: flex; justify-content: space-between; align-items: center; }
.chat-conv-list { flex: 1; overflow-y: auto; }
.chat-conv-item { padding: 12px 14px; border-bottom: 1px solid var(--border-soft); cursor: pointer; display: flex; gap: 10px; align-items: center; }
.chat-conv-item:hover { background: var(--bg-elevated); }
.chat-conv-item.active { background: var(--bg-elevated); box-shadow: inset 3px 0 0 var(--accent); }
.chat-avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--accent-dim); color: var(--accent); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.9286rem; flex-shrink: 0; position: relative; }
.chat-avatar .online-dot { position: absolute; bottom: -1px; right: -1px; width: 10px; height: 10px; border-radius: 50%; background: var(--green); border: 2px solid var(--bg-card); }
.chat-conv-meta { flex: 1; min-width: 0; }
.chat-conv-name { font-weight: 700; font-size: 0.9286rem; display: flex; justify-content: space-between; gap: 6px; }
.chat-conv-preview { font-size: 0.8571rem; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-unread-badge { background: var(--accent); color: var(--accent-text); font-size: 0.75rem; font-weight: 800; border-radius: 100px; padding: 2px 7px; flex-shrink: 0; }
.chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.chat-thread-header { padding: 14px; border-bottom: 1px solid var(--border-soft); font-weight: 700; display: flex; align-items: center; gap: 10px; }
.chat-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.chat-bubble-row { display: flex; }
.chat-bubble-row.mine { justify-content: flex-end; }
/* max-width lives on the flex item (this wrapper), not on .chat-bubble
   itself - a percentage max-width on .chat-bubble resolved against this
   unstyled wrapper's own auto/shrink-to-fit width, a circular dependency
   that made Chrome compute a near-zero available width and wrap message
   text character-by-character. Resolving the percentage against the flex
   row (which has a definite width) fixes it. */
.chat-bubble-row > div { max-width: 62%; min-width: 0; }
.chat-bubble { padding: 9px 13px; border-radius: 14px; font-size: 0.9286rem; line-height: 1.45; background: var(--bg-elevated); border: 1px solid var(--border-soft); word-wrap: break-word; }
.chat-bubble-row.mine .chat-bubble { background: var(--accent-dim); border-color: transparent; }
.chat-bubble-meta { font-size: 0.75rem; color: var(--text-faint); margin-top: 4px; display: flex; align-items: center; gap: 8px; }
.chat-bubble-row.mine .chat-bubble-meta { justify-content: flex-end; }
.chat-edited-label { font-style: italic; opacity: 0.8; }

/* Read/delivered/sent ticks - see tickStatusFor()/ticksHtml() in
   public/chat.js. Single check = sent, double = delivered, double + accent
   color = read - derived from the other participant's last_read_at/
   last_delivered_at rather than a per-message status column. */
.chat-tick { font-size: 0.8571rem; letter-spacing: -2px; color: var(--text-faint); }
.chat-tick-read { color: var(--accent); }

/* Per-message hover actions (reply/edit/delete). Not hover-gated for
   clickability - only their resting opacity is low, so they still work on
   touch devices (SuiteOS Go) that have no hover state at all. */
.chat-msg-actions { display: inline-flex; gap: 4px; opacity: 0.55; }
.chat-bubble-row:hover .chat-msg-actions { opacity: 1; }
.chat-msg-actions button { background: none; border: none; color: var(--text-faint); cursor: pointer; font-size: 0.8571rem; padding: 2px; line-height: 1; }
.chat-msg-actions button:hover { color: var(--accent); }

.chat-deleted-msg { font-style: italic; color: var(--text-faint); }

/* Quoted-reply block shown above a message's own text when it replies to
   an earlier one - see replyQuoteHtml() in public/chat.js. Clicking it
   scrolls the original into view (data-scroll-to-id) if it's still in the
   currently loaded message window. */
.chat-reply-quote { border-left: 3px solid var(--accent); background: rgba(255,255,255,0.05); border-radius: 6px; padding: 5px 9px; margin-bottom: 6px; cursor: pointer; }
.chat-reply-quote-deleted { border-left-color: var(--text-faint); font-style: italic; }
.chat-reply-quote-name { font-size: 0.7857rem; font-weight: 700; color: var(--accent); }
.chat-reply-quote-text { font-size: 0.8214rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 260px; }

/* Brief highlight flash when a reply-quote click scrolls a message into view. */
.chat-bubble-flash .chat-bubble { animation: chat-bubble-flash-anim 1.2s ease; }
@keyframes chat-bubble-flash-anim {
  0% { box-shadow: 0 0 0 2px var(--accent); }
  100% { box-shadow: none; }
}

/* Composer banner - "Replying to X" / "Editing message", shown above the
   input row while state.replyTo/editingMessageId is set (see
   composerBannerHtml() in public/chat.js). */
.chat-composer-banner { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--bg-elevated); border-top: 1px solid var(--border-soft); }
.chat-composer-banner-bar { width: 3px; align-self: stretch; background: var(--accent); border-radius: 2px; flex-shrink: 0; }
.chat-composer-banner-text { flex: 1; min-width: 0; }
.chat-composer-banner-title { font-size: 0.7857rem; font-weight: 700; color: var(--accent); }
.chat-composer-banner-preview { font-size: 0.8214rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-bubble-file { display: flex; align-items: center; gap: 8px; }
.chat-bubble-file img { max-width: 220px; max-height: 220px; border-radius: 8px; display: block; }
.chat-typing { font-size: 0.8214rem; color: var(--text-faint); padding: 0 16px 4px; font-style: italic; }
.chat-input-row { padding: 12px; border-top: 1px solid var(--border-soft); display: flex; gap: 8px; align-items: flex-end; }
.chat-input-row textarea { flex: 1; resize: none; min-height: 40px; max-height: 120px; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px; color: var(--text); padding: 9px 12px; font-size: 0.9286rem; font-family: inherit; }
.chat-input-row textarea:focus { outline: none; border-color: var(--accent); }
.chat-empty { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--text-faint); text-align: center; padding: 20px; }
.chat-colleague-row { display: flex; align-items: center; gap: 10px; padding: 9px 8px; border-radius: 6px; cursor: pointer; }
.chat-colleague-row:hover { background: var(--bg-elevated); }
.chat-colleague-row.disabled { opacity: 0.5; cursor: not-allowed; }
.chat-icon-btn { background: none; border: 1px solid var(--border); color: var(--text-muted); border-radius: 8px; padding: 8px 10px; cursor: pointer; font-size: 1.0714rem; line-height: 1; }
.chat-icon-btn:hover { border-color: var(--accent); color: var(--accent); }
.chat-call-btn { margin-left: auto; }

/* ---------------------------------------------------------------------
   Calling - full-screen-ish overlay for an incoming/outgoing/active 1:1
   audio call (see the "Calling" section of public/chat.js). Appended
   directly to <body> by chat.js rather than living inside #chat-app, so a
   call survives chat.js re-rendering the conversation list/thread
   underneath it - see ensureCallOverlay()'s comment.
   --------------------------------------------------------------------- */
.call-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.72); display: none; align-items: center; justify-content: center; z-index: 200; }
.call-overlay.open { display: flex; }
.call-card { background: var(--bg-card); border: none; border-radius: 20px; padding: 36px 32px; width: 280px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; box-shadow: 10px 10px 22px var(--neu-dark), -10px -10px 22px var(--neu-light), 0 20px 50px rgba(0,0,0,0.35); }
.call-avatar-big { width: 84px; height: 84px; border-radius: 50%; background: var(--accent-dim); color: var(--accent); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1.7143rem; margin-bottom: 8px; }
.call-name { font-weight: 700; font-size: 1.1429rem; }
.call-status { color: var(--text-faint); font-size: 0.9286rem; margin-bottom: 18px; min-height: 1.2em; }
.call-actions { display: flex; gap: 20px; align-items: center; }
.call-btn { width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer; font-size: 1.4286rem; display: flex; align-items: center; justify-content: center; color: #fff; }
.call-btn-accept { background: var(--green); }
.call-btn-decline, .call-btn-end { background: var(--red); }
.call-btn-mute { background: var(--bg-elevated); border: 1px solid var(--border); color: var(--text); width: 44px; height: 44px; font-size: 1.1429rem; }
.call-btn-mute.active { background: var(--accent-dim); border-color: var(--accent); color: var(--accent); }

/* ---------------------------------------------------------------------
   Responsive shell - tablet/phone navigation + layout
   ---------------------------------------------------------------------
   Desktop keeps the always-visible sidebar. Below 1024px (tablets and
   phones, portrait or landscape) the sidebar becomes a slide-in drawer
   triggered by a hamburger button in the topbar, with a tap-to-close
   backdrop - see the .menu-toggle/.sidebar-backdrop markup in
   lib/layout.js and the toggle logic in public/app.js. */
.menu-toggle {
  display: none;
  width: 38px; height: 38px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--bg-card); color: var(--text); font-size: 1.2857rem; line-height: 1;
  align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0;
}
.menu-toggle:hover { border-color: var(--accent); color: var(--accent); }
.sidebar-backdrop {
  display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 40;
}

@media (max-width: 1024px) {
  /* Single root anchor bump - every rem-based font-size in the app
     scales from this one value, so this replaces what used to be dozens
     of separately-maintained per-class mobile overrides. */
  html { font-size: 15.5px; }
  .menu-toggle { display: flex; }
  .sidebar {
    z-index: 50; transform: translateX(-100%);
    transition: transform 0.2s ease; box-shadow: 4px 0 24px rgba(0,0,0,0.4);
  }
  .app-shell.nav-open .sidebar { transform: translateX(0); }
  .app-shell.nav-open .sidebar-backdrop { display: block; }
  .main-col { margin-left: 0; }
  .search-box { max-width: none; }
  .kbd { display: none; }
  .kpi-row, .quick-actions, .dept-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 720px) {
  /* Overrides the 1024px bump above - more specific breakpoint wins. */
  html { font-size: 19px; }
  .topbar { padding: 0 14px; gap: 10px; }
  .page { padding: 18px 16px 48px; }
  .page-header { flex-direction: column; align-items: stretch; }
  .page-header .btn-row, .page-header > a.btn, .page-header > .btn { align-self: flex-start; }
  .kpi-row, .quick-actions, .dept-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .modal { width: min(460px, 92vw); padding: 18px; }
  .id-card-sheet { justify-content: center; }

  /* ---------------------------------------------------------------
     Readability + touch targets. The desktop scale (13-14px text,
     mouse-sized buttons) is too small to comfortably read or tap on a
     phone - this bumps text, buttons, inputs, and nav rows up to a
     size a thumb can hit reliably (Apple/Google both recommend a
     ~44px minimum touch target) without touching the desktop layout
     at all, since this only applies inside this breakpoint.
     --------------------------------------------------------------- */
  .btn { padding: 12px 16px; min-height: 44px; }
  .btn.small { padding: 10px 13px; min-height: 40px; }
  .btn-row { gap: 10px; }
  .nav-item { padding: 13px 12px; gap: 12px; }
  .nav-icon { width: 20px; height: 20px; }
  .icon-btn, .menu-toggle { width: 44px; height: 44px; }
  .avatar { width: 36px; height: 36px; }
  /* Inputs used to need an explicit 16px here to dodge iOS Safari's
     auto-zoom-on-focus below that size - now unnecessary, since these
     inherit body's rem-based size, which is already well above 16px on
     phones once the root bump below kicks in. Padding still bumped for
     comfortable tapping. */
  .field input, .field select, .field textarea,
  .table-toolbar input, .table-toolbar select,
  .search-box input, select {
    padding: 12px 13px;
  }
  .checkbox-row { gap: 10px; }
  .checkbox-row input[type="checkbox"] { width: 20px; height: 20px; }
  .badge { padding: 5px 11px; }
  th { padding: 12px 14px; }
  td { padding: 14px; }
  .kv-row { padding: 10px 0; }
}

@media (max-width: 480px) {
  .kpi-row, .quick-actions { grid-template-columns: 1fr; }
  /* Kept as a real (2-col) grid even on small phones, not a single-column
     list - the user explicitly wants department cards to stay grid-based
     "as much as possible" (see the Choose a Section page). */
  .dept-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; }
  .detail-header { flex-direction: column; align-items: stretch; }
  .stat-row { flex-wrap: wrap; gap: 14px; }
}

/* Tables: two different treatments depending on how much room there is.
   Tablets (641-900px) get the original horizontal-scroll treatment - a
   table is still a reasonable format there. Phones (<=640px) get a much
   friendlier stacked-card treatment instead (see the block below) - a
   scrolling table with 5+ unlabeled columns is genuinely hard to use on
   a 375px screen no matter how big the text is. */
@media (min-width: 641px) and (max-width: 900px) {
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .table-wrap table { min-width: 640px; }
  .cal-table { min-width: 640px; }
  .table-wrap:has(.cal-table) { overflow-x: auto; }
}

/* Calendar grids (attendance/leave) stay as horizontally-scrollable
   tables even on phones - they're inherently a 7-day grid, not a list of
   records, so the card treatment below (which only targets plain
   .table-wrap tables, not .cal-table) would make them worse, not better. */
@media (max-width: 640px) {
  .table-wrap:has(.cal-table) { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .cal-table { min-width: 640px; }
}

/* Phone table -> card transform. public/app.js copies each column's
   header text onto every cell in that column as a data-label attribute
   on page load (see enhanceTablesForMobile()), so this works for every
   .table-wrap table across the whole app automatically - no per-page
   markup changes needed. Each row becomes its own card with
   "Column Name: value" lines instead of an unreadable tiny-text row. */
@media (max-width: 640px) {
  .table-wrap table:not(.cal-table) { min-width: 0; }
  .table-wrap table:not(.cal-table) thead { display: none; }
  .table-wrap table:not(.cal-table),
  .table-wrap table:not(.cal-table) tbody,
  .table-wrap table:not(.cal-table) tr,
  .table-wrap table:not(.cal-table) td {
    display: block; width: 100%;
  }
  .table-wrap table:not(.cal-table) tr {
    padding: 14px 16px; border-bottom: 1px solid var(--border-soft);
  }
  .table-wrap table:not(.cal-table) tr:last-child { border-bottom: none; }
  .table-wrap table:not(.cal-table) td {
    display: flex; justify-content: space-between; align-items: center;
    gap: 14px; padding: 6px 0; border: none; text-align: right;
  }
  .table-wrap table:not(.cal-table) td::before {
    content: attr(data-label);
    font-size: 0.7857rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.04em; color: var(--text-muted); text-align: left;
    flex-shrink: 0;
  }
  /* The first column is almost always the record's name/title across
     every table in this app - give it its own full-width line at a
     larger size instead of a cramped "Label: value" row, so each card
     reads like a heading followed by details. */
  .table-wrap table:not(.cal-table) td:first-child {
    display: block; text-align: left; font-size: 1.0714rem; font-weight: 700;
    padding-bottom: 8px;
  }
  .table-wrap table:not(.cal-table) td:first-child::before { display: none; }
  /* Action buttons/links (View, ID Card, Edit, etc.) read fine without a
     label and look better right-aligned/full-width than squeezed next
     to a redundant "Actions:" caption. */
  .table-wrap table:not(.cal-table) td:last-child:has(> a.btn, > button.btn) {
    justify-content: flex-end;
  }
  .table-wrap table:not(.cal-table) td:last-child:has(> a.btn, > button.btn)::before {
    display: none;
  }
}

/* Short/landscape viewports (phone rotated sideways) - vertical space is
   the scarce resource there, not width, so trim paddings instead of
   stacking things that don't need to stack. */
@media (max-height: 480px) and (orientation: landscape) {
  .topbar { height: 46px; }
  .page { padding: 14px 20px 30px; }
  .chat-shell { height: calc(100vh - 130px); min-height: 300px; }
}

/* Chat on phones: show one pane at a time (conversation list, or the open
   thread) instead of squeezing both into a narrow strip - toggled via the
   .mobile-thread-open class public/chat.js adds to .chat-shell whenever a
   conversation is selected, and the "back" button that appears only here. */
.chat-back-btn { display: none; }
@media (max-width: 760px) {
  .chat-shell {
    height: calc(100vh - 190px);
    height: calc(100dvh - 190px);
    min-height: 320px;
  }
  .chat-sidebar { width: 100%; border-right: none; }
  .chat-main { display: none; }
  .chat-shell.mobile-thread-open .chat-sidebar { display: none; }
  .chat-shell.mobile-thread-open .chat-main { display: flex; }
  .chat-back-btn { display: inline-flex; }
  .chat-bubble-row > div { max-width: 82%; }
  .chat-bubble { padding: 10px 14px; }
  .chat-conv-item { padding: 14px 16px; }
  .chat-icon-btn, .chat-back-btn { width: 44px; height: 44px; padding: 0; }
  .chat-avatar { width: 42px; height: 42px; }
  .chat-input-row textarea { padding: 11px 13px; }
  .chat-input-row .btn { min-height: 44px; }
}

/* ===== Document Control (routes/documents.js) ===== */
.mono { font-family: "SF Mono", "Cascadia Code", Consolas, monospace; }
.meta-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px;
  background: var(--bg-card); border: none; border-radius: var(--radius);
  padding: 16px; margin-bottom: 16px;
  box-shadow: 6px 6px 12px var(--neu-dark), -6px -6px 12px var(--neu-light);
}
.meta-item .k { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-faint); margin-bottom: 4px; }
.meta-item .v { font-size: 0.9643rem; color: var(--text); }
.doc-versions { position: relative; padding-left: 20px; }
.doc-versions::before { content: ""; position: absolute; left: 4px; top: 6px; bottom: 6px; width: 1px; background: var(--border); }
.doc-version { position: relative; padding-bottom: 18px; }
.doc-version:last-child { padding-bottom: 0; }
.doc-version::before {
  content: ""; position: absolute; left: -20px; top: 4px; width: 10px; height: 10px; border-radius: 50%;
  background: var(--bg-card); border: 2px solid var(--accent-dim);
}
.doc-version.current::before { border-color: var(--accent); background: var(--accent); }
.version-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.version-tag { font-size: 0.8571rem; font-weight: 700; color: var(--text-faint); }
.doc-version.current .version-tag { color: var(--accent); }
.version-who { font-size: 0.8929rem; color: var(--text); }
.version-when { font-size: 0.7857rem; color: var(--text-faint); margin-left: auto; }
.version-note { font-size: 0.8214rem; color: var(--text-faint); margin-top: 3px; }
.version-dl { font-size: 0.7857rem; color: var(--accent); margin-top: 4px; }
.version-dl a { color: inherit; }

@media (max-width: 900px) {
  .meta-grid { grid-template-columns: repeat(2, 1fr); }
}
