/* ============================================================================
   Digital Work Space — design system

   Direction: an HR system people keep open for eight hours, not a landing page.
   That means solid surfaces rather than glass, one accent rather than seven,
   crisp hairline borders, and type that holds up in a dense table of payroll
   figures. Every token name here predates this file's current values — the
   names are a contract with ~1,000 lines of component CSS and 49 pages, so
   values changed and names did not.

   Light is the primary experience (OS preference decides), because that is
   where payroll and attendance data is actually read. Dark is a full peer,
   not an afterthought.
   ============================================================================ */
:root {
  color-scheme: dark;

  /* ---------- Foundation (dark) ---------- */
  --bg-primary: #0B0F19;
  --bg-secondary: #111827;
  --bg-elevated: #1A2236;
  /* Table header band. Opaque, never a tint: these cells are position:sticky, and a translucent
     background would let the rows scroll through visibly underneath them. */
  --table-head-bg: #1E2740;
  /* Kept translucent: these are overlay fills (row hover, pressed states), not surfaces. */
  --surface-glass: rgba(255, 255, 255, .025);
  --surface-glass-strong: rgba(255, 255, 255, .06);
  --border-subtle: rgba(255, 255, 255, .09);
  --border-strong: rgba(255, 255, 255, .17);
  --border: var(--border-subtle);
  --scrim: rgba(2, 6, 16, .70);

  /* ---------- Text ---------- */
  --text-primary: #F9FAFB;
  --text-secondary: #98A2B3;
  --text-tertiary: #667085;
  --text-muted: var(--text-secondary);
  --text-on-accent: #FFFFFF;

  /* ---------- Brand ----------
     Violet is pulled toward indigo so the two read as one family. The old pair
     (#6366F1 + #8B5CF6) fought each other across the sidebar, topbar and every
     primary button. */
  --indigo: #6172F3;
  --indigo-dark: #4E5BC6;
  --violet: #7A85F5;
  --brand-gradient: linear-gradient(135deg, #4E5BC6, #7A85F5);
  --accent: var(--indigo);
  --accent-dark: var(--indigo-dark);
  --accent-soft: rgba(97, 114, 243, .16);
  --purple: var(--violet);

  /* ---------- Data / supporting colours ----------
     For charts and category marks only. Chrome does not use these. */
  --cyan: #67E3F9;
  --emerald: #47CD89;
  --pink: #F670C7;
  --orange: #FDB022;
  --blue: #84CAFF;

  /* ---------- Semantic ---------- */
  --success: #47CD89;
  --success-bg: rgba(71, 205, 137, .14);
  --danger: #F97066;
  --danger-bg: rgba(249, 112, 102, .14);
  --warning: #FDB022;
  --warning-bg: rgba(253, 176, 34, .14);
  --info: #84CAFF;
  --info-bg: rgba(132, 202, 255, .14);
  /* Text and icon on a filled toast — see the .toast rules near the bottom of this file. */
  --toast-ink: #0B1220;
  --gray: #98A2B3;
  --gray-bg: rgba(152, 162, 179, .14);
  --cyan-bg: rgba(103, 227, 249, .14);
  --pink-bg: rgba(246, 112, 199, .14);
  --purple-bg: rgba(122, 133, 245, .14);
  --danger-soft: var(--danger-bg);
  --warning-soft: var(--warning-bg);
  --info-soft: var(--info-bg);

  /* ---------- Chrome ----------
     The topbar used to be solid violet. An eight-hour tool should not shout. */
  /* The navigation rail is a separate surface from the content it navigates, so it gets its own
     colour rather than aliasing --bg-secondary. Aliased, light mode was a #FFFFFF rail against an
     #F7F8FA page — a 3% difference, which read as one continuous white area with a stray border
     down it. This token already existed and was simply never wired to .sidebar. */
  --sidebar-bg: #141C2E;
  --sidebar-bg-2: var(--bg-elevated);
  --sidebar-active: var(--indigo);
  --topbar-bg: var(--bg-secondary);

  /* ---------- Shape ----------
     Tightened. Large radii read consumer; enterprise density wants restraint. */
  --radius-sm: 6px;
  --radius: 8px;
  --radius-lg: 10px;
  --radius-xl: 14px;

  /* ---------- Elevation / motion ----------
     glow-indigo is retained as a name but is no longer a glow: a coloured halo
     under every brand element was the single biggest "not a real product" tell. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .32);
  --shadow-md: 0 4px 14px rgba(0, 0, 0, .38);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, .50);
  --glow-indigo: var(--shadow-sm);
  --transition: 140ms ease;
}

/* ---------- Light: the primary experience ---------- */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --bg-primary: #F7F8FA;
    --bg-secondary: #FFFFFF;
    --bg-elevated: #FFFFFF;
    --table-head-bg: #EFF1FA;
    --sidebar-bg: #141C2E;
    --surface-glass: rgba(16, 24, 40, .022);
    --surface-glass-strong: rgba(16, 24, 40, .05);
    --border-subtle: rgba(16, 24, 40, .09);
    --border-strong: rgba(16, 24, 40, .15);
    --scrim: rgba(16, 24, 40, .45);

    --text-primary: #101828;
    --text-secondary: #475467;
    --text-tertiary: #98A2B3;

    --indigo: #4F46E5;
    --indigo-dark: #4338CA;
    --violet: #6366F1;
    --brand-gradient: linear-gradient(135deg, #4F46E5, #6366F1);
    --accent-soft: rgba(79, 70, 229, .10);

    --cyan: #0E7090;
    --emerald: #067647;
    --pink: #C11574;
    --orange: #B54708;
    --blue: #175CD3;

    --success: #067647;
    --success-bg: rgba(6, 118, 71, .10);
    --danger: #B42318;
    --danger-bg: rgba(180, 35, 24, .10);
    --warning: #B54708;
    --warning-bg: rgba(181, 71, 8, .10);
    --info: #175CD3;
    --info-bg: rgba(23, 92, 211, .10);
    /* Text and icon on a filled toast — see the .toast rules near the bottom of this file. */
    --toast-ink: #FFFFFF;
    --gray: #475467;
    --gray-bg: rgba(71, 84, 103, .09);
    --cyan-bg: rgba(14, 112, 144, .10);
    --pink-bg: rgba(193, 21, 116, .10);
    --purple-bg: rgba(99, 102, 241, .10);

    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);
    --shadow-md: 0 4px 12px rgba(16, 24, 40, .08);
    --shadow-lg: 0 12px 32px rgba(16, 24, 40, .14);
  }
}

/* Explicit toggle always wins over the system preference. Same values as above. */
:root[data-theme="light"] {
  color-scheme: light;

  --bg-primary: #F7F8FA;
  --bg-secondary: #FFFFFF;
  --bg-elevated: #FFFFFF;
  --table-head-bg: #EFF1FA;
  --sidebar-bg: #141C2E;
  --surface-glass: rgba(16, 24, 40, .022);
  --surface-glass-strong: rgba(16, 24, 40, .05);
  --border-subtle: rgba(16, 24, 40, .09);
  --border-strong: rgba(16, 24, 40, .15);
  --scrim: rgba(16, 24, 40, .45);

  --text-primary: #101828;
  --text-secondary: #475467;
  --text-tertiary: #98A2B3;

  --indigo: #4F46E5;
  --indigo-dark: #4338CA;
  --violet: #6366F1;
  --brand-gradient: linear-gradient(135deg, #4F46E5, #6366F1);
  --accent-soft: rgba(79, 70, 229, .10);

  --cyan: #0E7090;
  --emerald: #067647;
  --pink: #C11574;
  --orange: #B54708;
  --blue: #175CD3;

  --success: #067647;
  --success-bg: rgba(6, 118, 71, .10);
  --danger: #B42318;
  --danger-bg: rgba(180, 35, 24, .10);
  --warning: #B54708;
  --warning-bg: rgba(181, 71, 8, .10);
  --info: #175CD3;
  --info-bg: rgba(23, 92, 211, .10);
  /* Text and icon on a filled toast — see the .toast rules near the bottom of this file. */
  --toast-ink: #FFFFFF;
  --gray: #475467;
  --gray-bg: rgba(71, 84, 103, .09);
  --cyan-bg: rgba(14, 112, 144, .10);
  --pink-bg: rgba(193, 21, 116, .10);
  --purple-bg: rgba(99, 102, 241, .10);

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);
  --shadow-md: 0 4px 12px rgba(16, 24, 40, .08);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, .14);
}
:root[data-theme="dark"] { color-scheme: dark; }
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  /* No webfont: these deploy on office LANs with no internet, where a Google
     Fonts link is a blocked request and a flash of nothing. The system UI stack
     is what every OS already renders best. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--indigo); outline-offset: 2px; border-radius: 4px; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); }

.ui-icon { display: inline-block; vertical-align: -3px; flex: none; }

/* AJAX top progress bar */
#ajax-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%; z-index: 999;
  background: var(--accent);
  transition: opacity 200ms ease;
}

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

/* ================= Sidebar ================= */
/* Standard expandable ERP-style sidebar by default (icon + visible label, click-to-expand
   accordion for groups) — a hover-triggered flyout read as unfamiliar/broken rather than
   premium, so that behavior is now opt-in via the collapse toggle (.sidebar.collapsed), where
   it correctly signals "this is a compact rail, hover for more" instead of being the default
   first impression. */
.sidebar {
  width: 252px;
  flex: none;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  display: flex;
  flex-direction: column;
  padding: 18px 12px;
  position: relative;
  z-index: 40;
  transition: width 200ms ease;
}
/* ---- Dark sidebar, in both themes -----------------------------------------------------------
   The panel is its own surface rather than a tinted edge of the page, so it carries its own
   palette. These are the SAME token names the page uses, redefined here: custom properties
   inherit, so every existing rule inside .sidebar (nav labels, children, the brand block, the
   theme toggle, the user chip, the footer) resolves against these without being rewritten.
   Measured against #141C2E: 16.3:1 for primary text, 10.9:1 for nav labels, 6.5:1 for captions. */
