:root {
  /* Brand palette sampled directly from the ATAD logo:
     navy #243090 (wordmark), gold #b49024 (outer ring), cyan #54c0cc (inner ring). */
  --brand-navy: #243090;
  --brand-navy-dark: #1a2470;
  --brand-gold: #b49024;
  --brand-cyan: #54c0cc;

  --bg: #f5f6fa;
  --bg-alt: #eef0f7;
  --panel: #ffffff;
  --border: #e3e6ef;
  --text: #171c31;
  --text-muted: #6b7288;
  --primary: var(--brand-navy);
  --primary-dark: var(--brand-navy-dark);
  --primary-soft: #eef0fb;
  --accent: var(--brand-cyan);
  --danger: #c0392b;
  /* Height of the fixed top navigation (62px + its 3px gold rule). Sticky
     table headers park directly underneath it. */
  --sticky-top: 62px;
  --danger-bg: #fdecea;
  --success-bg: #e8f7f1;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(23, 28, 49, 0.07), 0 1px 2px rgba(23, 28, 49, 0.05);
  --shadow-lg: 0 10px 30px rgba(23, 28, 49, 0.10);

  /* ONE typeface, and on the machines that matter most it is Apple's own.
     `-apple-system` resolves to SF Pro on a Mac and on an iPhone, so the MD's
     screen and an employee's payslip are set in the real thing rather than an
     imitation of it — no download, no flash while it loads, nothing to license.
     Windows falls to Segoe UI and Android to Roboto, each the native face of
     its own system, which is the same principle rather than a compromise of it.

     A second face was tried here — figures in a monospace cut — and it read as
     two fonts fighting on one screen. Apple sets AED prices in the same face as
     the sentence beside them; weight carries the emphasis, never a different
     typeface. Columns of salaries line up through `tabular-nums` instead, which
     is invisible and does the same job. */
  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
               "Helvetica Neue", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-family: var(--font-sans);

  /* Apple publishes the tracking for every point size of SF Pro, and the curve
     is not the obvious one: it is slightly loose at 11, crosses zero at 12,
     tightens to its trough at 17, then opens out again and goes positive for
     display sizes. Setting one value everywhere — or tightening headings on the
     assumption that bigger means tighter — is exactly what makes type look
     almost right. These are their numbers, converted from 1/1000 em. */
  --track-11: 0.006em;
  --track-12: 0em;
  --track-13: -0.006em;
  --track-14: -0.011em;
  --track-15: -0.016em;
  --track-17: -0.026em;
  --track-19: -0.024em;
  --track-22: -0.012em;
  --track-25: 0.006em;
  --track-28: 0.014em;
  --track-31: 0.013em;
}

* { box-sizing: border-box; }

/* Opening a panel locks the page with overflow:hidden, which takes the
   scrollbar away — and on a machine that shows scrollbars permanently the
   whole page then jumps sideways by its width and back again on close.
   Reserving the gutter costs nothing and stops the flash. */
html { scrollbar-gutter: stable; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
}

a { color: var(--primary); }

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

/* ---------- Top nav ---------- */
.topnav {
  background: var(--primary);
  color: #fff;
  padding: 0 24px;
  height: 62px;
  border-bottom: 3px solid var(--brand-gold);
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 20;
}
.topnav .brand { font-weight: 700; font-size: 17px; letter-spacing: 0.2px; }
.topnav .brand span { opacity: 0.75; font-weight: 400; font-size: 13px; margin-left: 8px; }
.topnav-links { display: flex; gap: 4px; }
.topnav-links a {
  color: rgba(255,255,255,0.85);
  text-decoration: none;
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
}
.topnav-links a:hover { background: rgba(255,255,255,0.12); }
.topnav-links a.active { background: rgba(255,255,255,0.18); color: #fff; }
.topnav-right { display: flex; align-items: center; gap: 14px; font-size: 14px; }
.topnav-right button {
  background: rgba(255,255,255,0.14);
  color: #fff;
  border: none;
  padding: 7px 14px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
}
.topnav-right button:hover { background: rgba(255,255,255,0.24); }

.page-wrap { max-width: 1180px; margin: 0 auto; padding: 28px 24px 60px; width: 100%; }
/* A few screens are a wide table and little else — the loans list carries
   twelve columns, and squeezing them into the reading width is what made every
   row wrap into three. */
.page-wrap.wide { max-width: 1480px; }

h1 { font-size: 22px; margin: 0 0 4px; }
h2 { font-size: 17px; margin: 0 0 14px; }
.subtitle { color: var(--text-muted); font-size: 14px; margin: 0 0 22px; }

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px 22px;
  margin-bottom: 20px;
}

