/* =========================================================================
   DESIGN TOKENS
   ========================================================================= */
:root {
  /* surfaces */
  --bg: #FFFFFF;
  --bg-cream: #FAF7F2;
  --bg-subtle: #F7F4EE;
  --bg-hover: #F1ECE1;
  --bg-elevated: #FFFFFF;

  /* text */
  --fg: #0A0A0A;
  --fg-secondary: #3F3F46;
  --fg-muted: #71717A;
  --fg-subtle: #A1A1AA;

  /* borders */
  --border: #E9E3D5;
  --border-soft: #F0EBDD;
  --border-strong: #D4CDBB;

  /* brand (default; overridden per org) */
  --brand: #0A0A0A;
  --brand-fg: #FFFFFF;
  --brand-hover: #27272A;
  --brand-soft: #F4F4F5;

  /* semantic */
  --success: #15803D;
  --success-soft: #DCFCE7;
  --danger: #B91C1C;
  --danger-soft: #FEE2E2;
  --warning: #B45309;
  --warning-soft: #FEF3C7;
  --info: #1D4ED8;
  --info-soft: #DBEAFE;

  /* layout */
  --sidebar-w: 248px;
  --topbar-h: 56px;
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 14px;

  /* typography */
  --font-display: 'Instrument Serif', Georgia, serif;
  --font-body: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  /* shadows — subtle only */
  --shadow-sm: 0 1px 2px rgba(10, 10, 10, 0.04);
  --shadow: 0 4px 12px rgba(10, 10, 10, 0.06);
  --shadow-lg: 0 12px 40px rgba(10, 10, 10, 0.10);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Nothing may push the document wider than the screen. `clip` (not `hidden`)
   stops the page-level horizontal scroll without turning the root into a scroll
   container — so the sticky topbar and the fixed off-canvas sidebar keep
   working, and designated `.table-wrap` regions still scroll internally. */
html { overflow-x: clip; max-width: 100%; }
body {
  overflow-x: clip;
  max-width: 100%;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; border: none; background: none; padding: 0; color: inherit; }
input, textarea, select { font: inherit; color: inherit; }
img { max-width: 100%; display: block; }
svg { flex-shrink: 0; }

/* =========================================================================
   TYPOGRAPHY
   ========================================================================= */
.serif { font-family: var(--font-display); font-weight: 400; letter-spacing: -0.01em; }
.mono { font-family: var(--font-mono); font-size: 0.92em; }
h1, h2, h3, h4, h5 { margin: 0; font-weight: 600; letter-spacing: -0.015em; }
h1 { font-size: 28px; }
h2 { font-size: 22px; }
h3 { font-size: 17px; }
h4 { font-size: 15px; }

.text-xs { font-size: 11px; }
.text-sm { font-size: 12px; }
.text-base { font-size: 14px; }
.text-lg { font-size: 16px; }
.text-xl { font-size: 20px; }
.text-2xl { font-size: 26px; }
.text-3xl { font-size: 34px; }
.text-4xl { font-size: 44px; }
.text-5xl { font-size: 56px; }

.muted { color: var(--fg-muted); }
.subtle { color: var(--fg-subtle); }
.secondary { color: var(--fg-secondary); }
.text-center { text-align: center; }
.text-right { text-align: right; }

.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-bold { font-weight: 700; }

/* =========================================================================
   LAYOUT HELPERS
   ========================================================================= */
.flex { display: flex; }
.inline-flex { display: inline-flex; }
.grid { display: grid; }
.hidden { display: none !important; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.justify-end { justify-content: flex-end; }
.flex-1 { flex: 1; min-width: 0; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.gap-1 { gap: 4px; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }
.gap-6 { gap: 24px; }
.gap-8 { gap: 32px; }
.w-full { width: 100%; }
.h-full { height: 100%; }
.min-w-0 { min-width: 0; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rounded { border-radius: var(--radius); }
.rounded-sm { border-radius: var(--radius-sm); }
.rounded-lg { border-radius: var(--radius-lg); }
.rounded-full { border-radius: 999px; }

.mt-1 { margin-top: 4px; } .mt-2 { margin-top: 8px; } .mt-3 { margin-top: 12px; }
.mt-4 { margin-top: 16px; } .mt-6 { margin-top: 24px; } .mt-8 { margin-top: 32px; }
.mb-1 { margin-bottom: 4px; } .mb-2 { margin-bottom: 8px; } .mb-3 { margin-bottom: 12px; }
.mb-4 { margin-bottom: 16px; } .mb-6 { margin-bottom: 24px; } .mb-8 { margin-bottom: 32px; }

.p-2 { padding: 8px; } .p-3 { padding: 12px; } .p-4 { padding: 16px; }
.p-6 { padding: 24px; } .p-8 { padding: 32px; }
.px-2 { padding-left: 8px; padding-right: 8px; }
.px-3 { padding-left: 12px; padding-right: 12px; }
.px-4 { padding-left: 16px; padding-right: 16px; }
.px-6 { padding-left: 24px; padding-right: 24px; }
.py-1 { padding-top: 4px; padding-bottom: 4px; }
.py-2 { padding-top: 8px; padding-bottom: 8px; }
.py-3 { padding-top: 12px; padding-bottom: 12px; }
.py-4 { padding-top: 16px; padding-bottom: 16px; }

/* =========================================================================
   BUTTONS
   ========================================================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.2;
  border: 1px solid transparent;
  transition: background 120ms, border-color 120ms, color 120ms, transform 100ms;
  white-space: nowrap;
  user-select: none;
}
.btn:active { transform: translateY(0.5px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
  background: var(--brand);
  color: var(--brand-fg);
  border-color: var(--brand);
}
.btn-primary:hover:not(:disabled) { background: var(--brand-hover); border-color: var(--brand-hover); }

.btn-secondary {
  background: var(--bg);
  color: var(--fg);
  border-color: var(--border);
}
.btn-secondary:hover:not(:disabled) { background: var(--bg-subtle); border-color: var(--border-strong); }

.btn-ghost {
  background: transparent;
  color: var(--fg-secondary);
}
.btn-ghost:hover:not(:disabled) { background: var(--bg-subtle); color: var(--fg); }

.btn-danger {
  background: var(--bg);
  color: var(--danger);
  border-color: var(--border);
}
.btn-danger:hover:not(:disabled) { background: var(--danger-soft); border-color: var(--danger); }

.btn-sm { padding: 5px 10px; font-size: 12px; border-radius: var(--radius-sm); }
.btn-lg { padding: 11px 18px; font-size: 14px; }
.btn-icon { padding: 8px; }
.btn-block { width: 100%; }

/* =========================================================================
   FORM FIELDS
   ========================================================================= */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.field label { font-size: 12px; font-weight: 500; color: var(--fg-secondary); }
.field .hint { font-size: 11px; color: var(--fg-muted); }
.field .error { font-size: 11px; color: var(--danger); }

.input, .select, .textarea {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  font-size: 13px;
  color: var(--fg);
  transition: border-color 120ms, box-shadow 120ms;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--fg);
  box-shadow: 0 0 0 3px rgba(10,10,10,0.06);
}
.input::placeholder, .textarea::placeholder { color: var(--fg-subtle); }
.textarea { min-height: 80px; resize: vertical; font-family: inherit; }
.select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; padding-right: 32px; }

.input-group { position: relative; }
.input-group .input-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--fg-muted); pointer-events: none; }
.input-group .input { padding-left: 34px; }

/* Password show/hide eye button */
.pw-field { position: relative; }
.pw-field .input { padding-right: 40px; }
.pw-field .pw-toggle { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); background: transparent; border: 0; padding: 6px; color: var(--fg-muted); cursor: pointer; display: inline-flex; align-items: center; line-height: 0; border-radius: 4px; }
.pw-field .pw-toggle:hover { color: var(--fg); background: var(--bg-cream); }

/* Checkbox / toggle */
.checkbox { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
/* .onbw-doc is a checkbox row at card size — it needs the same mark, not the
   browser's default blue, which is the one colour the app never uses. */
.checkbox input, .onbw-doc input { appearance: none; width: 16px; height: 16px; border: 1px solid var(--border-strong); border-radius: 4px; background: var(--bg); transition: 120ms; }
.checkbox input:checked, .onbw-doc input:checked { background: var(--brand); border-color: var(--brand); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); background-position: center; background-repeat: no-repeat; background-size: 12px; }

/* Radio rendered as a pill (a small set of mutually exclusive actions, shown
   inline rather than as a stack). `.preset-radio` is the same idea at card size
   — it carries its own box inline, so it only needs the states. */
.radio-pill {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
  padding: 6px 12px; border: 1px solid var(--border-soft); border-radius: 999px;
  background: var(--bg); font-size: 13px; transition: 120ms;
}
.radio-pill:hover { border-color: var(--border-strong); background: var(--bg-cream); }
.radio-pill input { accent-color: var(--brand); margin: 0; flex: none; }
.radio-pill:has(input:checked) { border-color: var(--brand); background: var(--bg-cream); }
.preset-radio:hover { background: var(--bg-cream) !important; }
.preset-radio:has(input:checked) { border-color: var(--brand) !important; }
.preset-radio:has(input:disabled) { opacity: .55; cursor: not-allowed; }

.toggle { position: relative; display: inline-block; width: 32px; height: 18px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-slider { position: absolute; inset: 0; background: var(--border-strong); border-radius: 999px; transition: 160ms; cursor: pointer; }
.toggle-slider::before { content: ''; position: absolute; height: 14px; width: 14px; left: 2px; top: 2px; background: white; border-radius: 50%; transition: 160ms; }
.toggle input:checked + .toggle-slider { background: var(--brand); }
.toggle input:checked + .toggle-slider::before { transform: translateX(14px); }

/* =========================================================================
   CARDS & CONTAINERS
   ========================================================================= */
.card {
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
}
.card-header { padding: 16px 20px; border-bottom: 1px solid var(--border-soft); }
.card-body { padding: 20px; }
.card-footer { padding: 14px 20px; border-top: 1px solid var(--border-soft); }

/* =========================================================================
   BADGES
   ========================================================================= */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  background: var(--bg-subtle);
  color: var(--fg-secondary);
  border: 1px solid var(--border-soft);
}
.badge-success { background: var(--success-soft); color: var(--success); border-color: transparent; }
.badge-danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.badge-warning { background: var(--warning-soft); color: var(--warning); border-color: transparent; }
.badge-info { background: var(--info-soft); color: var(--info); border-color: transparent; }
.badge-neutral { background: var(--bg-subtle); color: var(--fg-muted); border-color: transparent; }
/* `badge-muted` was already being written in 8 places across Events, Website,
   Certifications and Energy — for "Closed", "Archived", the states you want
   present but quiet — and had never existed, so all 8 silently rendered as a
   plain bordered badge. Defined here rather than edited out of the call sites,
   because the call sites were all asking for the same real thing: dimmer than
   neutral, and reading as switched-off rather than as a category. */
