/* =============================================================
   Apex Workforce — Web Stylesheet

   BRANDING: the Apex 2026 (Figma) design language, ported from the
   mobile apps so web and phone read as one product. The tokens below
   mirror, name for name and value for value:
     • android-workforce/app/src/main/java/com/apex/workforce/ui/theme/Color.kt
     • ios-workforce/ApexWorkforce/Theme.swift  (enum Palette)

   The three rules that define the look — keep new UI on them:
     1. Screens sit on a white → #F0F4FF vertical gradient, not flat grey.
     2. Inputs are the STANDARD box: 8px radius, 1px #A3A3A3 border,
        16px/10px padding, 14px text, #171717 on focus. See AppTextField
        in the Android app (memory "figma-redesign-input-spec").
     3. Primary actions are DARK PILLS: #171717, fully rounded, #FAFAFA text.
        Blue (#1F53E3) is for links, accents and avatars — not for buttons.

   The older `--primary` indigo tokens are kept as aliases so untouched
   screens keep rendering; they now resolve to the new blue.
============================================================= */

:root {
  /* --- Apex 2026 core (mirrors Color.kt / Palette) --- */
  --ink:       #171717;   /* primary text + dark pill buttons */
  --ink-700:   #404040;
  --ink-600:   #525252;   /* secondary text / subtitles */
  --ink-500:   #737373;   /* placeholders */
  --ink-400:   #a3a3a3;   /* input borders */
  --ink-50:    #fafafa;   /* text on dark buttons */
  --link-blue: #0053e2;   /* links / accents — the 2026 design blue */

  --screen-top: #ffffff;  /* screen gradient — top */
  --screen-bot: #f0f4ff;  /* screen gradient — bottom */
  --header-top: #1f53e3;  /* blue header gradient — top */
  --header-bot: #0f2a8f;  /* blue header gradient — bottom */

  --card-border: transparent; /* design: cards have no border */
  --line:        #e5e5e5; /* dividers / neutral hairlines */
  --name-ink:    #171717; /* Typography/900 */
  --avatar-bg:   #7086fd;
  --section-lbl: #6b7a99;

  /* Report performance bands. Read off a machine's AVERAGE per shift, never the range
     total — a total crosses any fixed threshold on day two of a month view. */
  --band-green: #12b76a;
  --band-amber: #ff8d28;
  --band-red:   #ff383c;

  --ok-green:   #12b76a;  /* active / positive */
  --warn-gold:  #cc9c00;  /* upad amounts */
  --danger-red: #b42318;  /* destructive */

  /* --- Surfaces + legacy aliases (kept so all screens keep working) --- */
  --bg:        #eef0f7;   /* Fig.screen — the page under the wash */
  --hero:      rgba(0,141,255,.20);  /* Fig.hero — 20% #008DFF, fading out by 200px */
  --surface:   #ffffff;
  --surface-2: #f8fafc;
  --border:    #e4e8f0;
  --text:      var(--ink);
  --muted:     var(--ink-600);

  --primary:   var(--link-blue);
  --primary-d: var(--header-bot);
  --primary-l: #e3eaf8;

  --green:     #16a34a;
  --green-l:   #e8f5e9;
  --red:       #dc2626;
  --red-l:     #ffebee;
  --amber:     #d97706;
  --amber-l:   #fff3e0;
  --blue:      var(--link-blue);

  --radius:    16px;      /* cards (Figma) */
  --radius-sm: 8px;       /* inputs (Figma standard box) */
  --radius-pill: 100px;   /* buttons, chips, badges */
  --shadow:    0 2px 2px rgba(0,0,0,.08);
  --shadow-lg: 0 10px 40px rgba(16,24,40,.18);
  --shadow-blue: 0 8px 20px rgba(31,83,227,.30);

  /* Measured from the Figma Staff frame (772:4070) — the same values the two apps use. */
  --c-worker:    #1f53e3;  --c-worker-l:  #ebf0ff;
  --c-super:     #8635f6;  --c-super-l:   #f1e9ff;
  --c-designer:  #ef0078;  --c-designer-l:#ffe6f0;
  --c-other:     #01897c;  --c-other-l:   #d8f4f0;

  /* Inline-SVG icons used as CSS masks (tinted with currentColor). */
  --eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
  --eye-off: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.6 6.1A9.9 9.9 0 0 1 12 6c6.5 0 10 7 10 7a15.6 15.6 0 0 1-2.9 3.7M6.6 6.6A15.6 15.6 0 0 0 2 13s3.5 7 10 7a9.9 9.9 0 0 0 4.4-1M3 3l18 18M9.9 10a3 3 0 0 0 4.2 4.2'/%3E%3C/svg%3E");
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* Screens sit on the brand gradient, fixed so it doesn't repeat on scroll. */
  background: linear-gradient(180deg, var(--screen-top) 0%, var(--screen-bot) 100%) fixed;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  font-size: 15px;
}

.hidden { display: none !important; }
.muted  { color: var(--muted); }
.small  { font-size: 12.5px; }
.center { text-align: center; }

/* ---------- Buttons — dark pill is the primary action ---------- */
.btn {
  border: none; border-radius: var(--radius-pill);
  padding: 12px 22px; font-size: 14px; font-weight: 600; cursor: pointer;
  transition: background .15s, transform .05s, box-shadow .15s, opacity .15s;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: #fff; color: var(--ink); border: 1px solid var(--ink-400);
}
.btn:hover { background: var(--screen-bot); }
.btn:active { transform: scale(.98); }
.btn:disabled { opacity: .5; cursor: default; }

/* The Figma pill: near-black fill, off-white label. */
.btn-primary { background: var(--ink); color: var(--ink-50); border-color: var(--ink); }
.btn-primary:hover { background: var(--ink-700); }
/* Blue accent pill, with the brand glow — for emphasis, used sparingly. */
.btn-accent { background: var(--link-blue); color: #fff; border-color: var(--link-blue); box-shadow: var(--shadow-blue); }
.btn-accent:hover { background: var(--header-bot); }
.btn-ghost { background: transparent; color: var(--ink-600); border: 1px solid var(--ink-400); }
.btn-ghost:hover { background: var(--screen-bot); }
.btn-danger { background: #fff; color: var(--danger-red); border-color: var(--danger-red); }
.btn-danger:hover { background: var(--red-l); }
.btn-block { width: 100%; }
.btn-sm { padding: 7px 14px; font-size: 13px; }

.icon-btn {
  background: transparent; border: none; cursor: pointer;
  font-size: 20px; color: var(--ink); line-height: 1; padding: 6px 8px; border-radius: 8px;
}
.icon-btn:hover { background: var(--screen-bot); }

/* ---------- Forms — the STANDARD input box ----------
   8px radius · 1px #A3A3A3 · 16/10 padding · 14px · #171717 on focus.
   Matches AppTextField on Android and AppTextField on iOS exactly. */
label { display: block; font-size: 14px; font-weight: 500; color: var(--ink); margin: 12px 0 4px; }
input, select, textarea {
  width: 100%; padding: 10px 16px; border: 1px solid var(--ink-400);
  border-radius: var(--radius-sm); font-size: 14px; background: var(--surface);
  color: var(--ink); font-family: inherit;
}
input::placeholder, textarea::placeholder { color: var(--ink-500); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--ink); box-shadow: none;
}
textarea { resize: vertical; min-height: 70px; }

/* ---------- Splash ---------- */
.splash {
  min-height: 100vh; display: flex; flex-direction: column; gap: 14px;
  align-items: center; justify-content: center;
  background: linear-gradient(180deg, var(--screen-top) 0%, var(--screen-bot) 100%);
}
.splash .muted { color: var(--ink-600); }
/* Offline / can't-reach-server state inside the splash (session still valid). */
.splash-error {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  max-width: 380px; padding: 0 20px; text-align: center;
}
.splash-error p { color: var(--ink-600); font-size: 14px; margin: 0; }

/* =============================================================
   LOGIN — logo, title, standard inputs, dark pill. Mirrors the
   Android/iOS login screens (gradient background, no heavy card).
============================================================= */
.login-screen {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: 20px; background: linear-gradient(180deg, var(--screen-top) 0%, var(--screen-bot) 100%);
}
.login-card {
  background: var(--surface); width: 100%; max-width: 400px;
  border: 1px solid var(--card-border);
  border-radius: 20px; padding: 36px 28px; box-shadow: var(--shadow);
}
.login-brand { text-align: center; margin-bottom: 30px; }
/* The brand mark itself — same SVG the mobile apps draw. */
/* The Stichbook wordmark is 330.593x48 — height is width / 6.8876. */
.login-logo { width: 200px; height: 29px; margin: 0 auto 6px; display: block; }
/* The in-app sidebar mark. 138x20 is the phone home header's size (Figma), so the
   wordmark carries equal weight on every surface. */
.login-logo.small { width: 138px; height: 20px; margin: 0; }
.login-brand h1 { font-size: 20px; font-weight: 600; color: var(--ink); }
.login-brand .muted { font-size: 16px; color: var(--ink-600); margin-top: 8px; }
.login-error { color: var(--danger-red); font-size: 13px; margin-top: 10px; }
.login-hint { margin-top: 18px; text-align: center; font-size: 12px; }

/* ---------- Password show/hide ----------
   The eye sits INSIDE the standard input box, so the input keeps its 8px/1px
   border and just reserves room on the right for the button. Icons are inline
   SVG masks (no asset files) tinted with currentColor, so they follow the theme. */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 46px; }