.sidebar {
  --text-primary: #F8FAFC;
  --text-secondary: #C7CFDE;
  --text-tertiary: #94A0B8;
  --border-subtle: rgba(255, 255, 255, .09);
  --border-strong: rgba(255, 255, 255, .18);
  --surface-glass: rgba(255, 255, 255, .05);
  --surface-glass-strong: rgba(255, 255, 255, .10);
  --bg-secondary: rgba(255, 255, 255, .06);

  /* One hue for both states. Solid for the selected row, a wash of the same colour for hover. */
  --nav-highlight: #4F46E5;
  --nav-highlight-soft: rgba(129, 140, 248, .16);
  --nav-highlight-edge: rgba(129, 140, 248, .45);
}

.sidebar .brand { display: flex; align-items: center; gap: 10px; padding: 2px 6px 16px; margin-bottom: 8px; border-bottom: 1px solid var(--border-subtle); }
.sidebar .brand-mark {
  width: 36px; height: 36px; border-radius: var(--radius-sm); flex: none;
  background: var(--brand-gradient); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 12px; letter-spacing: .02em;
  box-shadow: var(--glow-indigo);
}
/* A tenant logo sits in its own tile: no gradient or glow behind it, because those are the
   product's brand and would tint somebody else's mark. `contain` so a wide wordmark is letterboxed
   rather than cropped — logos are rarely square and cropping one is worse than showing it small. */
.sidebar .brand-mark.has-logo {
  background: var(--surface-glass-strong);
  box-shadow: none;
  overflow: hidden;
  padding: 3px;
}
.sidebar .brand-mark.has-logo img { width: 100%; height: 100%; object-fit: contain; display: block; }
.sidebar .brand-name { font-weight: 800; font-size: 15px; color: var(--text-primary); letter-spacing: .01em; white-space: nowrap; overflow: hidden; }

/* Straddles the sidebar edge — half on the dark panel, half on the page — so it takes the panel's
   own colours explicitly rather than inheriting --bg-elevated, which is white in light mode and
   would have left a pale icon on a white disc. Hovering fills it with the same indigo the nav
   uses for its selected row, so the whole column speaks one language. */