.badge-muted {
  background: transparent;
  color: var(--fg-muted);
  border-color: var(--border-soft);
  opacity: 0.85;
}
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: inline-block; }

/* Grid helpers */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
/* Four across for a row of stat tiles; two across before it drops to one, since
   four tiles side by side stop being readable well above the phone breakpoint. */
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
@media (max-width: 1000px) {
  .grid-4 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .grid-4 { grid-template-columns: 1fr 1fr; }
}

/* Stat card (used on project overview + elsewhere) */
.stat-card {
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
}
.stat-label { font-size: 12px; color: var(--fg-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.stat-value { font-size: 22px; font-weight: 600; margin-top: 4px; font-family: 'DM Sans', system-ui; }

/* Description list (used on overview detail panels) */
.dl { margin: 0; display: grid; grid-template-columns: 1fr; gap: 8px; }
.dl > div { display: grid; grid-template-columns: 140px 1fr; gap: 12px; align-items: baseline; }
.dl dt { font-size: 12px; color: var(--fg-muted); margin: 0; }
.dl dd { margin: 0; font-size: 14px; color: var(--fg-primary); }

/* Clickable list rows. Seven modules each named their own row class and gave it
   `cursor:pointer` inline with no hover state, so a row that is a link looked
   exactly like one that isn't. One rule, no markup churn. */
.ev-row, .cert-row, .wp-row, .ml-msg, .hh-drill-row[data-drill],
.act-table-row, .emp-row {
  transition: background 120ms;
}
.ev-row:hover, .cert-row:hover, .wp-row:hover, .ml-msg:hover,
.act-table-row:hover, .emp-row:hover,
.hh-drill-row[data-drill]:hover { background: var(--bg-cream); }
.act-table-row, .emp-row { cursor: pointer; }
a.ev-row { color: inherit; text-decoration: none; }
/* The remove button stays visible — hover-to-reveal has no equivalent on a
   phone, and these chips are edited on site. */
.att-chip .att-del { color: var(--fg-muted); display: inline-flex; align-items: center; justify-content: center; }
.att-chip .att-del:hover { color: var(--danger); border-color: var(--danger); }

/* Onboarding checklist row (home) */
.checklist-item {
  display: flex; gap: 10px; align-items: center;
  padding: 10px 0; border-bottom: 1px solid var(--border-soft);
}
.checklist-item:last-child { border-bottom: none; }

/* Grouping header inside a table body (employees grouped by station).
   `tr.…` rather than `.…` on purpose: below 640px `.table-cards td` sets its own
   padding and text-align, and at equal specificity it would win on source order
   — this used to be an inline style, which always won. */
tr.emp-group-row > td {
  background: var(--bg-subtle); padding: 8px 14px; text-align: left;
  font-weight: 600; font-size: 11px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--fg-muted);
}

/* Simple list row (e.g. retention tranches) */
.list-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 0; border-bottom: 1px solid var(--border-soft); gap: 12px;
}
.list-row:last-child { border-bottom: none; }

/* Plain styled link (distinct from .btn) */
.link { color: var(--brand, var(--fg-primary)); text-decoration: none; }
.link:hover { text-decoration: underline; }

/* Search highlight */
mark { background: #FFF3B0; color: inherit; padding: 0 2px; border-radius: 2px; }

/* Chevron affordance on clickable list rows */
.chevron { color: var(--fg-muted); display: inline-flex; align-items: center; }

/* Comms chat layout */
.chat-layout {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 16px;
  min-height: calc(100vh - 220px);
}
@media (max-width: 720px) { .chat-layout { grid-template-columns: 1fr; } }
.chat-sidebar {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--bg);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.chat-sidebar-header {
  padding: 14px 16px; border-bottom: 1px solid var(--border-soft);
  display: flex; align-items: center; justify-content: space-between;
}
.chat-channel-item {
  padding: 10px 16px; cursor: pointer; border-left: 3px solid transparent;
  display: flex; align-items: center; gap: 8px;
}
.chat-channel-item:hover { background: var(--bg-subtle); }
.chat-channel-item.active { background: var(--bg-subtle); border-left-color: var(--brand); font-weight: 500; }
.chat-channel-item .hash { color: var(--fg-muted); }
.chat-main {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--bg);
  display: flex; flex-direction: column; overflow: hidden;
}
.chat-main-header {
  padding: 14px 20px; border-bottom: 1px solid var(--border-soft);
  display: flex; align-items: center; justify-content: space-between;
}
.chat-messages {
  flex: 1; overflow-y: auto; padding: 16px 20px;
  display: flex; flex-direction: column; gap: 10px;
}
.chat-message { display: flex; gap: 10px; }
.chat-message .avatar { width: 32px; height: 32px; font-size: 12px; flex-shrink: 0; }
.chat-message-body { flex: 1; min-width: 0; }
.chat-message-meta { font-size: 12px; color: var(--fg-muted); margin-bottom: 2px; }
.chat-message-meta strong { color: var(--fg-primary); font-weight: 500; }
.chat-message-text { white-space: pre-wrap; word-break: break-word; font-size: 14px; line-height: 1.5; }
.chat-message-actions { opacity: 0; transition: opacity 0.1s; display: flex; gap: 4px; margin-top: 4px; }
.chat-message:hover .chat-message-actions { opacity: 1; }
.chat-reactions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.reaction-pill {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg-subtle); border: 1px solid var(--border-soft);
  border-radius: 999px; padding: 2px 8px; font-size: 12px; cursor: pointer;
}
.reaction-pill.mine { background: var(--brand); color: var(--brand-fg); border-color: transparent; }
.chat-composer {
  border-top: 1px solid var(--border-soft); padding: 12px 16px;
  display: flex; gap: 8px; align-items: flex-end;
}
.chat-composer textarea {
  flex: 1; min-height: 36px; max-height: 160px; resize: none;
  border: 1px solid var(--border-soft); border-radius: var(--radius);
  padding: 8px 12px; font: inherit; font-size: 14px; background: var(--bg);
  color: var(--fg-primary);
}

/* Payslip editor — itemized allowance / deduction / loan rows.
   Classes (not inline styles) so the amount field can go responsive. */
.ps-item-row { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.ps-item-label { flex: 1; min-width: 0; }
.ps-item-amt { width: 130px; flex: none; }
.ps-loan-name { flex: 1; min-width: 0; font-size: 13px; }
.ps-ded-row { border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 8px; margin-bottom: 6px; }
.ps-ded-row .ps-item-row { margin-bottom: 0; }
.ps-ded-reason { width: 100%; margin-top: 6px; font-size: 12px; }

/* Responsive table → cards. Opt a table in with `.table-cards` (+ its wrapper
   `.table-cards-wrap`) and give each <td> a data-label. Below 640px each row
   becomes a stacked label/value card instead of horizontally scrolling. */
@media (max-width: 640px) {
  .table-cards-wrap { overflow: visible; border: none; background: transparent; border-radius: 0; }
  .table-cards thead { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .table-cards, .table-cards tbody { display: block; }
  .table-cards tbody tr {
    display: block;
    border: 1px solid var(--border-soft);
    border-radius: var(--radius-lg);
    background: var(--bg);
    padding: 4px 14px;
    margin-bottom: 10px;
  }
  .table-cards tbody tr:hover { background: var(--bg); }
  .table-cards tbody tr:last-child td { border-bottom: none; }  /* override base rule scoping */
  .table-cards td {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 9px 0;
    text-align: right;
    border-bottom: 1px solid var(--border-soft);
    white-space: normal;
    /* Long unbreakable values (emails, account numbers, codes) wrap to the next
       line instead of forcing the card — and the page — wider than the screen. */
    overflow-wrap: anywhere;
    min-width: 0;
  }
  .table-cards td:last-child { border-bottom: none; }
  .table-cards td::before {
    content: attr(data-label);
    text-align: left;
    flex: 0 0 auto;
    font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--fg-muted);
  }
  /* Cells with no label (chevron, action buttons) span full width, right-aligned. */
  .table-cards td[data-label=""]::before, .table-cards td:not([data-label])::before { content: none; }
  .table-cards td[data-label=""] { justify-content: flex-end; padding-top: 4px; }
  /* When the stacked table sits directly inside a .card (no card-body padding),
     inset the item-cards so they float inside the section border. */
  .card > .table-cards-wrap { padding: 12px 12px 2px; }
  /* Same inset when nested in a padding-0 card-body (e.g. the #/me cards). */
  .card-body > .table-cards-wrap { padding: 4px 12px 10px; }
}

/* =========================================================================
   TABLES
   ========================================================================= */
.table-wrap {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg);
}
.table { width: 100%; border-collapse: collapse; }
.table th, .table td {
  padding: 12px 16px;
  text-align: left;
  font-size: 13px;
  border-bottom: 1px solid var(--border-soft);
}
.table th {
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
  background: var(--bg-subtle);
  white-space: nowrap;
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background 100ms; }
.table tbody tr:hover { background: var(--bg-subtle); }
.table .row-actions { opacity: 0; transition: opacity 120ms; }
.table tr:hover .row-actions { opacity: 1; }