.pw-toggle {
  position: absolute; top: 0; right: 0; height: 100%; width: 42px;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; padding: 0; cursor: pointer;
  color: var(--ink-600); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.pw-toggle:hover { color: var(--ink); }
.pw-toggle:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.pw-toggle::before {
  content: ""; width: 20px; height: 20px; background: currentColor;
  -webkit-mask: var(--eye) center / 20px 20px no-repeat;
  mask: var(--eye) center / 20px 20px no-repeat;
}
/* Pressed = password is visible, so show the "hide" (eye-off) icon. */
.pw-toggle[aria-pressed="true"]::before {
  -webkit-mask-image: var(--eye-off);
  mask-image: var(--eye-off);
}
/* The submit pill needs air under the last field on every auth form — the
   error <p> that would otherwise separate them is display:none until it fires. */
#login-form .btn-primary, #register-form .btn-primary,
#forgot-request-form .btn-primary, #forgot-verify-form .btn-primary
  { margin-top: 24px; padding: 14px; }

/* =============================================================
   APP SHELL
============================================================= */
.app { display: flex; min-height: 100vh; }
.sidebar {
  width: 240px; background: var(--surface); border-right: 1px solid var(--card-border);
  display: flex; flex-direction: column; padding: 18px 14px;
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 50;
}
.sidebar-brand {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 6px 6px 18px;
  border-bottom: 1px solid var(--line); margin-bottom: 12px;
}
.nav { display: flex; flex-direction: column; gap: 3px; flex: 1; }
.nav-item {
  display: flex; align-items: center; gap: 11px; padding: 11px 14px;
  border-radius: var(--radius-pill); color: var(--ink-600); font-weight: 600;
  font-size: 14px; cursor: pointer; text-decoration: none;
}
.nav-item:hover { background: var(--screen-bot); color: var(--ink); }
/* Active nav = the brand blue pill, matching the mobile selected states. */
.nav-item.active { background: var(--link-blue); color: #fff; }
.nav-ico { font-size: 17px; width: 22px; text-align: center; }

.content { flex: 1; margin-left: 240px; display: flex; flex-direction: column; min-width: 0; }
/* Blue gradient bar — hidden on desktop (the sidebar is the chrome). It reappears
   on mobile as a slim bar carrying the drawer toggle + view title. */
.topbar {
  background: linear-gradient(180deg, var(--header-top) 0%, var(--header-bot) 100%);
  border-bottom: none; padding: 16px 20px; color: #fff;
  display: none; align-items: center; gap: 12px; position: sticky; top: 0; z-index: 30;
}
.topbar h2 { font-size: 18px; font-weight: 600; flex: 1; color: #fff; }
.topbar .icon-btn { color: #fff; }
.topbar .icon-btn:hover { background: rgba(255,255,255,.16); }
#menu-toggle { display: none; }

/* Signed-in identity + logout, pinned to the sidebar bottom. */
.sidebar-user {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 6px 2px; margin-top: 8px; border-top: 1px solid var(--line);
}
.su-avatar {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: var(--link-blue); color: #fff; font-size: 13px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.su-meta { flex: 1; min-width: 0; }
.su-name {
  font-size: 13.5px; font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.su-role { font-size: 11px; color: var(--ink-500); }
.su-logout {
  flex-shrink: 0; color: var(--ink-500); font-size: 17px;
}
.su-logout:hover { background: var(--screen-bot); color: var(--danger-red); }
.view-container { padding: 20px; max-width: 1100px; width: 100%; }
/* The Attendance Calendar is a wide grid — let it use the full screen width
   instead of the 1100px reading column the other views use. */
.view-container.full-bleed { max-width: none; }
/* Production → Bulk add: a spreadsheet, so the whole width — without full-bleed's
   calendar-only flex layout. */
.view-container.wide { max-width: none; }

/* Print: strip the app chrome and buttons so a salary slip prints on its own.
   Triggered by the slip's "Print" button (window.print()). */
@media print {
  .sidebar, .topbar, .bottom-nav, #trial-banner, .back-bar, .no-print, .btn { display: none !important; }
  .content { margin-left: 0 !important; }
  .view-container, .view-container.full-bleed { max-width: none !important; padding: 0 !important; }
  /* Cards must be allowed to break across pages — a tall Days table forced to
     stay whole (page-break-inside:avoid) got bumped to page 2, leaving page 1
     with just the header + summary cards and a big blank. Let the table flow,
     but keep individual rows / summary blocks from splitting mid-content. */
  .card { box-shadow: none !important; border: 1px solid #ddd; page-break-inside: auto; }
  .card + .card { margin-top: 12px; }
  table { page-break-inside: auto; }
  thead { display: table-header-group; }
  tr, .slip-summary, .emp-row, .day-row, .setting-row { page-break-inside: avoid; }
  body, .app { background: #fff !important; }
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .print-only { display: block !important; }
  /* The slip swaps identities on paper: the detailed auditing cards go away and
     the one-page sheet the worker is handed takes their place. */
  .slip-screen { display: none !important; }
  .slip-print { display: block !important; }
  .slip-print .sp-abs-table tr, .slip-print .sp-foot { page-break-inside: avoid; }
  /* A slip printed from a page that is NOT a slip page (staff detail → Download):
     only its own host goes to paper. */
  body.printing-slip-only > *:not(#slip-print-host) { display: none !important; }
  body.printing-slip-only #slip-print-host { display: block !important; padding: 0 12px; }
  body.printing-report { page: report-page; }
  /* A scroll container prints as a CROP — whatever is scrolled out of view is
     simply missing from the paper. Let wide tables spill onto the sheet instead,
     and shrink the report's type so a nine-column range still fits across A4. */
  .table-wrap { overflow: visible !important; border: none !important; }
  .prod-rep th, .prod-rep td { padding: 5px 7px; font-size: 10.5px; }
}

.bottom-nav { display: none; }
.backdrop { position: fixed; inset: 0; background: rgba(15,23,42,.45); z-index: 45; }

/* =============================================================
   CARDS & SECTIONS
============================================================= */
.section-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.section-head h3 { font-size: 16px; font-weight: 600; color: var(--ink); }
.section-head .spacer { flex: 1; }

/* Cards: 16px radius, blue-tinted border, soft 2px shadow (Figma). */
.card {
  background: var(--surface); border: 1px solid var(--card-border);
  border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow);
}
.card + .card { margin-top: 18px; }

.cards-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 22px; }
.stat-card {
  background: var(--surface); border: 1px solid var(--card-border);
  border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow);
}
.stat-card .stat-ico {
  width: 40px; height: 40px; border-radius: 50%; display: flex;
  align-items: center; justify-content: center; font-size: 19px; margin-bottom: 10px;
}
.stat-card .stat-val { font-size: 26px; font-weight: 700; color: var(--ink); }
.stat-card .stat-label { font-size: 13px; color: var(--ink-600); margin-top: 2px; }
.ico-blue  { background: var(--primary-l); }
.ico-green { background: var(--green-l); }
.ico-amber { background: var(--amber-l); }
.ico-purple{ background: var(--c-super-l); }

/* Org banner on dashboard — same blue gradient as the mobile home header. */
.org-banner {
  display: flex; align-items: center; gap: 14px; margin-bottom: 20px;
  padding: 20px; border-radius: var(--radius); color: #fff;
  background: linear-gradient(180deg, var(--header-top) 0%, var(--header-bot) 100%);
  box-shadow: var(--shadow);
}
.org-banner .avatar { background: rgba(255,255,255,.22); }
.org-banner .ob-name { font-size: 18px; font-weight: 800; }
.org-banner .ob-sub { font-size: 13px; opacity: .9; margin-top: 2px; }

/* =============================================================
   SEARCH / FILTERS
============================================================= */
.search-wrap { position: relative; flex: 1; min-width: 200px; }
.search-wrap .search-ico { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); color: var(--ink-500); font-size: 16px; }
/* Search is a pill, like the mobile search bars. */
.search-input { padding-left: 40px; height: 46px; font-size: 14px; border-radius: var(--radius-pill); background: var(--surface); }
.search-big { box-shadow: var(--shadow); }

.filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.chip {
  padding: 8px 16px; border-radius: var(--radius-pill); background: var(--surface);
  border: 1px solid var(--ink-500); font-size: 13px; font-weight: 600; cursor: pointer; color: var(--ink-600);
}
.chip:hover { background: var(--screen-bot); }
.chip.active { background: var(--link-blue); color: #fff; border-color: var(--link-blue); }
/* A chip the rules block (machine already full / shared / over the daily cap) —
   greyed and untappable, with the reason inline. Mirrors MachineChip(enabled=false). */
.chip:disabled { background: #f5f5f5; color: rgba(115,115,115,.75); border-color: var(--line); cursor: not-allowed; }
.chip:disabled:hover { background: #f5f5f5; }
/* Wrapping chip row inside a form (machine + shift pickers). */
.chip-wrap { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.chip-wrap .chip { padding: 7px 12px; font-size: 12.5px; }

/* Group-by-floor toggle row */
.toggle-row { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; font-size: 13.5px; color: var(--ink-600); }

/* =============================================================
   BADGES
============================================================= */
.badge { display: inline-block; padding: 4px 12px; border-radius: var(--radius-pill); font-size: 11.5px; font-weight: 700; letter-spacing: .2px; }
.badge-worker     { background: var(--c-worker-l);   color: var(--c-worker); }
.badge-supervisor { background: var(--c-super-l);     color: var(--c-super); }
.badge-designer   { background: var(--c-designer-l);  color: var(--c-designer); }
.badge-other      { background: var(--c-other-l);     color: var(--c-other); }
.badge-active     { background: var(--green-l); color: var(--ok-green); }
.badge-inactive   { background: #eef0f3; color: var(--ink-600); }
.badge-floor      { background: var(--surface-2); color: var(--ink-600); border: 1px solid var(--line); }
.badge-star       { background: #fff6e0; color: var(--warn-gold); }
/* Quick-added from the Production app — details still missing. Amber, not green:
   this is an unfinished record, not a status. */
.badge-new        { background: var(--amber-l); color: var(--amber); }

/* Inline "this record needs something" strip inside a card. */
.notice {
  margin-top: 12px; padding: 10px 12px; border-radius: var(--radius-sm);
  font-size: 12.5px; line-height: 1.5;
}
.notice-new { background: var(--amber-l); color: var(--amber); }

/* =============================================================
   ROWS
============================================================= */
.row-list { display: flex; flex-direction: column; gap: 12px; }
.emp-row {
  background: var(--surface); border: 1px solid var(--card-border); border-radius: var(--radius);
  padding: 14px 16px; display: flex; align-items: center; gap: 13px; box-shadow: var(--shadow);
}
.emp-row.clickable { cursor: pointer; }
.emp-row.clickable:hover { border-color: var(--link-blue); }
.avatar {
  width: 42px; height: 42px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; font-weight: 700; font-size: 15px; color: #fff; flex-shrink: 0;
  background: var(--avatar-bg);
}
/* Employee ID: a fixed-width slot at the head of the row (never inline with the
   name), so the IDs read straight down the left edge whatever their length and
   the avatars/names after them all start at the same x. `.blank` keeps the space
   for an employee who has no ID rather than sliding their row out of line. */
.emp-id {
  flex-shrink: 0; width: 46px; font-size: 11px; font-weight: 700; letter-spacing: .2px;
  color: #4338ca; background: #eef2ff; border-radius: 5px; padding: 3px 6px;
  text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.emp-id.blank { background: transparent; }
/* Attendance rows are tall (the P/A controls sit under the name) — pin the ID to
   the top so it reads level with the name instead of floating mid-card. */
.att-row .emp-id { align-self: flex-start; margin-top: 2px; }
.emp-main { flex: 1; min-width: 0; }
.emp-name { font-weight: 600; font-size: 15px; color: var(--name-ink); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.emp-sub { color: var(--ink-600); font-size: 13px; margin-top: 2px; }
.emp-actions { display: flex; gap: 6px; flex-shrink: 0; }

/* Attendance controls — pill options, brand blue when selected */
.att-options { display: flex; gap: 6px; flex-wrap: wrap; }
.att-opt {
  border: 1px solid var(--ink-500); background: var(--surface); border-radius: var(--radius-pill);
  padding: 7px 14px; font-size: 13px; font-weight: 600; cursor: pointer; color: var(--ink-600);
}
.att-opt:hover { background: var(--screen-bot); }
.att-opt.sel { background: var(--link-blue); color: #fff; border-color: var(--link-blue); }
.att-opt.sel-absent { background: var(--danger-red); color: #fff; border-color: var(--danger-red); }
.att-opt.sel-present{ background: var(--ok-green); color: #fff; border-color: var(--ok-green); }
/* "½ Day" — amber, between present (green) and absent (red). */
.att-opt.sel-half   { background: var(--amber); color: #fff; border-color: var(--amber); }
.att-row .emp-actions { flex-direction: column; align-items: flex-end; }
.hours-input { width: 90px; }

/* Floor accordion */
.floor-group { border: 1px solid var(--card-border); border-radius: var(--radius); margin-bottom: 12px; overflow: hidden; box-shadow: var(--shadow); background: var(--surface); }
.floor-head {
  display: flex; align-items: center; gap: 10px; padding: 13px 15px; cursor: pointer;
  background: var(--surface); font-weight: 600; font-size: 14px; color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.floor-head .spacer { flex: 1; }
.floor-head .count { color: var(--ink-600); font-weight: 600; font-size: 13px; }
.floor-body { padding: 12px; display: flex; flex-direction: column; gap: 10px; }
.floor-body .search-input { height: 40px; }
.floor-group.collapsed .floor-body { display: none; }
.chevron { transition: transform .15s; }
.floor-group.collapsed .chevron { transform: rotate(-90deg); }

/* =============================================================
   TABLE (salary)
============================================================= */
.table-wrap { overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--card-border); }
table { width: 100%; border-collapse: collapse; background: var(--surface); }
th, td { padding: 11px 13px; text-align: left; font-size: 13.5px; white-space: nowrap; }
th { background: var(--surface-2); color: var(--section-lbl); font-size: 12px; text-transform: uppercase; letter-spacing: .3px; }
tbody tr { border-top: 1px solid var(--line); }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover { background: var(--screen-bot); }
td.num, th.num { text-align: right; }
.net-pos { color: var(--ok-green); font-weight: 700; }
.net-neg { color: var(--danger-red); font-weight: 700; }
.bonus-pos { color: var(--ok-green); font-weight: 600; }
tfoot td { background: var(--surface-2); font-weight: 700; border-top: 2px solid var(--line); }

/* ---- Field table (Settings -> Advanced Production Details) ----------------
   The same grid the Apex admin console uses for an org's production field table
   (admin-console/style.css .field-table): one row per field, its controls living
   in the cells. Rides on the shared `table` rules above and overrides only what a
   table of inputs needs — tighter padding, and inputs that fill their cell. */
.field-table { min-width: 660px; }
.field-table th, .field-table td { padding: 8px 10px; font-size: 13px; }
.field-table th.ft-c, .field-table td.ft-c { text-align: center; }
.field-table td input[type="text"],
.field-table td input[type="number"],
.field-table td select { width: 100%; padding: 7px 10px; font-size: 13px; }
/* `input { width: 100% }` is the page-wide rule for form boxes; a checkbox in a
   44px column must opt out of it. */
.field-table td input[type="checkbox"] {
  width: 16px; height: 16px; padding: 0; margin: 0;
  accent-color: var(--primary); cursor: pointer; vertical-align: middle;
}
.field-table td input[type="checkbox"]:disabled { cursor: default; opacity: .45; }
.field-table td.ft-photo { color: var(--ink-500); }
/* The Order box is 2 digits in a 74px column — the number spinner would eat half
   of it, and there is nothing to step through. */
.field-table .pf-order { appearance: textfield; -moz-appearance: textfield; text-align: center; }
.field-table .pf-order::-webkit-outer-spin-button,
.field-table .pf-order::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.field-table .ft-yes { color: var(--ok-green); font-weight: 700; }
.field-table .ft-no  { color: var(--ink-400); }
.field-table .ft-del {
  border: none; background: none; color: var(--ink-500); cursor: pointer;
  font-size: 14px; line-height: 1; padding: 4px 7px; border-radius: var(--radius-sm);
}
.field-table .ft-del:hover { background: var(--red-l); color: var(--danger-red); }

/* ---- Production → Bulk add grid ------------------------------------------
   A spreadsheet of inputs, the admin console's Production grid in this app's
   look: tight rows so a date's machines fit on screen, the ½ / tick columns
   centred, and a tint on rows the last save rejected. */
.bulk-wrap { border: 1px solid var(--line); max-height: 68vh; overflow: auto; }
/* A generated month is a thousand-odd rows: the header stays put while it scrolls. */
.bulk-grid thead th { position: sticky; top: 0; z-index: 1; }
.bulk-grid th.bg-num, .bulk-grid td.bg-num {
  width: 38px; text-align: right; color: var(--ink-500); font-variant-numeric: tabular-nums;
}
.bulk-gen { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.bulk-gen .field { display: flex; flex-direction: column; }
.bulk-gen .field label { margin-top: 0; }
.bulk-gen input[type="date"] { width: 170px; }
.bulk-gen .spacer { flex: 1; }
/* Columns menu: a <details>, so it opens and closes without script. */
.bulk-cols { position: relative; }
.bulk-cols > summary { list-style: none; cursor: pointer; }
.bulk-cols > summary::-webkit-details-marker { display: none; }
.bulk-cols-menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 5; min-width: 210px;
  display: flex; flex-direction: column; gap: 6px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.14);
}
.bulk-cols-menu label {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 13.5px; font-weight: 500; cursor: pointer; white-space: nowrap;
}
.bulk-cols-menu input[type="checkbox"] {
  width: 16px; height: 16px; margin: 0; padding: 0; accent-color: var(--link-blue);
}
.bulk-grid { min-width: 1060px; }
.bulk-grid th, .bulk-grid td { padding: 6px; font-size: 13px; }
.bulk-grid td input[type="text"], .bulk-grid td select { width: 100%; padding: 7px 8px; font-size: 13px; }
.bulk-grid th.bg-check, .bulk-grid td.bg-check { text-align: center; width: 38px; }
.bulk-grid td input[type="checkbox"] {
  width: 16px; height: 16px; padding: 0; margin: 0;
  accent-color: var(--link-blue); cursor: pointer; vertical-align: middle;
}
.bulk-grid tr.bg-bad td { background: var(--red-l); }
.bulk-grid .bg-del {
  border: none; background: none; color: var(--ink-500); cursor: pointer;
  font-size: 14px; line-height: 1; padding: 4px 7px; border-radius: var(--radius-sm);
}
.bulk-grid .bg-del:hover { background: var(--red-l); color: var(--danger-red); }
.bulk-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.bulk-actions .spacer { flex: 1; }
.bulk-msg { margin-top: 10px; font-size: 13px; line-height: 1.55; }
.bulk-err { color: var(--danger-red); }
.bulk-note { color: var(--warn-gold); }

/* =============================================================
   EMPTY STATES
============================================================= */
.empty { text-align: center; padding: 48px 20px; color: var(--ink-600); }
.empty .empty-ico { font-size: 44px; margin-bottom: 10px; }
.empty h4 { color: var(--ink); margin-bottom: 6px; }

/* =============================================================
   MODAL
============================================================= */
.modal { position: fixed; inset: 0; background: rgba(15,23,42,.5); display: flex; align-items: center; justify-content: center; z-index: 100; padding: 16px; }
.modal-card { background: var(--surface); border-radius: 18px; width: 100%; max-width: 440px; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow-lg); }
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 20px; border-bottom: 1px solid var(--line); position: sticky; top: 0; background: var(--surface); z-index: 1; }
.modal-head h3 { font-size: 17px; font-weight: 600; color: var(--ink); }
.modal-body { padding: 20px; }
/* The one modal that holds a table instead of a form: Employees → Add Many. A
   spreadsheet needs the width, and its own horizontal scroll inside .table-wrap. */
.modal-card.modal-wide { max-width: min(1100px, 96vw); }
.bulk-table { min-width: 820px; }
.bulk-table th, .bulk-table td { padding: 6px 8px; }
.bulk-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.bulk-table td input:disabled, .bulk-table td select:disabled { opacity: .45; }
.form-actions { display: flex; gap: 10px; margin-top: 22px; }
.form-actions .btn { flex: 1; }

/* =============================================================
   TOAST
============================================================= */
.toast {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--ink-50); padding: 13px 22px; border-radius: var(--radius-pill);
  font-weight: 600; font-size: 14px; z-index: 200; box-shadow: var(--shadow-lg);
  animation: toastIn .25s ease; max-width: 90vw; text-align: center;
}
.toast.success { background: var(--ok-green); }
.toast.error   { background: var(--danger-red); }
@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; } }

/* Sticky save bar */
.sticky-save {
  position: sticky; bottom: 0; background: var(--surface); border-top: 1px solid var(--line);
  padding: 12px 16px; margin: 18px -20px -20px; display: flex; gap: 10px; align-items: center;
  box-shadow: 0 -4px 16px rgba(16,24,40,.06);
}
.sticky-save .save-info { flex: 1; font-size: 13px; color: var(--ink-600); }
.btn.dirty { background: var(--amber); color: #fff; border-color: var(--amber); }
.btn.dirty:hover { background: #b96405; }

/* Toolbar */
.toolbar { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 16px; }
.toolbar .field { display: flex; flex-direction: column; }
.toolbar .field label { margin-top: 0; }
.toolbar input, .toolbar select { min-width: 150px; }

/* Attendance header: category filter chips on the left, date picker pushed to the
   right, all on one row (wraps to two on narrow screens). */
.att-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.att-toolbar .filters { flex: 1; margin-bottom: 0; }
.att-toolbar .field { display: flex; flex-direction: column; margin-left: auto; }
.att-toolbar .field label { margin-top: 0; }
.att-toolbar input[type="date"] { min-width: 150px; }

/* Upad screen: category filter chips and the "+ New Upad" button share one row
   (no page title); the button is pushed to the right. */
.adv-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.adv-toolbar .filters { margin-bottom: 0; }
.adv-toolbar .spacer { flex: 1; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* =============================================================
   SETTINGS — toggle switch + segmented + setting rows
============================================================= */
.switch { position: relative; display: inline-block; width: 46px; height: 26px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider { position: absolute; cursor: pointer; inset: 0; background: var(--ink-400); border-radius: var(--radius-pill); transition: .2s; }
.switch .slider::before { content: ""; position: absolute; height: 20px; width: 20px; left: 3px; bottom: 3px; background: #fff; border-radius: 50%; transition: .2s; box-shadow: 0 1px 3px rgba(0,0,0,.2); }
.switch input:checked + .slider { background: var(--link-blue); }
.switch input:checked + .slider::before { transform: translateX(20px); }

.setting-row { display: flex; align-items: center; gap: 12px; padding: 13px 0; border-top: 1px solid var(--line); }
.setting-row:first-of-type { border-top: none; }
.setting-row .sr-main { flex: 1; min-width: 0; }
.setting-row .sr-title { font-weight: 600; font-size: 14.5px; color: var(--ink); }
.setting-row .sr-sub { color: var(--ink-600); font-size: 12.5px; margin-top: 3px; line-height: 1.45; }

.stepper { display: flex; align-items: center; gap: 10px; }
.stepper .step-val { font-weight: 700; font-size: 18px; min-width: 28px; text-align: center; color: var(--ink); }
.stepper .btn { width: 38px; height: 38px; padding: 0; font-size: 20px; }

/* Segmented (status) control */
.segmented { display: inline-flex; border: 1px solid var(--ink-400); border-radius: var(--radius-pill); overflow: hidden; }
.segmented button { border: none; background: var(--surface); padding: 9px 18px; font-size: 13.5px; font-weight: 600; color: var(--ink-600); cursor: pointer; }
.segmented button.on-active { background: var(--ok-green); color: #fff; }
.segmented button.on-inactive { background: #eef0f3; color: var(--ink); }
/* Full-width variant for two long choices (e.g. the salary-change scope), so the
   labels wrap inside the modal instead of overflowing it. */
.segmented-block { display: flex; width: 100%; margin-bottom: 10px; }
.segmented-block button { flex: 1; padding: 9px 10px; line-height: 1.25; }
.segmented button.on-sel { background: var(--link-blue); color: #fff; }

/* Mode chips (cash/bank) */
.mode-chips { display: flex; gap: 10px; }
.mode-chips .chip.active { background: var(--link-blue); color: #fff; border-color: var(--link-blue); }

/* Salary slip */
.slip-summary { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.slip-summary .si { background: var(--screen-bot); border: 1px solid var(--card-border); border-radius: 12px; padding: 14px; }
.slip-summary .si .lbl { font-size: 12px; color: var(--ink-600); }
.slip-summary .si .val { font-size: 18px; font-weight: 700; margin-top: 3px; color: var(--ink); }

/* -------------------------------------------------------------
   THE PRINTED SLIP (.slip-print, built by slipMinimalHTML)

   Paper only — never drawn on screen, where the detailed .slip-screen cards are
   the ones being read.

   ON BRAND, not on theme: this sheet leaves the building with the org's name on
   it, so it carries the apex mark and the 2026 palette — ink #171717, the design
   blue #0053E2 on the rules and the net, the same weights the app uses. What it
   does NOT carry is the app's furniture: no cards, no shadows, no tinted screen
   gradient. It is photocopied, folded into a wage packet and argued over, so
   everything is ink on white, and the blue is spent only where it earns its
   keep: the two rules that frame the money, and the net figure itself.
------------------------------------------------------------- */
/* A little air at the top for printers driven with zero page margins, so the
   mark never lands hard against the cut edge. */
.slip-print { display: none; color: var(--ink); font-size: 13px; padding-top: 6px; }
#slip-print-host { display: none; }
.slip-print .sp-head { text-align: center; border-bottom: 2px solid var(--link-blue); padding-bottom: 12px; }
/* The needle wordmark SIGNS the sheet from the bottom corner rather than heading
   it. The org's own name is the headline — this is their document; the mark only
   says what made it, the way a printer's imprint sits at the foot of a page. */
.slip-print .sp-foot { display: flex; justify-content: flex-end; margin-top: 26px; }
.slip-print .sp-logo { width: 58px; height: auto; display: block; opacity: .85; }
.slip-print .sp-org { font-size: 19px; font-weight: 800; letter-spacing: .2px; color: var(--ink); }
.slip-print .sp-title { font-size: 11px; letter-spacing: 2.5px; text-transform: uppercase;
  margin-top: 4px; color: var(--ink-600); font-weight: 700; }
.slip-print .sp-period { font-size: 12px; margin-top: 5px; color: var(--ink-600); }
.slip-print .sp-who { display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; margin: 18px 0 12px; }
.slip-print .sp-name { font-size: 20px; font-weight: 800; letter-spacing: -.2px; }
.slip-print .sp-cat { font-size: 11px; text-transform: uppercase; letter-spacing: 1.2px;
  font-weight: 700; color: var(--ink-600); }

.slip-print .sp-table { width: 100%; border-collapse: collapse; }
/* The app's table skin — striped rows, small-caps blue headers — is for scanning a
   grid of data. This is a document, so it is reset back to plain type on white. */
.slip-print .sp-table th, .slip-print .sp-table td {
  border: none; border-bottom: 1px solid var(--line); padding: 9px 2px; font-size: 14px;
  background: none; color: var(--ink); text-transform: none; letter-spacing: 0; }
.slip-print .sp-table th { text-align: left; font-weight: 500; }
.slip-print .sp-table td { text-align: right; font-weight: 700; white-space: nowrap; }
.slip-print .sp-table tr:hover th, .slip-print .sp-table tr:hover td { background: none; }
/* The working under a line — "₹650 × 30 days", or the net's whole sum — is the
   point of the sheet: it must sit with its label, not become a row of its own. */
.slip-print .sp-sub { display: block; font-size: 11.5px; color: var(--ink-600);
  font-weight: 400; margin-top: 3px; letter-spacing: .1px; }
.slip-print .sp-net th, .slip-print .sp-net td {
  border-top: 2px solid var(--link-blue); border-bottom: none; padding-top: 12px;
  font-size: 17px; font-weight: 800; color: var(--ink); }
.slip-print .sp-net td { color: var(--link-blue); }

.slip-print .sp-abs { margin-top: 22px; }
.slip-print .sp-abs-head { font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 1.2px; color: var(--ink-600);
  border-bottom: 1px solid var(--ink); padding-bottom: 5px; }
.slip-print .sp-abs-table { width: 100%; border-collapse: collapse; }
.slip-print .sp-abs-table td { border: none; border-bottom: 1px dotted #d4d4d4; padding: 5px 2px;
  font-size: 12.5px; background: none; color: var(--ink); }
.slip-print .sp-abs-table td.sp-mark { text-align: right; white-space: nowrap; }
.slip-print .sp-abs-table td.sp-mark.half { color: var(--ink-600); }

.day-row { display: flex; align-items: flex-start; gap: 12px; padding: 9px 12px; border-top: 1px solid var(--line); font-size: 13.5px; }
.day-row:first-child { border-top: none; }
.day-row .d-date { flex: 1; white-space: nowrap; }
.day-row .d-detail { text-align: right; }
.audit { font-size: 12px; color: var(--ink-500); margin-top: 4px; }
.back-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }

/* CSV import drop area */
.csv-box { border: 1.5px dashed var(--ink-400); border-radius: var(--radius); padding: 18px; text-align: center; }

/* =============================================================
   PRODUCTION — grid of shift squares
   A square is one machine-shift (Latest) or one machine/karigar's totals over a
   date range. auto-fill keeps them square-ish at every width: as many 240px
   columns as fit, and one per row on a phone.
============================================================= */
.prod-toolbar { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.prod-toolbar .field { display: flex; flex-direction: column; }
.prod-toolbar .field label { margin-top: 0; }
/* Machine-group picks under the Group box on the machine form. */
.mg-picks { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.prod-toolbar .spacer { flex: 1; }
.prod-toolbar .segmented button { padding: 9px 14px; }

/* Grid layout — the whole floor as a wall of colour, one square per machine.
   Tinted by the SAME diagnosis the list rows use, so the two layouts can never
   disagree about a machine. Clicking a square opens its full row underneath. */
.prod-squares { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
.pg-square {
  display: flex; flex-direction: column; gap: 3px; text-align: left;
  border: 1.5px solid; border-radius: var(--radius); padding: 10px 12px 11px;
  font: inherit; cursor: pointer; transition: transform .1s ease, box-shadow .12s ease;
}
.pg-square:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
.pg-square.sel { outline: 2px solid var(--link-blue); outline-offset: 1px; }
.pg-top { display: flex; align-items: center; gap: 6px; }
.pg-badge {
  min-width: 22px; height: 22px; padding: 0 5px; border-radius: 7px; background: rgba(0,0,0,.07);
  font-size: 12px; font-weight: 700; color: var(--ink); display: inline-flex;
  align-items: center; justify-content: center;
}
.pg-warn { margin-left: auto; font-size: 13px; }
.pg-name { font-size: 12px; font-weight: 600; color: var(--ink-700);
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pg-val { font-size: 19px; font-weight: 800; color: var(--ink); line-height: 1.15; }
.pg-val.pg-dash { color: var(--ink-500); }
.pg-meta { font-size: 11px; color: var(--ink-600); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Shared tones. A row wears them as a left edge, a square as a whole tint —
   same three meanings either way: green fine, amber worth a look, red go now. */
.tone-good { background: #e7f8ef; border-color: #9fdcbe; }
.tone-ok   { background: #fff7e0; border-color: #ebd28c; }
.tone-poor { background: #fdeceb; border-color: #f2b3ad; }
/* Idle is not a fourth verdict — it is the absence of one, so it recedes
   rather than competing with the machines that have something to say. */
.pg-square.tone-idle { background: var(--surface-2); border-color: var(--ink-400); border-style: dashed; }
.prod-row.tone-good { background: var(--surface); border-left: 3px solid var(--ok-green); border-color: var(--card-border); }
.prod-row.tone-ok   { background: var(--surface); border-left: 3px solid var(--warn-gold); border-color: var(--card-border); }
.prod-row.tone-poor { background: var(--surface); border-left: 3px solid var(--danger-red); border-color: var(--card-border); }

.pc-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; }
.pm { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; font-size: 12.5px; }
.pm-lab { color: var(--ink-600); white-space: nowrap; }
.pm-val { font-weight: 700; color: var(--ink); text-align: right;
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A derived Frames count (Total Stitch ÷ Design Stitch) is never shown as if it
   had been recorded — it reads lighter and carries the ~ the markup adds. */
.pm.derived .pm-val { font-weight: 600; color: var(--ink-500); font-style: italic; }

.pc-design { font-size: 12px; color: var(--ink-600); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-bonus { font-size: 12.5px; font-weight: 700; color: var(--ok-green); }
.pc-foot { font-size: 12px; color: var(--ink-600); border-top: 1px solid var(--line); padding-top: 8px;
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-link { color: var(--link-blue); font-weight: 600; }

/* =============================================================
   PRODUCTION — the one-day floor view
   Day bar → summary tiles → one row per machine (day | night | analysis).
============================================================= */
.prod-daybar { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.prod-daybar .btn { min-width: 38px; }
.pd-date { display: flex; flex-direction: column; line-height: 1.25; }
.pd-date strong { font-size: 15px; color: var(--ink); }

.prod-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(172px, 1fr)); gap: 12px; }
.ps-tile {
  background: var(--surface); border: 1px solid var(--card-border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 12px 14px;
}
.ps-lab { font-size: 12px; color: var(--ink-600); font-weight: 600; }
.ps-val { font-size: 23px; font-weight: 800; color: var(--ink); margin-top: 3px; line-height: 1.15;
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-of  { font-size: 13px; font-weight: 600; color: var(--ink-500); }
/* Wraps rather than truncating — an elided "21,96,439 total stit…" is worse than
   two lines, and these subs are the actual numbers. */
.ps-sub { font-size: 11.5px; color: var(--ink-600); margin-top: 3px; line-height: 1.4; }

/* Factory efficiency — a full-width strip above the tiles, tinted by band. It
   describes the whole floor rather than a slice of it, so it gets its own row
   instead of competing with four tiles. */
.prod-eff {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 12px 22px; margin-bottom: 12px;
  border: 1.5px solid; border-radius: var(--radius-pill);
}
.prod-eff .spacer { flex: 1; }
.pe-val { font-size: 27px; font-weight: 800; color: var(--ink); line-height: 1; }
.pe-pct { font-size: 15px; font-weight: 700; color: var(--ink-600); margin-left: 1px; }
.pe-ico { font-size: 15px; }
.pe-lab { font-size: 15px; font-weight: 600; color: var(--ink); }
.pe-sub { font-size: 13px; color: var(--ink-600); }
.prod-eff.good { background: #e7f8ef; border-color: #9fdcbe; }
.prod-eff.ok   { background: #fff7e0; border-color: #ebd28c; }
.prod-eff.poor { background: #fdeceb; border-color: #f2b3ad; }

@media (max-width: 700px) {
  /* Wraps to two lines here, and a pill radius around a two-line block reads
     as a mistake — square it off. */
  .prod-eff { border-radius: var(--radius); padding: 12px 16px; }
  .prod-eff .spacer { display: none; }
  .pe-sub { flex-basis: 100%; }
}

.prod-rows { display: flex; flex-direction: column; gap: 8px; }
/* A machine is a card: its number and name across the top, then a body split
   25% day / 25% night / 50% analysis. 1fr 1fr 2fr rather than literal
   percentages so the gaps come out of the columns instead of overflowing. */
.prod-row {
  background: var(--surface); border: 1px solid var(--card-border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px 13px;
}
.prow-body { display: grid; grid-template-columns: 1fr 1fr 2fr; gap: 12px; align-items: stretch; }
.prow-top { display: flex; align-items: center; gap: 9px; margin-bottom: 9px; }
.prow-top .spacer { flex: 1; }
.prod-colhead {
  display: grid; grid-template-columns: 1fr 1fr 2fr; gap: 12px; padding: 0 13px 2px;
  font-size: 11.5px; font-weight: 700; color: var(--ink-600);
  text-transform: uppercase; letter-spacing: .03em;
}
/* The month table's own column widths — it has five, not three. */
.prod-colhead.prow-monthhead { grid-template-columns: 1.4fr 90px 130px 110px 1.5fr; }
.prod-colhead .num { text-align: right; }
/* A machine that recorded nothing at all recedes, but stays on the page — the
   whole point of giving every machine a row is that the blanks are visible.
   (The green/amber/red edges live with the shared .tone-* rules above.) */
.prod-row.prow-idle { background: var(--surface-2); border-style: dashed; }
.prow-badge {
  width: 28px; height: 28px; flex: 0 0 28px; border-radius: 9px; background: var(--link-blue);
  color: #fff; font-weight: 700; font-size: 13px; display: flex; align-items: center; justify-content: center;
}
.prow-name { font-weight: 700; font-size: 13.5px; color: var(--name-ink); min-width: 0;
             overflow: hidden; text-overflow: ellipsis; }
.prow-meta { font-size: 11px; color: var(--ink-600); line-height: 1.35; }
.prow-meta b { color: var(--ink); }
.prow-meta-idle { color: var(--ink-500); font-style: italic; }
.prow-cell { display: flex; flex-direction: column; gap: 8px; min-width: 0; }

/* A recorded shift. */
.pc-entry { background: var(--screen-bot); border-radius: 12px; padding: 10px 12px;
            display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.pc-entry.night { background: #eef1fc; }
.pce-top { display: flex; align-items: baseline; gap: 8px; }
.pce-val { font-size: 20px; font-weight: 800; color: var(--ink); line-height: 1.1; }
.pce-share { font-size: 10.5px; font-weight: 700; color: var(--ink-600);
             background: var(--surface); border-radius: var(--radius-pill); padding: 2px 7px; }
.pce-who { font-size: 11.5px; color: var(--ink-600);
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Utilisation: run time as a share of run + stop. */
.pce-util { display: flex; align-items: center; gap: 7px; }
.pu-bar { flex: 1; height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; }
.pu-bar i { display: block; height: 100%; border-radius: 3px; background: var(--ok-green); }
.pu-bar i.ok   { background: var(--warn-gold); }
.pu-bar i.poor { background: var(--danger-red); }
.pu-txt { font-size: 11px; font-weight: 700; color: var(--ink-600); white-space: nowrap; }
/* Shown in place of utilisation when run + stop can't both be true. */
.pce-bad { font-size: 11px; font-weight: 700; color: var(--warn-gold); }

/* A shift with nothing recorded. Says so plainly rather than leaving a hole. */
.pc-missing {
  border: 1.5px dashed var(--ink-400); border-radius: 12px; padding: 12px;
  text-align: center; color: var(--ink-500); flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
}
.pcm-ico { font-size: 18px; opacity: .5; }
.pcm-txt { font-size: 12.5px; font-weight: 700; color: var(--ink-600); }
.pcm-sub { font-size: 11px; line-height: 1.35; }

/* Half the row, and it exists for the graph — so the numbers sit on one line at
   the top and the chart takes the rest of the height. */
.prow-analysis { border-left: 1px solid var(--line); padding-left: 14px; gap: 4px; }
.pa-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.pa-total { font-size: 21px; font-weight: 800; color: var(--ink); line-height: 1.1; }
.pa-lab { font-size: 11px; color: var(--ink-600); }
.pa-delta { font-size: 12px; text-align: right; }
.pa-nospark { display: flex; align-items: center; justify-content: center; min-height: 32px; }

/* Findings under the graph — what the numbers say out loud. Silent when there
   is nothing to report, so a line here always means something. */
.pa-notes { display: flex; flex-direction: column; gap: 3px; margin-top: 2px; }
.pa-note { font-size: 11.5px; line-height: 1.4; }
.pa-note b { font-weight: 700; }
.pa-note.warn { color: var(--warn-gold); }
.pa-note.warn b { color: var(--danger-red); }
.pa-note.ok { color: var(--ok-green); }
.pa-up   { color: var(--ok-green);   font-weight: 700; }
.pa-down { color: var(--danger-red); font-weight: 700; }
.pa-flat { color: var(--ink-500);    font-weight: 600; }
.pa-bits { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 11.5px; color: var(--ink-600); }
.pa-bits b { color: var(--ink); }
.pa-idle { font-size: 12.5px; text-align: center; }

/* Sparkline. Stretched to the cell width (preserveAspectRatio="none"), so every
   stroke uses non-scaling-stroke to keep an even weight at any aspect. */
/* Smaller than it was: the findings below it earn the space back. */
.pspark { display: block; width: 100%; height: 32px; flex: 0 0 auto; overflow: visible; margin: 2px 0 4px; }
.pspark polyline, .pspark line { fill: none; }
.psp-par  { stroke: var(--ink-400); stroke-width: 1; stroke-dasharray: 2 3; opacity: .8; }
.psp-hist { stroke: var(--ink-400); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.psp-now  { stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.psp-dot  { stroke-width: 5; stroke-linecap: round; }
.psp-now.up,   .psp-dot.up   { stroke: var(--ok-green); }
.psp-now.down, .psp-dot.down { stroke: var(--danger-red); }
.psp-now.flat, .psp-dot.flat { stroke: var(--ink-500); }

/* Month rows have no shift cells, so they stay a single flat grid: identity,
   three figures, trend. */
.prod-row.prow-month {
  display: grid; grid-template-columns: 1.4fr 90px 130px 110px 1.5fr; gap: 12px; align-items: center;
}
.prod-row .num { text-align: right; }
.prow-who { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.prow-id { display: flex; align-items: center; gap: 8px; min-width: 0; }
.prow-fig { font-size: 14px; color: var(--ink); text-align: right; }
.prow-fig b { font-size: 15px; }
.prow-trend { justify-content: center; gap: 2px; }

/* A karigar's month row is a way in, not just a figure: it opens that karigar's
   own printable sheet. Only those rows get the pointer and the lift, so a machine
   row — which opens nothing — doesn't look clickable. */
.prod-row.prow-click { cursor: pointer; transition: transform .12s ease, box-shadow .12s ease; }
.prod-row.prow-click:hover { box-shadow: var(--shadow-lg); transform: translateY(-1px); }
.prod-row.prow-click:focus-visible { outline: 2px solid var(--link-blue); outline-offset: 2px; }
.prow-open { font-size: 11px; font-weight: 700; color: var(--link-blue); }

/* Collapsible designs block. The native <details> marker is replaced by a caret
   that turns, so the whole summary row is the hit target. */
.prod-designs { margin: 22px 0 0; }
.prod-designs > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 9px 12px; border: 1px solid var(--card-border); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow); user-select: none;
}
.prod-designs > summary::-webkit-details-marker { display: none; }
.prod-designs > summary:hover { border-color: var(--link-blue); }
.prod-designs > summary .spacer { flex: 1; }
.pdz-caret { color: var(--ink-500); font-size: 12px; transition: transform .15s ease; display: inline-block; }
.prod-designs[open] > summary { border-radius: var(--radius) var(--radius) 0 0; margin-bottom: 0; }
.prod-designs[open] .pdz-caret { transform: rotate(90deg); }
.pdz-title { font-size: 15px; font-weight: 600; color: var(--ink); }
.prod-designs > .table-wrap { border-top-left-radius: 0; border-top-right-radius: 0; border-top: none; }

.pd-flag { font-size: 10.5px; font-weight: 700; color: var(--warn-gold);
           background: #fff8e1; border-radius: var(--radius-pill); padding: 2px 7px; margin-left: 6px;
           white-space: nowrap; }

/* -------------------------------------------------------------
   Range report — the flat printable table
------------------------------------------------------------- */
/* Tighter than the salary table: this one carries a column per production field,
   so it has to stay readable at eight or nine columns wide. */
.prod-rep th, .prod-rep td { padding: 8px 10px; font-size: 13px; }
.prod-rep tbody tr:nth-child(even) { background: var(--screen-bot); }
.prod-rep-head { margin-bottom: 12px; }
/* Shown only on paper — on screen the section head above the table says the same. */
.print-only { display: none; }
/* The report grows sideways with every field the org enables, so it prints
   landscape. A NAMED page, applied only while the report is being printed, so
   the salary slips keep their portrait sheet. Browsers without named-page
   support just print it portrait — narrower, still complete. */
@page report-page { size: A4 landscape; margin: 12mm; }

@media (max-width: 900px) {
  /* The two shifts stay side by side; the analysis drops below them full width. */
  .prow-body { grid-template-columns: 1fr 1fr; gap: 10px; }
  .prow-analysis { grid-column: 1 / -1; border-left: none; border-top: 1px solid var(--line);
                   padding-left: 0; padding-top: 10px; }
  .prod-colhead { display: none; }
  /* Month: name on its own line, the three figures in a row, trend underneath. */
  .prod-row.prow-month { grid-template-columns: repeat(3, 1fr); }
  .prow-trend { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .prow-body { grid-template-columns: 1fr; }
  .prod-row.prow-month { grid-template-columns: repeat(3, 1fr); }
}

/* =============================================================
   RESPONSIVE
============================================================= */
@media (max-width: 1000px) { .cards-grid { grid-template-columns: repeat(2, 1fr); } }

@media (max-width: 760px) {
  .sidebar { transform: translateX(-100%); transition: transform .25s ease; box-shadow: var(--shadow-lg); }
  .app.drawer-open .sidebar { transform: translateX(0); }
  .content { margin-left: 0; }
  .topbar { display: flex; }
  #menu-toggle { display: inline-block; }
  .view-container { padding: 16px 14px 90px; }
  .bottom-nav {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; background: var(--surface);
    border-top: 1px solid var(--line); z-index: 40; padding: 6px 4px; justify-content: space-around;
  }
  .bn-item { display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: 10.5px; font-weight: 600; color: var(--ink-500); text-decoration: none; padding: 4px 6px; flex: 1; }
  .bn-item span { font-size: 19px; }
  .bn-item.active { color: var(--link-blue); }
  .grid-2 { grid-template-columns: 1fr; }
  .slip-summary { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 420px) {
  .cards-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .stat-card .stat-val { font-size: 22px; }
  .emp-row { flex-wrap: wrap; }
}

/* ---- Register link + trial/subscription banner --------------------------- */
.login-hint a { color: var(--link-blue); font-weight: 600; text-decoration: none; }
.login-hint a:hover { text-decoration: underline; }

.trial-banner {
  padding: 10px 16px;
  text-align: center;
  font-size: 13.5px;
  font-weight: 600;
  border-bottom: 1px solid rgba(0, 0, 0, .06);
}
.trial-banner.hidden { display: none; }
.trial-banner.info   { background: var(--primary-l); color: var(--header-bot); }
.trial-banner.warn   { background: var(--amber-l);   color: var(--warn-gold); }
.trial-banner.danger { background: var(--red-l);     color: var(--danger-red); }

/* The operator's note on a production entry — the one warm surface in the app, because
   a note is a human remark on an otherwise machine-read record. Matches the phones. */
.pc-note {
  margin-top: 6px; padding: 8px 10px; border-radius: 10px;
  background: #fff3cc; color: var(--ink); font-size: 12.5px; line-height: 1.35;
}
.pc-note b {
  display: block; font-size: 9.5px; font-weight: 700; letter-spacing: .8px;
  text-transform: uppercase; color: #8a7b4a; margin-bottom: 3px;
}

/* -------------------------------------------------------------
   Forgot password (WhatsApp OTP reset)
------------------------------------------------------------- */
/* The confirmation twin of .login-error — same slot, positive colour. Used when
   a password was changed but no session came back, so the login screen has to
   say "that worked" rather than show nothing. */
.login-ok { color: var(--ok-green); font-size: 13px; margin-top: 10px; }

/* Six digits read as digits, not prose. Tabular figures stop the box from
   twitching as the code is typed. */
.otp-input {
  letter-spacing: 8px;
  text-align: center;
  font-size: 20px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.otp-input::placeholder { letter-spacing: 8px; color: var(--ink-400); font-weight: 400; }

/* Resend, while the 60s server cooldown is still running. Greyed and inert —
   the countdown text is the explanation, so no error is needed. */
.login-hint a.is-disabled {
  color: var(--ink-500);
  font-weight: 400;
  pointer-events: none;
  text-decoration: none;
}

/* ---- Production field table (Settings → Advanced Production Details) ----
   The same shape as the table in the Apex admin console, so an org's super admin
   and an Apex admin are looking at the one layout. Two cells are deliberately not
   editable here: "Photo name" (the slip-column OCR mapping) always, and "Type" for
   a built-in field — both stay with the console. See app.js → advFieldRows. */
.field-table-wrap { border: 1px solid var(--line); border-radius: 12px; overflow-x: auto; }
.field-table { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 620px; }
.field-table th {
  text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-500); font-weight: 600; padding: 9px 10px; border-bottom: 1px solid var(--line);
}
.field-table td { padding: 6px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.field-table tr:last-child td { border-bottom: none; }
.field-table td input[type="text"], .field-table td input[type="number"], .field-table td select {
  width: 100%; margin: 0; padding: 7px 9px; border-radius: 8px;
  background: #fff; border: 1px solid var(--ink-400); color: var(--ink); font-size: 13px;
}
.field-table td input[type="checkbox"] { width: auto; margin: 0; cursor: pointer; }
.field-table td:first-child, .field-table td:nth-child(2),
.field-table td:nth-child(6), .field-table td:last-child { text-align: center; }
/* Console-owned cells: shown so the table reads the same, but not editable. */
.field-table td .pf-locked {
  display: inline-block; color: var(--ink-500); font-size: 12.5px;
  padding: 7px 0; white-space: nowrap;
}
.field-table .pf-del {
  border: none; background: none; cursor: pointer; color: #dc2626;
  font-size: 15px; line-height: 1; padding: 4px 6px;
}

/* ---- Subscription (billing Phase 4) ---- */
.badge-expired { background: var(--red-l); color: var(--danger-red); }
.sub-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; }
.sub-tile { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; }
.sub-tile .k { font-size: 12px; color: var(--ink-600); }
.sub-tile .v { font-size: 18px; font-weight: 700; color: var(--ink); margin-top: 3px; }
.sub-tile .s { font-size: 12px; color: var(--ink-600); margin-top: 2px; }
.sub-notice { border-radius: var(--radius); padding: 12px 14px; margin-bottom: 14px; font-size: 13.5px; line-height: 1.5; }
.sub-notice.warn   { background: var(--amber-l); color: var(--warn-gold); }
.sub-notice.danger { background: var(--red-l);   color: var(--danger-red); }
.sub-pay { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px;
  padding: 14px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.sub-pay-main { flex: 1 1 260px; min-width: 0; }
.sub-pay .sr-title { font-weight: 600; font-size: 14.5px; color: var(--ink); }
.sub-pay .sr-sub { color: var(--ink-600); font-size: 12.5px; margin-top: 3px; line-height: 1.45; }
.sub-qty { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 8px 0 4px; }
.sub-qty label { font-size: 13px; font-weight: 500; color: var(--ink); margin: 0; }
.sub-qty input { width: 90px; margin: 0; }

/* ---- Plan strip: last 7 days / grace / expired (applyBilling → planStrip) ---- */
.trial-banner.plan-strip { display: flex; align-items: center; justify-content: center; gap: 8px 14px; flex-wrap: wrap; }
.plan-strip-text { line-height: 1.4; }
.plan-strip-btn {
  padding: 5px 14px; border-radius: var(--radius-pill); border: 0; cursor: pointer;
  background: var(--ink); color: #fff; font: inherit; font-size: 12.5px; font-weight: 700; white-space: nowrap;
}
.plan-strip-btn:hover { background: var(--ink-700); }
.plan-strip-note { font-weight: 500; opacity: .85; white-space: nowrap; }

/* ---- Invoices (invoice-doc.js draws the document itself) ---- */
.inv-preview { max-height: 68vh; overflow: auto; border: 1px solid var(--line); border-radius: 12px; background: #fff; }

/* ---- Register: price summary under "Number of Machines" ---- */
.reg-price { margin: 10px 0 4px; padding: 10px 12px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--line); font-size: 13px; }
.reg-price-row { display: flex; justify-content: space-between; gap: 10px; padding: 2px 0; color: var(--ink-600); }
.reg-price-row.total { color: var(--ink); font-weight: 700; font-size: 14px; }
.reg-price-foot { margin-top: 4px; font-size: 11.5px; color: var(--ink-600); }
#reg-resend.disabled { pointer-events: none; opacity: .6; }
#register-form input[readonly] { opacity: .7; }
.inv-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
