* { box-sizing: border-box; }
body { margin: 0; font-family: Arial, Helvetica, sans-serif; background: #f4f6f9; color: #1b1b1b; }
.topline { height: 6px; background: #002050; }
.powered-by { position: fixed; bottom: 14px; right: 18px; display: flex; align-items: center; gap: 6px; font-size: 11px; color: #a7adb8; z-index: 5; pointer-events: none; }
.powered-by img { height: 13px; width: auto; opacity: .85; }

/* ---- Collapsible left sidebar --------------------------------------
   Wraps the authenticated content on every page (index.html's appScreen,
   and the "already signed in" state on admin/createbatch/batchdetails)
   — cross-page navigation (Batch Management, Master Data) lives here
   instead of as links inside each page's top header. Collapse state is
   a pure per-browser UI preference (shared/sidebar.js), stored in
   localStorage so it stays consistent as the user moves between pages. */
.app-shell { display: flex; min-height: 100vh; }
.sidebar { width: 216px; flex-shrink: 0; background: #fff; border-right: 1px solid #dfe3e8; display: flex; flex-direction: column; transition: width .18s ease; overflow: hidden; }
.sidebar.collapsed { width: 60px; }
.sidebar-top { display: flex; align-items: center; padding: 16px 14px; gap: 8px; border-bottom: 1px solid #eef0f4; min-height: 57px; }
.sidebar-top a { display: flex; align-items: center; gap: 8px; color: #002050; font-weight: 700; font-size: 15px; text-decoration: none; white-space: nowrap; overflow: hidden; flex-shrink: 0; }
.sidebar-toggle { margin-left: auto; background: none; border: 0; cursor: pointer; padding: 6px; border-radius: 6px; color: #6b7684; display: flex; flex-shrink: 0; }
.sidebar-toggle:hover { background: #f4f6fa; }
.sidebar-nav { padding: 10px; display: flex; flex-direction: column; gap: 3px; }
.sidebar-link { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; color: #3a4356; text-decoration: none; font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; }
.sidebar-link:hover { background: #f4f6fa; }
.sidebar-link.active { background: #eaf1fd; color: #0078d4; }
.sidebar-link svg { flex-shrink: 0; }
/* Bottom-pinned profile + sign-out — margin-top:auto pushes it to the
   bottom of the sidebar's column flex layout regardless of how much nav
   content is above it. */
.sidebar-bottom { margin-top: auto; border-top: 1px solid #eef0f4; padding: 10px; display: flex; flex-direction: column; gap: 4px; }
.sidebar-profile { display: flex; align-items: center; gap: 10px; padding: 8px 12px; color: #3a4356; font-size: 12.5px; font-weight: 600; }
.sidebar-profile .lbl { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; min-width: 0; }
.profile-icon { width: 30px; height: 30px; border-radius: 50%; background: #eaf1fd; color: #0078d4; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.sidebar-signout { width: 100%; border: 0; background: none; cursor: pointer; text-align: left; font-family: inherit; }
/* Collapsed: the top row switches to a stacked (icon, then toggle)
   layout — side-by-side with only ~32px of usable width left after the
   toggle button, the brand link (a flex container in its own right, with
   overflow:hidden) could get squeezed to zero width, silently hiding the
   logo entirely. Stacking avoids that width fight and is also just what
   was asked for: collapsing shows the bar-chart logo, clearly, on its
   own row. */
.sidebar.collapsed .sidebar-top { flex-direction: column; gap: 10px; padding: 14px 8px; }
.sidebar.collapsed .sidebar-toggle { margin-left: 0; }
.sidebar.collapsed .sidebar-toggle svg { transform: rotate(180deg); }
.sidebar.collapsed .lbl { display: none; }
.sidebar.collapsed .sidebar-link { justify-content: center; }
.sidebar.collapsed .sidebar-profile { justify-content: center; }
.page-main { flex: 1; min-width: 0; }
header.app-header { background: #fff; border-bottom: 1px solid #dfe3e8; padding: 12px 22px; display: flex; justify-content: space-between; align-items: center; }
header.app-header .brand { font-weight: 700; color: #002050; font-size: 18px; }
.brand-icon { vertical-align: -3px; margin-right: 6px; }
header.app-header .brand a { color: inherit; text-decoration: none; }
header.app-header .brand .tag { font-weight: 400; font-size: 12px; color: #6b7684; margin-left: 8px; }
.page-tag { font-weight: 700; color: #002050; font-size: 21px; }
.header-left { display: flex; align-items: center; gap: 12px; }
.back-btn { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 6px; color: #6b7684; text-decoration: none; flex-shrink: 0; }
.back-btn:hover { background: #f4f6fa; color: #002050; }
header.app-header .who { display: flex; gap: 10px; align-items: center; font-size: 13px; color: #444; }
.container { max-width: 1400px; margin: 0 auto; padding: 24px 22px 60px; }
h1 { color: #002050; margin: 0 0 4px; font-size: 22px; }
h2 { color: #002050; font-size: 17px; margin: 0 0 12px; }
.sub { color: #6b7684; margin: 0 0 18px; }
.btn { border: 0; border-radius: 6px; padding: 9px 14px; font-weight: 600; font-size: 13px; cursor: pointer; background: #0078d4; color: #fff; }
.btn.gray { background: #6b7684; }
.btn.green { background: #107c10; }
.btn.red { background: #c50f1f; }
.btn.outline { background: #fff; color: #0078d4; border: 1px solid #0078d4; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.topbar { display: flex; justify-content: space-between; gap: 20px; align-items: flex-start; margin-bottom: 20px; flex-wrap: wrap; }
.filters { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.filters input, .filters select, .field input, .field select { padding: 9px 10px; border: 1px solid #c2c9d1; border-radius: 6px; background: #fff; font-size: 13px; min-height: 36px; }
.filters input { width: 220px; }
.count { color: #6b7684; font-size: 13px; }
.card { background: #fff; border-radius: 10px; padding: 18px 20px; box-shadow: 0 1px 4px rgba(0,0,0,.06); margin-bottom: 18px; }
.tablewrap { background: #fff; border-radius: 10px; overflow: auto; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
table { width: 100%; min-width: 900px; border-collapse: collapse; }
th { background: #002b67; color: #fff; padding: 11px 12px; text-align: left; font-size: 12.5px; white-space: nowrap; }
td { padding: 10px 12px; border-bottom: 1px solid #eaedf1; font-size: 13.5px; white-space: nowrap; }
tr.inactive-row td { color: #9aa3ad; background: #fafbfc; }
.linkbtn { border: 0; background: none; color: #0078d4; font-weight: 700; cursor: pointer; padding: 0; font-size: inherit; }
.status-open { color: #107c10; font-weight: 700; }
.status-closed { color: #c50f1f; font-weight: 700; }
.pill { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 700; }
.pill.active { background: #e6f4ea; color: #107c10; }
.pill.inactive { background: #eceef1; color: #6b7684; }
.field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.field label { font-size: 12.5px; font-weight: 600; color: #37424d; }
.field .hint { font-size: 11.5px; color: #8a93a0; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
/* Read-only "Label ... Value" fact rows, one line each (section 15i item
   4). .kvgrid alone (no .kvbox children) is used for the batch header's
   meta line — a flat row of facts with no grouping needed. .kvbox wraps
   a related group of .kv rows in its own bordered card (section 15j item
   3, Batch Overview) so columns of facts read as distinct boxes instead
   of one run-on grid with no visual boundary between them. Distinct from
   .field (label-above-input), which stays as-is for editable form
   fields. */
.kvgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, max-content)); gap: 14px 28px; align-items: start; }
/* Forced 4-column variant for the batch header's meta line (section 15l
   item 2) — sizing-to-content (plain .kvgrid) let 7 facts wrap wherever
   they happened to fit, unpredictably, with nothing marking it as a
   group. This forces a clean 4-then-3 two-line layout every time, always
   wrapped in a .kvbox below so it reads as one visible, bounded block. */
.kvgrid.fourcol { grid-template-columns: repeat(4, minmax(150px, 1fr)); }
@media (max-width: 900px) { .kvgrid.fourcol { grid-template-columns: repeat(2, 1fr); } }
/* A clearly-bordered card with a colored top edge (not a near-invisible
   1px hairline) so each group of facts reads as its own distinct box at
   a glance, not just loosely-related rows. */
.kvbox { background: #fff; border: 1px solid #ccd4de; border-top: 3px solid #0078d4; border-radius: 8px; padding: 6px 16px 4px; box-shadow: 0 1px 3px rgba(0,0,0,.05); }
.kvboxtitle { font-size: 11px; font-weight: 700; color: #6b7684; text-transform: uppercase; letter-spacing: .03em; padding: 8px 0 6px; }
/* Grid of *boxed* card groups (Batch Overview's 4 groups) — plain .kvgrid
   sizes each column to its own content (max-content), which left the 4
   boxes at different widths, ragged gaps between them, a large empty gap
   after the last box, and different heights per box (jagged bottom edge)
   — read as "misaligned" rather than a clean grid (section 15l item 1).
   This instead fills each row evenly (auto-fit + 1fr) and lets CSS
   Grid's default row-stretch give every box in the row equal height. */
.kvboxgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
/* Label and value sit close together with a small fixed gap — NOT
   justify-content:space-between, which (combined with the grid column
   stretching to fill available width) was shoving short values far away
   from their label with a big empty gap in between. */
.kv { display: flex; justify-content: flex-start; align-items: baseline; gap: 10px; padding: 6px 0; border-bottom: 1px solid #eef1f5; font-size: 13px; }
.kv:last-child { border-bottom: 0; }
.kv .k { color: #6b7684; font-weight: 600; white-space: nowrap; }
.kv .v { color: #1b2733; font-weight: 700; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 18px; }
.notice { padding: 10px 14px; border-radius: 6px; margin-bottom: 16px; font-size: 13px; }
.notice.error { background: #fde7e9; color: #a4262c; }
.notice.success { background: #e6f4ea; color: #107c10; }
.notice.info { background: #eaf3fb; color: #004578; }
/* ---- Sign-in screen (index.html) --------------------------------------
   Two-column marketing-style layout: a hero panel (left) describing the
   product, and the actual sign-in card (right). Only .login-hero and
   .login-card-wrap are direct children of .login-screen; everything
   else nests inside those two. */
.login-screen { min-height: 100vh; display: flex; flex-wrap: wrap; background: #eef2fc url('img/login-bg.png') center center / cover no-repeat; }
.login-hero { position: relative; flex: 1 1 520px; padding: 48px 56px; overflow: hidden; min-width: 320px; }
.hero-blob { display: none; } /* the real wave art now comes from login-bg.png on .login-screen itself */
.hero-topscript { position: absolute; top: 28px; right: 40px; font-family: 'Caveat', cursive; font-weight: 600; font-size: 19px; line-height: 1.15; color: #3b5bdb; text-align: right; transform: rotate(-3deg); }
.hero-logo { display: flex; align-items: center; gap: 10px; margin-bottom: 34px; position: relative; }
.hero-wordmark { font-size: 24px; font-weight: 800; line-height: 1; }
.hero-wordmark .navy { color: #142850; }
.hero-wordmark .blue { color: #2f80ed; }
.hero-tagline { font-size: 10.5px; font-weight: 700; letter-spacing: .12em; color: #8a93a0; margin-top: 3px; }
.hero-heading { position: relative; font-size: 42px; line-height: 1.12; font-weight: 800; color: #142850; margin: 0 0 18px; }
.hero-grad { background: linear-gradient(90deg, #2f6fed, #5aa6ff); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero-desc { position: relative; max-width: 460px; color: #5b6478; font-size: 14.5px; line-height: 1.6; margin: 0 0 30px; }
.hero-features { position: relative; display: flex; gap: 26px; flex-wrap: wrap; margin-bottom: 34px; }
.hero-feature { display: flex; flex-direction: column; align-items: center; text-align: center; width: 94px; }
.feat-icon { width: 54px; height: 54px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; }
.feat-icon.purple { background: #ede6fb; }
.feat-icon.blue { background: #ddebfc; }
.feat-icon.green { background: #dff3e6; }
.feat-icon.orange { background: #fde9d7; }
.feat-label { font-size: 12px; font-weight: 700; color: #142850; line-height: 1.35; }
.hero-script { position: relative; font-family: 'Caveat', cursive; font-weight: 700; font-size: 26px; line-height: 1.2; color: #2f6fed; margin-bottom: 22px; }
.hero-photo { position: relative; display: flex; align-items: flex-end; gap: 14px; max-width: 380px; }
.hero-photo-plant { width: 26px; height: 46px; border-radius: 40% 40% 10px 10px; background: linear-gradient(180deg, #7fb069, #4d7c4a); flex-shrink: 0; }
.hero-photo-laptop { flex: 1; height: 120px; border-radius: 10px 10px 4px 4px; background: linear-gradient(135deg, #2a3550, #3d4a6b); display: flex; align-items: center; justify-content: center; box-shadow: 0 10px 24px rgba(20,40,80,.18); }
.hero-photo-text { font-size: 10px; font-weight: 700; letter-spacing: .14em; color: rgba(255,255,255,.6); text-align: center; line-height: 1.9; }

.login-card-wrap { flex: 1 1 420px; min-width: 320px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 32px; }
.login-card { background: #fff; border-radius: 20px; padding: 38px 40px; width: 100%; max-width: 460px; box-shadow: 0 12px 40px rgba(20,40,90,.1); text-align: center; }
.login-card .card-title { font-size: 21px; font-weight: 800; color: #142850; margin: 16px 0 6px; }
.login-card .sub { font-size: 13px; color: #6b7684; margin: 0 0 22px; }
.ms-logo { display: flex; justify-content: center; }
.ms-signin-btn { width: 100%; display: flex; align-items: center; justify-content: center; gap: 10px; border: 0; border-radius: 8px; padding: 13px 16px; background: linear-gradient(180deg, #1a6fe0, #1259c4); color: #fff; font-size: 14.5px; font-weight: 700; cursor: pointer; box-shadow: 0 4px 14px rgba(21,101,216,.35); }
.ms-signin-btn:hover { filter: brightness(1.05); }
.ms-btn-icon { background: #fff; border-radius: 3px; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.ms-btn-arrow { display: flex; margin-left: auto; }
.or-divider { display: flex; align-items: center; gap: 14px; color: #a7adb8; font-size: 11.5px; font-weight: 700; letter-spacing: .06em; margin: 22px 0; }
.or-divider::before, .or-divider::after { content: ''; flex: 1; height: 1px; background: #e4e8f0; }
.new-here h3 { font-size: 14.5px; color: #142850; margin: 0 0 6px; }
.new-here p { font-size: 12.5px; color: #6b7684; line-height: 1.55; margin: 0 0 20px; }
.trust-row { display: flex; gap: 10px; }
.trust-badge { flex: 1; background: #f4f6fa; border-radius: 12px; padding: 12px 8px; display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: #142850; text-align: center; }
.trust-badge span { display: block; font-weight: 500; color: #8a93a0; font-size: 10px; margin-top: 1px; }
.login-footer { margin-top: 18px; font-size: 11.5px; color: #a7adb8; }
@media (max-width: 900px) {
  .login-hero { padding: 36px 28px 12px; }
  .hero-topscript { position: static; text-align: left; transform: none; margin-bottom: 16px; }
  .hero-heading { font-size: 32px; }
  .hero-photo { display: none; }
}
/* Shown by default (no JS needed) on every page while the initial data/
   session load is in flight, so navigating between pages never flashes
   the wrong screen (e.g. the sign-in screen) before the real one is
   known — replaced by the actual content once init() resolves. */
.page-loading { min-height: 70vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; color: #6b7684; font-size: 13.5px; }
.page-loading .brand { font-size: 22px; font-weight: 800; color: #002050; }
.spinner { width: 28px; height: 28px; border: 3px solid #dfe3e8; border-top-color: #0078d4; border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.tabs-admin { display: flex; gap: 4px; border-bottom: 1px solid #dfe3e8; margin-bottom: 18px; }
.tabs-admin button { border: 0; background: none; padding: 10px 16px; font-size: 13.5px; font-weight: 600; color: #6b7684; cursor: pointer; border-bottom: 2px solid transparent; }
.tabs-admin button.active { color: #002050; border-bottom-color: #0078d4; }
.hidden { display: none !important; }
.mini { font-size: 12px; color: #8a93a0; }
dialog.modal { border: 0; border-radius: 10px; max-width: 640px; width: 92vw; padding: 22px; box-shadow: 0 8px 32px rgba(0,0,0,.25); }
dialog.modal::backdrop { background: rgba(10, 20, 40, .45); }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }
.segtoggle { display: inline-flex; background: #eceef1; border-radius: 8px; padding: 3px; gap: 2px; flex-shrink: 0; }
.segtoggle button { border: 0; background: none; padding: 8px 16px; font-size: 12.5px; font-weight: 600; color: #6b7684; cursor: pointer; border-radius: 6px; }
.segtoggle button.active { background: #fff; color: #002050; box-shadow: 0 1px 3px rgba(0,0,0,.15); }
.savebar { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin: 4px 0 14px; padding: 10px 14px; border-radius: 6px; background: #fff8e1; flex-wrap: wrap; }
.savebar.clean { background: #eaf7ec; }
.savebar .msg { font-size: 12.5px; font-weight: 600; }
select.monthcell { min-height: 30px; padding: 3px 4px; font-size: 12px; }
/* Frozen (sticky) leading columns — Classroom Performance's Employee Code/
   Name so they stay visible while scrolling through many assessment/
   attempt columns. .fixedw pins a column to a known width so a second
   frozen column (Name) can sit at a predictable `left` offset next to it;
   a single frozen column (e.g. the certification table's merged Employee
   cell) doesn't need a fixed width since nothing sits to its right. */
.frozen-col1 { position: sticky; left: 0; z-index: 2; background: #fff; }
.frozen-col1.fixedw { width: 110px; min-width: 110px; max-width: 110px; }
.frozen-col2 { position: sticky; left: 110px; z-index: 2; background: #fff; }
th.frozen-col1, th.frozen-col2 { z-index: 3; background: #002b67; }
tr.inactive-row td.frozen-col1, tr.inactive-row td.frozen-col2 { background: #fafbfc; }
.frozen-edge { box-shadow: 2px 0 4px -2px rgba(0,0,0,.25); }
.ragpill { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 700; }
.ragpill.green { background: #e6f4ea; color: #107c10; }
.ragpill.amber { background: #fff4ce; color: #8a6a00; }
.ragpill.red { background: #fde7e9; color: #a4262c; }
.ragpill.none { background: #eceef1; color: #6b7684; }
/* Session Planner Month Grid calendar view, added after seeing the tab
   live (Table View stays available via the same segmented-toggle pattern
   Attendance's Daily/Monthly View already uses). 7 columns, one per
   weekday; a day cell can hold more than one (Training Phase, Day) badge
   in the rare case two phases' Session Dates land on the same date. */
.calgrid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.calhead { text-align: center; font-size: 11px; font-weight: 700; color: #6b7684; padding: 4px 0 8px; text-transform: uppercase; letter-spacing: .03em; }
.calcell { min-height: 74px; background: #fff; border: 1px solid #e4e8ee; border-radius: 8px; padding: 6px; display: flex; flex-direction: column; gap: 4px; }
.calcell.empty { background: transparent; border-color: transparent; }
.calcell.weekoff { background: #fafbfc; }
.calcell.today { border-color: #0078d4; border-width: 2px; }
.caldate { font-size: 11.5px; font-weight: 700; color: #37424d; }
.calmini { font-size: 10.5px; color: #8a93a0; }
.calbadge { border-radius: 6px; padding: 4px 6px; cursor: pointer; font-size: 10.5px; line-height: 1.3; }
.calbadge.pending { background: #eef2f7; border: 1px solid #d8dfe8; }
.calbadge.done { background: #e6f4ea; border: 1px solid #bfe6c7; }
.calbadge.selected { outline: 2px solid #0078d4; outline-offset: 1px; }
.calbadgephase { display: flex; align-items: center; font-weight: 700; color: #002050; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.calbadgemeta { color: #6b7684; }

/* Reports tab "dashboard" look (section 15n) — the Reports tab now
   renders inline using the same visual language (banner, big stat cards,
   color-tagged sections) as the standalone Dashboard/email report built
   from this same data (buildDashboardHtml / buildEmailSafeReportHtml in
   reports.js), so what's on the tab already IS the report, not a plainer
   summary you only see the "real" version of via Preview/Copy/Download. */
.report-banner { background: #002050; color: #fff; border-radius: 10px; padding: 20px 24px; margin-bottom: 18px; }
.report-banner .rtitle { font-size: 20px; font-weight: 800; margin-bottom: 4px; }
.report-banner .rsub { opacity: .85; font-size: 13px; }
.report-greeting { font-size: 14px; margin: 0 0 18px; color: #1b1b1b; }
.report-greeting div { margin-bottom: 2px; }
.dstatgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 18px; }
.dstat { background: #fff; border-radius: 10px; padding: 14px 16px; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
.dstat .n { font-size: 20px; font-weight: 800; color: #002050; }
.dstat .l { font-size: 12px; color: #6b7684; }
.tag { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 700; }
.tag.red { background: #fde7e9; color: #a4262c; }
.tag.green { background: #e6f4ea; color: #107c10; }
.tag.amber { background: #fff4ce; color: #8a6a00; }
.tag.gray { background: #eceef1; color: #6b7684; }
.card ul { margin: 0; padding-left: 18px; font-size: 13.5px; }
.card li { margin-bottom: 8px; }
.card .none { color: #8a93a0; font-size: 13px; margin: 0; }