/* =========================================================================
   AVATAR
   ========================================================================= */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--bg-subtle);
  color: var(--fg-secondary);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  border: 1px solid var(--border-soft);
  overflow: hidden;
  flex-shrink: 0;
}
.avatar-sm { width: 24px; height: 24px; font-size: 10px; }
.avatar-lg { width: 48px; height: 48px; font-size: 15px; }
.avatar-xl { width: 64px; height: 64px; font-size: 20px; }
.avatar img { width: 100%; height: 100%; object-fit: cover; }

/* =========================================================================
   APP SHELL
   ========================================================================= */
#app {
  min-height: 100vh;
  background: var(--bg-cream);
}

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
}

/* Sidebar */
.sidebar {
  background: var(--bg);
  border-right: 1px solid var(--border-soft);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}
.sidebar-header {
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-soft);
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--topbar-h);
  position: relative;   /* anchors the org-switcher dropdown (position:absolute) */
}
.org-switcher { transition: background 120ms; }
.org-switcher:hover { background: var(--bg-subtle); }
.sidebar-logo {
  width: 28px; height: 28px;
  border-radius: 7px;
  background: var(--brand);
  color: var(--brand-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 17px;
  overflow: hidden;
}
.sidebar-logo img { width: 100%; height: 100%; object-fit: cover; }

.sidebar-nav { flex: 1; overflow-y: auto; padding: 12px 8px; }
.nav-section-title { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--fg-subtle); padding: 12px 10px 6px; }
.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  color: var(--fg-secondary);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 100ms, color 100ms;
  margin-bottom: 1px;
}
.nav-item:hover { background: var(--bg-subtle); color: var(--fg); }
.nav-item.active { background: var(--fg); color: var(--bg); }
.nav-item.active .nav-icon { color: var(--bg); }
.nav-icon { color: var(--fg-muted); width: 16px; height: 16px; }

/* Unread counter on a nav item (WhatsApp, Mail). Pushed to the right edge by
   margin-left:auto so it sits flush regardless of how long the label is, and
   inverted on the active row where the background is the foreground colour. */
.nav-count {
  margin-left: auto;
  min-width: 18px;
  padding: 1px 6px;
  border-radius: 9px;
  background: var(--brand);
  color: var(--brand-fg);
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
  text-align: center;
}
.nav-item.active .nav-count { background: var(--bg); color: var(--fg); }
.nav-item.active .nav-icon { color: var(--bg); }
.nav-item .nav-badge { margin-left: auto; font-size: 10px; padding: 1px 6px; background: var(--bg-subtle); border-radius: 999px; color: var(--fg-muted); }

.sidebar-footer {
  padding: 12px;
  border-top: 1px solid var(--border-soft);
}
.user-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background 100ms;
}
.user-chip:hover { background: var(--bg-subtle); }

/* Main */
.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  width: 100%;
}

.topbar {
  height: var(--topbar-h);
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 20px;
  position: sticky;
  top: 0;
  z-index: 10;
}
.topbar-title { font-size: 14px; font-weight: 600; color: var(--fg); }
.topbar-search {
  flex: 1;
  max-width: 480px;
  position: relative;
}
.topbar-search .input { padding-left: 34px; background: var(--bg-cream); border-color: transparent; }
.topbar-search .input:focus { background: var(--bg); border-color: var(--border); }

.page {
  padding: 28px 32px 64px;
  max-width: 1280px;
  width: 100%;
  margin: 0 auto;
}
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}
/* Both `<h1 class="page-title">` and `<div class="page-title">` are in use across
   the app. h1–h5 are margin-reset above, so those two already render
   identically — but `<p class="page-subtitle">` was NOT: it kept the browser's
   1em bottom margin, making every header written with a <p> sit 13px taller
   than one written with a <div>. Pinning all four sides here means the markup
   variant can no longer show through. */
.page-title { font-size: 24px; font-weight: 600; letter-spacing: -0.02em; margin: 0; }
.page-subtitle { color: var(--fg-muted); font-size: 13px; margin: 3px 0 0; }

/* =========================================================================
   AUTH (login/signup)
   ========================================================================= */
.auth-layout {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--bg);
}
.auth-panel {
  display: flex;
  flex-direction: column;
  padding: 32px 48px;
  max-width: 560px;
  margin: 0 auto;
  width: 100%;
  justify-content: center;
}
.auth-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 48px;
  position: absolute;
  top: 28px;
  left: 48px;
}
.auth-brand-mark {
  width: 32px; height: 32px;
  background: var(--fg);
  color: var(--bg);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display);
  font-size: 19px;
}
.auth-brand-name { font-family: var(--font-display); font-size: 22px; font-style: italic; }
.auth-heading { font-size: 36px; letter-spacing: -0.03em; font-weight: 500; margin-bottom: 8px; line-height: 1.1; }
.auth-heading .serif { font-style: italic; font-weight: 400; }
.auth-sub { color: var(--fg-muted); font-size: 14px; margin-bottom: 32px; }

.auth-hero {
  background: var(--bg-cream);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 48px;
  position: relative;
  overflow: hidden;
}
.auth-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at 20% 30%, rgba(180, 160, 120, 0.08), transparent 40%),
    radial-gradient(circle at 80% 70%, rgba(120, 140, 110, 0.08), transparent 40%);
}
.auth-hero-quote {
  font-family: var(--font-display);
  font-size: 38px;
  line-height: 1.15;
  letter-spacing: -0.02em;
  max-width: 440px;
  position: relative;
}
.auth-hero-quote em { font-style: italic; }
.auth-hero-attribution { color: var(--fg-muted); font-size: 13px; margin-top: 24px; position: relative; }

/* =========================================================================
   MODAL / DRAWER
   ========================================================================= */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 10, 10, 0.35);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  animation: fadeIn 160ms forwards;
}
@keyframes fadeIn { to { opacity: 1; } }
.modal {
  background: var(--bg);
  border-radius: var(--radius-lg);
  max-width: 520px;
  width: 100%;
  max-height: 90vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-lg);
  transform: translateY(8px);
  animation: slideUp 180ms forwards;
}
@keyframes slideUp { to { transform: translateY(0); } }
.modal-header { padding: 18px 20px; border-bottom: 1px solid var(--border-soft); display: flex; align-items: center; justify-content: space-between; }
.modal-title { font-size: 16px; font-weight: 600; }
.modal-body { padding: 20px; overflow-y: auto; flex: 1; }
.modal-footer { padding: 14px 20px; border-top: 1px solid var(--border-soft); display: flex; gap: 8px; justify-content: flex-end; }
.modal-close { color: var(--fg-muted); padding: 4px; border-radius: 6px; }
.modal-close:hover { background: var(--bg-subtle); color: var(--fg); }

/* Construction 3-phase stepper */
.con-stepper { display: flex; align-items: center; gap: 8px; margin: 14px 0 4px; flex-wrap: wrap; }
.con-step { display: flex; align-items: center; gap: 8px; }
.con-step-dot {
  width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600; background: var(--bg-subtle); color: var(--fg-muted);
  border: 1px solid var(--border-soft); flex: none;
}
.con-step-label { font-size: 13px; color: var(--fg-muted); font-weight: 500; }
.con-step.current .con-step-dot { background: var(--brand); color: var(--brand-fg); border-color: var(--brand); }
.con-step.current .con-step-label { color: var(--fg); }
.con-step.done .con-step-dot { background: var(--success, #15803d); color: #fff; border-color: transparent; }
.con-step.done .con-step-label { color: var(--fg-secondary); }
.con-step-bar { flex: 1 1 32px; min-width: 24px; height: 2px; background: var(--border-soft); border-radius: 2px; }
.con-step-bar.done { background: var(--success, #15803d); }
@media (max-width: 640px) { .con-step-label { display: none; } .con-step-bar { min-width: 16px; } }

/* Bill of Quantities (construction) */
.boq-section-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--border-soft); background: var(--bg-subtle);
}
.boq-typechips { display: flex; gap: 10px; flex-wrap: wrap; }
.boq-typechip {
  display: flex; align-items: center; gap: 8px; padding: 8px 12px;
  border: 1px solid var(--border-soft); border-radius: var(--radius); background: var(--bg);
}
.boq-typechip > span { font-size: 16px; }

/* Construction schedule filter bar (Program of Works) */
.con-sched-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }

/* Unsaved-draft restore banner (dialog auto-save) */
.draft-restore-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 10px 12px;
  background: var(--warning-soft); border: 1px solid var(--warning); border-radius: var(--radius);
}
.draft-restore-text { font-size: 13px; color: var(--warning); font-weight: 500; }

/* Drawer (right-side slide-in) */
.drawer {
  background: var(--bg);
  width: 560px;
  max-width: 95vw;
  height: 100vh;
  margin-left: auto;
  margin-right: 0;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  animation: slideLeft 200ms forwards;
  border-left: 1px solid var(--border);
}
@keyframes slideLeft { to { transform: translateX(0); } }
.overlay.drawer-overlay { padding: 0; justify-content: flex-end; }
.drawer .modal-body { flex: 1; }

/* =========================================================================
   DROPDOWN
   ========================================================================= */
.dropdown { position: relative; display: inline-block; }
.dropdown-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 200px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 4px;
  z-index: 50;
  animation: fadeIn 100ms;
}
.dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--fg-secondary);
  cursor: pointer;
  width: 100%;
  text-align: left;
}
.dropdown-item:hover { background: var(--bg-subtle); color: var(--fg); }
.dropdown-divider { height: 1px; background: var(--border-soft); margin: 4px 0; }

/* -------------------------------------------------------------------------
   COMBOBOX (comboboxHtml / wireCombobox in core/ui.js)
   The menu sits IN FLOW rather than absolutely positioned: these live inside
   .modal-body, which scrolls and clips, so an absolute menu would be cut off
   at the dialog edge. Open, it pushes the fields below it down.
   ------------------------------------------------------------------------- */
.combo { position: relative; }
.combo-menu {
  position: static;
  right: auto;
  min-width: 0;
  width: 100%;
  max-height: 232px;
  overflow-y: auto;
  margin-top: 4px;
  animation: none;
}
.combo-item { justify-content: flex-start; }
.combo-item.active { background: var(--bg-subtle); color: var(--fg); }
.combo-item-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combo-item-meta { margin-left: auto; flex: none; padding-left: 10px; color: var(--fg-muted); font-size: 12px; }
.combo-empty { cursor: default; color: var(--fg-muted); }
.combo-empty:hover { background: transparent; color: var(--fg-muted); }

