/* Inter Variable — self-hosted, no external requests (2026-07-28 rebrand).
   font-weight: 100 900 covers the whole variable axis, so every existing
   font-weight rule (400/600/700 etc.) already used across the app "just
   works" against this one file — no other CSS needed to change. */
@font-face {
  font-family: 'Inter Variable';
  src: url('/static/fonts/InterVariable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Inter Variable';
  src: url('/static/fonts/InterVariable-Italic.woff2') format('woff2');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

:root {
  /* Azure Pulse — 2026-07-28 ZED BPO rebrand: deep cool slate + electric
     azure (matches the re-tinted logo + payslip PDF). Zednex keeps its violet
     override; Medical shares this parent palette by design. */
  --bg: #0b0f17;
  --panel: #111827;
  --panel-2: #182236;
  --border: rgba(255, 255, 255, 0.08);
  --text: #e6ebf4;
  --muted: #7d8aa0;
  --accent: #2f7df6;
  --accent-soft: rgba(47, 125, 246, 0.16);
  --ok: #4caf7d;
  --warn: #d9a441;
  --bad: #e2685f;
  --ok-soft: rgba(76, 175, 125, 0.16);
  --warn-soft: rgba(217, 164, 65, 0.16);
  --bad-soft: rgba(226, 104, 95, 0.16);
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
  /* Tells the browser to render native widget internals (the <select> arrow and
     its popup list, the date picker's calendar) dark — CSS can style the box
     but not those parts. Without it they render light on the slate. */
  color-scheme: dark;
}

/* Grey→azure gradient for the wordmark and neutral headings, matching the CRM
   topbar (Raymond, 2026-07-28: flat bright white read as dull next to the
   rebrand). Applies to ZED and Medical, which share the parent palette by
   design; Zednex opts out in its own override block (partials/nav.ejs) to keep
   its violet identity. Falls back to flat --text where background-clip:text is
   unsupported. Not applied to KPI figures — those are already accent-coloured. */
.brand > span,
h1,
.card h2 {
  background: linear-gradient(120deg, var(--text) 62%, #63a4ff 100%);
  -webkit-background-clip: text; background-clip: text;
  color: var(--text); /* fallback */
  -webkit-text-fill-color: transparent;
  width: fit-content; /* keep the gradient ramp tight to the glyphs */
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}
a { color: var(--accent); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

.topbar {
  display: flex; align-items: center; gap: 20px;
  padding: 14px 24px; border-bottom: 1px solid var(--border);
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 16px; white-space: nowrap; flex-shrink: 0; }
.brand-logo { height: 24px; width: auto; display: block; flex-shrink: 0; }
.topbar nav { display: flex; gap: 4px; flex: 1; flex-wrap: wrap; }
.topbar nav a { color: var(--muted); text-decoration: none; font-size: 13px; padding: 6px 12px; border-radius: 8px; transition: color .15s ease, background .15s ease; }
.topbar nav a:hover { color: var(--text); background: var(--panel-2); }
.topbar nav a.active { color: var(--text); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
/* --- Login page (2026-08-02, session auth replaced the browser's Basic Auth
   dialog). Deliberately mirrors the CRM/Chat sign-in so the three apps feel
   like one system. --- */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.login-card { width: 100%; max-width: 360px; margin: 0; }
.login-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 22px; }
.login-brand img { height: 34px; }
.login-brand span { font-size: 20px; font-weight: 600; }
.login-field { display: block; margin-bottom: 14px; }
.login-field span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 5px; }
.login-field input { width: 100%; }
.login-btn { width: 100%; margin-top: 6px; }
.login-err {
  background: rgba(220, 76, 70, .12); border: 1px solid rgba(220, 76, 70, .4);
  color: #ff9a94; font-size: 13px; border-radius: 8px; padding: 9px 11px; margin-bottom: 16px;
}

.who { color: var(--muted); font-size: 13px; display: flex; align-items: center; gap: 12px; }
/* Sign out — deliberately quiet. It sits next to the username, not in the nav,
   so it reads as an account action rather than another section to visit. */
.who .logout {
  color: var(--muted); text-decoration: none; font-size: 12px;
  border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px;
  white-space: nowrap; transition: color .15s ease, border-color .15s ease;
}
.who .logout:hover { color: var(--accent); border-color: var(--accent); }

.container { max-width: 1200px; margin: 0 auto; padding: 24px; }

.card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  padding: 20px; margin-bottom: 20px; box-shadow: 0 20px 45px -32px rgba(0, 0, 0, 0.7);
}
.card h2 { margin-top: 0; font-size: 16px; }

.grid-form { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.grid-form .full { grid-column: 1 / -1; }
.grid-form label, .inline-form label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
/* Base styling for EVERY form control, not just those inside .grid-form /
   .inline-form. The attendance check-in/out time pickers (and any other bare
   <select> in a table cell) were falling through to the browser's native
   light-mode widget — bright white slabs on the deep slate (Raymond,
   2026-07-28). Styling the elements themselves means new markup inherits the
   theme by default instead of having to remember a wrapper class. */
input, select, textarea {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 8px; padding: 8px 10px; font-size: 14px;
  font-family: inherit;
}
select { cursor: pointer; }
input:hover, select:hover, textarea:hover { border-color: rgba(47, 125, 246, 0.45); }
input:focus, select:focus, textarea:focus { border-color: var(--accent); }
input:disabled, select:disabled, textarea:disabled { opacity: .45; cursor: not-allowed; }
/* Compact form controls sitting inside table rows — the time pickers appear
   six-to-a-row, so the default padding would blow the row height out. */
.time-cell select { padding: 4px 6px; font-size: 13px; border-radius: 6px; }

.grid-form input, .grid-form select, .grid-form textarea,
.inline-form input, .inline-form select {
  background: var(--bg); margin-top: 2px;
}
fieldset { border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px; display: flex; gap: 14px; align-items: flex-end; }
fieldset legend { font-size: 12px; color: var(--muted); padding: 0 6px; }

.inline-form { display: flex; gap: 16px; align-items: flex-end; margin-bottom: 12px; }

button, .btn-secondary {
  background: var(--accent); color: #fff; border: none; border-radius: 8px;
  padding: 9px 18px; font-size: 14px; font-weight: 600; cursor: pointer; text-decoration: none;
  display: inline-block; transition: transform .15s ease, box-shadow .15s ease, background .15s ease, border-color .15s ease;
}
button:hover { transform: translateY(-1px); box-shadow: 0 8px 20px -8px var(--accent-soft), 0 8px 20px -10px rgba(47, 125, 246, 0.45); }
button:active { transform: translateY(0); }
.btn-secondary { background: transparent; color: var(--text); border: 1px solid var(--border); margin-left: 8px; }
.btn-secondary:hover { border-color: var(--accent); color: var(--accent); box-shadow: none; }

/* Wide tables scroll INSIDE their card instead of spilling out of it. The
   Payroll table reached 15 columns once Leaves/Approved/Unpaid were added and
   its intrinsic width exceeded the panel, so rows rendered past the rounded
   background (Raymond, 2026-08-01). width:100% only sets a MINIMUM here — the
   table still grows to fit its columns and the wrapper scrolls.
   NOTE: overflow-x:auto makes this a scroll container, which per spec forces
   overflow-y:auto too. Fine today because no table in this app has a sticky
   header — if one is ever added, its `top` resolves against THIS box, not the
   viewport (the exact trap that hid the CRM's first table row). */
.tablewrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: .03em; }
td { font-variant-numeric: tabular-nums; transition: background .15s ease; }
tr:hover td { background: var(--panel-2); }
.total-row td { font-weight: 700; border-top: 2px solid var(--border); }

.pill { font-size: 11px; padding: 2px 9px; border-radius: 999px; background: var(--border); color: var(--text); text-transform: capitalize; transition: background .15s ease; }
.pill-active { background: var(--ok-soft); color: var(--ok); }
.pill-on_leave { background: var(--accent-soft); color: var(--accent); }
.pill-suspended { background: var(--warn-soft); color: var(--warn); }
.pill-left, .pill-terminated { background: var(--bad-soft); color: var(--bad); }
.badge-auto { display: inline-block; margin-left: 6px; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--warn-soft); color: var(--warn); text-transform: uppercase; letter-spacing: .04em; cursor: help; vertical-align: middle; }

.no-pay-row td { color: var(--muted); }
.no-pay { font-weight: 600; letter-spacing: .04em; }

.pay-paid { background: var(--ok-soft); color: var(--ok); border-color: transparent; }
.pay-pending { background: var(--warn-soft); color: var(--warn); border-color: transparent; }

.kpis { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-bottom: 20px; }
.kpi {
  background: linear-gradient(120deg, var(--panel-2), var(--panel));
  border: 1px solid var(--border); border-radius: 12px; padding: 18px; text-align: center;
  box-shadow: 0 14px 30px -22px rgba(0, 0, 0, 0.7);
}
.kpi-value { font-family: var(--mono); font-size: 26px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.kpi-label { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* Real-time total bar (Payroll tab) — a standalone elevated KPI, not just
   another table row, since it's the one number the whole page exists to
   answer: "how much do I owe this month, right now." */
.kpi-total {
  background: linear-gradient(120deg, var(--panel-2), var(--panel));
  border: 1px solid var(--border); border-radius: 12px; padding: 16px 20px;
  margin-bottom: 18px; display: flex; justify-content: space-between; align-items: center;
  box-shadow: 0 14px 30px -22px rgba(0, 0, 0, 0.7);
}
.kpi-total .l { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.kpi-total .n { font-family: var(--mono); font-size: 24px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }

.muted { color: var(--muted); font-size: 13px; }
.banner-ok { color: var(--ok); font-size: 13px; }

/* Paid-holiday bar on the Attendance page — a whole-day flag, so it reads as
   its own band above the per-employee table rather than another table row. */
.holiday-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px; margin-bottom: 16px; border-radius: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  transition: background .15s ease, border-color .15s ease;
}
.holiday-bar.is-holiday { background: var(--ok-soft); border-color: rgba(76, 175, 125, 0.35); }
.holiday-bar .holiday-check { display: flex; align-items: center; gap: 8px; font-size: 14px; white-space: nowrap; }
.holiday-bar input[type="text"] { flex: 1; min-width: 220px; }
.holiday-bar input[type="text"]:disabled { opacity: .5; }
.holiday-bar .muted { flex-basis: 100%; font-size: 12px; }

input.calc-input { width: 80px; }
input, select, textarea { transition: border-color .15s ease; }
input:hover, select:hover { border-color: rgba(255, 255, 255, 0.18); }

@media (max-width: 900px) {
  .grid-form { grid-template-columns: 1fr; }
  .kpis { grid-template-columns: repeat(2, 1fr); }
  fieldset { flex-direction: column; align-items: stretch; }
}

/* ==========================================================================
   NOCTURNE — appended 2026-08-25 (pilot: Payroll screen).
   Structure, type and spacing ported from the Claude Design "Nocturne" system
   per NOCTURNE-UI-PORT-BRIEF.md. Its COLOUR tokens are deliberately NOT ported
   — the system's accent is a blurple; this app's palette already matches the
   mockups exactly, so not one colour token above this line changes.

   ▸ TO REVERT: delete from this banner to the end of the file, delete
     public/app.js, and remove the two <script src="/static/app.js"> tags
     (src/views/partials/nav.ejs, src/views/login.ejs). Nothing else was edited.
   ========================================================================== */

:root {
  /* The rule behind the Nocturne fading row divider (mockup value). Declared
     here rather than reused from --border because that one is also the border
     of every input and card, and the two want to diverge. */
  --divider: rgba(148, 163, 184, 0.15);
  --rule: rgba(230, 235, 244, 0.08);
  --rail-collapsed: 64px;
  --rail-open: 216px;
}

/* ---- Type ---------------------------------------------------------------
   System values: body 15/1.55, headings line-height 1.12 / -0.015em, and
   heading weight 500 (--font-heading-weight — NOT 600). */
body { font-size: 15px; line-height: 1.55; }
h1, h2, h3, h4, h5, h6 { line-height: 1.12; letter-spacing: -0.015em; font-weight: 500; }
h1 { font-size: 42px; }
/* .card h2 is the PAGE title (company — month — screen), not a panel eyebrow,
   so it takes the system's h4 step and keeps Raymond's approved gradient
   (2026-07-28) rather than becoming a 13px micro-cap, which would bury the
   most important context on the screen. The h6 micro-cap treatment the system
   specifies for eyebrows is used below on table headers and stat labels, where
   it belongs. */
.card h2 { font-size: 20px; margin-bottom: 18px; }

/* ---- The rail -----------------------------------------------------------
   Raymond, verbatim: "an auto hiding side bar so when we hover the mouse over
   it it pops and when we hover back it collapse." Not a click toggle.

   The layout track NEVER changes width: body keeps a fixed 64px inset and the
   rail expands OVER the content. If the track resized, every hover would
   reflow the page and a table someone is reading would jump sideways under the
   cursor.

   :focus-within as well as :hover — hover alone makes the whole menu
   unreachable by keyboard.

   The delay is on the way CLOSED only (transition-delay resets to 0 on hover),
   so brushing past the rail on the way to the table does not make it flap. */
body:has(> .topbar) { padding-left: var(--rail-collapsed); }

.topbar {
  position: fixed; top: 0; left: 0; bottom: 0;
  width: var(--rail-collapsed);
  flex-direction: column; align-items: stretch; gap: 0;
  padding: 20px 14px 16px;
  background: var(--bg);
  border-bottom: none;
  border-right: 1px solid var(--divider);
  overflow: hidden;
  /* Deliberately low. A high z-index (or a transform/filter/isolation on body
     or the page wrapper) is the documented way to silently break an overlay;
     this app has none today, and nothing here introduces one. */
  z-index: 20;
  transition: width .16s ease .18s, box-shadow .16s ease .18s;
}
.topbar:hover, .topbar:focus-within {
  width: var(--rail-open);
  transition-delay: 0s;
  /* Elevation, not a higher z-index — without it the open rail reads as though
     the table merged into it. */
  box-shadow: 22px 0 46px -26px rgba(0, 0, 0, 0.95);
}

.brand { padding: 0 6px; margin-bottom: 16px; font-size: 15px; font-weight: 600; gap: 10px; align-items: center; }
.brand > span { font-size: 13px; line-height: 1.25; white-space: normal; }
.brand-logo { height: 26px; }
.brand > span,
.who .who-name,
.who .logout,
.topbar nav a .nav-label,
.nav-group {
  opacity: 0; transition: opacity .1s ease;
}
.topbar:hover .brand > span, .topbar:focus-within .brand > span,
.topbar:hover .who .who-name, .topbar:focus-within .who .who-name,
.topbar:hover .who .logout, .topbar:focus-within .who .logout,
.topbar:hover .nav-group, .topbar:focus-within .nav-group,
.topbar:hover nav a .nav-label, .topbar:focus-within nav a .nav-label {
  opacity: 1; transition-delay: .08s;
}

.topbar nav {
  flex-direction: column; flex-wrap: nowrap; align-items: stretch;
  gap: 1px; flex: 1 1 auto;
  overflow-y: auto; overflow-x: hidden;
  margin: 0 -4px;
}
.topbar nav a {
  display: flex; align-items: center; gap: 12px;
  padding: 7px 10px; font-size: 13.5px; border-radius: 8px;
  white-space: nowrap;
}
/* The azure-outlined active tab (Raymond, 2026-07-28) is kept — in a rail the
   tint alone is quieter than he asked for. Text takes the mockup's accent-300. */
.topbar nav a.active { color: #90bbfc; background: rgba(47, 125, 246, 0.13); }

/* Section labels, injected by app.js. h6 micro-cap values from the system. */
.nav-group {
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); padding: 14px 10px 4px; white-space: nowrap;
}
.nav-group:first-child { padding-top: 4px; }

/* ---- Route glyphs -------------------------------------------------------
   At 64px a text-only rail is blank. These are masks, not a font and not
   markup: currentColor tints them, so they inherit hover/active for free, and
   there is no glyph-coverage lottery across machines. Keyed off href.

   --glyph is defaulted HERE, not only on the href rules: an unset custom
   property makes `mask` invalid, which means NO mask, which paints the full
   18px currentColor square. A route added to nav.ejs and not mapped below
   would render a solid block, not a blank slot. It gets a neutral dot.

   It is set on the <a>, NOT on ::before: a custom property declared directly
   on the pseudo-element beats one inherited from its parent, so putting the
   fallback there silently shadowed every per-href override below and painted
   the same dot on all twelve routes. */
.topbar nav a {
  --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3C/svg%3E");
}
.topbar nav a::before {
  content: ''; flex: 0 0 18px; width: 18px; height: 18px;
  background: currentColor;
  -webkit-mask: var(--glyph) center / contain no-repeat;
  mask: var(--glyph) center / contain no-repeat;
}
.topbar nav a[href="/"]           { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E"); }
.topbar nav a[href="/attendance"] { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E"); }
.topbar nav a[href="/payroll"]    { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5.5' width='19' height='13' rx='2'/%3E%3Ccircle cx='12' cy='12' r='2.6'/%3E%3Cpath d='M6 9.5v5M18 9.5v5'/%3E%3C/svg%3E"); }
.topbar nav a[href="/commissions"]{ --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 20h18'/%3E%3Cpath d='M6.5 20v-5M11.5 20V7M16.5 20v-9M21 20v-3'/%3E%3C/svg%3E"); }
.topbar nav a[href="/expenses"]   { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 7.5A2.5 2.5 0 0 1 5.5 5H19a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5.5A2.5 2.5 0 0 1 3 16.5z'/%3E%3Cpath d='M3 8.5h18'/%3E%3Ccircle cx='16.8' cy='13' r='1.3'/%3E%3C/svg%3E"); }
.topbar nav a[href="/employees"]  { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3.2'/%3E%3Cpath d='M3 20a6 6 0 0 1 12 0'/%3E%3Cpath d='M16.5 5.6a3 3 0 0 1 0 5.3'/%3E%3Cpath d='M18.5 20a5.6 5.6 0 0 0-2-4'/%3E%3C/svg%3E"); }
.topbar nav a[href="/org"]        { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='3' width='6' height='5' rx='1'/%3E%3Crect x='2' y='16' width='6' height='5' rx='1'/%3E%3Crect x='16' y='16' width='6' height='5' rx='1'/%3E%3Cpath d='M12 8v3.5M5 16v-2.5h14V16'/%3E%3C/svg%3E"); }
.topbar nav a[href="/rules"]      { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6h16M4 12h16M4 18h16'/%3E%3Ccircle cx='9' cy='6' r='2'/%3E%3Ccircle cx='15' cy='12' r='2'/%3E%3Ccircle cx='8' cy='18' r='2'/%3E%3C/svg%3E"); }
.topbar nav a[href="/events"]     { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 8v4.2l3 1.8'/%3E%3Cpath d='M3.4 12a8.6 8.6 0 1 0 2.7-6.2'/%3E%3Cpath d='M3 4v4h4'/%3E%3C/svg%3E"); }
.topbar nav a[href="/users"]      { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.5'/%3E%3Cpath d='M5 20a7 7 0 0 1 14 0'/%3E%3C/svg%3E"); }
.topbar nav a[href="/companies"]  { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='3' width='16' height='18' rx='1.5'/%3E%3Cpath d='M8.5 7.5h2M13.5 7.5h2M8.5 11.5h2M13.5 11.5h2M8.5 15.5h2M13.5 15.5h2'/%3E%3C/svg%3E"); }
.topbar nav a[href="/ips"]        { --glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3l7.5 3v5.6c0 4.6-3.1 8.3-7.5 9.4-4.4-1.1-7.5-4.8-7.5-9.4V6z'/%3E%3C/svg%3E"); }

/* ---- Rail footer (account) ---------------------------------------------- */
.who {
  margin-top: auto; flex-shrink: 0;
  padding: 12px 6px 0; gap: 9px;
  border-top: 1px solid var(--divider);
}
.who-avatar {
  flex: 0 0 28px; width: 28px; height: 28px; border-radius: 50%;
  background: #131f38; color: #90bbfc;
  display: grid; place-items: center;
  font-size: 10.5px; font-weight: 600; letter-spacing: .02em;
}
.who-name { flex: 1 1 auto; min-width: 0; font-size: 12.5px; white-space: nowrap; overflow: hidden; }
.who .logout { flex: 0 0 auto; }

/* ---- The animated ZED mark ---------------------------------------------- */
.zed-mark { position: relative; display: block; flex: 0 0 auto; }
.zed-mark-half { position: absolute; inset: 0; opacity: 0; }
.zed-mark-half img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; display: block; }
.zed-mark-seam {
  position: absolute; left: 50%; top: -10%; bottom: -10%; width: 1.5px;
  transform: translateX(-50%); opacity: 0; pointer-events: none;
  background: linear-gradient(180deg, transparent, rgba(235, 240, 248, 0.95), transparent);
}
.login-brand .zed-mark { margin-right: 2px; }

/* ---- De-carded surfaces -------------------------------------------------
   Nocturne puts page content on the ground and reserves the raised surface for
   things that are genuinely raised. The login card is the exception — it is a
   floating object on an empty page and stays a card. */
.card:not(.login-card) {
  background: transparent; border: none; box-shadow: none;
  padding: 0; margin-bottom: 30px;
}
.container { padding: 28px 36px 40px; }

/* ---- Stat figures: label ABOVE the number, de-carded --------------------
   order: on .l/.n means the template's span order never has to change. */
.kpi-total {
  background: none; border: none; box-shadow: none;
  padding: 0; margin-bottom: 26px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
}
.kpi-total .l { order: 1; font-size: 11px; letter-spacing: .08em; }
.kpi-total .n { order: 2; font-size: 32px; font-weight: 600; }

.kpis { grid-template-columns: repeat(auto-fit, minmax(0, max-content)); gap: 46px; justify-content: start; margin-bottom: 30px; }
.kpi {
  background: none; border: none; box-shadow: none;
  padding: 0; text-align: left;
  display: flex; flex-direction: column;
}
.kpi .kpi-label { order: 1; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; margin: 0; }
.kpi .kpi-value { order: 2; font-size: 27px; font-weight: 600; margin-top: 6px; }

/* ---- The Nocturne fading row rule ---------------------------------------
   The system's own name for it. The rule is painted by the ROW, not the cell,
   so one fade spans the whole row instead of restarting at every cell
   boundary. Cells keep a transparent border so the layout box is unchanged.

   The hover tint moves to the row too: a tint on the cell would paint OVER the
   row's rule and erase it on exactly the row under the cursor. Rule is listed
   first in the shorthand, so it stays the topmost layer. */
th, td { border-bottom: 1px solid transparent; padding: 10px 14px; }
table { font-size: 14px; }
th { letter-spacing: .08em; font-weight: 500; }

thead tr {
  background: linear-gradient(to right, transparent, var(--divider) 48px,
              var(--divider) calc(100% - 48px), transparent) no-repeat bottom / 100% 1px;
}
tbody tr {
  background: linear-gradient(to right, transparent, var(--rule) 48px,
              var(--rule) calc(100% - 48px), transparent) no-repeat bottom / 100% 1px;
  transition: background-color .15s ease;
}
tbody tr:hover {
  background:
    linear-gradient(to right, transparent, var(--rule) 48px,
      var(--rule) calc(100% - 48px), transparent) no-repeat bottom / 100% 1px,
    linear-gradient(rgba(230, 235, 244, 0.04), rgba(230, 235, 244, 0.04));
}
tbody tr:hover td { background: transparent; }
.total-row td { border-top: 1px solid var(--divider); }

/* ---- Page composition (Nocturne mockups) --------------------------------
   The header bar, the de-carded stat row, the slim table and its per-row
   expander. Added 2026-08-25 with the payroll.ejs re-lay-out. */
.page-head { display: flex; align-items: center; gap: 14px; margin-bottom: 26px; flex-wrap: wrap; }
.page-title { font-size: 22px; font-weight: 600; margin: 0 auto 0 0; }

/* Month stepper. The two selects sit inside one ring so year+month read as a
   single control, the way the mockup's segment does, without giving up the
   ability to jump straight to any month. */
.monthbar { display: flex; align-items: center; margin: 0; }
.monthbar .seg { padding: 0 2px; }
.monthbar .step {
  display: grid; place-items: center; width: 28px; height: 30px;
  border-radius: 8px; color: var(--muted); text-decoration: none; font-size: 15px;
  transition: color .15s ease, background .15s ease;
}
.monthbar .step:hover { color: var(--text); background: var(--panel-2); }
.seg {
  display: flex; align-items: center; border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--accent);
}
.seg select {
  background: transparent; border: none; border-radius: 8px;
  color: #90bbfc; font-size: 12.5px; padding: 6px 4px 6px 8px;
}
.seg select:hover, .seg select:focus { border: none; background: var(--accent-soft); }
.co-form { margin-bottom: 0; }

/* ---- Stat row ----------------------------------------------------------- */
.statrow { display: flex; align-items: flex-end; gap: 52px; margin-bottom: 28px; flex-wrap: wrap; }
.stat { display: flex; flex-direction: column; }
.stat .l { order: 1; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.stat .n {
  order: 2; margin-top: 6px; font-family: var(--mono);
  font-size: 24px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.stat .n.accent { font-size: 32px; color: #4f95f7; }
.stat .n.warn { color: var(--warn); }
.stat .of { color: var(--muted); }

/* ---- Table -------------------------------------------------------------- */
.paytable .num, .paytable .act { text-align: right; }
.paytable th.num, .paytable th.act { text-align: right; }
.paytable .strong { font-weight: 600; }
/* Zero is MUTED, never blank — an empty money cell reads as "no value on
   file" rather than "nothing was deducted". */
.paytable .zero { color: var(--muted); }
.paytable .name { white-space: nowrap; }
.paytable tbody tr.is-open {
  background:
    linear-gradient(to right, transparent, var(--rule) 48px,
      var(--rule) calc(100% - 48px), transparent) no-repeat bottom / 100% 1px,
    linear-gradient(var(--accent-soft), var(--accent-soft));
}

.tag {
  display: inline-block; font-size: 10px; font-weight: 600; padding: 2px 8px;
  border-radius: 999px; letter-spacing: .01em; vertical-align: middle;
}
.tag-warn { background: rgba(245, 158, 11, .15); color: #fbbf24; }
.tag-accent { background: var(--accent-soft); color: #90bbfc; }
.tag-ok { background: var(--ok-soft); color: var(--ok); }
.paytable .name .tag { margin-left: 8px; }

/* Ghost action — a real button/link, quiet until wanted. */
.btn-ghost {
  background: transparent; border: none; color: #4f95f7;
  font-size: 12px; font-weight: 500; font-family: inherit;
  padding: 4px 8px; border-radius: 6px; cursor: pointer; text-decoration: none;
  display: inline-block; transition: background .15s ease, color .15s ease;
}
.btn-ghost:hover { background: var(--accent-soft); box-shadow: none; transform: none; }

/* ---- Row expander -------------------------------------------------------
   The detail row is only hidden/shown — its inputs stay in the DOM, so a
   collapsed row still submits with the payroll form. */
.detailrow > td { padding: 0 0 14px; border-bottom: none; }
.detailrow { background: none !important; }
.detail {
  display: flex; gap: 28px; align-items: flex-end; flex-wrap: wrap;
  margin: 6px 0 0; padding: 18px 20px;
  border: 1px solid rgba(47, 125, 246, .35); border-radius: 10px;
  background: var(--panel);
}
.detail .field { display: flex; flex-direction: column; gap: 5px; width: 118px; }
.detail .field > span { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.detail .field input { text-align: right; }
.detail .field.ro b { font-family: var(--mono); font-size: 15px; font-weight: 600; }
.detail .workings { font-size: 12.5px; line-height: 1.8; color: var(--muted); font-variant-numeric: tabular-nums; }
.detail .workings .k { display: inline-block; min-width: 168px; }
.detail .workings b { color: var(--text); font-family: var(--mono); font-weight: 500; }
.detail-actions { display: flex; gap: 10px; align-items: center; margin-left: auto; }
.detail-actions select { padding: 5px 8px; font-size: 12px; }

@media (max-width: 900px) {
  .statrow { gap: 28px; }
  .detail-actions { margin-left: 0; }
}

/* Company switcher, relocated into the rail by app.js. */
.rail-co { margin: 16px 0 18px; opacity: 0; transition: opacity .1s ease; }
.topbar:hover .rail-co, .topbar:focus-within .rail-co { opacity: 1; transition-delay: .08s; }
.rail-co select { width: 100%; font-size: 12.5px; padding: 6px 8px; }
.stat .n .cur { font-size: .62em; color: var(--muted); font-weight: 500; margin-right: 2px; }

/* ---- Shared page furniture (Dashboard onward) --------------------------- */
.eyebrow {
  font-size: 13px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 10px;
}
/* Primary action rendered as a LINK (navigates rather than submits). Matches
   the button treatment so the header bar reads as one row of controls. */
.btn-primary {
  background: var(--accent); color: #fff; border: none; border-radius: 8px;
  padding: 9px 18px; font-size: 14px; font-weight: 600; text-decoration: none;
  display: inline-block; transition: transform .15s ease, box-shadow .15s ease, background .15s ease;
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 8px 20px -10px rgba(47, 125, 246, .45); color: #fff; }
.stat .n.sm { font-size: 27px; }

/* Cost bar on the Dashboard's monthly table — scaled to the year's own peak. */
.bar-col { width: 120px; }
td.bar-col { padding-right: 0; }
.bar {
  display: block; height: 2px; border-radius: 2px; background: var(--accent);
  min-width: 6px; opacity: .85;
}

/* A link inside a muted-zero cell must stay muted — otherwise "0.00" lights up
   blue and reads as a live figure worth clicking. */
td.zero a { color: inherit; }
/* Row-label links (the Dashboard's month column) read as text until hovered:
   the whole row is navigable, so twelve blue words is noise, not affordance. */
table tbody td > a:not(.btn-ghost) { color: var(--text); text-decoration: none; }
table tbody td > a:not(.btn-ghost):hover { color: var(--accent); }

/* ---- Attendance --------------------------------------------------------- */
.chiprow { display: flex; gap: 8px; margin: 0 0 16px; }
.tag-ghost { background: transparent; box-shadow: inset 0 0 0 1px var(--accent); color: #90bbfc; }
.seg-date { position: relative; display: flex; align-items: center; }
.seg-date-label { color: #90bbfc; font-size: 12.5px; padding: 6px 8px; white-space: nowrap; }
.seg-date input[type="date"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; border: none; padding: 0; cursor: pointer;
}
.seg-date:hover .seg-date-label, .seg-date:focus-within .seg-date-label {
  background: var(--accent-soft); border-radius: 6px;
}
.step.is-off { color: var(--muted); opacity: .3; display: grid; place-items: center; width: 28px; height: 30px; }
/* Screen-reader-only label — the date input needs a name, the segment does not
   need to show one. */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* The status tag doubles as the on-leave control. The checkbox stays a real
   checkbox (same name, same submit) — it is just presented beside its meaning. */
.statustoggle { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
.statustoggle input { margin: 0; }
.atttable .timeval { font-variant-numeric: tabular-nums; }
.atttable .time-cell { white-space: nowrap; }
.atttable .time-cell select { margin-right: 1px; }

/* ---- Employees ---------------------------------------------------------- */
.searchbox { width: 220px; font-size: 12.5px; padding: 7px 10px; }
.deptfilter { font-size: 12.5px; padding: 7px 10px; }
.submeta { font-size: 12px; color: var(--muted); margin: -14px 0 22px; }
.formcard {
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  padding: 20px; margin-bottom: 26px;
}
.empdetail {
  flex-direction: column; align-items: stretch; gap: 18px;
  /* .detail sets flex-wrap:wrap, which is right for the Payroll row (a wrapping
     ROW of fields). Inherited onto this COLUMN it made the panel resolve a
     stretched height and blow a ~220px hole under the facts. */
  flex-wrap: nowrap;
}
.factgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px 24px;
  /* A grid inside a flex parent inherits a definite height and then STRETCHES
     its rows to fill it — which pushed "Payroll window" ~100px below the rest.
     Pin the rows to their content instead. */
  align-content: start; align-items: start;
  flex: 0 0 auto;
}
.factgrid .k { display: block; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 3px; }
.factgrid b { font-size: 13.5px; font-weight: 500; }
.factgrid b.zero { color: var(--muted); }

.audit { border-top: 1px solid var(--divider); padding-top: 14px; }
.audit .eyebrow { margin-bottom: 8px; }
.auditrow {
  display: grid; grid-template-columns: 170px 110px 1fr; gap: 14px;
  align-items: baseline; padding: 8px 2px;
  border-bottom: 1px solid var(--divider);
}
.auditrow:last-child { border-bottom: none; }
.auditrow .ts { font-family: var(--mono); font-size: 11.5px; color: var(--muted); }
.auditrow .tag { justify-self: start; text-transform: capitalize; }
.auditrow .what { font-size: 12.5px; color: var(--muted); }
.auditrow .what b { color: var(--text); font-family: var(--mono); font-weight: 500; }
.tag-bad { background: var(--bad-soft); color: var(--bad); }

@media (max-width: 900px) {
  .auditrow { grid-template-columns: 1fr; gap: 4px; }
}

/* ---- Settings tabs ------------------------------------------------------ */
.settings-tabs { display: flex; gap: 4px; margin: 0 0 20px; flex-wrap: wrap; }
.settings-tab {
  font-size: 13px; padding: 7px 14px; border-radius: 8px;
  color: var(--muted); text-decoration: none;
  transition: color .15s ease, background .15s ease;
}
.settings-tab:hover { color: var(--text); background: var(--panel-2); }
.settings-tab.active { color: #90bbfc; background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
.rules-grid { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1100px) { .rules-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 760px)  { .rules-grid { grid-template-columns: 1fr; } }

/* ---- Sign in ------------------------------------------------------------ */
.login-brand { justify-content: center; margin-bottom: 14px; }
.login-title {
  font-size: 21px; font-weight: 600; text-align: center; margin: 0 0 4px;
  width: auto; /* the gradient rule sets fit-content, which breaks centring */
}
.login-sub { font-size: 12.5px; color: var(--muted); text-align: center; margin: 0 0 22px; }

/* ---- Audit trail page + employee pay records ---------------------------- */
.filterbar { display: flex; gap: 10px; align-items: center; margin-bottom: 18px; flex-wrap: wrap; }
.filterbar select { font-size: 12.5px; padding: 7px 10px; }
.filterbar .showing { margin-left: auto; font-size: 12px; color: var(--muted); }
.auditlist {
  border: 1px solid var(--divider); border-radius: 12px;
  background: rgba(20, 29, 47, .35); padding: 4px 18px;
}
.auditrow.wide { grid-template-columns: 170px 150px 110px 1fr 70px; }
.auditrow.wide .who { font-size: 12.5px; font-weight: 600; }
.auditrow.wide .btn-ghost { justify-self: end; }
.pager { display: flex; gap: 14px; align-items: center; justify-content: center; margin-top: 18px; }

.records { border-top: 1px solid var(--divider); padding-top: 14px; }
.records .eyebrow { margin-bottom: 8px; }
.recrow {
  display: grid; grid-template-columns: 170px 90px 1fr; gap: 14px;
  align-items: baseline; padding: 7px 2px; border-bottom: 1px solid var(--divider);
}
.recrow:last-child { border-bottom: none; }
.recrow .m { font-size: 12.5px; }
.recrow .tag { justify-self: start; text-transform: capitalize; }
.recrow .v { font-family: var(--mono); font-size: 13px; font-variant-numeric: tabular-nums; text-align: right; }

@media (max-width: 900px) {
  .auditrow.wide { grid-template-columns: 1fr; gap: 4px; }
  .recrow { grid-template-columns: 1fr auto; }
}

/* Admin-only destructive action (employee delete, 2026-08-19). Deliberately
   NOT the accent colour -- it must not read as a normal save button.
   Production's own definition, kept verbatim through the Nocturne deploy: a
   deep blood-red reads as destructive far more clearly than the --bad salmon. */
.btn-danger { background: #7f1d1d; color: #fff; border: 1px solid #b91c1c; }
.btn-danger:hover { background: #b91c1c; box-shadow: none; }
.btn-danger + .muted { margin-left: 10px; font-size: 12px; }