.sidebar-collapse-btn {
  position: absolute; top: 66px; right: -12px; width: 24px; height: 24px; border-radius: 50%;
  background: var(--sidebar-bg); border: 1px solid rgba(255, 255, 255, .22); color: #C7CFDE;
  display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 45; padding: 0;
  transition: background var(--transition), color var(--transition), border-color var(--transition); box-shadow: var(--shadow-sm);
}
.sidebar-collapse-btn:hover { color: #fff; background: var(--nav-highlight, #4F46E5); border-color: transparent; }
.sidebar-collapse-btn svg { transition: transform 200ms ease; }
.sidebar.collapsed .sidebar-collapse-btn svg { transform: rotate(180deg); }

/* Now the foot of the rail, not under the brand — so it is bounded above by a rule rather than
   below, and no longer competes with the product name for the top of the column. */
.sidebar .user-box {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 6px 10px; width: 100%;
}
.sidebar .user-box .avatar {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  background: var(--surface-glass-strong); border: 1px solid var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 12px; color: var(--text-primary);
}
.sidebar .user-box .name { font-weight: 600; color: var(--text-primary); font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar .user-box .role { font-size: 11px; color: var(--text-tertiary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.sidebar nav { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 4px 0; display: flex; flex-direction: column; gap: 2px; width: 100%; }
.sidebar nav::-webkit-scrollbar { width: 5px; }

.nav-group { position: relative; width: 100%; }
.nav-group > .nav-label {
  display: flex; align-items: center; gap: 12px; width: 100%; height: 42px; padding: 0 11px;
  border-radius: var(--radius-sm); cursor: pointer;
  font-size: 13.5px; font-weight: 600; color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
}
.nav-group > .nav-label .nav-ico { flex: none; width: 18px; display: flex; align-items: center; justify-content: center; color: #fff; }

/* Dimmed at rest so the column reads as one list rather than twelve badges; full strength on
   hover, on the open group, and on the active row. */
.nav-group > .nav-label .nav-ico { opacity: .82; transition: opacity var(--transition); }
.nav-group > .nav-label:hover .nav-ico,
.nav-group.open > .nav-label .nav-ico,
.nav-group.has-active > .nav-label .nav-ico,
.nav-group > .nav-label.active .nav-ico { opacity: 1; }
.nav-group > .nav-label .chev { flex: none; margin-left: auto; opacity: .55; transition: transform 200ms ease; }
.nav-group.open > .nav-label .chev { transform: rotate(180deg); }
/* Hover and selected are the same indigo, at two strengths: hovering shows you where you are about
   to go in the colour that will mark it once you are there, and the selected row is simply the
   loudest version of it. Two different hues here would read as two different kinds of state. */
.nav-group > .nav-label:hover { background: var(--nav-highlight-soft); color: var(--text-primary); }
.nav-group.open > .nav-label { color: var(--text-primary); }
.nav-group > .nav-label.active {
  background: var(--nav-highlight); color: #fff;
  box-shadow: inset 0 0 0 1px var(--nav-highlight-edge);
}
/* A collapsed group holding the current page — marked, but never louder than the page itself. */
.nav-group.has-active > .nav-label { background: var(--surface-glass); color: var(--text-primary); }

/* Always-visible label text (was a hover tooltip in an earlier iteration) */
.nav-group > .nav-label .rail-tip {
  font-size: 13.5px; font-weight: 600; color: inherit; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; flex: 1;
}

/* In-place accordion for grouped nav items */
.nav-children {
  overflow: hidden; max-height: 0; padding: 0 0 0 38px;
  transition: max-height 220ms ease;
}
.nav-group.open .nav-children { max-height: 480px; }
.nav-children .flyout-title { display: none; }
.nav-children a {
  display: block; padding: 8px 10px; margin: 1px 0; font-size: 13px; color: var(--text-secondary); border-radius: 8px;
  transition: background var(--transition), color var(--transition);
}
.nav-children a:hover { background: var(--nav-highlight-soft); color: var(--text-primary); }
.nav-children a.active {
  background: var(--nav-highlight); color: #fff; font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--nav-highlight-edge);
}

.sidebar .rail-bottom { margin-top: auto; padding-top: 10px; border-top: 1px solid var(--border-subtle); }
/* The brand block is now two lines — the tenant's name over what the product is. */
.sidebar .brand-titles { min-width: 0; }
.sidebar .brand-sub {
  font-size: 11px; color: var(--text-tertiary); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sidebar .rail-footer {
  padding: 8px 6px 2px; border-top: 1px solid var(--border-subtle);
  font-size: 10.5px; line-height: 1.5; color: var(--text-tertiary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Collapsed to an icon rail there is no room for any of it, and a truncated copyright line is
   worse than none. */
.sidebar.collapsed .brand-sub,
.sidebar.collapsed .rail-footer,
.sidebar.collapsed .user-box > div:not(.avatar) { display: none; }
.sidebar.collapsed .user-box { justify-content: center; padding: 12px 0 10px; }

/* ---------- Collapsed mode: compact icon rail with hover tooltip / flyout ---------- */
.sidebar.collapsed { width: 76px; padding: 18px 0; align-items: center; }
.sidebar.collapsed .brand { flex-direction: column; padding: 0 0 16px; }
.sidebar.collapsed .brand-name { display: none; }
.sidebar.collapsed .user-box { flex-direction: column; padding: 4px 0 14px; }
.sidebar.collapsed .user-box .name, .sidebar.collapsed .user-box .role { display: none; }
.sidebar.collapsed nav { align-items: center; overflow: visible; }
.sidebar.collapsed .nav-group { width: 52px; }
.sidebar.collapsed .nav-group > .nav-label { width: 52px; justify-content: center; padding: 0; position: relative; }
.sidebar.collapsed .nav-group > .nav-label .chev { display: none; }
.sidebar.collapsed .nav-group > .nav-label.active::before {
  content: ''; position: absolute; left: -13px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 20px; border-radius: 3px; background: var(--brand-gradient);
}
.sidebar.collapsed .nav-group > .nav-label .rail-tip {
  /* This tooltip floats over the page surface, not the dark sidebar panel. Earlier this inherited
     .sidebar's dark-optimized (light-on-dark) text tokens via var(--text-primary) etc., which
     paired light-gray text with a light card and went nearly invisible. Using `revert` on those
     custom properties to undo it did NOT work — revert on a custom property undoes ALL author
     styling for it (there is no browser-default to fall back to), so var(--text-primary) just
     became invalid instead of resolving to :root's value. Simplest fix that actually works: give
     this small popup its own fixed light-card palette instead of inheriting anything. */
  position: absolute; left: calc(100% + 12px); top: 50%; transform: translateY(-50%) translateX(-4px);
  background: #fff; border: 1px solid #E4E7EC; color: #101828;
  padding: 6px 10px; border-radius: 8px; white-space: nowrap;
  box-shadow: var(--shadow-md); opacity: 0; pointer-events: none; transition: opacity 150ms ease, transform 150ms ease;
  z-index: 60; flex: none;
}
.sidebar.collapsed .nav-group:not(.has-children):hover > .nav-label .rail-tip { opacity: 1; transform: translateY(-50%) translateX(0); }
.sidebar.collapsed .nav-children {
  /* Same reasoning as .rail-tip above — fixed light-card palette, not inherited from .sidebar. */
  position: absolute; left: calc(100% + 12px); top: 50%; transform: translateY(-50%) translateX(-6px) scale(.98);
  min-width: 200px; max-height: none; background: #fff; border: 1px solid #E4E7EC;
  border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 8px; z-index: 60; margin: 0;
  opacity: 0; visibility: hidden; transition: opacity 160ms ease, transform 160ms ease, visibility 160ms;
}
.sidebar.collapsed .nav-group.has-children:hover .nav-children,
.sidebar.collapsed .nav-group.has-children.open .nav-children {
  opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0) scale(1);
}
.sidebar.collapsed .nav-children::before {
  content: ''; position: absolute; right: 100%; top: 50%; transform: translateY(-50%);
  border: 6px solid transparent; border-right-color: #fff;
}
.sidebar.collapsed .nav-children .flyout-title {
  display: block; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: #98A2B3; padding: 6px 10px 4px;
}
.sidebar.collapsed .nav-children a { padding: 8px 10px; color: #475467; }
.sidebar.collapsed .nav-children a:hover { color: #101828; }

/* ================= Topbar (floating) ================= */
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
/* A real app bar: flush to the top, edge to edge, one hairline separating it
   from the content. The floating rounded card that used to sit here wasted
   vertical space on every page and never aligned with the sidebar. */
.topbar {
  margin: 0; padding: 10px 20px;
  background: var(--bg-secondary);
  border: 0; border-bottom: 1px solid var(--border-subtle); border-radius: 0;
  display: flex; align-items: center; gap: 10px;
  position: sticky; top: 0; z-index: 20;
}
.topbar-search {
  flex: 1; min-width: 100px; max-width: 320px; display: flex; align-items: center; gap: 8px;
  background: var(--surface-glass-strong); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: 8px 12px; color: var(--text-tertiary);
  transition: border-color var(--transition), background var(--transition);
}
.topbar-search:focus-within { border-color: rgba(99, 102, 241, .55); background: var(--surface-glass); }
.topbar-search input {
  border: none; background: none; outline: none; color: var(--text-primary); font-size: 13px; flex: 1;
  padding: 0; min-width: 0;
}
.topbar-search input::placeholder { color: var(--text-tertiary); }
.topbar-greeting { font-size: 17px; font-weight: 700; color: var(--text-primary); white-space: nowrap; }
.topbar-actions { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
.topbar-icon-btn {
  width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
  color: var(--text-secondary); cursor: pointer; position: relative; transition: background var(--transition), color var(--transition);
  border: none; background: none;
}
.topbar-icon-btn:hover { background: var(--surface-glass-strong); color: var(--text-primary); }
.topbar-icon-btn .dot {
  position: absolute; top: 6px; right: 6px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--danger); border: 2px solid var(--bg-secondary);
}
.topbar-date {
  display: flex; flex-direction: column; align-items: flex-end; margin-right: 4px;
}
.topbar-date .d1 { font-size: 12.5px; font-weight: 700; color: var(--text-primary); }
.topbar-date .d2 { font-size: 10.5px; color: var(--text-tertiary); }

.mobile-menu-btn { display: none; }
.topbar .user-menu { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 5px 8px 5px 5px; border-radius: 999px; transition: background var(--transition); margin-left: 6px; }
.topbar .user-menu:hover { background: var(--surface-glass-strong); }
.topbar .user-menu .avatar {
  width: 34px; height: 34px; border-radius: 50%; background: var(--brand-gradient);
  color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px;
}
.impersonate-bar {
  display: flex; align-items: center; gap: 8px; color: var(--warning); background: var(--warning-bg);
  border: 1px solid rgba(251, 191, 36, .3); border-radius: 999px; padding: 6px 14px 6px 16px; font-size: 12.5px; flex: none;
}
.impersonate-bar .btn { margin-left: 6px; }

/* Dropdown panel (profile / notifications) */
.dropdown-panel {
  position: absolute; top: calc(100% + 10px); right: 0; min-width: 240px; max-width: 320px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); padding: 8px; z-index: 70; opacity: 0; visibility: hidden;
  transform: translateY(-6px); transition: opacity 150ms ease, transform 150ms ease, visibility 150ms;
}
.dropdown-panel.open { opacity: 1; visibility: visible; transform: none; }
.dropdown-panel .dd-header { padding: 8px 10px 6px; font-size: 12px; font-weight: 700; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .04em; }
.dropdown-panel .dd-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px; font-size: 13px;
  color: var(--text-secondary); cursor: pointer; transition: background var(--transition), color var(--transition);
}
.dropdown-panel .dd-item:hover { background: var(--surface-glass-strong); color: var(--text-primary); }
.dropdown-panel .dd-sep { height: 1px; background: var(--border-subtle); margin: 6px 4px; }
.dropdown-panel .dd-empty { padding: 20px 10px; text-align: center; color: var(--text-tertiary); font-size: 12.5px; }
.dropdown-wrap { position: relative; }
.dropdown-panel.search-results { left: 0; right: auto; top: calc(100% + 8px); width: max(100%, 260px); }
.dropdown-panel .dd-item mark { background: rgba(99, 102, 241, .35); color: inherit; border-radius: 3px; }
.dropdown-panel .dd-item.active-hl { background: var(--surface-glass-strong); color: var(--text-primary); }
.dd-note { padding: 10px 10px 4px; font-size: 12px; color: var(--text-tertiary); line-height: 1.5; }

@media (max-width: 700px) {
  .topbar { flex-wrap: wrap; row-gap: 8px; }
  .topbar-greeting { display: none; }
  .impersonate-bar span, .impersonate-bar b { white-space: nowrap; }
}

.content { padding: 22px 20px 32px; animation: fadeIn 180ms ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.breadcrumb { color: var(--text-muted); font-size: 12px; margin-bottom: 6px; }
.page-title { display: none; }

/* ================= Cards ================= */
/* A card is a solid panel, not a pane of frosted glass. The blur was costing a
   repaint on every scroll and, over a busy page, made nothing look grouped —
   everything was equally translucent, so nothing read as separate. */
.card {
  background: var(--bg-secondary); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
  padding: 18px; margin-bottom: 16px;
  box-shadow: var(--shadow-sm); transition: box-shadow var(--transition), border-color var(--transition);
}
.card-header {
  font-size: 13px; font-weight: 650; letter-spacing: 0; text-transform: none; color: var(--text-primary);
  border-bottom: 1px solid var(--border-subtle); padding-bottom: 12px; margin-bottom: 14px;
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px;
}

/* ================= Buttons ================= */
.btn {
  display: inline-flex; align-items: center; gap: 6px; border: none; border-radius: var(--radius);
  padding: 9px 16px; font-size: 13px; cursor: pointer; font-weight: 600;
  transition: background var(--transition), box-shadow var(--transition), transform 80ms ease, border-color var(--transition);
}
.btn:active:not(:disabled) { transform: translateY(1px); }
/* Solid, not a gradient with a coloured halo. A primary button appears many
   times on a page; a glow on each one turns a form into a light show. */
.btn-primary { background: var(--accent); color: #fff; box-shadow: var(--shadow-sm); }
.btn-primary:hover { background: var(--accent-dark); }
.btn-outline { background: var(--bg-secondary); border: 1px solid var(--border-strong); color: var(--text-primary); }
.btn-outline:hover { background: var(--surface-glass-strong); border-color: var(--text-tertiary); }
.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover { background: #ef5350; }
.btn-warning { background: var(--warning); color: #1a1200; }
.btn-warning:hover { filter: brightness(1.08); }
.btn-sm { padding: 6px 11px; font-size: 12px; }

/* Row actions inside a data table are tonal, not solid. Every row carries an Edit and a Delete,
   so two saturated blocks per row turned a quiet list into a wall of orange and red and gave the
   destructive action the same visual weight as the routine one. The tint keeps the colour coding
   (and the semantic tokens, so both themes follow automatically) while letting the data read
   first; hover fills the button in, so the affordance is still obvious.

   Deliberately scoped to .data-table: `.btn-danger` is also the confirm button in showConfirm()
   (js/ui.js), where a destructive choice SHOULD be solid and unmissable. That one is untouched. */
.data-table .btn-sm.btn-danger,
.data-table .btn-sm.btn-warning {
  font-weight: 500;
  box-shadow: none;
  border: 1px solid transparent;
}
/* Edit is the routine action, so it borrows the app's own accent rather than a warning colour —
   nothing about editing a department is a caution. Delete keeps the danger tokens. */
.data-table .btn-sm.btn-warning {
  background: var(--accent-soft);
  color: var(--accent);
}
.data-table .btn-sm.btn-warning:hover {
  background: var(--accent);
  color: var(--text-on-accent);
  filter: none;
}
.data-table .btn-sm.btn-danger {
  background: var(--danger-bg);
  color: var(--danger);
}
.data-table .btn-sm.btn-danger:hover {
  background: var(--danger);
  color: #fff;
}
.data-table .btn-sm.btn-warning:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Row actions as icons only, with the wording moved into the tooltip (Customers table).
   Three labelled buttons could not sit side by side in a narrow Actions column, so they wrapped
   onto three lines and every row rendered at triple height. Square icon buttons keep one row to
   one line; title + aria-label carry the label for both hover and screen readers. */
.action-icons { display: inline-flex; gap: 6px; }
.data-table .btn-sm.btn-icon { padding: 6px; line-height: 0; }
.data-table .btn-sm.btn-icon .ui-icon { margin: 0; }

/* Employees shown as used/limit in the Customers table; this marks the pair once the plan cap
   is reached, because that is the point at which the customer cannot add anybody else. */
.count-over { color: var(--danger); font-weight: 600; }

/* The customer-facing organization number. Tabular figures so a column of them lines up, and
   monospace-ish weight so it reads as an identifier to be copied rather than as prose. */
.org-id { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text-secondary); letter-spacing: .02em; }

/* Active/Inactive switch in a table row (Customers).
   A <button role="switch"> rather than a checkbox: pressing it fires a request immediately
   instead of holding a value some later form submit will send, and aria-checked is what tells a
   screen reader which of the two states it is currently in. The written label stays beside it —
   a bare track with no word next to it forces the reader to learn which side means on. */
.switch {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 0; border: none; background: none; cursor: pointer;
  font: inherit; font-size: 12px; color: var(--text-secondary);
}
.switch-track {
  position: relative; flex: none; width: 34px; height: 19px;
  border-radius: 999px; background: var(--border-strong);
  transition: background var(--transition);
}
.switch-thumb {
  position: absolute; top: 2px; left: 2px; width: 15px; height: 15px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
  transition: transform var(--transition);
}
.switch.on .switch-track { background: var(--success); }
.switch.on .switch-thumb { transform: translateX(15px); }
.switch.on { color: var(--success); font-weight: 600; }
.switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
/* Disabled only while its request is in flight, so the cursor says "working", not "forbidden". */
.switch:disabled { opacity: .55; cursor: progress; }

/* ---------- Master dashboard: renewal + ticket panes ---------- */

/* Two panes side by side, stacking below the width where a scrolling list inside half a screen
   stops being readable. */
.dash-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; align-items: start; }

/* A stat tile that is also a link. It inherits every .stat-card rule; this only removes the
   underline and inherited link colour the anchor would otherwise bring with it. */
.stat-link { text-decoration: none; color: inherit; }
.stat-link:hover { text-decoration: none; }

.dash-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.dash-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px; border: 1px solid var(--border); border-radius: 999px;
  background: none; cursor: pointer; font: inherit; font-size: 12.5px;
  color: var(--text-secondary); transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.dash-tab:hover { border-color: var(--text-tertiary); color: var(--text-primary); }
.dash-tab.active { background: var(--accent-soft); border-color: transparent; color: var(--accent); font-weight: 600; }
.dash-tab-count {
  min-width: 20px; padding: 0 5px; border-radius: 999px;
  background: var(--surface-glass-strong); font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums; text-align: center;
}
.dash-tab.active .dash-tab-count { background: var(--accent); color: #fff; }

/* Fixed height so a long list scrolls inside its own pane instead of pushing everything below it
   off the page. Short lists simply do not fill it — min-height would leave a hole under two rows. */
.dash-scroll { max-height: 320px; overflow-y: auto; margin: 0 -4px; padding: 0 4px; }

.dash-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 8px; border-radius: 8px;
  text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--border);
}
.dash-row:last-child { border-bottom: none; }
.dash-row:hover { background: var(--surface-glass-strong); text-decoration: none; }
/* min-width:0 is what lets the ellipsis below actually happen — without it a flex child refuses to
   shrink past its content and the long title pushes the badge out of the card. */
.dash-row-main { flex: 1; min-width: 0; }
.dash-row-title {
  font-size: 13px; font-weight: 600; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dash-row-sub {
  font-size: 11.5px; color: var(--text-tertiary); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.data-table .btn-sm.btn-danger:focus-visible  { outline: 2px solid var(--danger);  outline-offset: 1px; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn.is-loading { cursor: wait; }

/* ================= Forms ================= */
.form-row { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 14px; }
.form-group { flex: 1; min-width: 200px; }
.form-group label { display: block; font-size: 12.5px; font-weight: 600; color: var(--text-secondary); margin-bottom: 5px; }
.form-group .hint { font-size: 11.5px; color: var(--text-tertiary); margin-top: 3px; }
input[type="text"], input[type="number"], input[type="date"], input[type="time"],
input[type="email"], input[type="password"], input[type="tel"], select, textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--border-strong); border-radius: var(--radius); font-size: 13px;
  font-family: inherit; transition: border-color var(--transition), box-shadow var(--transition), background var(--transition);
  /* Solid, not a grey wash. A filled field on a card on a page reads as three
     shades of nothing; a white field with a real border reads as a field. */
  background: var(--bg-secondary); color: var(--text-primary);
}
input::placeholder, textarea::placeholder { color: var(--text-tertiary); }
input:hover, select:hover, textarea:hover { border-color: var(--text-tertiary); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--indigo); box-shadow: 0 0 0 3px var(--accent-soft);
}
input[readonly] { background: transparent; color: var(--text-secondary); }
textarea { resize: vertical; }
select option { background: var(--bg-elevated); color: var(--text-primary); }
.section-title {
  font-weight: 700; font-size: 13px; margin: 18px 0 10px; padding: 9px 12px; border-radius: 8px;
  color: var(--text-primary); border: 1px solid var(--border-subtle);
}
.section-title.rules { background: var(--success-bg); }
.section-title.hours { background: var(--info-bg); }
.section-title.ot { background: var(--warning-bg); }
.section-title.breaks { background: var(--purple-bg); }
.section-title.weekoff { background: var(--info-bg); }
.section-title.missed { background: var(--danger-bg); }
.section-title.latelogin { background: var(--warning-bg); }
.section-title.missedbreak { background: var(--gray-bg); }

/* ================= Split form layout (add / edit pages) ================= */
.form-card { padding: 0; }
.form-card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding: 15px 20px; border-bottom: 2px solid var(--indigo);
  font-size: 15px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-secondary);
}
.form-split { display: flex; flex-wrap: wrap; }
.form-split > .form-col { flex: 1 1 340px; min-width: 0; padding: 20px; }
.form-split > .form-col + .form-col { border-left: 1px solid var(--border-subtle); }
/* A tinted band, matching the table header treatment, so a long form reads as a stack of labelled
   groups rather than one continuous run of fields. Same --table-head-bg token, because these are
   the same idea in two places and they should not drift apart.

   The offsets are set per container, not on .form-legend itself: it appears inside .form-section
   (shift form, padding 18px 20px) AND inside .form-col (employee form, padding 20px). One shared
   negative margin would pull the band off-centre in whichever container it was not written for. */
.form-legend {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  background: var(--table-head-bg);
  border-bottom: 1px solid var(--border-strong);
}
.form-section > .form-legend { margin: -18px -20px 18px; padding: 11px 20px; }
.form-col > .form-legend    { margin: -20px -20px 18px; padding: 11px 20px; }
/* The accent bar marks which sections are mandatory, carried on the left edge now that the
   underline is a shared border rather than this element's own colour. */
.form-legend.is-required { color: var(--indigo); box-shadow: inset 3px 0 0 var(--indigo); }
.form-legend.is-optional { color: var(--text-secondary); }
/* A band flush against the card's top edge follows its rounding; one after a divider does not. */
.form-card > .form-section:first-of-type > .form-legend,
.form-card .form-split:first-of-type > .form-col > .form-legend {
  border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm);
}
.form-col .form-group { margin-bottom: 16px; }
.form-col .form-group:last-child { margin-bottom: 0; }
.form-group label .req { color: var(--danger); font-weight: 700; margin-left: 2px; }
.form-actions {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap;
  padding: 16px 20px; border-top: 1px solid var(--border-subtle);
}
.form-actions .spacer { margin-right: auto; }
.form-alert-slot:not(:empty) { padding: 16px 20px 2px; }

/* Stacked sections of a long form, each a fixed 4-up grid. Fields that only apply when a switch
   above them is on are hidden rather than greyed, so a section shrinks to what is actually in use. */
/* Divider on the top edge of every section but the first, rather than the bottom edge of every
   section but the last — the actions bar carries its own top border, so a bottom rule here would
   draw a second line right against it. */
.form-section { padding: 18px 20px; }
/* No divider between sections: each one now opens with its own tinted legend band, and a rule
   directly above that band reads as a doubled line. */
.form-section + .form-section { border-top: none; }
.form-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px 16px; }
.form-grid + .form-grid { margin-top: 14px; }
.form-grid > .form-group { min-width: 0; margin-bottom: 0; }
.form-grid > .form-group.span-2 { grid-column: span 2; }
@media (max-width: 1180px) {
  .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-grid > .form-group.span-2 { grid-column: span 2; }
}
@media (max-width: 620px) {
  .form-section { padding: 16px; }
  .form-grid, .form-grid > .form-group.span-2 { grid-template-columns: minmax(0, 1fr); grid-column: auto; }
}

/* Inline radio / checkbox rows inside a form group */
.form-group .radio-inline { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; padding-top: 5px; }
.form-group .radio-inline label,
.form-group .check-inline {
  display: inline-flex; align-items: center; gap: 7px; margin: 0;
  font-size: 13px; font-weight: 500; color: var(--text-primary); cursor: pointer;
}
.form-group .radio-inline input, .form-group .check-inline input { accent-color: var(--indigo); margin: 0; }

/* Toggle chips (week off days, and similar multi-selects) */
.chip-group { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 2px; }
.chip-group .chip {
  display: inline-flex; align-items: center; justify-content: center; position: relative;
  min-width: 54px; padding: 7px 12px; margin: 0; border: 1px solid var(--border-strong); border-radius: 9px;
  background: var(--surface-glass-strong); color: var(--text-secondary);
  font-size: 12.5px; font-weight: 600; cursor: pointer; user-select: none;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.chip-group .chip input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.chip-group .chip:hover { border-color: var(--indigo); color: var(--text-primary); }
.chip-group .chip.is-on {
  background: var(--brand-gradient); border-color: transparent; color: #fff;
  box-shadow: 0 4px 14px rgba(99, 102, 241, .3);
}
.chip-group .chip:focus-within { outline: 2px solid var(--indigo); outline-offset: 2px; }

/* File input, styled like the other controls */
input[type="file"] {
  width: 100%; padding: 7px 11px; border: 1px solid var(--border-strong); border-radius: 9px;
  background: var(--surface-glass-strong); color: var(--text-secondary); font-size: 13px; font-family: inherit;
}
input[type="file"]::file-selector-button {
  margin: 0 10px 0 0; padding: 6px 12px; border: 1px solid var(--border-strong); border-radius: 7px;
  background: var(--surface-glass-strong); color: var(--text-primary);
  font-family: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
input[type="file"]::file-selector-button:hover { border-color: var(--indigo); }

@media (max-width: 900px) {
  .form-split > .form-col + .form-col { border-left: none; border-top: 1px solid var(--border-subtle); }
}
@media (max-width: 560px) {
  .form-split > .form-col { padding: 16px; }
  .form-actions { padding: 14px 16px; }
  .form-actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* ================= Tables ================= */
.table-wrap { overflow-x: auto; border-radius: var(--radius); }
/* The table is the workhorse of an HR system — employees, attendance, payroll,
   leave are all tables. Figures get tabular numerals so columns of hours and
   amounts line up digit for digit; a proportional font makes a salary column
   ragged and genuinely harder to scan. */
table.data-table {
  width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px;
  font-variant-numeric: tabular-nums;
}
table.data-table th {
  /* Its own token rather than --bg-secondary: in light mode that resolves to #FFFFFF, identical
     to the card behind it, so the header row was invisible and the columns had no anchor. */
  text-align: left; background: var(--table-head-bg); padding: 10px 12px;
  border-bottom: 1px solid var(--border-strong);
  font-size: 11px; font-weight: 650; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: .04em;
  white-space: nowrap; position: sticky; top: 0; z-index: 1;
}
/* Round the band's outer corners so it sits inside the card rather than bleeding to its edges. */
table.data-table thead tr:first-child th:first-child { border-top-left-radius: var(--radius-sm); }
table.data-table thead tr:first-child th:last-child { border-top-right-radius: var(--radius-sm); }
table.data-table td {
  padding: 11px 12px; border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle; color: var(--text-primary);
}
/* Numeric columns are opted in per page with .num — right-aligned so the units
   place stacks, which is the whole point of a money or hours column. */
table.data-table th.num, table.data-table td.num { text-align: right; }
/* Explanatory prose in a table cell — the attendance engine's status_reason, which is a full
   sentence ("Late Present / Checked Out — Checked in after Check-In End Time…"). Capped and
   wrapped, because one long reason in an unconstrained cell stretches the whole table sideways;
   set smaller and quieter than the figures it is explaining. The full string is on the title. */
.data-table td.reason-cell {
  max-width: 280px; white-space: normal; line-height: 1.45;
  font-size: 11.5px; color: var(--text-secondary);
}
table.data-table tbody tr { transition: background var(--transition); }
table.data-table tbody tr:hover td { background: var(--surface-glass); }
table.data-table tbody tr:last-child td { border-bottom: none; }
/* ---------- Tabs ----------
   Two or three views of the same subject inside one card. A pill row rather than underlined
   text: the sidebar already uses an underline-free vocabulary, and a filled pill survives the
   theme switch without needing a separate border colour for each side. */
.tabs { display: flex; gap: 6px; margin-bottom: 16px; flex-wrap: wrap; }
.tab-btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 15px; border: 1px solid var(--border); border-radius: 999px;
  background: none; cursor: pointer; font: inherit; font-size: 13px; font-weight: 550;
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.tab-btn:hover { border-color: var(--text-tertiary); color: var(--text-primary); }
.tab-btn.active { background: var(--accent-soft); border-color: transparent; color: var(--accent); font-weight: 650; }
.tab-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* A count riding on a tab — how many rows are selected, how many are waiting. */
.tab-count {
  min-width: 20px; padding: 0 6px; border-radius: 999px; background: var(--surface-glass-strong);
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; text-align: center;
}
.tab-btn.active .tab-count { background: var(--accent); color: var(--text-on-accent); }

/* A ticked row in a selection table. Tinted rather than outlined, so a long list of ticks reads
   as one block at a glance instead of as a stack of separate boxes. */
.data-table tr.row-selected > td { background: var(--accent-soft); }

.table-toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; gap: 10px; flex-wrap: wrap; }
.table-toolbar .filters { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.table-toolbar .filters select, .table-toolbar .filters input { width: auto; min-width: 140px; }
.search-input-wrap { position: relative; display: inline-flex; align-items: center; }
.search-input-wrap .ui-icon { position: absolute; left: 9px; color: var(--text-tertiary); pointer-events: none; }
.search-input-wrap input { padding-left: 30px; min-width: 220px; }

.badge { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 700; white-space: nowrap; }
.badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge-present, .badge-active { background: var(--success-bg); color: var(--success); }
/* Late Present is a full present day, so it stays in the success family — tinted amber to read as
   "present, with a caveat" rather than as a separate outcome. */
.badge-late_present { background: var(--warning-bg); color: var(--warning); }
/* Early Present is likewise a full present day — tinted cyan so it reads as a variation on
   present rather than a problem. */
.badge-early_present { background: var(--cyan-bg); color: var(--cyan); }
.badge-absent { background: var(--danger-bg); color: var(--danger); }
.badge-half_day { background: var(--warning-bg); color: var(--warning); }
.badge-leave { background: var(--info-bg); color: var(--info); }
.badge-week_off, .badge-inactive { background: var(--gray-bg); color: var(--gray); }
.badge-holiday { background: var(--purple-bg); color: var(--violet); }
.badge-pending { background: var(--warning-bg); color: var(--warning); }
.badge-approved { background: var(--success-bg); color: var(--success); }
.badge-rejected { background: var(--danger-bg); color: var(--danger); }
.badge-fingerprint { background: var(--info-bg); color: var(--info); }
.badge-face { background: var(--purple-bg); color: var(--violet); }
.badge-card { background: var(--success-bg); color: var(--success); }
.badge-password { background: var(--warning-bg); color: var(--warning); }
.badge-manual { background: var(--gray-bg); color: var(--gray); }
.badge-unknown { background: var(--danger-bg); color: var(--danger); }

.pagination-info { color: var(--text-muted); font-size: 12.5px; }
.empty-state { text-align: center; padding: 46px 10px; color: var(--text-tertiary); }
.empty-state .ui-icon { opacity: .45; margin-bottom: 8px; }
.empty-state .empty-title { font-size: 13px; }
.empty-state .empty-sub { font-size: 12px; margin-top: 5px; opacity: .75; }
.alert { display: flex; align-items: flex-start; gap: 9px; padding: 10px 14px; border-radius: 10px; font-size: 13px; margin-bottom: 14px; }
.alert .ui-icon { margin-top: 1px; flex: none; }
.alert-danger { background: var(--danger-bg); color: var(--danger); }
.alert-success { background: var(--success-bg); color: var(--success); }
.alert-warning { background: var(--warning-bg); color: var(--warning); }
.alert-info { background: var(--info-bg); color: var(--info); }

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 18px; }
.stat-card {
  background: var(--surface-glass); border: 1px solid var(--border-subtle); border-radius: var(--radius); padding: 14px;
  box-shadow: var(--shadow-sm); transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
  border-top: 2px solid var(--indigo);
}
.stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.stat-card .value { font-size: 24px; font-weight: 700; line-height: 1.2; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.stat-card .label { font-size: 11.5px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .03em; margin-top: 2px; }
.stat-card.has-icon { display: flex; align-items: center; gap: 12px; }
.stat-card .stat-icon {
  width: 40px; height: 40px; border-radius: 10px; flex: none;
  display: flex; align-items: center; justify-content: center; font-size: 18px;
  background: var(--accent-soft); color: var(--indigo);
}
.stat-card.c-teal { border-top-color: var(--emerald); }
.stat-card.c-teal .stat-icon { background: var(--success-bg); color: var(--success); }
.stat-card.c-red { border-top-color: var(--danger); }
.stat-card.c-red .stat-icon { background: var(--danger-bg); color: var(--danger); }
.stat-card.c-blue { border-top-color: var(--blue); }
.stat-card.c-blue .stat-icon { background: var(--info-bg); color: var(--info); }
.stat-card.c-orange { border-top-color: var(--orange); }
.stat-card.c-orange .stat-icon { background: var(--warning-bg); color: var(--warning); }
.stat-card.c-purple { border-top-color: var(--violet); }
.stat-card.c-purple .stat-icon { background: var(--purple-bg); color: var(--violet); }
.stat-card.c-gray { border-top-color: var(--gray); }
.stat-card.c-gray .stat-icon { background: var(--gray-bg); color: var(--gray); }

.quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.quick-action {
  background: var(--surface-glass); border: 1px solid var(--border-subtle); border-radius: var(--radius); padding: 14px;
  display: flex; gap: 12px; align-items: center; box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.quick-action:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.quick-action .icon {
  width: 40px; height: 40px; border-radius: 10px; background: var(--brand-gradient);
  color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 17px; flex: none;
}
.quick-action .title { font-weight: 700; font-size: 13.5px; color: var(--text-primary); }
.quick-action .sub { font-size: 11.5px; color: var(--text-tertiary); }
.quick-action.c-teal .icon { background: linear-gradient(135deg, #34d399, #059669); }
.quick-action.c-red .icon { background: linear-gradient(135deg, #f87171, #dc2626); }
.quick-action.c-blue .icon { background: linear-gradient(135deg, #60a5fa, #2563eb); }
.quick-action.c-orange .icon { background: linear-gradient(135deg, #fbbf24, #d97706); }
.quick-action.c-purple .icon { background: linear-gradient(135deg, #a78bfa, var(--violet)); }
.quick-action.c-gray .icon { background: linear-gradient(135deg, #94a3b8, #64748b); }

/* ================= Modal ================= */
.modal-overlay {
  position: fixed; inset: 0; background: var(--scrim); display: none; align-items: center; justify-content: center; z-index: 200;
  backdrop-filter: blur(3px);
}
.modal-overlay.open { display: flex; animation: overlayIn 150ms ease; }
@keyframes overlayIn { from { opacity: 0; } to { opacity: 1; } }
.modal-box {
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: var(--radius-lg); width: 520px; max-width: 92vw; max-height: 88vh; overflow-y: auto;
  box-shadow: var(--shadow-lg); animation: modalIn 180ms cubic-bezier(.2,.9,.3,1.2);
}
@keyframes modalIn { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }
.modal-box .modal-header { padding: 15px 18px; border-bottom: 1px solid var(--border-subtle); font-weight: 700; color: var(--text-primary); display: flex; justify-content: space-between; align-items: center; }
.modal-x { cursor: pointer; color: var(--text-tertiary); display: flex; padding: 4px; border-radius: 6px; transition: background var(--transition), color var(--transition); }
.modal-x:hover { background: var(--surface-glass-strong); color: var(--text-primary); }
.modal-box .modal-body { padding: 18px; }
.modal-box .modal-footer { padding: 12px 18px; border-top: 1px solid var(--border-subtle); display: flex; justify-content: flex-end; gap: 8px; }
.confirm-icon { width: 36px; height: 36px; border-radius: 50%; background: var(--info-bg); color: var(--info); display: flex; align-items: center; justify-content: center; flex: none; }
.confirm-icon.danger { background: var(--danger-bg); color: var(--danger); }

/* ================= Toasts ================= */
#toast-host { position: fixed; top: 16px; right: 16px; z-index: 999; display: flex; flex-direction: column; gap: 8px; }
.toast {
  display: flex; align-items: center; gap: 10px; background: var(--bg-elevated); border: 1px solid var(--border-strong);
  border-radius: 10px; padding: 11px 14px; box-shadow: var(--shadow-lg); font-size: 13px; min-width: 260px; max-width: 360px;
  opacity: 0; transform: translateX(20px); transition: opacity 200ms ease, transform 200ms ease; border-left: 3px solid var(--info); color: var(--text-primary);
}
.toast.show { opacity: 1; transform: none; }
.toast span:not(.toast-close) { flex: 1; }
.toast-close { cursor: pointer; color: var(--text-tertiary); flex: none; display: flex; }
.toast-close:hover { color: var(--text-primary); }
/* Filled rather than tinted. --toast-ink is the one token that makes this work in both themes:
   light-theme semantic colours are dark enough for white text, dark-theme ones are light enough
   for near-black. The left border matches the fill so the old 3px stripe does not show as a seam. */
.toast-success, .toast-danger, .toast-warning, .toast-info {
  color: var(--toast-ink);
  border-color: transparent;
}
.toast-success .ui-icon, .toast-danger .ui-icon, .toast-warning .ui-icon, .toast-info .ui-icon { color: var(--toast-ink); }
/* The close button inherits the ink at reduced strength, then comes to full on hover — a
   tertiary-grey X is invisible against a saturated fill. */
.toast-success .toast-close, .toast-danger .toast-close,
.toast-warning .toast-close, .toast-info .toast-close { color: var(--toast-ink); opacity: .72; }
.toast-success .toast-close:hover, .toast-danger .toast-close:hover,
.toast-warning .toast-close:hover, .toast-info .toast-close:hover { color: var(--toast-ink); opacity: 1; }

.toast-success { background: var(--success); border-left-color: var(--success); }
.toast-danger  { background: var(--danger);  border-left-color: var(--danger); }
.toast-warning { background: var(--warning); border-left-color: var(--warning); }
.toast-info    { background: var(--info);    border-left-color: var(--info); }

/* ================= Spinner / loading ================= */
.spinner {
  display: inline-block; width: 15px; height: 15px; border: 2px solid rgba(255,255,255,.15);
  border-top-color: currentColor; border-radius: 50%; animation: spin 700ms linear infinite; vertical-align: -3px;
}
.btn .spinner { border-color: rgba(255,255,255,.35); border-top-color: #fff; }
.btn-outline .spinner, .btn-warning .spinner { border-color: rgba(0,0,0,.15); border-top-color: currentColor; }
.spinner-sm { width: 12px; height: 12px; border-width: 2px; }
.spinner-lg { width: 26px; height: 26px; border-width: 3px; }
@keyframes spin { to { transform: rotate(360deg); } }
.table-loading { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 30px 0; color: var(--text-tertiary); }
.page-loading { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 60px 0; color: var(--text-tertiary); font-size: 13.5px; }

/* ================= Skeleton loaders ================= */
.skeleton { position: relative; overflow: hidden; background: var(--surface-glass-strong); border-radius: 8px; }
.skeleton::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.08), transparent);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }
.skeleton-stat { height: 66px; border-radius: var(--radius); border: 1px solid var(--border-subtle); }
.skeleton-line { height: 12px; margin: 6px 0; }

/* ================= Login ================= */
/* A calm neutral ground. The two lavender radial washes that used to sit here
   were the first thing anyone saw and made the product read as a consumer app
   before a single field was filled in. */
.login-page { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 24px; background: var(--bg-primary); }
.login-box { background: var(--bg-secondary); border: 1px solid var(--border-subtle); padding: 32px; border-radius: var(--radius-xl); width: 380px; max-width: 100%; box-shadow: var(--shadow-lg); animation: modalIn 180ms ease; }
.login-box .brand-badge {
  width: 46px; height: 46px; border-radius: 14px; background: var(--brand-gradient);
  color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 18px; margin-bottom: 14px;
  box-shadow: var(--glow-indigo);
}
.login-box h1 { font-size: 19px; font-weight: 650; margin: 0 0 4px; color: var(--text-primary); letter-spacing: -.01em; }
.login-box .sub { color: var(--text-tertiary); font-size: 12.5px; margin-bottom: 20px; }

.avatar-fallback {
  display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px;
  border-radius: 50%; background: var(--accent-soft); color: var(--indigo); font-weight: 700; font-size: 12.5px;
}
.grid-day-cell { text-align: center; min-width: 62px; }
.legend-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 5px; }

@media (max-width: 860px) {
  /* Mobile is always the off-canvas drawer, always in its full labeled form — the desktop
     collapse toggle (icon-only rail) doesn't apply here, so its narrower width is overridden. */
  .sidebar, .sidebar.collapsed {
    position: fixed; z-index: 50; height: 100vh; width: 260px; transform: translateX(-100%);
    transition: transform 220ms ease; padding: 18px 12px; box-shadow: var(--shadow-lg); align-items: stretch;
  }
  .sidebar.open { transform: none; }
  .sidebar.collapsed .brand, .sidebar.collapsed .user-box { flex-direction: row; }
  .sidebar.collapsed .brand-name,
  .sidebar.collapsed .user-box .name, .sidebar.collapsed .user-box .role { display: block; }
  .sidebar.collapsed nav { align-items: stretch; }
  .sidebar.collapsed .nav-group { width: 100%; }
  .sidebar.collapsed .nav-group > .nav-label { width: 100%; justify-content: flex-start; padding: 0 11px; }
  .sidebar.collapsed .nav-group > .nav-label .chev { display: block; }
  .sidebar.collapsed .nav-group > .nav-label .rail-tip { position: static; opacity: 1; visibility: visible; transform: none; background: none; border: none; box-shadow: none; padding: 0; color: inherit; }
  /* Reset the desktop rail's absolute/hover-gated flyout back to a normal accordion — show/hide
     is driven by max-height + .open here, not opacity/visibility, so only the clicked group
     expands instead of every group rendering open at once. */
  .sidebar.collapsed .nav-children {
    position: static; max-height: 0; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: none; background: none; padding: 0 0 0 38px; overflow: hidden;
    transition: max-height 220ms ease;
  }
  .sidebar.collapsed .nav-group.open .nav-children { max-height: 480px; }
  .sidebar.collapsed .nav-children::before { display: none; }
  .sidebar.collapsed .nav-children .flyout-title { display: none; }
  /* The desktop-only fixed light-card palette above (for the floating flyout) does not apply here
     — on mobile this is back to a plain in-place accordion on the dark sidebar itself, so its text
     needs the sidebar's own light-on-dark colours, not the flyout's fixed dark-on-light ones. */
  .sidebar.collapsed .nav-children a { color: var(--text-secondary); }
  .sidebar.collapsed .nav-children a:hover { color: var(--text-primary); }
  .sidebar-collapse-btn { display: none; }
  .sidebar-backdrop { position: fixed; inset: 0; background: var(--scrim); z-index: 45; display: none; }
  .sidebar-backdrop.open { display: block; }
  .topbar { margin: 10px 12px 0; }
  .topbar-date { display: none; }
  .mobile-menu-btn { display: flex; }
  .content { padding: 14px; }
}
/* ---------- Charts (hand-built SVG donut + CSS bar charts, no library) ---------- */
.charts-row { display: grid; grid-template-columns: minmax(280px, 1fr) minmax(320px, 1.4fr); gap: 16px; align-items: stretch; }
@media (max-width: 900px) { .charts-row { grid-template-columns: 1fr; } }

.donut-chart-row { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; justify-content: center; padding: 6px 0; }
.donut-chart-row svg circle { transition: stroke-dasharray 600ms ease; }
.donut-legend { display: flex; flex-direction: column; gap: 8px; min-width: 140px; }
.donut-legend-item { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-primary); }
.donut-legend-item b { margin-left: auto; font-variant-numeric: tabular-nums; }
.donut-legend-item .legend-dot { width: 10px; height: 10px; }

.dept-chart { display: flex; flex-direction: column; gap: 16px; }
.dept-block .dept-name { font-size: 12.5px; font-weight: 700; color: var(--text-primary); margin-bottom: 6px; }
.dept-series { display: flex; flex-direction: column; gap: 5px; }
.series-row { display: grid; grid-template-columns: 56px 1fr 26px; align-items: center; gap: 8px; }
.series-row .series-label { font-size: 11px; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: .02em; }
.series-track { background: var(--surface-glass-strong); border-radius: 5px; height: 14px; overflow: hidden; }
.series-fill { height: 100%; border-radius: 5px; transition: width 600ms cubic-bezier(.2,.8,.2,1); min-width: 2px; }
.series-fill.present { background: linear-gradient(90deg, var(--emerald), #059669); }
.series-fill.absent { background: linear-gradient(90deg, #f2777a, var(--danger)); }
.series-row .series-count { font-size: 12px; font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-primary); }
.chart-empty { color: var(--text-tertiary); font-size: 12.5px; text-align: center; padding: 30px 0; }

/* Payslip document */
.payslip-sheet { background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: 28px 32px; max-width: 780px; margin: 0 auto; color: var(--text-primary); }
.payslip-header { text-align: center; border-bottom: 2px solid var(--border-strong); padding-bottom: 14px; margin-bottom: 18px; }
.payslip-company { font-size: 20px; font-weight: 800; letter-spacing: .02em; }
.payslip-title { font-size: 13px; font-weight: 700; letter-spacing: .12em; color: var(--text-tertiary); margin-top: 4px; }
.payslip-period { font-size: 12.5px; color: var(--text-tertiary); margin-top: 2px; }
.payslip-meta { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px 20px; margin-bottom: 16px; }
.payslip-meta div { display: flex; flex-direction: column; gap: 2px; }
.payslip-meta span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-tertiary); }
.payslip-meta b { font-size: 13.5px; }
.payslip-note { background: var(--warning-bg); color: var(--warning); border-radius: 8px; padding: 8px 12px; font-size: 12.5px; margin-bottom: 16px; }
.payslip-section-label { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-tertiary); margin-bottom: 8px; }
.payslip-attendance { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; margin-bottom: 18px; }
.payslip-att-cell { border-radius: 10px; padding: 8px 6px; text-align: center; }
.payslip-att-cell b { display: block; font-size: 17px; }
.payslip-att-cell span { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .03em; opacity: .85; margin-top: 2px; }
.payslip-att-cell.present { background: var(--success-bg); color: var(--success); }
.payslip-att-cell.absent { background: var(--danger-bg); color: var(--danger); }
.payslip-att-cell.half-day { background: var(--warning-bg); color: var(--warning); }
.payslip-att-cell.week-off { background: var(--gray-bg); color: var(--gray); }
.payslip-att-cell.holiday { background: var(--purple-bg); color: var(--violet); }
.payslip-att-cell.paid-leave { background: var(--info-bg); color: var(--info); }
.payslip-att-cell.unpaid-leave { background: var(--gray-bg); color: var(--gray); }
.payslip-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; border-top: 1px solid var(--border-subtle); border-bottom: 1px solid var(--border-subtle); padding: 16px 0; margin-bottom: 16px; }
.payslip-col-title { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-tertiary); margin-bottom: 8px; }
.payslip-col table { width: 100%; border-collapse: collapse; font-size: 13px; }
.payslip-col td { padding: 5px 0; border-bottom: 1px dashed var(--border-subtle); }
.payslip-col td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.payslip-col tr.total td { border-bottom: none; border-top: 2px solid var(--border-strong); font-weight: 700; padding-top: 8px; }
.payslip-col td.muted { color: var(--text-tertiary); border-bottom: none; font-style: italic; }
.payslip-net { display: flex; align-items: center; justify-content: space-between; background: var(--brand-gradient); color: #fff; border-radius: 10px; padding: 14px 20px; }
.payslip-net span { font-size: 13px; letter-spacing: .04em; text-transform: uppercase; opacity: .85; }
.payslip-net b { font-size: 22px; font-variant-numeric: tabular-nums; }
.payslip-footer { text-align: center; margin-top: 18px; }
/* Per-employee monthly attendance sheet — built on demand, one A4 page per employee, and
   handed to html2pdf.js (public/js/reports-monthly.js) for a real one-click .pdf download.
   html2canvas (which html2pdf uses internally) can't measure/rasterize a display:none element,
   so this sits off-screen instead of hidden — visually absent from the page without being
   display:none. Always plain black-on-white regardless of the app's theme since it's never
   meant to be seen directly. */
#print-sheet { position: absolute; left: -10000px; top: 0; width: 820px; }
/* html2canvas's document-cloning step doesn't reliably capture position:fixed/absolute content
   (a known limitation — the clone can mis-measure it as zero-height) — so for the brief moment
   generation actually runs (public/js/reports-monthly.js), this drops back into plain static
   flow instead, which it renders correctly, then goes back to hidden once the PDF is done. */
#print-sheet.generating { position: static; width: 820px; background: #fff; }

@media print {
  .sidebar, .topbar, .no-print { display: none !important; }
  .app-shell, .main, .content { display: block !important; margin: 0 !important; padding: 0 !important; }
  body { background: #fff !important; color: #000 !important; }
  .payslip-sheet { box-shadow: none; border: none; max-width: none; padding: 0; background: #fff; color: #000; }
  #print-sheet { display: none !important; }
  @page { size: A4; margin: 12mm; }
}

/* =========================================================================
   Customer App additions — pagination, the company profile page, the payroll
   dashboard and the employee 360 profile. Appended rather than woven into the
   sections above so the diff against the previous stylesheet stays readable.
   ========================================================================= */

/* Field help — the "?" beside a label (helpTip in js/ui.js). Shown on hover AND on keyboard
   focus, so the explanation is not mouse-only. */
.help-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: 5px; vertical-align: 1px;
  border-radius: 50%; cursor: help; position: relative;
  background: var(--surface-glass-strong); color: var(--text-tertiary);
  font-size: 10px; font-weight: 700; line-height: 1;
  transition: background var(--transition), color var(--transition);
}
.help-tip:hover, .help-tip:focus-visible { background: var(--accent); color: var(--text-on-accent); outline: none; }

.help-tip::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 7px); left: 50%; transform: translateX(-50%);
  /* Wide enough for a full sentence, capped so it never spans the viewport. min() rather than a
     fixed width so it still fits on a phone. */
  width: max-content; max-width: min(280px, 70vw);
  padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--bg-elevated); color: var(--text-primary);
  border: 1px solid var(--border-strong); box-shadow: var(--shadow-md);
  font-size: 11.5px; font-weight: 500; line-height: 1.5; text-align: left;
  white-space: normal; letter-spacing: 0; text-transform: none;
  opacity: 0; visibility: hidden; transition: opacity .12s ease;
  z-index: 60; pointer-events: none;
}
.help-tip:hover::after, .help-tip:focus-visible::after { opacity: 1; visibility: visible; }
/* Inputs sit in a grid that clips — the tooltip must escape its cell or it is cut off. */
.form-group { overflow: visible; }
/* Near the right edge the centred tooltip would run off-screen, so the last column's tips
   right-align to their own icon instead. */
.form-group:last-child .help-tip::after,
.form-row > .form-group:nth-child(4) .help-tip::after { left: auto; right: -4px; transform: none; }
@media (max-width: 700px) {
  /* One column on a phone: centring on the icon is fine again, and 70vw keeps it on screen. */
  .form-group:last-child .help-tip::after,
  .form-row > .form-group:nth-child(4) .help-tip::after { left: 50%; right: auto; transform: translateX(-50%); }
}

/* Support tickets (js/support.js, js/master-tickets.js). Cards, not a data table: the two things
   that matter are a long description and a long solution, and neither survives a table cell. */
.ticket {
  border: 1px solid var(--border-subtle); border-radius: var(--radius);
  padding: 14px 16px; margin-bottom: 10px; background: var(--surface-glass);
}
.ticket-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.ticket-subject { flex: 1; min-width: 0; font-size: 14.5px; font-weight: 700; color: var(--text-primary); }
.ticket-badges { display: flex; gap: 6px; flex: none; }
.ticket-meta { font-size: 11.5px; color: var(--text-tertiary); margin-top: 3px; }
/* pre-wrap, not a plain div: people paste steps to reproduce across several lines, and
   collapsing that whitespace turns a numbered list into one unreadable paragraph. */
.ticket-body {
  margin-top: 10px; font-size: 13px; line-height: 1.6; color: var(--text-secondary);
  white-space: pre-wrap; word-break: break-word;
}
.ticket-resolution {
  margin-top: 12px; padding: 11px 13px; border-radius: var(--radius-sm);
  background: var(--success-bg); border-left: 3px solid var(--success);
  font-size: 13px; line-height: 1.6; color: var(--text-secondary);
  white-space: pre-wrap; word-break: break-word;
}
.ticket-resolution-head {
  display: flex; align-items: center; gap: 6px; margin-bottom: 5px;
  font-size: 11.5px; font-weight: 700; color: var(--success);
  text-transform: uppercase; letter-spacing: .04em;
}
.ticket-actions { margin-top: 12px; display: flex; gap: 8px; flex-wrap: wrap; }
/* Who to call. Given its own tinted strip rather than a line of meta text, because on the Master
   Admin's queue this is the thing most tickets are actually resolved with. */
.ticket-contact {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 10px; padding: 8px 11px; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--text-secondary); font-size: 12.5px;
}
.ticket-contact .ui-icon { color: var(--accent); flex: none; }
.ticket-contact-actions { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }
@media (max-width: 560px) {
  .ticket-contact-actions { margin-left: 0; width: 100%; }
}
/* The original complaint, shown while the Master Admin writes the answer — so the reply is
   written against what was actually asked rather than from memory of the list row. */
.ticket-quote {
  padding: 11px 13px; margin-bottom: 14px; border-radius: var(--radius-sm);
  background: var(--surface-glass); border-left: 3px solid var(--border-strong);
  font-size: 13px; line-height: 1.6; color: var(--text-secondary);
  white-space: pre-wrap; word-break: break-word; max-height: 190px; overflow-y: auto;
}
@media (max-width: 560px) {
  .ticket-head { flex-direction: column; gap: 6px; }
}

/* Support contact links in the header's Help panel — icons rather than a paragraph of text, so
   the three ways to reach support are scannable at a glance and tappable on a phone. */
.support-links { display: flex; gap: 6px; padding: 6px; }
.support-link {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 6px; border-radius: var(--radius-sm);
  font-size: 11.5px; font-weight: 600; color: var(--text-secondary);
  text-align: center; transition: background var(--transition), color var(--transition);
}
.support-link:hover { background: var(--surface-glass-strong); color: var(--text-primary); }
.support-ico {
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
/* Each channel keeps the colour people already associate with it — WhatsApp green, a neutral
   accent for the phone, amber for mail — so the icons are identifiable without reading labels. */
.support-ico.phone    { background: var(--accent-soft); color: var(--accent); }
.support-ico.whatsapp { background: rgba(37, 211, 102, .16); color: #25D366; }
.support-ico.mail     { background: var(--warning-bg); color: var(--warning); }

/* Password field with a reveal toggle. The button sits inside the field's padding rather than
   beside it, so the input keeps the same width as every other control in the form. */
.password-field { position: relative; display: block; }
.password-field input { width: 100%; padding-right: 38px; }
.password-toggle {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  background: none; border: none; border-radius: 6px; cursor: pointer;
  color: var(--text-tertiary); transition: color var(--transition), background var(--transition);
}
.password-toggle:hover { color: var(--text-primary); background: var(--surface-glass-strong); }
.password-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Company logo picker — Master Admin company modal (js/master-companies.js) */
.logo-picker { display: flex; align-items: flex-start; gap: 14px; }
.logo-preview {
  flex: none; width: 76px; height: 76px; border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong); background: var(--surface-glass);
  display: flex; align-items: center; justify-content: center; overflow: hidden; padding: 5px;
  font-size: 11px; color: var(--text-tertiary); text-align: center;
}
/* `contain`, never `cover`: a logo is rarely square and cropping somebody's brand mark is worse
   than showing it letterboxed. */
.logo-preview img { width: 100%; height: 100%; object-fit: contain; display: block; }
.logo-picker-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.logo-picker-actions .hint { flex-basis: 100%; margin: 0; }

/* Notification list — Customer App (js/notifications.js). Deliberately not the .data-table
   treatment: these are things to read and act on, not records to scan in columns. */
.note-legend {
  font-size: 12.5px; color: var(--text-tertiary);
  padding: 0 2px 12px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 4px;
}
.note-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 10px; border-radius: var(--radius-sm);
  border-bottom: 1px solid var(--border-subtle);
  color: inherit; transition: background var(--transition);
}
.note-row:last-child { border-bottom: none; }
.note-row:hover { background: var(--surface-glass-strong); }
/* Unread is carried by a left bar and weight, not a wash of colour across the row — with a feed
   that is mostly unread, a tinted background on every row stops distinguishing anything. */
.note-row.unread { box-shadow: inset 2px 0 0 var(--accent); }
.note-row.unread .note-title { font-weight: 700; color: var(--text-primary); }
.note-ico {
  flex: none; width: 30px; height: 30px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-glass-strong); color: var(--text-secondary);
}
.note-ico.info    { background: var(--accent-soft);  color: var(--accent); }
.note-ico.success { background: var(--success-bg);   color: var(--success); }
.note-ico.warning { background: var(--warning-bg);   color: var(--warning); }
.note-ico.danger  { background: var(--danger-bg);    color: var(--danger); }
.note-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.note-title { font-size: 13.5px; font-weight: 600; color: var(--text-primary); }
.note-sub { font-size: 12.5px; color: var(--text-secondary); line-height: 1.45; }
.note-meta {
  flex: none; display: flex; align-items: center; gap: 8px;
  font-size: 11.5px; color: var(--text-tertiary); white-space: nowrap;
}
@media (max-width: 640px) {
  .note-meta { display: none; }
}

/* Pagination (see createPager / pagerInfoHtml / pagerControlsHtml in js/ui.js). Split into two
   bars: pager-top (row count + "Showing X of Y") sits above the table, pager-bottom (Previous /
   Page N of M / Next) sits below it. */
.pager {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.pager-top {
  justify-content: space-between;
  padding: 2px 2px 12px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border-subtle);
}
.pager-bottom {
  justify-content: center;
  padding: 12px 2px 2px;
  margin-top: 8px;
  border-top: 1px solid var(--border-subtle);
}
.pager-info { font-size: 12.5px; color: var(--text-tertiary); display: flex; align-items: center; gap: 12px; }
.pager-controls { display: flex; align-items: center; gap: 8px; }
.pager-page { font-size: 12.5px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.pager-size { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-tertiary); }
.pager-size select {
  padding: 4px 6px;
  font-size: 12.5px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  background: var(--surface);
  color: var(--text-primary);
}

/* Sortable column headers (see sortableHeader in js/ui.js). The neutral double-chevron is dimmed
   until the column is the active sort, so a busy header row does not read as seven active states. */
.data-table th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.data-table th.sortable .ui-icon { margin-left: 5px; vertical-align: -2px; opacity: .35; transition: opacity .12s ease; }
.data-table th.sortable:hover .ui-icon { opacity: .7; }
.data-table th.sortable.sorted { color: var(--text-primary); }
.data-table th.sortable.sorted .ui-icon { opacity: 1; }

/* A labelled progress meter — leave balances, plan usage */
.meter { height: 8px; border-radius: 999px; background: var(--surface-glass-strong); overflow: hidden; }
.meter > span { display: block; height: 100%; border-radius: 999px; background: var(--indigo); transition: width 240ms ease; }
.meter > span.warn { background: var(--warning); }
.meter > span.over { background: var(--danger); }
.meter-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 12.5px; margin-bottom: 5px; }
.meter-row b { font-variant-numeric: tabular-nums; }

/* Definition list used by the company and employee profile pages */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px 22px;
}
.detail-item .k {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-tertiary);
  margin-bottom: 3px;
}
.detail-item .v { font-size: 13.5px; font-weight: 600; color: var(--text-primary); word-break: break-word; }

/* Employee 360 header */
.profile-head { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.profile-avatar {
  width: 68px;
  height: 68px;
  border-radius: 20px;
  object-fit: cover;
  background: var(--brand-gradient);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: 800;
  flex: none;
  overflow: hidden;
}
.profile-avatar img { width: 100%; height: 100%; object-fit: cover; }
.profile-name { font-size: 19px; font-weight: 700; color: var(--text-primary); }
.profile-meta { font-size: 12.5px; color: var(--text-tertiary); margin-top: 2px; }
.profile-head-actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* Payroll dashboard KPI strip */
.kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.kpi {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  padding: 15px 16px;
  box-shadow: var(--shadow-sm);
}
.kpi .k { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-tertiary); }
.kpi .v {
  font-size: 23px;
  font-weight: 700;
  color: var(--text-primary);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
.kpi .sub { font-size: 11.5px; color: var(--text-tertiary); margin-top: 3px; }
.kpi.accent { border-left: 3px solid var(--indigo); }
.kpi.good .v { color: var(--success); }
.kpi.bad .v { color: var(--danger); }

/* Right-aligned numeric table columns — money and day counts read wrong when ragged */
.data-table td.num, .data-table th.num { text-align: right; font-variant-numeric: tabular-nums; }

@media (max-width: 700px) {
  .profile-head-actions { margin-left: 0; width: 100%; }
  .pager { justify-content: center; }
}

/* ================= Printed salary documents (public/js/salary-slip.js) =================
   Ruled black-on-white tables rather than the app's own palette: these are meant to be printed
   and filed, and a screen-tinted sheet photocopies badly. They keep the same look on screen so
   what you see before pressing Print is what comes out. */
.slip-sheet {
  background: #fff; color: #000; max-width: 210mm; margin: 0 auto 18px;
  padding: 14mm 12mm; border: 1px solid var(--border-subtle); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); font-size: 12.5px;
}
.slip-sheet-wide { max-width: 297mm; } /* the register is landscape A4 */
.slip-title { text-align: center; font-size: 17px; font-weight: 800; margin-bottom: 4px; }
.slip-subtitle { text-align: center; font-size: 12px; color: #444; margin-bottom: 12px; }
.slip-table { width: 100%; border-collapse: collapse; }
.slip-table td, .slip-table th { border: 1px solid #000; padding: 5px 7px; vertical-align: middle; }
.slip-table .slip-head th { text-align: center; font-weight: 700; background: #f1f1f1; }
.slip-table .slip-k { font-weight: 600; }
.slip-table .slip-v { text-align: right; }
.slip-table .slip-v-l { text-align: left; }
.slip-table .slip-total td { font-weight: 700; background: #f7f7f7; }
.slip-note { margin-top: 10px; font-size: 12px; font-style: italic; }

/* Register: many numeric columns, so centre them and keep the text ones left */
.slip-register { font-size: 11px; }
.slip-register td, .slip-register th { text-align: center; padding: 4px 5px; }
.slip-register td.l, .slip-register th.l { text-align: left; }
.slip-register .slip-sign-cell { min-width: 90px; height: 26px; }

/* Signed by hand on the printed sheet — nothing here stores a signature image */
.slip-signatures { display: flex; justify-content: space-between; gap: 24px; margin-top: 34px; }
.slip-sign { flex: 1; text-align: center; }
.slip-sign-line { border-top: 1px solid #000; margin-bottom: 5px; }
.slip-sign span { font-size: 11.5px; font-weight: 600; }

@media print {
  .slip-sheet { border: none; box-shadow: none; margin: 0; padding: 0; max-width: none; border-radius: 0; }
  .slip-sheet + .slip-sheet { page-break-before: always; }
  /* Orientation is not set here. A named page (page: landscapeSheet) needs Chrome 118+ and was
     being ignored, and @page cannot be scoped to a class — so salary-report.js injects a
     document-level @page while the register is open instead. */
}
/* ================= Printed Monthly Attendance sheet (public/js/reports-monthly.js) =============
   A4 portrait, exactly one page per employee, rendered into #print-sheet and rasterised by
   html2pdf. All white, no fills — this is a document to be printed, signed and filed, and colour
   only costs ink and photocopies badly. Text is bold throughout instead: at 2x html2canvas scale a
   normal-weight 9.5-10.5px black reads thin and grey, not the crisp black a printed sheet wants.

   Sizing is in px, not mm, because html2pdf does not honour mm here — it rasterises #print-sheet
   at its 820px width and scales that to the printable width (A4 210mm less the 6mm margin each
   side = 198mm). One PDF page is therefore 285mm tall / (198mm / 820px) = 1180px of content.
   Pinning each page element to exactly that, with overflow hidden, is what stops a 31-day month
   dribbling a few rows onto a second sheet. A 31-day month uses about 970px of the 1180. */
.attendance-sheet-page { width: 820px; height: 1180px; overflow: hidden; padding: 6px 12px; background: #fff; }

.ar-report { width: 100%; height: 100%; display: flex; flex-direction: column; color: #000; background: #fff; font-family: Arial, Helvetica, sans-serif; }
.ar-title {
  border: 1.5px solid #000; height: 30px; display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700; letter-spacing: .02em; margin-bottom: 10px;
}
.ar-info, .ar-summary, .ar-days { width: 100%; border-collapse: collapse; table-layout: fixed; background: #fff; }
.ar-info { border: 1.5px solid #000; }
.ar-summary { border: 1.5px solid #000; margin-top: 12px; }
.ar-info td, .ar-summary td { border: 1px solid #000; height: 19px; padding: 1px 5px; font-size: 10.5px; vertical-align: middle; }
.ar-info td.label, .ar-summary td.label { width: 17%; font-weight: 700; }
.ar-info td.value, .ar-summary td.value { width: 16%; font-weight: 700; }

.ar-days { border: 1.5px solid #000; margin-top: 12px; flex: 1 1 auto; }
.ar-days tbody { height: 100%; }
.ar-days th, .ar-days td {
  border: 1px solid #000; padding: 1px 2px; text-align: center; vertical-align: middle;
  font-size: 9.5px; line-height: 1.05;
}
.ar-days th { height: 26px; font-weight: 700; }
.ar-days td { height: 20px; font-weight: 700; }
.ar-info, .ar-summary, .ar-title { flex: 0 0 auto; }
.ar-days td.day { font-weight: 700; text-align: left; padding-left: 4px; }
.ar-days td.status { font-weight: 700; }
.ar-info tr > *:last-child,
.ar-summary tr > *:last-child,
.ar-days tr > *:last-child { border-right: 1.5px solid #000; }
.ar-days th:nth-child(1), .ar-days td:nth-child(1) { width: 12%; }
.ar-days th:nth-child(n+2), .ar-days td:nth-child(n+2) { width: 11%; }
/* Weekends are marked by italicising the day label rather than by a fill — the one distinction
   worth keeping once the tints are gone, and it survives a photocopy. */
.ar-days tr.weekend td.day { font-style: italic; }
.ar-days .manual-mark { font-size: 8px; vertical-align: super; margin-left: 1px; }


/* The sign-in mode switch. It was a bare <a> inheriting body colour, so it read
   as a stray sentence rather than the control it is. */
.login-box #toggle-mode {
  display: inline-block; margin: 2px 0 18px;
  font-size: 12.5px; font-weight: 600; color: var(--accent);
  border-bottom: 1px solid transparent; transition: border-color var(--transition);
}
.login-box #toggle-mode:hover { border-bottom-color: currentColor; }