/* =========================================================================
   TOAST
   ========================================================================= */
#toasts {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.toast {
  background: var(--fg);
  color: var(--bg);
  padding: 10px 14px;
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: toastIn 180ms;
  max-width: 360px;
  display: flex;
  align-items: center;
  gap: 8px;
}
@keyframes toastIn { from { transform: translateX(20px); opacity: 0; } }
.toast-success { background: var(--success); }
.toast-danger { background: var(--danger); }

/* =========================================================================
   EMPTY STATE
   ========================================================================= */
.empty {
  padding: 48px 24px;
  text-align: center;
  color: var(--fg-muted);
}
.empty-icon {
  width: 48px; height: 48px;
  margin: 0 auto 16px;
  background: var(--bg-subtle);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--fg-subtle);
}
.empty-title { color: var(--fg); font-weight: 500; margin-bottom: 4px; }

/* =========================================================================
   SPINNER
   ========================================================================= */
.spinner {
  width: 16px; height: 16px;
  border: 2px solid var(--border);
  border-top-color: var(--fg);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }
.spinner-lg { width: 28px; height: 28px; border-width: 3px; }
.spinner-sm { width: 12px; height: 12px; border-width: 2px; }
.loading-center { display: flex; align-items: center; justify-content: center; padding: 60px; }

/* Loading placeholder. Callers give it an inline height and nothing else, so the
   background and the shimmer have to live here — without them the eleven
   `<div class="skeleton" style="height:200px">` in the app are blank space. */
.skeleton {
  background: linear-gradient(90deg, var(--bg-subtle) 25%, var(--border-soft) 50%, var(--bg-subtle) 75%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
  border-radius: var(--radius);
  width: 100%;
}
@keyframes skeleton-shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; background: var(--bg-subtle); }
}

/* =========================================================================
   TABS
   ========================================================================= */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border-soft); margin-bottom: 20px; }
/* On narrow screens the tab strip scrolls horizontally instead of bleeding off
   the edge (which html overflow-x:clip would otherwise cut off unreachably). */
@media (max-width: 720px) {
  .tabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { white-space: nowrap; flex: 0 0 auto; }
}

/* Module name is shown by the page <h1>; the topbar copy was a duplicate. */
.topbar-title { display: none; }

/* Collapsible filter panel (employee directory). Desktop: filters sit inline in
   the toolbar. Mobile: they collapse behind a "Filters" button and drop down as
   a stacked panel so they never push the table off-screen. */
@media (min-width: 721px) {
  .filter-collapse { display: contents; }
  .filter-toggle { display: none !important; }
}
@media (max-width: 720px) {
  .filter-collapse { display: none; width: 100%; }
  .filter-collapse.open {
    display: flex; flex-direction: column; gap: 10px; width: 100%;
    background: var(--bg); border: 1px solid var(--border-soft);
    border-radius: var(--radius); padding: 12px; margin-top: 2px;
  }
  .filter-collapse.open .select { max-width: none !important; width: 100%; }
  .filter-toggle { display: inline-flex; }
}
.tab {
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--fg-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 100ms, border-color 100ms;
}
.tab:hover { color: var(--fg); }
.tab.active { color: var(--fg); border-bottom-color: var(--fg); }
/* Most tabs are <a>. Mail's folders are <button> — same strip, so the UA's
   button chrome has to go or one module's tabs come out boxed and grey. */
button.tab { background: none; border: 0; border-bottom: 2px solid transparent; font: inherit; font-size: 13px; font-weight: 500; }
button.tab.active { border-bottom-color: var(--fg); }
/* An unread count riding along in a tab. Deliberately not `.badge`: a pill on
   every folder turns a quiet strip into a scoreboard. */