.panel-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--primary);
  color: #fff;
  border: none;
  padding: 9px 16px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { background: var(--primary-dark); }
.btn.secondary { background: #eef1f4; color: var(--text); }
.btn.secondary:hover { background: #e2e7ec; }
.btn.danger { background: var(--danger); }
.btn.danger:hover { background: #a3372a; }
.btn.small { padding: 5px 11px; font-size: 12.5px; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); }
th { color: var(--text-muted); font-weight: 600; font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.03em; }
tbody tr:hover { background: #fafbfc; }
/* Every figure in the app takes even digit widths, so a column of salaries
   reads as a column. That is all the mono face was ever for. */
td.num, th.num { text-align: right; }
/* A figure that wraps has been read wrong at least once. "2,600.00" breaking
   after the comma reads as two numbers, and it is also what makes a tight
   table suddenly two lines deep instead of narrower. Money keeps its line;
   the column is only ever as wide as its widest figure. */
td.num, th.num { white-space: nowrap; }
td.num, td.sn, th.sn, input.editf, .amount, .mono, .stat-card .value {
  font-variant-numeric: tabular-nums;
}

.badge { display: inline-block; padding: 3px 9px; border-radius: 20px; font-size: 12px; font-weight: 600; }
.badge.active { background: var(--success-bg); color: var(--accent); }
.badge.inactive { background: #f1f2f4; color: var(--text-muted); }
.badge.draft { background: #fff4e5; color: #b06a00; }
.badge.finalized { background: var(--success-bg); color: var(--accent); }

label { display: block; font-size: 13px; font-weight: 600; color: var(--text-muted); margin-bottom: 5px; }
input[type=text], input[type=number], input[type=email], input[type=password], input[type=date], select, textarea {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 14px;
  background: #fff;
  color: var(--text);
}
input:focus, select:focus, textarea:focus { outline: 2px solid #b9d0ea; border-color: var(--primary); }
.field { margin-bottom: 14px; }
.field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px 18px; }

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(15, 23, 33, 0.45);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 40px 16px; z-index: 50; overflow-y: auto;
}
.modal {
  background: #fff; border-radius: 12px; width: 100%; max-width: 640px;
  padding: 24px 26px; box-shadow: 0 20px 50px rgba(0,0,0,0.25);
}
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }

.hint { font-size: 12.5px; color: var(--text-muted); margin-top: 4px; }
.error-text { color: var(--danger); font-size: 13.5px; background: var(--danger-bg); padding: 9px 12px; border-radius: 8px; margin: 10px 0; }
.success-text { color: var(--accent); font-size: 13.5px; background: var(--success-bg); padding: 9px 12px; border-radius: 8px; margin: 10px 0; }

.empty-state { text-align: center; padding: 40px 20px; color: var(--text-muted); }

.login-wrap {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, #163c6f, #1d4f91 55%, #0f9d78);
}
.login-card {
  background: #fff; border-radius: 14px; padding: 36px 34px; width: 100%; max-width: 380px;
  box-shadow: 0 30px 60px rgba(0,0,0,0.25);
}
.login-card h1 { font-size: 19px; margin-bottom: 2px; }
.login-card .subtitle { margin-bottom: 24px; }

.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-bottom: 22px; }
.stat-card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow); }
.stat-card .value { font-size: 24px; font-weight: 700; }
.stat-card .label { font-size: 12.5px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }

/* A count that is also the way to reach what it counts. */
button.stat-card.stat-action {
  text-align: left; font: inherit; cursor: pointer; display: block; width: 100%;
}
button.stat-card.stat-action:hover { background: #fff7f6; }

.tag-input-row { display: flex; gap: 8px; }
.pill-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.pill { background: #eef1f4; border-radius: 20px; padding: 5px 12px; font-size: 13px; display: flex; align-items: center; gap: 8px; }
.pill.addition { background: var(--success-bg); color: var(--accent); }
.pill.deduction { background: var(--danger-bg); color: var(--danger); }
.pill button { border: none; background: transparent; cursor: pointer; font-size: 13px; color: inherit; opacity: 0.7; }

.mapping-table td, .mapping-table th { padding: 8px 10px; }
.unmatched-row { background: #fff8ec; }

@media print {
  .no-print { display: none !important; }
  body { background: #fff; }
  .page-wrap { padding: 0; max-width: none; }
}


/* ---------- Brand additions ---------- */
.brand-logo { height: 30px; width: auto; display: block; flex-shrink: 0; }
.topnav .brand { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.topnav .brand-text { display: flex; flex-direction: column; line-height: 1.15; white-space: nowrap; }
.topnav .brand-text .co { font-weight: 700; font-size: 13.5px; letter-spacing: .01em; white-space: nowrap; }
.topnav .brand-text .sub { font-size: 11px; opacity: .75; letter-spacing: .08em; text-transform: uppercase; }

/* The nav carries six items for admins, so it has to degrade gracefully on a
   narrow window rather than wrapping the company name onto three lines. */
.topnav { gap: 18px; }
.topnav-links {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.topnav-links::-webkit-scrollbar { display: none; }
.topnav-links a { white-space: nowrap; flex-shrink: 0; }
.topnav-right { flex-shrink: 0; display: flex; align-items: center; gap: 12px; white-space: nowrap; }

/* Two sections of the bar are one job under two names — a month of phone
   bills and a month of vehicle charges, both read, settled and handed to that
   month's payroll run — so they sit behind one button beside Payroll Runs.
   The panel hangs off the bar rather than off the strip of links, because the
   strip scrolls sideways and a box that scrolls clips what paints outside it. */
.nav-group-btn {
  display: inline-flex; align-items: center; gap: 4px;
  background: none; border: none; cursor: pointer; font-family: inherit;
  color: rgba(255,255,255,0.85);
  padding: 8px 14px; border-radius: 8px;
  font-size: 14px; font-weight: 500;
  white-space: nowrap; flex-shrink: 0;
}
.nav-group-btn:hover { background: rgba(255,255,255,0.12); }
.nav-group-btn.active { background: rgba(255,255,255,0.18); color: #fff; }
.nav-chevron { width: 13px; height: 13px; transition: transform 0.2s ease; }
.nav-group-btn.is-open .nav-chevron { transform: rotate(180deg); }

.nav-menu {
  position: absolute; z-index: 30; min-width: 236px;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--bg-alt); border: 1px solid var(--border);
  border-radius: 12px; padding: 6px; box-shadow: var(--shadow);
}
.nav-menu[hidden] { display: none; }
.nav-menu a { display: block; padding: 9px 12px; border-radius: 8px; text-decoration: none; color: var(--text); }
.nav-menu a:hover, .nav-menu a:focus-visible { background: var(--primary-soft); text-decoration: none; }
.nav-menu a.active { background: var(--primary-soft); }
.nav-menu-label { display: block; font-size: 13.5px; font-weight: 600; }
.nav-menu-note { display: block; font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }

@media (max-width: 1100px) {
  .topnav .brand-text { display: none; }   /* logo alone still identifies the site */
}
@media (max-width: 700px) {
  .topnav { padding: 0 14px; gap: 12px; }
  .topnav-right span { display: none; }    /* keep the log-out button reachable */
}

/* Nav links: gold underline on the active page */
.topnav-links a {
  position: relative;
  padding: 20px 12px;
  border-radius: 0;
  transition: color .15s ease, background .15s ease;
}
.topnav-links a.active::after {
  content: "";
  position: absolute;
  left: 10px; right: 10px; bottom: -3px;
  height: 3px;
  background: var(--brand-gold);
  border-radius: 2px 2px 0 0;
}
.topnav-links a:hover { background: rgba(255,255,255,.08); }

/* Login screen */
.login-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(1100px 500px at 50% -10%, rgba(84,192,204,.20), transparent 60%),
    linear-gradient(160deg, var(--brand-navy) 0%, var(--brand-navy-dark) 55%, #131a52 100%);
}
.login-card {
  background: var(--panel);
  border-radius: 16px;
  padding: 38px 36px 32px;
  width: 100%;
  max-width: 420px;
  box-shadow: var(--shadow-lg);
  border-top: 4px solid var(--brand-gold);
}
.login-card .login-logo { height: 46px; margin: 0 auto 22px; display: block; }
.login-card h1 { font-size: 20px; margin: 0 0 4px; text-align: center; }
.login-card .subtitle { text-align: center; margin: 0 0 24px; }

/* Buttons feel a touch more solid */
.btn { transition: background .15s ease, box-shadow .15s ease, transform .05s ease; }
.btn:active { transform: translateY(1px); }

/* Tables: clearer rows, sticky headers on long lists */
table thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--bg-alt);
  border-bottom: 1px solid var(--border);
}
table tbody tr:hover { background: var(--primary-soft); }

/* Panels lift slightly */
.panel { box-shadow: var(--shadow); }

/* Payslip print: keep the logo, drop the chrome */
/* Printing a run means printing sixty payslips, and each one has to be a page
   on its own — a slip split across two sheets is not a payslip, it is two bits
   of paper. Landscape is the default because that is how they are filed.
   The date, page number and site address that appear in the corners come from
   the browser, not from here: untick "Headers and footers" under More settings
   in the print dialog to lose them. */
@media print {
  @page { size: A4 landscape; margin: 11mm 14mm; }

  .no-print { display: none !important; }
  body { background: #fff; }
  .page-wrap { padding: 0; max-width: none; }

  .slip {
    border: none !important;
    box-shadow: none !important;
    margin: 0 auto;
    padding: 0;
    break-after: page;
    page-break-after: always;
    break-inside: avoid;
    page-break-inside: avoid;
  }
  .slip:last-child { break-after: auto; page-break-after: auto; }

  /* A table must not be the thing that splits a slip in half. */
  .slip table, .slip tr, .slip .slip-header, .slip .slip-totals {
    break-inside: avoid;
    page-break-inside: avoid;
  }
}

/* ---------------------------------------------------------------------------
   Overlay panels (modals), row highlighting and table tidy-ups.
   --------------------------------------------------------------------------- */

/* Stop the page behind an open panel from scrolling under it. */
body.modal-open { overflow: hidden; }

/* A close cross in the corner of a panel, so there is always a way out that
   doesn't depend on finding the right button at the bottom. */
.modal { position: relative; }
.modal-close {
  position: absolute; top: 12px; right: 12px;
  width: 30px; height: 30px; line-height: 1;
  border: none; border-radius: 8px; background: transparent;
  color: var(--text-muted); font-size: 20px; cursor: pointer;
}
.modal-close:hover { background: #eef1f4; color: var(--text); }

/* Wide panels — the payslip, for instance — need more room than a form. */
.modal.wide { max-width: 780px; }

/* Buttons that live in the last column of a table: keep them on one line and
   evenly spaced instead of wrapping under each other. */
.row-actions { display: flex; gap: 6px; flex-wrap: nowrap; justify-content: flex-end; white-space: nowrap; }
.row-actions .btn { flex: 0 0 auto; }

/* A table where one record is meant to read as one line. Long names and
   descriptions are cut with an ellipsis and carry the full text as a tooltip,
   which is better than the same row wrapping into three or four lines and
   losing the shape of the table. */
table.one-line th, table.one-line td { white-space: nowrap; padding: 9px 10px; font-size: 13px; }
table.one-line td { max-width: 190px; overflow: hidden; text-overflow: ellipsis; }
table.one-line td.check-cell, table.one-line td.row-actions { max-width: none; overflow: visible; }
table.one-line th .hint { font-size: 11px; font-weight: 400; }
table.one-line .btn.small { padding: 4px 9px; }

/* ---------------------------------------------------------------------------
   The employee's own page. Opened on a phone, by someone who is not logged in
   and did not choose to be here — so it is a list of months and nothing else,
   with targets big enough for a thumb.
   --------------------------------------------------------------------------- */
body.portal { background: var(--bg); }
.portal-shell { max-width: 620px; margin: 0 auto; padding: 0 16px 48px; }
/* Two rows at every width: the company and the light/dark switch, then the
   person. Names here run to four and five words; beside the logo they got a
   column two words wide, and beside a switch pinned to the corner they ran
   underneath it. On their own row they wrap cleanly and nothing sits on them. */
.portal-head {
  padding: 20px 4px 16px; border-bottom: 2px solid var(--primary); margin-bottom: 18px;
}
.portal-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 16px;
}
.portal-bar img { height: 36px; width: auto; flex-shrink: 1; min-width: 0; max-width: calc(100% - 84px); object-fit: contain; object-position: left center; }
.portal-bar .theme-switch { flex-shrink: 0; margin-left: auto; }
.portal-name { font-size: 20px; font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.portal-sub { font-size: 13px; color: var(--text-muted); margin-top: 4px; }
.portal-intro { font-size: 13px; color: var(--text-muted); margin: 0 4px 14px; }
.portal-list { display: flex; flex-direction: column; gap: 10px; }
.portal-card {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 16px 18px; min-height: 60px;
}
.portal-card:hover { border-color: var(--primary); }
.portal-month { font-size: 15px; font-weight: 600; }
.portal-net { text-align: right; white-space: nowrap; }
.portal-net-label { display: block; font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; }
.portal-net strong { font-size: 16px; }
.portal-empty { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px 22px; text-align: center; }
.portal-empty h2 { margin: 0 0 8px; font-size: 17px; }
.portal-empty p { margin: 0; color: var(--text-muted); font-size: 13.5px; }
/* A phone: the same two rows, a size smaller. */
@media (max-width: 460px) {
  .portal-head { padding: 16px 4px 14px; }
  .portal-bar { margin-bottom: 12px; }
  .portal-bar img { height: 30px; }
  .portal-name { font-size: 17px; }
}
@media print {
  .portal-shell { max-width: none; padding: 0; }
  .portal-head { display: none; }
}

/* A figure this person is not entitled to. Shown as a dash rather than a zero
   in a box, so it reads as "not applicable" and not "nothing this month". */
.not-entitled { color: var(--text-muted); opacity: .6; cursor: help; }

/* Serial-number column. */
td.sn, th.sn { width: 34px; color: var(--text-muted); font-variant-numeric: tabular-nums; text-align: right; }

/* Editable figures inside a table. The stepper arrows Chrome adds to a number
   field eat about 18px of the box, which was clipping longer values such as
   129.75 — they are hidden here and the width set from the content instead. */
table input[type="number"].editf {
  -moz-appearance: textfield;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
table input[type="number"].editf::-webkit-outer-spin-button,
table input[type="number"].editf::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}

/* A row that has been edited this session. The flash draws the eye at the
   moment of the change; the tint is what remains afterwards. The colour sits
   on the row rather than its cells so the frozen first and last columns can
   pick it up with background:inherit. */
table tbody tr.row-edited, table tbody tr.row-edited:hover { background: #fffaf0; }
@keyframes rowFlash {
  from { background: #ffe9b8; }
  to   { background: #fffaf0; }
}
table tbody tr.row-flash { animation: rowFlash 1.1s ease-out; }

/* A row added by "+ Add all active employees", so it is obvious who arrived. */
table tbody tr.row-added, table tbody tr.row-added:hover { background: #eefaf1; }

/* ---------------------------------------------------------------------------
   Payslip. Shared by the printable page and the overlay inside a payroll run.
   --------------------------------------------------------------------------- */
.slip { background: #fff; border: 1px solid var(--border); border-radius: 10px; padding: 30px 34px; max-width: 720px; margin: 0 auto 30px; }
.slip-header { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 2px solid var(--primary); padding-bottom: 16px; margin-bottom: 20px; }
.slip-header h2 { margin: 0; font-size: 20px; }
.slip-meta { text-align: right; font-size: 13px; color: var(--text-muted); }
.slip table { margin-bottom: 0; }
.slip th { font-size: 12px; }
.slip .hint { display: inline; font-size: 12px; }
.slip-totals { display: flex; justify-content: flex-end; margin-top: 16px; }
.slip-totals table { width: auto; min-width: 260px; }
.net-row td { font-weight: 700; font-size: 16px; border-top: 2px solid var(--text); }
.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }

/* Inside the overlay the slip is already on a white panel, so it drops its own
   border and outer spacing. The header keeps clear of the close cross. */
.modal .slip { border: none; padding: 0; margin: 0; max-width: none; }
.modal .slip .slip-meta { padding-right: 26px; }

@media (max-width: 640px) { .cols { grid-template-columns: 1fr; } }

/* Names get a column of their own wide enough for most of them to sit on one
   line; the handful of very long ones wrap onto a second rather than forcing
   the whole table wider than the panel it sits in. */
td.name-cell, th.name-cell { min-width: 132px; }

/* ---------------------------------------------------------------------------
   The payroll run table. Thirteen columns of editable figures is a lot to fit,
   so this one is packed tighter than the rest of the app: less padding, and
   fields sized to the largest figure they will ever hold rather than to a
   comfortable form width.
   --------------------------------------------------------------------------- */
#payslipsWrap table { font-size: 13px; }
#payslipsWrap th, #payslipsWrap td { padding: 8px 5px; }
#payslipsWrap th { font-size: 12px; letter-spacing: 0; }
#payslipsWrap .btn.small { padding: 4px 8px; font-size: 12px; }
#payslipsWrap tbody tr { background: #fff; }

/* Thirteen columns of editable figures have to fit inside the panel at any
   window width, because the moment this table needs a sideways scrollbar it
   becomes its own scrolling box — and a table inside a scrolling box cannot
   keep its header floating under the top navigation as the page scrolls.
   Fitting is therefore not a nicety; it is what makes the frozen header work.

   So the fields take whatever width their column is given rather than a fixed
   one, and each column is held just wide enough for the largest figure it can
   hold. The employee's name absorbs whatever is left over. */
#payslipsWrap input.editf { width: 100%; min-width: 0; padding: 6px 6px; font-size: 13px; }
#payslipsWrap td.num, #payslipsWrap th.num { min-width: 66px; }
#payslipsWrap td.name-cell, #payslipsWrap th.name-cell { min-width: 140px; width: 100%; }
#payslipsWrap td.sn, #payslipsWrap th.sn { min-width: 30px; width: 30px; }
/* The addition/deduction pair shares one column. */
#payslipsWrap td.pair { white-space: nowrap; min-width: 98px; }
#payslipsWrap td.pair input.editf { width: calc(50% - 7px); }
#payslipsWrap td.actions-cell { width: 1%; }

/* Below a wide desktop the table can no longer fit, so it scrolls sideways
   inside its panel instead of spilling out over the page. The employee's name
   and the buttons at the end stay frozen in place while it does, because those
   are the two things you need in order to know which row you are looking at
   and to act on it.

   The container is only given a scrollbar at those narrower widths: making an
   element scrollable also makes it the reference for sticky positioning, which
   would stop the table headers sticking to the top of the window on the wide
   screens where none of this is needed. */
/* A table too wide for its panel scrolls sideways inside it rather than
   spilling out over the page. Whether that is needed is measured in script,
   not guessed from the window width, because it depends on how wide the panel
   actually is.

   Making an element scrollable also makes it the reference for sticky
   positioning, so a scrolling table would otherwise lose its floating header.
   It is given a height as well, which puts the header back — sticking to the
   top of the scrolling box instead of to the top of the window — and the
   employee's name and the buttons at the end are frozen to the left and right
   edges while it scrolls, so it stays clear which row is which and what can be
   done to it. A table that fits needs none of this and keeps the ordinary page
   behaviour, with its header sticking under the top navigation. */
.table-scroll.is-scrolling {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-scroll.is-scrolling > table { margin-bottom: 0; }

/* Before a table is allowed to scroll it is given the chance to shrink: on a
   narrower screen the editable figures give up their fixed widths and take
   whatever the column allows. Keeping the whole table on screen is worth more
   than a comfortable input box, because it is what lets the header go on
   floating under the top navigation as the page scrolls — a table inside its
   own scrolling box cannot do that. */
@media (max-width: 1250px) {
  #payslipsWrap input.editf { width: 100% !important; min-width: 40px; }
  #payslipsWrap td.num { min-width: 0; }
}

.table-scroll.is-scrolling td.sn, .table-scroll.is-scrolling th.sn,
.table-scroll.is-scrolling td.name-cell, .table-scroll.is-scrolling th.name-cell,
.table-scroll.is-scrolling td.actions-cell, .table-scroll.is-scrolling th.actions-cell {
  position: sticky; background: inherit; box-sizing: border-box;
}
/* Frozen body cells sit above the scrolling ones; the frozen headers must sit
   above both, since the ordinary headers are themselves sticky at z-index 2. */
.table-scroll.is-scrolling tbody td.sn,
.table-scroll.is-scrolling tbody td.name-cell,
.table-scroll.is-scrolling tbody td.actions-cell { z-index: 1; }
/* A pinned header cell has to be opaque, or rows slide visibly under it — but
   painting it `--bg-alt` made it a different grey from the white header beside
   it, which read as a patch over the last column. The card's own colour is
   just as opaque and disappears. */
.table-scroll.is-scrolling thead th.sn,
.table-scroll.is-scrolling thead th.name-cell,
.table-scroll.is-scrolling thead th.actions-cell { z-index: 3; background: var(--panel); }

.table-scroll.is-scrolling td.sn, .table-scroll.is-scrolling th.sn { left: 0; width: 40px; min-width: 40px; }
.table-scroll.is-scrolling td.name-cell, .table-scroll.is-scrolling th.name-cell {
  left: 40px; box-shadow: 1px 0 0 var(--border);
}
.table-scroll.is-scrolling td.actions-cell, .table-scroll.is-scrolling th.actions-cell {
  right: 0; box-shadow: -1px 0 0 var(--border);
}

/* The comment above says a scrolling wrapper becomes the header's own sticky
   reference instead of the window, and that is the half of the story that
   was actually built: nothing here yet gives the wrapper the height that
   would let the header re-freeze against ITS top instead. Left alone, the
   header keeps the offset meant to clear the window's fixed nav bar — which,
   measured against the wrapper instead, plants it partway down the first
   row rather than above it. There is nothing inside this wrapper for the
   header to clear, so it sticks to the wrapper's own top edge here. The
   header rides away with the rest of the table on a page scroll at this
   width, rather than floating under the nav; that is the narrower trade a
   table already too wide for its panel makes. */
.table-scroll.is-scrolling thead th { top: 0; }


/* ---------------------------------------------------------------------------
   Messages. These replace the browser's own alert boxes, which name the site
   and look like an error the page has thrown.
   --------------------------------------------------------------------------- */
.toast-host {
  position: fixed; right: 20px; bottom: 20px; z-index: 200;
  display: flex; flex-direction: column; gap: 10px; align-items: flex-end;
  max-width: min(420px, calc(100vw - 40px)); pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--text); color: #fff;
  padding: 12px 12px 12px 15px; border-radius: 10px;
  box-shadow: 0 12px 30px rgba(0,0,0,0.25);
  font-size: 13.5px; line-height: 1.45;
  animation: toastIn .22s ease-out;
}
.toast-body { flex: 1; }
.toast-x {
  background: none; border: none; color: inherit; opacity: 0.6;
  font-size: 17px; line-height: 1; cursor: pointer; padding: 0 2px;
}
.toast-x:hover { opacity: 1; }
.toast-success { background: var(--accent); }
.toast-error { background: var(--danger); }
.toast-out { animation: toastOut .22s ease-in forwards; }
@keyframes toastIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes toastOut { to { opacity: 0; transform: translateY(6px); } }

.confirm-body { font-size: 14px; line-height: 1.55; max-height: 46vh; overflow-y: auto; }
.confirm-body ol, .confirm-body ul { margin: 10px 0 0; padding-left: 22px; }
.confirm-body li { margin-bottom: 2px; }

/* ---------------------------------------------------------------------------
   Headings and column names are Title Case rather than shouted in capitals.
   --------------------------------------------------------------------------- */
th { text-transform: none; letter-spacing: 0; font-size: 13px; }
#payslipsWrap th { font-size: 12px; }

/* Each table's own header stays in view while that table is being scrolled
   through, and gives way to the next table's header underneath it — the same
   behaviour as a frozen pane in Excel. The offset clears the top navigation,
   which is itself fixed to the top of the window. */
table thead th { top: var(--sticky-top, 0px); }

/* The itemised lines under a grouped deduction — each fine under Vehicle
   Fines, for instance. Indented and lighter so the total stays the headline. */
.slip tr.sub-row td { padding-top: 4px; padding-bottom: 4px; border-bottom: none; font-size: 12.5px; color: var(--text-muted); }
.slip tr.sub-row td:first-child { padding-left: 26px; }

/* The payroll release date sits beside the run's status badge. */
.release-field { display: inline-flex; align-items: center; gap: 8px; margin-left: 14px; }
.release-field label { display: inline; margin: 0; font-size: 12.5px; }
.release-field input[type=date] { width: auto; margin: 0; padding: 5px 9px; font-size: 13px; }
.badge.released { background: var(--primary-soft); color: var(--primary); }

/* A highlighted note inside a panel — used to flag something that will happen
   when an action is taken, such as names being corrected on import. */
.panel-note {
  background: var(--primary-soft); border: 1px solid var(--border);
  border-radius: 8px; padding: 11px 14px; margin: 12px 0; font-size: 13.5px;
}

/* ---------------------------------------------------------------------------
   SEARCHING FOR A PERSON
   These started life inside staff.html for its own filter box. The employee
   pickers now use the same list, so the rules live here.
   --------------------------------------------------------------------------- */
.suggest-box {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 40;
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
  margin-top: 4px; max-height: 260px; overflow-y: auto;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.suggest-item { padding: 8px 12px; cursor: pointer; font-size: 14px; }
.suggest-item:hover, .suggest-item.active { background: var(--primary-soft); }
.suggest-item .code { color: var(--text-muted); font-size: 12px; }
.suggest-item.is-none { cursor: default; color: var(--text-muted); }
.suggest-item.is-none:hover { background: none; }
/* The blank is a decision here — "nobody yet", "same as SIM" — so it is
   reachable, but set apart from the people above it. */
.suggest-item.is-blank { color: var(--text-muted); font-style: italic; border-top: 1px solid var(--border); }

/* The picker itself. The <select> is still the value and still fires change;
   it is laid invisibly over the input rather than hidden, because a `required`
   control that cannot be focused makes Chrome refuse to submit the form at all
   instead of showing its "please choose" bubble. */
.picker { position: relative; display: block; }
.picker > select.emp-picker {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; pointer-events: none; margin: 0; border: 0; padding: 0;
  -webkit-appearance: none; appearance: none;
}
.picker > .picker-input { margin: 0; width: 100%; padding-right: 34px; }
.picker > .picker-input.is-empty { color: var(--text-muted); }
.picker > .picker-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; padding: 0; border: 0; border-radius: 980px;
  background: none; color: var(--text-muted); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.picker > .picker-clear:hover { background: rgba(0, 0, 0, 0.07); color: var(--text); }
.picker > .picker-clear svg { width: 13px; height: 13px; }

/* One panel per page, on <body>: half these pickers sit inside a table that
   scrolls sideways, and a scroll container clips anything painted outside it.
   Above the dialogs at z-index 50, below the messages at 200. */
.picker-panel {
  position: fixed; z-index: 120; top: 0; left: 0; right: auto;
  margin: 0; min-width: 240px;
}
.picker-panel[hidden] { display: none; }

/* ---------------------------------------------------------------------------
   DOCUMENTS
   A paperclip appears only where something is attached — on every row it would
   mean nothing. With several it carries the count, so it widens into a pill
   rather than squeezing a number into a 30px circle.
   --------------------------------------------------------------------------- */
.btn.paperclip.has-count { width: auto; padding: 0 10px 0 8px; gap: 4px; }
.btn.paperclip .clip-count { font-size: 12px; font-variant-numeric: tabular-nums; line-height: 1; }

.doc-section { margin: 16px 0 4px; }
.doc-section:empty { display: none; }
.doc-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 6px; }
.doc-title { margin: 0; font-size: 14px; }
.doc-add { cursor: pointer; }
.doc-add input { display: none; }
.doc-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); }
.doc-list li {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 2px; border-bottom: 1px solid var(--border);
}
.doc-list .doc-icon { color: var(--text-muted); display: flex; }
.doc-list .doc-icon .ico { width: 16px; height: 16px; }
.doc-list .doc-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.doc-list .doc-open {
  text-align: left; padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--link, var(--primary)); font: inherit; font-size: 14px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.doc-list .doc-open:hover { text-decoration: underline; text-underline-offset: 2px; }
.doc-list .hint { font-size: 12px; }
.doc-empty { margin: 4px 0 0; }

/* A long table that is not the point of the screen, but is still worth being
   able to open. The import review shows four lines about the people who need
   a decision; all sixty-two rows live in here, shut. */
details.import-all { margin: 14px 0 0; }
details.import-all > summary {
  cursor: pointer; font-size: 13px; color: var(--link, var(--primary));
  padding: 6px 2px; width: max-content; list-style-position: outside;
}
details.import-all > summary:focus-visible { outline: 2.5px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
details.import-all > table { margin-top: 8px; }

/* The line-items button carries a figure now, so it must not wrap onto two
   lines and make its row taller than the rest. */
#payslipsWrap td:has(> [data-items]) { white-space: nowrap; }
#payslipsWrap [data-items] { white-space: nowrap; }

/* ---------------------------------------------------------------------------
   One card per Etisalat bill during an import: every charge Etisalat printed,
   and what happens to it.
   --------------------------------------------------------------------------- */
.bill-card {
  border: 1px solid var(--border); border-radius: 10px; background: #fff;
  padding: 14px 16px; margin-bottom: 14px;
}
.bill-head { display: flex; justify-content: space-between; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.bill-head-right { display: flex; align-items: center; gap: 8px; }
.bill-card table { font-size: 13px; }
.bill-card th, .bill-card td { padding: 7px 8px; vertical-align: top; }
.bill-card .hint { font-size: 12px; }
.bill-foot {
  display: flex; justify-content: space-between; align-items: center; gap: 14px;
  flex-wrap: wrap; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border);
}
tr.needs-answer > td { background: var(--danger-bg); }

/* Amounts on a payslip never wrap — "AED 1,250.50" on two lines reads as two
   different numbers. */
.slip td.num, .slip th.num { white-space: nowrap; }

/* Telling staff their salary is out. The WhatsApp green is the app's own, so
   the button is recognisable at a glance in a long list of names. */
.btn.wa { background: #25d366; border-color: #25d366; color: #fff; }
.btn.wa:hover { background: #1fb457; border-color: #1fb457; }
.linkish {
  border: none; background: none; padding: 0 0 0 6px; cursor: pointer;
  font-size: 12px; color: var(--text-muted); text-decoration: underline;
}
.linkish:hover { color: var(--text); }

/* ---------------------------------------------------------------------------
   A payslip being drawn into a downloaded PDF (js/payslipPdf.js). Laid out off
   screen at the width it is captured at; the picture is taken of a copy with
   the theme forced to light, so nothing here needs a dark-mode rule.
   --------------------------------------------------------------------------- */
.pdf-stage { position: absolute; left: -20000px; top: 0; background: #fff; pointer-events: none; }
/* No card edge on paper — the same as print, and outranking the theme's own
   border on .slip the same way the print block does. */
.pdf-stage .slip { border: none !important; box-shadow: none !important; border-radius: 0 !important; background: #fff !important; margin: 0; max-width: none; }