.tab-count { font-size: 11px; color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.tab.active .tab-count { color: var(--fg); }

/* =========================================================================
   STAT CARDS (dashboard)
   ========================================================================= */
.stat {
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
}
.stat-label { font-size: 12px; color: var(--fg-muted); margin-bottom: 6px; }
.stat-value { font-family: var(--font-display); font-size: 38px; letter-spacing: -0.02em; line-height: 1; }
.stat-meta { font-size: 11px; color: var(--fg-muted); margin-top: 6px; }

/* ---- Home dashboard ---- */
/* Module stat cards double as a link into the module. */
.home-mod-card { cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease; }
.home-mod-card:hover { border-color: var(--border-strong); }
.home-mod-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.home-mod-reports {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 12px;
  font-size: 13px; font-weight: 500; color: var(--fg-muted); text-decoration: none;
}
.home-mod-reports:hover { color: var(--brand); }
/* Quick-action chips */
.quick-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.quick-action {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 14px; border: 1px solid var(--border-soft); border-radius: var(--radius-lg);
  background: var(--bg); color: var(--fg); font: inherit; font-size: 14px; font-weight: 500;
  cursor: pointer; transition: border-color .15s ease, color .15s ease;
}
.quick-action:hover { border-color: var(--brand); color: var(--brand); }
.quick-action svg { color: var(--fg-muted); flex-shrink: 0; }
.quick-action:hover svg { color: var(--brand); }
/* Two-column "set up + recent activity" row; stacks on mobile. */
.home-split { display: grid; grid-template-columns: 2fr 1fr; gap: 20px; }
@media (max-width: 768px) { .home-split { grid-template-columns: 1fr; } }

/* =========================================================================
   RESPONSIVE
   ========================================================================= */
.sidebar-backdrop {
  display: none;
  position: fixed; inset: 0;
  background: rgba(10,10,10,0.25);
  z-index: 40;
}

@media (max-width: 900px) {
  .auth-layout { grid-template-columns: 1fr; }
  .auth-hero { display: none; }
  .auth-brand { position: static; margin-bottom: 24px; }

  .shell { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed;
    left: 0; top: 0;
    width: 280px;
    z-index: 50;
    transform: translateX(-100%);
    transition: transform 200ms;
    box-shadow: var(--shadow-lg);
  }
  .sidebar.open { transform: translateX(0); }
  .sidebar-backdrop.open { display: block; }

  .topbar { padding: 0 12px; }
  .topbar-menu-btn { display: flex !important; }

  .page { padding: 20px 16px 48px; }
  /* Title + actions stack instead of fighting for one row on a phone. */
  .page-header { flex-wrap: wrap; }
  /* …and the action cluster itself wraps, so multiple buttons (e.g. HR's
     Resolve / Export / Import / Add) don't force the page wider than the
     screen and trigger sideways scroll. */
  .page-header > .flex { flex-wrap: wrap; }

  .drawer { width: 100%; }
  .modal { max-width: 100%; }
  .overlay { padding: 12px; }
  .modal-footer { flex-wrap: wrap; }

  .auth-panel { padding: 32px 24px; }
  .auth-heading { font-size: 28px; }

  /* iOS Safari zooms the page when a focused input's font is < 16px. Bump
     every form control to 16px on mobile to stop the lurch-on-tap. */
  .input, .select, .textarea { font-size: 16px; }

  /* Wide tables: .table-wrap is overflow:hidden for rounded corners, which
     CLIPS content on a phone. Switch to horizontal scroll so nothing is lost. */
  .table-wrap, .table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* Detail lists stack label over value instead of a fixed 140px column. */
  .dl > div { grid-template-columns: 1fr; gap: 2px; }

  /* Break long unbreakable strings (emails, URLs, account numbers, codes) so
     they wrap inside the frame instead of pushing content off-screen. Scoped to
     content containers — not to .truncate cells, which keep their ellipsis. */
  .dl > div > *, .list-row, .stat-value, .badge, .page-title, .card-body p, .text-sm { overflow-wrap: anywhere; }
}

/* Touch devices have no :hover — reveal hover-gated actions so edit / delete /
   react buttons aren't permanently invisible on a phone. */
@media (hover: none) {
  .table .row-actions,
  .chat-message-actions { opacity: 1; }
}

/* Bigger tap targets on touch pointers (44px is the accessibility guideline). */
@media (pointer: coarse) {
  .btn { min-height: 40px; }
  .btn-sm { min-height: 34px; }
  .btn-icon, .modal-close { min-width: 40px; min-height: 40px; }
}

/* Very small / older phones (down to 320px). */
@media (max-width: 520px) {
  .page { padding: 16px 12px 40px; }
  .page-title { font-size: 20px; }
  .overlay { padding: 8px; }
  .stat-card { padding: 14px; }
  .stat-value { font-size: 19px; }
  /* Footer actions stretch + wrap so they never get clipped or squeezed. */
  .modal-footer { gap: 8px; }
  .modal-footer .btn { flex: 1 1 auto; }

  /* Topbar: drop the flex spacer (scoped to topbar) so search uses the row
     instead of splitting it 50/50 with the spacer and shrinking to a sliver. */
  .topbar .flex-1 { display: none; }
  .topbar-search { max-width: none; }
  .topbar-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  /* Payslip rows: shrink the amount field so the label keeps usable width
     on a narrow phone (the fields scroll their own content if needed). */
  .ps-item-amt { width: 104px; }
}

.topbar-menu-btn { display: none; }

/* =========================================================================
   UTILITY: SCROLL
   ========================================================================= */
.scrollable { overflow-y: auto; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 10px; border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

/* =========================================================================
   COLOR SWATCH GRID (for brand picker)
   ========================================================================= */
.swatch-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px; }
.swatch {
  aspect-ratio: 1;
  border-radius: 8px;
  cursor: pointer;
  border: 2px solid transparent;
  transition: transform 100ms;
  position: relative;
}
.swatch:hover { transform: scale(1.05); }
.swatch.active { border-color: var(--fg); }
.swatch.active::after {
  content: '✓';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-weight: 700;
  font-size: 13px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}

/* =========================================================================
   PERMISSION GRID (role editor)
   ========================================================================= */
.perm-group {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 12px;
}
.perm-group-title { font-weight: 600; font-size: 13px; margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
.perm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 0;
  border-top: 1px solid var(--border-soft);
}
.perm-row:first-of-type { border-top: none; }
.perm-label { font-size: 13px; }
.perm-desc { font-size: 11px; color: var(--fg-muted); }


/* Progress bar */
.progress-bar { position: relative; width: 100%; height: 6px; background: var(--bg-subtle); border-radius: 999px; overflow: hidden; }
.progress-bar-fill { position: absolute; top: 0; left: 0; height: 100%; background: var(--brand); border-radius: 999px; transition: width 0.3s ease; }

/* Segmented toggle (e.g. Email / Phone on login) */
.seg-toggle { display: inline-flex; background: var(--bg-subtle); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 3px; gap: 3px; }
.seg-btn { padding: 6px 16px; border-radius: calc(var(--radius) - 3px); font-size: 13px; font-weight: 500; color: var(--fg-muted); transition: background 120ms, color 120ms; }
.seg-btn.active { background: var(--bg); color: var(--fg); box-shadow: var(--shadow-sm); }

/* Platform notifications — bell dropdown panel + banner */
.notif-panel {
  position: absolute; top: calc(100% + 6px); right: 0;
  width: 340px; max-width: calc(100vw - 24px);
  background: var(--bg); border: 1px solid var(--border-soft);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  z-index: 60; overflow: hidden;
}
.notif-panel-head { padding: 10px 14px; font-weight: 600; font-size: 13px; border-bottom: 1px solid var(--border-soft); }
.notif-panel-body { max-height: 360px; overflow-y: auto; }
.notif-item { display: flex; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--border-soft); align-items: flex-start; }
.notif-item:last-child { border-bottom: none; }
.notif-item.is-read { opacity: 0.55; }
.notif-panel-foot { display: flex; align-items: center; gap: 6px; justify-content: center; padding: 11px; font-size: 13px; font-weight: 500; color: var(--fg); border-top: 1px solid var(--border-soft); background: var(--bg-subtle); cursor: pointer; }
.notif-panel-foot:hover { background: var(--bg-cream); }
.notif-banner-item { display: flex; align-items: center; gap: 12px; padding: 10px 16px; font-size: 13px; background: #FEF9E7; border-bottom: 1px solid rgba(10,10,10,0.06); }
.notif-banner-item.is-critical { background: #FDECEA; }

/* Public disbursement page: hide action buttons when printing. */
@media print { .dsb-actions { display: none !important; } }

/* Inline alerts (form-level status messages) */
.alert { border-radius: var(--radius); padding: 10px 12px; font-size: 13px; line-height: 1.45; border: 1px solid transparent; }
.alert-danger  { background: rgba(220,38,38,0.08);  border-color: rgba(220,38,38,0.25);  color: var(--danger); }
.alert-success { background: rgba(22,163,74,0.08);  border-color: rgba(22,163,74,0.25);  color: var(--success); }
.alert-info    { background: rgba(37,99,235,0.08);  border-color: rgba(37,99,235,0.22);  color: var(--info); }
/* Warning banner: amber wash + a left accent, but DARK body text so it reads
   cleanly on the cream UI (orange-on-cream was too low-contrast). */
.alert-warning {
  background: rgba(193,128,24,0.10);
  border-color: rgba(193,128,24,0.30);
  border-left: 3px solid rgba(193,128,24,0.75);
  color: var(--fg);
}
.alert-warning strong { color: var(--fg); }
.alert-warning .text-sm { color: var(--fg-secondary); }
.alert-warning .attn-chip {
  background: var(--bg);
  color: var(--fg);
  border: 1px solid rgba(193,128,24,0.45);
  font-weight: 500;
}
.alert-warning .attn-chip:hover { border-color: rgba(193,128,24,0.85); }

/* Text color utilities */
.text-success { color: var(--success); }
.text-danger  { color: var(--danger); }
.text-warning { color: var(--warning); }
.text-info    { color: var(--info); }

/* Household ledger row: edit/delete sit on the left, revealed on hover so they
   don't clutter every row. On touch devices (no hover) they stay visible. */
.hh-led-row .hh-led-actions { opacity: 0; transition: opacity .12s ease; }
.hh-led-row:hover .hh-led-actions,
.hh-led-row:focus-within .hh-led-actions { opacity: 1; }
@media (hover: none) { .hh-led-row .hh-led-actions { opacity: 1; } }

/* =============================================================================
   DOOR CHECK-IN SCANNER (#/events/<id>/checkin)
   =============================================================================
   Designed for one hand, in the dark, with a queue forming. Everything is
   bigger than the rest of the app on purpose: the steward is holding a phone at
   arm's length and glancing, not reading. */

.ck-wrap { max-width: 560px; margin: 0 auto; }

/* The camera frame. A fixed aspect box so the layout doesn't jump between
   "camera off" and a stream arriving at whatever resolution the device gives. */
.ck-stage {
  /* min-height is the fallback, not decoration: aspect-ratio is Safari 15+ and
     the likely device at the door is an older phone. */
  position: relative; width: 100%; aspect-ratio: 4 / 3; min-height: 260px;
  background: #111; border-radius: var(--radius-lg, 14px); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.ck-stage video { width: 100%; height: 100%; object-fit: cover; display: block; }
.ck-stage-off { color: rgba(255,255,255,.72); text-align: center; padding: 24px; }

/* Reticle — a corner-bracket frame, not a full box, so it doesn't compete with
   the QR's own quiet zone. */
.ck-reticle {
  position: absolute; inset: 18% 14%; pointer-events: none;
  border-radius: 12px;
  box-shadow: 0 0 0 100vmax rgba(0,0,0,.32);
}
.ck-reticle::before, .ck-reticle::after,
.ck-reticle > i::before, .ck-reticle > i::after {
  content: ''; position: absolute; width: 26px; height: 26px;
  border: 3px solid rgba(255,255,255,.92);
}
.ck-reticle::before { top: -2px; left: -2px;  border-right: 0; border-bottom: 0; border-radius: 10px 0 0 0; }
.ck-reticle::after  { top: -2px; right: -2px; border-left: 0;  border-bottom: 0; border-radius: 0 10px 0 0; }
.ck-reticle > i::before { bottom: -2px; left: -2px;  border-right: 0; border-top: 0; border-radius: 0 0 0 10px; }
.ck-reticle > i::after  { bottom: -2px; right: -2px; border-left: 0;  border-top: 0; border-radius: 0 0 10px 0; }

.ck-cam-actions {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 10px;
  display: flex; gap: 8px; justify-content: center;
  background: linear-gradient(to top, rgba(0,0,0,.55), transparent);
}
.ck-cam-actions .btn { backdrop-filter: blur(6px); }

/* The verdict. Colour is the message — the steward reads the band before the
   words. Deliberately loud; this is the only place in Peepu that shouts. */
.ck-verdict {
  border-radius: var(--radius-lg, 14px); padding: 18px 18px 16px;
  border: 1px solid transparent; margin-top: 14px;
}
.ck-verdict-name { font-size: 1.5rem; font-weight: 600; line-height: 1.2; word-break: break-word; }
.ck-verdict-head { font-size: .78rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 6px; }
.ck-verdict-note { font-size: .875rem; margin-top: 6px; }
/* The table, on admission. Second only to the name in size, because it is the
   next thing out of the steward's mouth. */
.ck-table {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 10px; padding: 6px 12px; border-radius: 999px;
  background: rgba(0,0,0,.06); border: 1px solid currentColor;
  font-size: 1.05rem; font-weight: 600; letter-spacing: .01em;
}
.ck-verdict-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.ck-ok        { background: #e7f6ec; border-color: #b7e0c5; color: #14532d; }
.ck-warn      { background: #fdf3e2; border-color: #f0d9ad; color: #6b4708; }
.ck-bad       { background: #fdeaea; border-color: #f3c2c2; color: #7f1d1d; }
.ck-neutral   { background: var(--bg-subtle); border-color: var(--border-soft); color: var(--fg); }
.ck-verdict .btn { border-color: currentColor; }

/* Party stepper: how many actually walked in. */
.ck-party { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.ck-party button {
  width: 40px; height: 40px; border-radius: 999px; font-size: 20px; line-height: 1;
  border: 1px solid currentColor; background: transparent; color: inherit; cursor: pointer;
}
.ck-party button:disabled { opacity: .35; cursor: default; }
.ck-party-n { font-size: 1.25rem; font-weight: 600; min-width: 2ch; text-align: center; }

/* Counters strip */
.ck-counts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px; }
.ck-count { background: var(--bg-subtle); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 10px 12px; }
.ck-count-n { font-size: 1.35rem; font-weight: 600; line-height: 1.1; }
.ck-count-l { font-size: .68rem; text-transform: uppercase; letter-spacing: .08em; color: var(--fg-muted, var(--fg-secondary)); }

/* Recent scans */
.ck-recent-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--border-soft); font-size: .875rem; }
.ck-dot { width: 8px; height: 8px; border-radius: 999px; flex: 0 0 auto; }

/* Search results in the manual fallback */
.ck-hit { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--border-soft); }
.ck-hit:first-child { border-top: 0; }

/* Unsynced badge — writes that failed and are waiting to retry. Must be
   impossible to miss: an unsynced scan is a guest who is inside the building
   but not in the report. */
.ck-unsynced { background: rgba(193,128,24,.14); border: 1px solid rgba(193,128,24,.4); color: var(--fg); border-radius: 999px; padding: 3px 10px; font-size: .75rem; font-weight: 600; }

/* =============================================================================
   VENUE FLOOR PLAN  (#/events/<id>/seating)
   =============================================================================
   The canvas is an SVG whose viewBox is the room in METRES, so every coordinate
   in the code is a real-world measurement and the same markup prints correctly
   at any size. Strokes use vector-effect so they stay hairlines as it scales. */

.fp-layout { display: grid; grid-template-columns: 1fr 300px; gap: 16px; align-items: start; }
@media (max-width: 980px) { .fp-layout { grid-template-columns: 1fr; } }

/* The area outside the room reads as off-floor, so overflow is obvious. */
.fp-stage {
  position: relative; background: var(--bg-subtle);
  border: 1px solid var(--border-soft); border-radius: var(--radius-lg, 14px);
  overflow: hidden;
}
.fp-svg { display: block; width: 100%; height: auto; touch-action: none; }
.fp-floor { fill: var(--bg); }
/* The venue's real walls. Drawn over the grid, under the furniture: the canvas
   extends past it (the floor is boundless) so this is the only thing that still
   says "the hall is 20 by 14". */
.fp-room { fill: none; stroke: var(--border-strong); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.fp-grid line { stroke: var(--border-soft); stroke-width: .5; vector-effect: non-scaling-stroke; opacity: .55; }

.fp-item { cursor: grab; }
.fp-item.is-dragging { cursor: grabbing; }
.fp-item .fp-body { vector-effect: non-scaling-stroke; stroke-width: 1.5; }
.fp-item.is-selected .fp-body { stroke: var(--brand); stroke-width: 3; }
.fp-chair { fill: var(--bg); stroke: var(--fg-muted); stroke-width: 1; vector-effect: non-scaling-stroke; opacity: .8; }
.fp-chair.is-taken { fill: var(--brand); stroke: var(--brand); opacity: 1; }
/* NO font-size here. The viewBox is in metres, so a CSS px on an SVG <text>
   resolves to a user unit — `font-size: 11px` meant eleven METRES of letter and
   buried the plan. Size is set per element, in metres, by seatLabelSize(). CSS
   would win over the presentation attribute, so it must stay out of it. */
.fp-label { font-weight: 600; text-anchor: middle; dominant-baseline: middle; fill: var(--fg); pointer-events: none; }
.fp-sub { text-anchor: middle; dominant-baseline: middle; fill: var(--fg-muted); pointer-events: none; }

/* Tables read as objects; areas read as zones — filled flat, no chair ring. */
.fp-table .fp-body { fill: var(--bg); stroke: var(--fg-secondary); }
.fp-table.is-full .fp-body { fill: var(--success-soft, #e7f6ec); stroke: #7fb894; }
.fp-table.is-over .fp-body { fill: #fdeaea; stroke: #d98b8b; }
.fp-area .fp-body { stroke-dasharray: 4 3; }

.fp-toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 12px; }
.fp-hint { font-size: 12px; color: var(--fg-muted); }

/* Guest rail */
.fp-rail { position: sticky; top: 12px; }
.fp-guest {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 8px 10px; border: 1px solid transparent; border-radius: 8px;
  background: transparent; font: inherit; color: inherit; cursor: pointer;
}
.fp-guest:hover { background: var(--bg-subtle); }
/* "Armed" — tapped in the rail, waiting for a table. Tap-to-arm beats drag:
   it is the only model that works identically with a mouse and a thumb. */
.fp-guest.is-armed { background: var(--brand); color: var(--brand-fg); border-color: var(--brand); }
.fp-guest.is-armed .muted, .fp-guest.is-armed .text-xs { color: inherit; opacity: .8; }
.fp-armed-banner {
  position: sticky; top: 0; z-index: 2;
  background: var(--brand); color: var(--brand-fg);
  border-radius: 8px; padding: 8px 10px; font-size: 13px; margin-bottom: 10px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.fp-stage.is-arming .fp-table { cursor: copy; }
.fp-stage.is-arming .fp-table .fp-body { stroke-dasharray: 5 3; }

/* List view */
/* Client detail: the summary rail drops under the main column on narrow
   screens rather than squeezing both. */
@media (max-width: 900px) { .cl-layout { grid-template-columns: 1fr !important; } }
/* Invoice detail: same rail, and the preview iframe shortens so the actions and
   the details are still reachable without scrolling past a full page of A4. */
@media (max-width: 900px) {
  .invd-layout { grid-template-columns: 1fr !important; }
  .invd-layout #invd-frame { height: 520px; }
}

.fp-tablecard { border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 12px; }
.fp-tablecard + .fp-tablecard { margin-top: 10px; }
.fp-seatrow { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-top: 1px solid var(--border-soft); font-size: 14px; }
.fp-seatrow:first-of-type { border-top: 0; }

/* Capacity meter */
.fp-meter { height: 5px; border-radius: 999px; background: var(--bg-subtle); overflow: hidden; margin-top: 6px; }
.fp-meter > span { display: block; height: 100%; background: var(--brand); }
.fp-meter.is-over > span { background: var(--danger); }

/* =========================================================================
   ACTIVITY — the feed row and the detail dialog
   ========================================================================= */
.act-row {
  display: flex;
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 12px 20px;
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
  text-align: left;
  transition: background 120ms;
}
.act-row:last-child { border-bottom: none; }
.act-row:hover { background: var(--bg-cream); }
.act-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.act-row-count { flex: none; }
/* The chevron is a hint that the row opens something, not a control — it sits
   quiet until the row is hovered. */
.act-row-chev { flex: none; display: flex; color: var(--fg-muted); opacity: 0.45; transition: opacity 120ms; }
.act-row:hover .act-row-chev { opacity: 1; }

.act-detail-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.act-detail-entity { font-size: 13px; color: var(--fg-muted); text-transform: capitalize; }
.act-detail-subject { font-weight: 600; font-size: 14px; }
.act-detail-meta {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; margin-bottom: 14px;
  background: var(--bg-subtle); border-radius: var(--radius);
}

.act-changes { display: flex; flex-direction: column; gap: 2px; }
.act-change { padding: 10px 0; border-bottom: 1px solid var(--border-soft); }
.act-change:last-child { border-bottom: none; }
.act-change-field { font-size: 12px; color: var(--fg-muted); margin-bottom: 4px; }
.act-change-vals { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; }
/* The old value is struck through rather than merely greyed: at a glance the
   eye needs to know which of the two is current without reading the arrow. */
.act-change-from { text-decoration: line-through; color: var(--fg-muted); overflow-wrap: anywhere; }
.act-change-to { font-weight: 600; overflow-wrap: anywhere; }
.act-change-vals svg { flex: none; color: var(--fg-muted); }
.act-change-redacted { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--fg-muted); font-style: italic; }

.act-nochanges { font-size: 13px; color: var(--fg-muted); padding: 12px 0; }
.act-extras { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border-soft); display: flex; flex-direction: column; gap: 6px; }
.act-extra { display: flex; justify-content: space-between; gap: 12px; font-size: 12px; }

/* =========================================================================
   EMPLOYEE DETAIL (#/hr/employees/<id>)
   ========================================================================= */
.emp-detail-ident { display: flex; align-items: center; gap: 14px; margin-top: 8px; }

/* The pay breakdown: gross, each deduction, then net. Rules rather than inline
   styles so the ≤640px table-card treatment can reach them. */
.pay-line {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 9px 0; border-bottom: 1px solid var(--border-soft);
}
.pay-line:last-child { border-bottom: none; }
.pay-line-head { border-bottom-color: var(--border); }
.pay-line-amt { color: var(--danger); }
.pay-line-total {
  border-top: 2px solid var(--border); border-bottom: none;
  margin-top: 4px; padding-top: 12px; font-size: 15px;
}

/* =========================================================================
   HR DOCUMENTS — the template editor and the rendered document
   ========================================================================= */
.doc-tmpl-row { cursor: pointer; transition: background 120ms; }
.doc-tmpl-row:hover { background: var(--bg-cream); }
.doc-row-icon { flex: none; display: flex; color: var(--fg-muted); }

/* Body on the left, live preview on the right. Stacks below 900px — a split
   pane on a phone gives two unusable columns instead of one usable one. */
.doc-editor { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 8px; }
@media (max-width: 900px) { .doc-editor { grid-template-columns: 1fr; } }
.doc-editor-pane { min-width: 0; }
.doc-editor-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 12px; font-weight: 500; color: var(--fg-secondary); margin-bottom: 6px;
}
.doc-body-input {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12.5px; line-height: 1.6; min-height: 340px; resize: vertical; white-space: pre;
  overflow-wrap: normal; overflow-x: auto;
}
.doc-help {
  background: var(--bg-subtle); border-radius: var(--radius); padding: 10px 12px;
  margin-bottom: 8px; font-size: 12px; color: var(--fg-secondary);
  display: flex; flex-direction: column; gap: 4px;
}
.doc-help code {
  background: var(--bg); border: 1px solid var(--border-soft); border-radius: 4px;
  padding: 1px 5px; font-size: 11.5px;
}

.doc-tokens { margin-top: 10px; }
.doc-tok-group { margin-bottom: 8px; }
.doc-tok-group-title { font-size: 11px; color: var(--fg-muted); margin-bottom: 4px; }
.doc-tok {
  display: inline-block; margin: 0 4px 4px 0; padding: 3px 9px;
  border: 1px solid var(--border-soft); border-radius: 999px;
  background: var(--bg-subtle); font-size: 11.5px; color: var(--fg-secondary);
  transition: background 120ms, border-color 120ms;
}
.doc-tok:hover { background: var(--bg); border-color: var(--border-strong); color: var(--fg); }

.doc-var-row { display: grid; grid-template-columns: 1fr 1.4fr auto auto; gap: 6px; margin-bottom: 6px; align-items: center; }
@media (max-width: 640px) { .doc-var-row { grid-template-columns: 1fr 1fr; } }

.doc-warn {
  display: flex; gap: 8px; align-items: flex-start; margin-top: 10px;
  padding: 9px 11px; border-radius: var(--radius);
  background: var(--warning-soft); color: var(--warning); font-size: 12px; line-height: 1.5;
}
.doc-warn svg { flex: none; margin-top: 1px; }
.doc-warn code { background: rgba(0,0,0,.06); border-radius: 4px; padding: 1px 4px; }
.doc-warn-danger { background: var(--danger-soft); color: var(--danger); }

/* The document itself. Serif and generously leaded so the preview reads like
   the letter it will become, not like app chrome. */
.doc-paper {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 28px 30px; max-height: 620px; overflow-y: auto;
  font-family: var(--font-display, Georgia, serif); color: var(--fg);
  font-size: 14px; line-height: 1.65;
}
.doc-h1 { font-size: 17px; text-align: center; text-transform: uppercase; letter-spacing: 1px; margin: 0 0 16px; font-weight: 600; }
.doc-h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .6px; margin: 20px 0 7px; font-weight: 600; }
.doc-p { margin: 0 0 11px; }
.doc-ul { margin: 0 0 11px 18px; padding: 0; }
.doc-ul li { margin-bottom: 4px; }
.doc-terms { margin: 0 0 14px; display: block; }
.doc-terms > div { display: flex; gap: 12px; padding: 5px 0; border-bottom: 1px solid var(--border-soft); }
.doc-terms dt { width: 40%; font-weight: 600; margin: 0; font-size: 13px; }
.doc-terms dd { margin: 0; flex: 1; font-size: 13px; }
.doc-rule { border: none; border-top: 1px solid var(--border); margin: 20px 0; }
.doc-pagebreak { border-top: 1px dashed var(--border-strong); margin: 22px 0; text-align: center; }
.doc-pagebreak span { display: inline-block; transform: translateY(-9px); background: var(--bg); padding: 0 8px; font-size: 10.5px; color: var(--fg-muted); font-family: var(--font-body); }
.doc-sign { margin-top: 28px; }
.doc-ack { margin-top: 24px; }
/* Blank space to write in, then the rule, then the caption under it. */
.doc-sign-field { margin: 22px 0 14px; width: 62%; max-width: 320px; }
.doc-sign-rule { height: 26px; border-bottom: 1px solid var(--fg); }
.doc-sign-cap { font-size: 10.5px; color: var(--fg-muted); font-family: var(--font-body); margin-top: 3px; }
.doc-sign-name { margin-top: 6px; }
.doc-fill { display: inline-block; min-width: 190px; border-bottom: 1px solid var(--fg-muted); }
/* An unresolved placeholder must be impossible to miss in a preview. */
.doc-token-missing { background: var(--warning-soft); color: var(--warning); border-radius: 3px; padding: 0 3px; font-family: var(--font-mono, monospace); font-size: 12px; }

.doc-detail-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }

/* -------------------------------------------------------------------------
   PORTAL — "finish setting up your employment"
   The one card that stands between a new hire and the rest of the portal, so
   it is the only place in My space that carries the brand tint.
   ------------------------------------------------------------------------- */
.onb-card { border-color: var(--brand); background: var(--bg-cream); }
.onb-head { display: flex; gap: 12px; align-items: flex-start; }
.onb-icon {
  flex: none; width: 40px; height: 40px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand); color: var(--brand-fg);
}
.onb-title { margin: 0; font-size: 15px; }
.onb-docs { margin-top: 16px; display: flex; flex-direction: column; gap: 8px; }
.onb-doc {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 13px; background: var(--bg); border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.onb-reject { color: var(--danger); }

/* Settings sub-sections inside one card (letterhead, signatory). */
.section-divider { height: 1px; background: var(--border-soft); margin: 22px 0 18px; }
.settings-subhead { margin: 0 0 2px; font-size: 13px; font-weight: 600; color: var(--fg); }

/* -------------------------------------------------------------------------
   ONBOARDING WIZARD
   ------------------------------------------------------------------------- */
.onbw-steps { display: flex; gap: 6px; margin-bottom: 18px; flex-wrap: wrap; }
.onbw-steps span {
  font-size: 11.5px; color: var(--fg-muted); padding: 4px 11px;
  border-radius: 999px; background: var(--bg-subtle); white-space: nowrap;
}
.onbw-steps span.active { background: var(--brand); color: var(--brand-fg); font-weight: 500; }
.onbw-docs { display: flex; flex-direction: column; gap: 8px; }
.onbw-doc {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  padding: 11px 13px; border: 1px solid var(--border-soft); border-radius: var(--radius);
  transition: border-color 120ms, background 120ms;
}
.onbw-doc:hover { border-color: var(--border-strong); background: var(--bg-subtle); }
.onbw-doc input { margin-top: 2px; flex: none; }

/* -------------------------------------------------------------------------
   SUBMISSIONS — Sent → Signed → Approved, per required document
   The three states are the question HR actually asks, so they are a track
   rather than a single status word buried in a list.
   ------------------------------------------------------------------------- */
.sub-row {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 13px 20px; border-bottom: 1px solid var(--border-soft);
}
.sub-row:last-child { border-bottom: none; }
.sub-main { flex: 1 1 200px; min-width: 0; }
/* Fixed widths so the three dots line up vertically down the list — a ragged
   track is unreadable as a column of states, which is the whole point of it. */
.sub-track { display: flex; align-items: center; gap: 0; flex: none; width: 248px; }
.sub-step { display: flex; align-items: center; gap: 6px; padding-right: 14px; position: relative; }
/* The connector between steps, drawn from the step it leaves. */
.sub-step:not(:last-child)::after {
  content: ''; position: absolute; right: 4px; top: 9px;
  width: 6px; height: 1px; background: var(--border-strong);
}
.sub-dot {
  width: 18px; height: 18px; border-radius: 50%; flex: none;
  border: 1.5px solid var(--border-strong); background: var(--bg);
  display: flex; align-items: center; justify-content: center; color: var(--brand-fg);
}
.sub-step.done .sub-dot { background: var(--success); border-color: var(--success); color: #fff; }
.sub-step.bad .sub-dot { border-color: var(--danger); background: var(--danger-soft); }
.sub-step-label { font-size: 11.5px; color: var(--fg-muted); }
.sub-step.done .sub-step-label { color: var(--fg); }
.sub-actions { display: flex; align-items: center; gap: 6px; flex: none; min-width: 132px; justify-content: flex-end; }
@media (max-width: 640px) {
  .sub-row { align-items: flex-start; gap: 10px; }
  .sub-track { order: 3; width: 100%; }
  .sub-actions { min-width: 0; }
  .sub-actions { order: 2; }
}

/* -------------------------------------------------------------------------
   EMPLOYEE HANDBOOK
   ------------------------------------------------------------------------- */
.hb-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.hb-steps { margin: 0; padding-left: 20px; font-size: 13px; color: var(--fg-secondary); }
.hb-steps li { margin-bottom: 8px; }
.hb-excluded { opacity: 0.55; }

/* The three steps in My space. A numbered list, because the order matters:
   you cannot confirm what you have not opened. */
.hb-mysteps { margin: 16px 0 0; padding: 0; list-style: none; counter-reset: hbs; }
.hb-mysteps li {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 11px 13px; margin-bottom: 8px;
  background: var(--bg); border: 1px solid var(--border-soft); border-radius: var(--radius);
  font-size: 13px;
}
.hb-mysteps li::before {
  counter-increment: hbs; content: counter(hbs);
  width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-subtle); color: var(--fg-muted); font-size: 11px; font-weight: 600;
}
.hb-mysteps li.done::before { content: '✓'; background: var(--success); color: #fff; }
.hb-mysteps li > span:first-of-type { flex: 1; min-width: 120px; }
.hb-mysteps li.done > span:first-of-type { color: var(--fg-muted); text-decoration: line-through; }

/* =========================================================================
   EMPLOYEE MASTER-DETAIL (#/hr/employees/<id>)
   The directory stays on the left so reviewing a team is a series of clicks,
   not a series of round trips through the full table.
   ========================================================================= */
.emp-split { display: grid; grid-template-columns: 290px minmax(0, 1fr); align-items: start; }
.emp-split-main { min-width: 0; }
/* `.page` centres itself in a 1280px measure. Inside the split that measure is
   ~290px narrower and no longer centred on the screen, so the detail would sit
   visibly off-axis. Left-align it and let it use the room it has. */
.emp-split-main > .page { margin: 0; max-width: 1180px; }
.emp-back-mobile { display: none; }

.emp-rail {
  position: sticky;
  /* --topbar-h, not a hardcoded number: the topbar height is a variable and
     guessing it leaves the rail either clipped or floating. The rail scrolls
     inside what's left rather than with the page, so the detail can be long
     without dragging the list out of reach. */
  top: var(--topbar-h);
  height: calc(100vh - var(--topbar-h));
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--border);
  background: var(--bg);
}
.emp-rail-head { padding: 18px 14px 10px; border-bottom: 1px solid var(--border-soft); flex: none; }
.emp-rail-search { position: relative; margin-top: 10px; }
.emp-rail-search .input { padding-left: 30px; height: 34px; font-size: 13px; }
.emp-rail-search-icon {
  position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
  display: flex; color: var(--fg-muted); pointer-events: none;
}
.emp-rail-list { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding-bottom: 12px; }

.emp-rail-group {
  display: flex; justify-content: space-between; gap: 8px;
  position: sticky; top: 0; z-index: 1;
  padding: 8px 14px 6px; background: var(--bg-cream);
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--fg-muted); border-bottom: 1px solid var(--border-soft);
}
.emp-rail-group span { font-weight: 500; letter-spacing: 0; text-transform: none; }

.emp-rail-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; color: inherit; text-decoration: none;
  border-left: 2px solid transparent; transition: background 120ms;
}
.emp-rail-row:hover { background: var(--bg-subtle); }
.emp-rail-row.active { background: var(--bg-cream); border-left-color: var(--brand); }
.emp-rail-row.active .emp-rail-name { font-weight: 600; }
.emp-rail-name { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.emp-rail-sub { font-size: 11px; color: var(--fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.emp-rail-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.emp-rail-dot.warn { background: var(--warning); }
.emp-rail-dot.off { background: var(--danger); }
.emp-rail-empty { padding: 24px 14px; font-size: 12.5px; color: var(--fg-muted); }

/* A rail beside a detail pane needs roughly 1000px to be worth having. Below
   that it becomes two cramped columns instead of one usable one, so the detail
   takes the full width and the page's own back link returns. */
@media (max-width: 1000px) {
  .emp-split { display: block; }
  .emp-rail { display: none; }
  .emp-back-mobile { display: inline-flex; align-items: center; gap: 4px; }
}


/* ── Website overview (what #/website opens on) ────────────────────────────
   The module used to open straight into the editor, but most visits are "is it
   up, how is it doing, send me the link" rather than "change the copy". */
.wo-top { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; margin-bottom: 20px; align-items: start; }
.wo-thumb-card { overflow: hidden; }
/* A live thumbnail rather than a screenshot: a stored image goes stale the
   first time anybody edits, and this cannot. The frame is laid out at a real
   desktop width and scaled, so the thumbnail shows the DESKTOP layout — at
   card width the site would render its own mobile breakpoint. */
.wo-thumb { position: relative; height: 260px; overflow: hidden; background: #fff; }
/* Width and scale are set by woFitThumb() from the card's measured width. */
.wo-frame {
  width: 1280px; height: 940px; border: 0;
  transform-origin: top left;
  pointer-events: none;               /* it is a picture, not a page to browse */
}
/* The whole thumbnail is the edit affordance; the button inside it is the
   visible half of that, and appears on hover or focus. */
.wo-thumb-hit {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(8, 8, 56, 0); transition: background 140ms;
  text-decoration: none;
}
.wo-thumb-hit > .btn { opacity: 0; transition: opacity 140ms; }
.wo-thumb-hit:hover { background: rgba(8, 8, 56, .28); }
.wo-thumb-hit:hover > .btn, .wo-thumb-hit:focus-visible > .btn { opacity: 1; }
.wo-thumb-hit:focus-visible { background: rgba(8, 8, 56, .28); outline: 2px solid var(--brand); outline-offset: -2px; }

.wo-split { display: grid; grid-template-columns: 1.5fr 1fr; gap: 16px; }

@media (max-width: 900px) {
  .wo-top, .wo-split { grid-template-columns: 1fr; }
  .wo-thumb { height: 200px; }
}

/* ── Website studio ────────────────────────────────────────────────────────
   Full-screen: pages on the left, the selected section's form in the middle,
   and the REAL rendered site in an iframe on the right. It takes over the
   viewport the same way the review screen does — a site editor squeezed beside
   the app sidebar leaves neither the form nor the preview wide enough to work
   in, and while you are in here the app's nav is for a different product. */
.ws-root {
  position: fixed;
  inset: 0;
  /* Under `.overlay` (100) and `#toasts` (200). The studio raises real dialogs —
     page settings, the section-type picker, every confirm — and at a z-index
     above the overlay they would open BEHIND it: a dead grey screen with no way
     out. Nothing else is on the page while the studio is up, so it only has to
     beat the document flow. */
  z-index: 90;
  background: var(--bg);
  display: grid;
  grid-template-rows: auto 1fr;
  overflow: hidden;
}
.ws-top {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 56px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg);
}
.ws-mark {
  width: 28px; height: 28px; border-radius: 7px;
  background: var(--brand); color: var(--brand-fg);
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.ws-title { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ws-device { display: inline-flex; border: 1px solid var(--border-soft); border-radius: 8px; overflow: hidden; }
.ws-device-btn {
  border: 0; background: none; font: inherit; font-size: 12px;
  padding: 5px 11px; cursor: pointer; color: var(--fg-muted);
}
.ws-device-btn.active { background: var(--bg-cream); color: var(--fg); font-weight: 600; }

.ws-body { display: grid; grid-template-columns: 236px minmax(300px, 400px) 1fr; min-height: 0; }
.ws-rail { border-right: 1px solid var(--border-soft); overflow-y: auto; padding: 12px 8px 32px; }
.ws-edit { border-right: 1px solid var(--border-soft); overflow-y: auto; padding: 0 0 40px; }
.ws-preview { background: var(--bg-subtle); min-width: 0; display: flex; flex-direction: column; }

.ws-rail-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 10px 8px;
  font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--fg-muted);
}
.ws-page {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 10px; border-radius: 8px; cursor: pointer;
  font-size: 13px; transition: background 120ms;
}
.ws-page:hover { background: var(--bg-cream); }
.ws-page.active { background: var(--bg-cream); font-weight: 600; }
.ws-page-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px; }
/* Published vs draft, at a glance, without spending a badge on every row. */
.ws-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--border); flex: none; }
.ws-dot.live { background: var(--success); }

.ws-sections { margin: 2px 0 8px 12px; border-left: 1px solid var(--border-soft); padding-left: 4px; }
.ws-sec {
  display: flex; align-items: center; gap: 4px;
  padding: 6px 8px; border-radius: 7px; cursor: pointer;
  font-size: 12.5px; transition: background 120ms;
}
.ws-sec:hover { background: var(--bg-cream); }
.ws-sec.active { background: var(--brand); color: var(--brand-fg); }
.ws-sec-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-sec-sub { display: block; font-size: 11px; opacity: .7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The row tools stay put rather than appearing on hover: a section is reordered
   and removed from here, and hover-to-reveal has no equivalent on a touchpad
   user's muscle memory — or on a tablet at all. */
.ws-sec-tools { display: inline-flex; gap: 1px; flex: none; }
.ws-icon-btn {
  border: 0; background: none; cursor: pointer; color: inherit;
  padding: 2px 4px; border-radius: 5px; font: inherit; font-size: 12px; line-height: 1;
  display: inline-flex; align-items: center;
}
.ws-icon-btn:hover { background: rgba(0, 0, 0, .08); }
.ws-icon-btn:disabled { opacity: .3; cursor: default; }

.ws-edit-head {
  display: flex; align-items: center; gap: 8px;
  padding: 14px 16px; border-bottom: 1px solid var(--border-soft);
  position: sticky; top: 0; background: var(--bg); z-index: 1;
}
.ws-edit-title { font-size: 15px; font-weight: 600; }
#ws-form { padding: 16px; }
/* Two columns do not fit a 380px pane — the site pane's paired fields stack. */
.ws-grid2 { display: grid; grid-template-columns: 1fr; gap: 12px; }
.ws-edit .card { border: 0; border-bottom: 1px solid var(--border-soft); border-radius: 0; margin: 0 !important; }
.ws-edit .card-footer { padding-bottom: 16px; }
.ws-form-foot {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border-soft);
}

/* The frame is laid out at a real desktop width and scaled down to fit (see
   wsFitFrame) — a 700px-wide iframe would trip the site's own mobile
   breakpoint while the toolbar says Desktop. The size and transform are set in
   JS because they depend on the pane's measured width. */
.ws-frame-wrap { flex: 1; min-height: 0; display: flex; justify-content: center; padding: 14px; overflow: hidden; }
.ws-frame {
  border: 0; background: #fff; flex: none;
  transform-origin: top center;
  border-radius: 10px; box-shadow: 0 1px 20px rgba(0, 0, 0, .10);
}
/* A phone-width frame, so the layout can be checked where most guests read it. */
.ws-frame-wrap.mobile { align-items: flex-start; }

@media (max-width: 1100px) {
  /* No room for three columns. The preview is the first thing to go — the
     editor still works, and Open opens the real page in a tab. */
  .ws-body { grid-template-columns: 220px 1fr; }
  .ws-preview { display: none; }
}
@media (max-width: 760px) {
  .ws-body { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .ws-rail { border-right: 0; border-bottom: 1px solid var(--border-soft); max-height: 40vh; }
  .ws-device { display: none; }
}

/* ── Mail ──────────────────────────────────────────────────────────────────
   Folders were a third column. Three columns inside a 1280px page left the
   message list at ~340px and the reader at whatever was left, so the two
   surfaces you actually read were the two being squeezed by a list of six
   words that never changes. The folders are a horizontal strip now and the
   split below it is list + reader only.

   The strip is the app's ordinary `.tabs`, so Mail looks like WhatsApp, HR and
   everything else — it briefly had pills of its own and read as a different
   product. Only the scrolling is Mail's: `.tabs` scrolls sideways below 720px,
   and a mailbox with a dozen Zoho labels needs it at every width. */
.ml-folderbar {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin-bottom: 14px;
}
.ml-folderbar::-webkit-scrollbar { display: none; }
.ml-folderbar .tab { white-space: nowrap; flex: 0 0 auto; }

/* List and reader each scroll on their own, so working down an inbox doesn't
   move the message you are reading. */
.ml-split {
  display: grid;
  grid-template-columns: minmax(320px, 420px) 1fr;
  gap: 14px;
  align-items: stretch;
  height: calc(100vh - 258px);
  min-height: 440px;
}
.ml-split > .card { overflow: hidden; display: flex; flex-direction: column; }
.ml-scroll { overflow-y: auto; flex: 1; min-height: 0; }

@media (max-width: 900px) {
  /* Below this the two panes would each be too narrow to read. The reader sits
     under the list instead, and both give up the fixed height so the page
     scrolls as one thing. */
  .ml-split { grid-template-columns: 1fr; height: auto; min-height: 0; }
  .ml-scroll { overflow-y: visible; }
}

/* ── Mail compose dock ─────────────────────────────────────────────────────
   Docked bottom-right rather than a modal, so a half-written message can be
   parked while you go and look something up. Minimising collapses the body and
   keeps the DOM — the draft survives because it is never destroyed, not because
   anything is saved anywhere.
   z-index sits under the modal layer (200): a confirm dialog raised FROM the
   composer must still land on top of it. */
.compose-dock {
  position: fixed;
  right: 24px;
  bottom: 0;
  width: min(560px, calc(100vw - 32px));
  background: var(--bg);
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 -2px 24px rgba(0, 0, 0, .13);
  z-index: 150;
  display: flex;
  flex-direction: column;
  max-height: min(80vh, 720px);
}
.compose-dock-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
  flex: none;
}
.compose-dock-title { font-size: 13px; font-weight: 600; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.compose-dock-body { padding: 14px; overflow-y: auto; }
.compose-dock-foot { padding: 12px 14px; border-top: 1px solid var(--border-soft);
  display: flex; align-items: center; gap: 8px; flex: none; }
.compose-dock.min .compose-dock-body,
.compose-dock.min .compose-dock-foot { display: none; }
.compose-dock.min { max-height: none; }

/* An attached file, before it is sent. */
.attach-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; margin: 0 6px 6px 0;
  border: 1px solid var(--border); border-radius: 999px;
  font-size: 12px; max-width: 100%;
}
.attach-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attach-chip button { border: 0; background: none; cursor: pointer; color: var(--fg-muted);
  padding: 0; line-height: 1; font-size: 14px; }
.attach-chip button:hover { color: var(--danger); }
