@import url('./logo-icons.css?v=20261017-home-icons');
:root {
  --hd-blue: #123885;
  --hd-blue-dark: #0e2c68;
  --hd-teal: #12897d;
  --hd-bg: #f4f6f9;
  --hd-card: #ffffff;
  --hd-text: #1c2733;
  --hd-muted: #6b7785;
  --hd-border: #e2e7ee;
  --hd-danger: #c0392b;
  --hd-success: #1e8e5a;
  /* Single shared "payroll" brown-yellow tan, per explicit request ("dinh dang mau cua hai cot nay
     thong nhat nhu tai admin - mau vang nau nhu nhau tren toan he thong") - the Meals/Official paid
     working days columns on employee/attendance-entry.html and admin/attendance-overview.html used
     to each hardcode their own #ece4c9 (identical value, but two separate places that could drift),
     and that value itself read as near-white once screen/JPEG-compressed rather than a clearly
     visible brown-yellow. One variable, referenced by both pages (and the color-mix zebra-tint
     variant on the overview page), so every approver sees the exact same color and it can only ever
     be changed in one place. */
  --hd-payroll-tan: #e6c887;
  --hd-radius: 14px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --header-height: 60px;
  /* App chrome (top header bar + left nav sidebar). Both are now white - the Handong navy only
     survives in the logo badge image itself (icons/handong-logo-original.png ships with its own navy square
     baked in), everything else in the header/sidebar uses dark text/icons on white instead. The
     sidebar's own white background is set directly on .app-sidebar rather than through a variable
     here (nothing else ever referenced --hd-chrome-sidebar). */
  --hd-chrome-header: #ffffff;
  --hd-chrome-accent: var(--hd-teal);
}

/* Shared four-tab navigation for the Official Contract Center. */
.contract-center-tabs { display:grid; grid-template-columns:repeat(4,minmax(150px,1fr)); gap:7px; margin:12px 0 14px; padding:5px; border:1px solid #dbe5ef; border-radius:13px; background:#eef3f7; }
.contract-center-tab { display:flex; align-items:center; justify-content:center; min-height:38px; padding:7px 10px; border-radius:9px; color:#506176; font-size:11px; font-weight:750; line-height:1.25; text-align:center; text-decoration:none; }
.contract-center-tab:hover { color:#123885; background:rgba(255,255,255,.75); }
.contract-center-tab.active { color:#fff; background:linear-gradient(105deg,#123885,#12897d); box-shadow:0 4px 11px rgba(18,56,133,.2); }
@media (max-width:760px) {
  .contract-center-tabs { grid-template-columns:1fr 1fr; }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--hd-bg);
  color: var(--hd-text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-tap-highlight-color: transparent;
}

a { color: var(--hd-blue); text-decoration: none; }

/* Compact default heading spacing everywhere (page titles, section titles, card titles) so content
   sits close under the header/heading instead of the browser's large default h-tag margins. */
h1, h2, h3, h4 { margin-top: 0; margin-bottom: 8px; }

.app-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--hd-chrome-header);
  color: var(--hd-text);
  padding: 10px 16px;
  min-height: var(--header-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--hd-border);
  box-shadow: 0 2px 8px rgba(15,23,42,0.05);
  box-sizing: border-box;
}

.app-header .brand {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.2px;
  /* Per explicit request ("chu ben Handong E&C chuyen dung mau logo xanh cho dong bo") - matches
     the logo square's own navy (--hd-blue) instead of inheriting the page's plain dark text color. */
  color: var(--hd-blue);
}
.app-header .brand small {
  display: block;
  font-weight: 400;
  font-size: 11px;
  opacity: 0.7;
}

.app-header.admin-header { justify-content: flex-start; gap: 16px; padding: 6px 16px; min-height: 0; }
.admin-header-left, .header-left { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.admin-header-left .brand, .header-left .brand { font-size: 15px; }
/* Per explicit request ("ap dung logo nay cho... cho goc nay") - the small header badge
   (top-left, next to "Admin Panel"/"Handong") now matches the same crisp-square treatment as
   .logo-mark on the auth screens, instead of its old 28-29%-radius rounded-squircle crop. */
/* Original logo only (explicit rule 2026-10-16: "100% Logo gốc... không được phép chỉnh sửa"): the
   original file (icons/handong-logo-original.png = official HD_Sub Logo_2026 -02), sized by height with its own aspect ratio -
   never cropped, recoloured, rounded or boxed. */
.admin-header .logo-badge { height: 32px; }
.logo-badge {
  height: 32px; width: auto; max-width: none; border-radius: 0;
  display: block; object-fit: contain; flex: 0 0 auto; background: none; box-shadow: none;
}
.admin-nav { display: flex; gap: 4px; overflow-x: auto; flex: 1 1 0%; min-width: 0; }
.admin-nav a {
  padding: 8px 12px; border-radius: 999px; white-space: nowrap; flex: 0 0 auto;
  background: rgba(0,0,0,0.045); color: var(--hd-text); font-size: 13px; font-weight: 600;
}
.admin-nav a.active { background: var(--hd-blue); color: #fff; }
.admin-header .link-btn { flex: 0 0 auto; width: auto; }
/* Fills the space between the logo/brand cluster and the right-side controls (role-switch link,
   if shown + the language flags + Log out) - replaces the old .admin-nav's flex:1 job now that the
   top nav has moved into the left sidebar. Using an always-present spacer (rather than
   margin-left:auto on whichever control happens to be first) keeps the whole control cluster
   pinned together as one group even when role-switch-link is visible alongside the flags - two
   separate auto-margins would each grab their own share of free space and split the group apart. */
.header-spacer { flex: 1 1 auto; }

.app-header button.link-btn {
  background: rgba(0,0,0,0.05);
  color: var(--hd-text);
  border: none;
  padding: 8px 12px;
  border-radius: 10px;
  font-size: 13px;
}
.app-header button.link-btn:hover { background: rgba(0,0,0,0.08); }
/* Match the original logo's straight edges without resizing the logo or the controls. */
.app-header #logout-btn, #login-form #submit-btn { border-radius: 0; }

.container {
  max-width: 640px;
  margin: 0 auto;
  padding: 10px 16px calc(24px + var(--safe-bottom));
}

/* Drawer twin of the header's #role-switch-link (see auth.js) - hidden here on desktop/tablet,
   where the header copy already does the job; the media query below is the only thing that ever
   reveals it, and only for accounts where auth.js has also cleared its inline display:none. */
.sidebar-role-switch { display: none; }

/* Found alongside the sidebar drawer fix - on a real phone the header (logo + "HANDONG E&C" +
   role-switch link + language flags + Log out) already overflowed its own row on its own,
   wrapping "Admin Panel"/"My employee view" onto a second line and pushing the flags/Log out
   button half off-screen. Trimmed to what a phone actually has room for: the wordmark text and
   the admin/employee role-switch link (a desktop convenience, not core navigation - the same
   destination is one tap away via the hamburger menu regardless) drop out, logo shrinks a touch. */
@media (max-width: 480px) {
  .app-header .brand { display: none; }
  .header-left .logo-badge { height: 32px; width: auto; }
  #role-switch-link { display: none !important; }
  /* The header link above disappears at this width, so its drawer twin (js/sidebar.js injects
     #role-switch-link-mobile, auth.js keeps both in sync) becomes the only way to switch between
     Admin Panel and My employee view on a phone. Deliberately NOT !important here (unlike
     #role-switch-link above): this element starts with an inline style="display:none" in the
     markup and only auth.js clears that inline style for an account that actually has the other
     side to switch to - an !important rule would force it to show for every account regardless. */
  .sidebar-role-switch { display: flex; background: rgba(18,56,133,0.05); font-weight: 800; }
}

/* Checked on a real phone per explicit request ("thiết lập cỡ chữ (size) phù hợp nhất") - text
   sized fine on a desktop monitor read noticeably small held close on an actual handset. Bumped
   the drawer nav (the single most-tapped/most-read UI on a phone) and the info-grid field labels
   (used across My Profile's Employment/Contract/Personal sections and equivalent admin detail
   views) by ~1.5px each, phone-only - desktop keeps the original sizes, which were never the
   problem there. */
@media (max-width: 480px) {
  .sidebar-section-head, .sidebar-flat-link, .sidebar-link, .sidebar-stub { font-size: 13.5px; }
  .info-field .info-label { font-size: 11px; }
  .info-field .info-value { font-size: 13.5px; }
  /* Report/data tables (admin/results.html's competency-gap and onboarding tables, and every
     other admin table built on this same shared rule) stay genuinely wide on a phone - many
     columns of real data don't fit any narrower, and their own overflow-x:auto wrapper already
     handles that (see the .app-main audit) - but the TEXT inside was still sized for a desktop
     monitor. Bumped so scrolling through a dense report on a phone is still comfortable to read. */
  table { font-size: 12.5px; }
  th { font-size: 11.5px; }
}

.container.narrow { max-width: 420px; }

.container.wide { max-width: 1180px; }
@media (min-width: 900px) {
  .container.wide { padding-left: 32px; padding-right: 32px; }
  .container.wide .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; align-items: start; }
  .container.wide .card-grid > .card { margin-bottom: 0; }
}

/* Admin pages: fill the whole screen width instead of centering with a cap */
.container.full { max-width: none; }
@media (min-width: 900px) {
  .container.full { padding-left: 28px; padding-right: 28px; }
}

/* Page-level blueprint sidebar (js/sidebar.js) - persistent left nav shared by every admin/employee
   page, replacing the old horizontal admin-nav/employee-nav tab bars. */
.app-shell { display: flex; align-items: flex-start; min-height: calc(100vh - var(--header-height)); }
/* Stable navigation (2026-10-14, "chuyển thư mục / tab không rung giật"). Measured on live with
   Chrome's layout-shift API before this change:
   1. every page: .app-main jumped 64-268px sideways when js/sidebar.js drew the sidebar after the
      first paint - the bare <nav> had no width until JS added .app-sidebar. The nav now reserves
      the sidebar's exact width from the very first paint (64px when the person keeps it collapsed,
      read by the inline script next to every <nav id="app-sidebar">), and that script also paints
      the last sidebar this person saw, so the menu is there immediately instead of popping in.
   2. every tab switch: the page shifted 15px left/right whenever the new tab's content was short
      enough to drop the vertical scrollbar (or long enough to bring it back). The scrollbar gutter
      is now always reserved, so switching tabs never moves anything sideways. */
html { scrollbar-gutter: stable; }
@media (min-width: 901px) {
  #app-sidebar:not(.app-sidebar) {
    flex: 0 0 268px; width: 268px; align-self: flex-start;
    position: sticky; top: var(--header-height); height: calc(100vh - var(--header-height));
    background: #f7f7f5; border-right: 1px solid #e5e5e2;
  }
  html.sb-collapsed #app-sidebar:not(.app-sidebar) { flex-basis: 64px; width: 64px; }
}
/* Page-to-page: the browser cross-fades between pages (Chrome/Edge 126+) instead of flashing a
   blank page; the header and sidebar are matched across pages so they stay perfectly still while
   only the content area changes. Browsers without support simply navigate as before. */
@view-transition { navigation: auto; }
.app-header { view-transition-name: hd-header; }
#app-sidebar { view-transition-name: hd-sidebar; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 140ms; }
::view-transition-old(hd-header), ::view-transition-new(hd-header),
::view-transition-old(hd-sidebar), ::view-transition-new(hd-sidebar) { animation: none; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }
/* Settle before showing: measured shifts of 0.1-0.2 (cards appearing, tables filling, "Loading..."
   lines replaced) on Dashboard, IT, Attendance periods, Account, Competency... The content area now
   stays invisible while the page's first data is loading and appears once no "Loading..." /
   "Đang tải..." text is visible in it and it has stopped changing for 0.2 s (inline script beside
   <nav id="app-sidebar">) - never longer than 3 s. Size changes count as changes too (late images). Network activity is deliberately not a signal:
   sidebar badges keep requests running on every page. A page that renders in several steps sets
   <html data-hd-busy> until its last step (official-contracts.js, results.html). Header and sidebar show immediately.
   No loading bar (removed 2026-10-29 at HR's request) - the content simply fades in once ready.
   Opacity (not visibility) keeps everything measurable and focusable for scripts. */
html.hd-settling .app-main { opacity: 0; pointer-events: none; }
.app-main { transition: opacity 0.14s ease; }
@media (prefers-reduced-motion: reduce) { .app-main { transition: none; } }
.app-sidebar {
  --sidebar-surface: #f7f7f5;
  --sidebar-hover: #ececea;
  --sidebar-active: #e4e4e1;
  --sidebar-text: #2f2f2f;
  --sidebar-muted: #6f6f6f;
  --sidebar-focus: rgba(18, 56, 133, 0.22);
  width: 268px; flex: 0 0 268px;
  background: var(--sidebar-surface);
  border-right: 1px solid #e5e5e2;
  position: sticky;
  top: var(--header-height);
  height: calc(100vh - var(--header-height));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  color: var(--sidebar-text);
  transition: width 0.18s ease, flex-basis 0.18s ease;
}
.app-sidebar.collapsed { width: 64px; flex-basis: 64px; }
/* Collapsed mode leaves the normal sticky-in-flow layout for a fixed overlay pinned at the exact
   spot the collapsed rail already sits (left:0, same top/height) - #app-sidebar-spacer (inserted by
   js/sidebar.js right after <nav>, sibling-selected below) reserves that same 64px of flex space so
   .app-main never reflows, whether the rail is resting at 64px or hover-expanded to 268px. Only
   .collapsed switches to this model - the normal (non-collapsed) sidebar is untouched, still plain
   position:sticky, zero behavior change there. */
.app-sidebar.collapsed {
  position: fixed;
  left: 0;
  z-index: 400;
  transition: width 0.16s ease, box-shadow 0.16s ease;
}
.app-sidebar.collapsed:hover {
  width: 268px;
  box-shadow: 8px 0 30px rgba(15,23,42,0.16);
}
.app-sidebar.collapsed:hover .sidebar-section-label,
.app-sidebar.collapsed:hover .sidebar-chevron { display: revert; }
/* Only an already-.open section reveals its body on hover-expand, matching the normal (non-
   collapsed) sidebar exactly - a blanket "show all bodies on hover" would be wrong here, since
   plain `display: revert` resets to the UA default (block for a div) rather than falling through to
   the .open rule below, so this needs its own explicit, more specific selector instead. */
.app-sidebar.collapsed:hover .sidebar-section.open .sidebar-section-body { display: block; }
#app-sidebar-spacer { flex: 0 0 0; width: 0; }
#app-sidebar.collapsed ~ #app-sidebar-spacer { flex: 0 0 64px; width: 64px; }
.sidebar-scroll {
  flex: 1; overflow-y: auto; overflow-x: hidden; padding: 2px 7px 12px; /* 2px top: menu starts right under the top bar (request 2026-10-17) */
  scrollbar-width: thin; scrollbar-color: #c7c7c3 transparent;
}
.sidebar-scroll::-webkit-scrollbar { width: 6px; }
.sidebar-scroll::-webkit-scrollbar-track { background: transparent; }
.sidebar-scroll::-webkit-scrollbar-thumb { background: #c7c7c3; border-radius: 999px; }
.sidebar-section { margin: 1px 0; border: 0; }
.sidebar-section-head {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 40px;
  background: transparent; border: 0; border-radius: 9px; text-align: left; cursor: pointer;
  padding: 9px 10px; color: var(--sidebar-text); font-size: 13px; font-weight: 500;
  line-height: 1.25; transition: background-color 0.14s ease, color 0.14s ease;
}
.sidebar-section-head:hover { background: var(--sidebar-hover); }
.sidebar-section-head:focus-visible,
.sidebar-flat-link:focus-visible,
.sidebar-link:focus-visible,
.sidebar-collapse-btn:focus-visible { outline: 2px solid var(--sidebar-focus); outline-offset: -2px; }
.sidebar-section-icon {
  position: relative; width: 22px; min-width: 22px; height: 22px; flex: 0 0 22px;
  display: flex; align-items: center; justify-content: center; color: #383838;
}
.sidebar-section-icon svg { width: 18px; height: 18px; flex: 0 0 auto; stroke-width: 1.8; }
.sidebar-section-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-chevron {
  width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 9px; opacity: 0.48; transition: transform 0.18s ease; flex: 0 0 auto;
}
.sidebar-section.open .sidebar-chevron { transform: rotate(180deg); }
/* Child items keep the same quiet, rounded visual language as ChatGPT's nested navigation. */
.sidebar-section-body { display: none; padding: 2px 0 4px; background: transparent; }
.sidebar-section.open .sidebar-section-body { display: block; }
.sidebar-section:has(.sidebar-link.active) > .sidebar-section-head { background: rgba(0,0,0,0.035); }
.sidebar-flat-link {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 40px;
  padding: 9px 10px; color: var(--sidebar-text); font-size: 13px; font-weight: 500;
  line-height: 1.25; text-decoration: none; border: 0; border-radius: 9px; cursor: pointer;
  transition: background-color 0.14s ease, color 0.14s ease;
}
.sidebar-flat-link:hover { background: var(--sidebar-hover); }
.sidebar-flat-link.active { background: var(--sidebar-active); color: #111; font-weight: 600; }
.sidebar-link, .sidebar-stub {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 35px; margin: 1px 0; padding: 7px 10px 7px 42px;
  font-size: 12.5px; line-height: 1.25; border: 0; border-radius: 8px;
  transition: background-color 0.14s ease, color 0.14s ease;
}
.sidebar-link { color: var(--sidebar-muted); cursor: pointer; text-decoration: none; }
.sidebar-link:hover { background: var(--sidebar-hover); color: #111; }
.sidebar-link.active { background: var(--sidebar-active); color: #111; font-weight: 600; }
/* Red count badge (e.g. unread "Library changed" notifications) on a sidebar-link, plus a small
   dot echoed onto its parent section header so it's still visible while that section is collapsed. */
.sidebar-badge {
  display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 999px; background: #d92d20; color: #fff;
  font-size: 9.5px; font-weight: 700; flex: 0 0 auto; box-shadow: 0 0 0 2px var(--sidebar-surface);
}
/* Same numbered-badge treatment as the notification bell, pinned to the section icon itself (not
   just the text label) so it stays visible while the sidebar is collapsed to icon-only width -
   .sidebar-section-label is display:none in that state, so anything anchored to the label
   disappears with it; the icon never does. */
.sidebar-icon-badge {
  position: absolute; top: -6px; right: -8px; display: flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px; background: #d92d20;
  color: #fff; font-size: 9px; font-weight: 700; line-height: 16px; box-shadow: 0 0 0 2px var(--sidebar-surface);
  cursor: pointer;
}
.sidebar-badge { cursor: pointer; }
/* Several counts on one sidebar item are shown as ONE total (sidebar.js mergeSidebarBadges). */
#app-sidebar [data-merged="1"] { display: none !important; }
.sidebar-stub { color: #a0a09c; cursor: default; }
.sidebar-collapse-btn {
  flex: 0 0 auto; width: calc(100% - 14px); min-height: 38px; margin: 0 7px 7px;
  border: 0; border-radius: 9px; background: transparent; color: #777; padding: 9px; cursor: pointer; font-size: 13px;
  transition: background-color 0.14s ease, color 0.14s ease;
}
.sidebar-collapse-btn:hover { color: #111; background: var(--sidebar-hover); }
.app-sidebar.collapsed .sidebar-section-label,
.app-sidebar.collapsed .sidebar-chevron,
.app-sidebar.collapsed .sidebar-section-body { display: none; }
.app-sidebar.collapsed .sidebar-collapse-btn { transform: rotate(180deg); }
/* Separates Part 1 (the person's own Employee Portal sections, labeled "My workspace") from Part 2
   (their delegated admin sections, labeled "Delegated admin access" - both merged in by
   js/sidebar.js's renderMergedSidebar) - per explicit request that the two read as clearly distinct
   groups on the one page, on desktop as legibly as they already do on the mobile drawer. Each
   carries its own .sidebar-section-icon/.sidebar-section-label pair (same classes real sections use)
   so the icon-only collapsed rail and its hover-to-expand behavior apply here with no extra rules. */
.sidebar-divider {
  display: flex; align-items: center; gap: 10px; margin: 10px 3px 4px; padding: 10px 7px 6px;
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em;
  color: #0b746d; border-top: 1px solid #dededa;
}
.sidebar-divider .sidebar-section-icon svg { width: 14px; height: 14px; }
/* Part 1's own label, in the app's blue rather than the admin-teal used for Part 2, and with no
   top border of its own since it's the very first thing in the sidebar (nothing above to divide
   from) - the two colors alone are enough to read as "your section" vs "delegated section". */
.sidebar-divider-user { color: var(--hd-blue, #123885); border-top: none; margin-top: 0; }
/* Icon-only collapsed rail: the shared .sidebar-section-label rule below already hides the text,
   but the divider itself must stay visible (not display:none, the previous behavior) as a compact
   colored marker - otherwise Part 1/Part 2 icons blend into one undifferentiated list with zero
   boundary, which was exactly the "clear on mobile, not on desktop" gap this fixes. Hovering to the
   expanded rail restores the normal full-width label via the existing hover-reveal rule. */
.app-sidebar.collapsed .sidebar-divider { justify-content: center; padding: 10px 0 6px; }
.app-sidebar.collapsed:hover .sidebar-divider { justify-content: flex-start; padding: 10px 7px 6px; }
/* max-width:100% alongside min-width:0 - found testing landscape phone/tablet widths (~700-900px,
   between the mobile drawer breakpoint and desktop): min-width:0 alone wasn't enough to stop this
   flex item from sizing itself off .container.wide's 1180px cap (its content's "preferred" width)
   instead of the actual space .app-shell had for it, pushing the whole page into horizontal
   scroll. Capping it to 100% of its own flex allocation fixes that at every width, mobile through
   desktop, with no effect on the normal case where content already fits. */
.app-main { flex: 1; min-width: 0; max-width: 100%; }
/* Hamburger toggle (js/sidebar.js injects this into .app-header) - invisible on desktop, where the
   sidebar is always its own icon rail/panel; only meaningful once the drawer rules below kick in. */
#mobile-nav-toggle {
  display: none; flex: 0 0 auto; align-items: center; justify-content: center;
  width: 34px; height: 34px; margin-right: 6px; border: none; border-radius: 8px;
  background: transparent; color: var(--hd-blue, #123885); font-size: 20px; cursor: pointer;
}
#mobile-nav-toggle:hover { background: rgba(18,56,133,0.08); }
#app-sidebar-backdrop {
  display: none; position: fixed; inset: 0; top: var(--header-height); z-index: 590;
  background: rgba(15,23,42,0.45);
}
/* Per explicit request ("trình bày trên điện thoại thật gọn gàng và thuận tiện") - below 900px the
   sidebar used to render as a permanently-expanded full-width list (every section AND every child
   link visible at once) stacked above the page content, so reaching anything on a phone meant
   scrolling past the entire nav tree first. It's now a slide-in drawer instead: closed by default,
   opened via the hamburger button in the header, closes on backdrop tap or on picking any link. */
@media (max-width: 900px) {
  .app-shell { flex-direction: column; }
  #mobile-nav-toggle { display: inline-flex; }
  .app-sidebar, .app-sidebar.collapsed {
    position: fixed; left: 0; top: var(--header-height); z-index: 600;
    width: 88%; max-width: 310px; flex-basis: auto; height: calc(100vh - var(--header-height));
    transform: translateX(-100%); box-shadow: 10px 0 32px rgba(15,23,42,0.22);
    transition: transform 0.22s ease;
  }
  .app-sidebar.collapsed:hover { width: 88%; max-width: 310px; }
  .app-sidebar.mobile-open, .app-sidebar.collapsed.mobile-open { transform: translateX(0); }
  .app-sidebar.collapsed .sidebar-section-label, .app-sidebar.collapsed .sidebar-chevron, .app-sidebar.collapsed .sidebar-section-body { display: revert; }
  /* Same reasoning as the line above: a desktop icon-only collapse preference persists into
     localStorage and can carry over to a phone session, but the mobile drawer has no icon-only rail
     at all - so the compact/centered divider treatment above (for desktop's collapsed rail) must
     not apply here, or the Part 1/Part 2 divider would render cramped even though its label text is
     already forced back to full-width by the rule above. */
  .app-sidebar.collapsed .sidebar-divider { justify-content: flex-start; padding: 10px 7px 6px; }
  .sidebar-collapse-btn { display: none; }
  #app-sidebar-spacer { display: none; }
  #app-sidebar-backdrop.open { display: block; }
}

/* Workforce structure cards (js/workforce-overview.js output) - visual redesign (bar-chart units,
   company accent colors, status chips for resignations), shared by admin/personnel.html's Overview
   panel and admin/dashboard.html's Admin Dashboard Workforce snapshot. Hues are the three lowest-
   index slots of the validated 8-color categorical ramp (dataviz skill): blue, aqua, violet. */
.wf-company-card {
  background: var(--hd-card);
  border: 1px solid var(--hd-border);
  border-radius: 12px;
  padding: 13px 16px;
  margin-top: 10px;
}
.wf-company-card:first-child { margin-top: 0; }
.wf-company-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 11px; }
.wf-company-name { font-size: 14.5px; font-weight: 800; flex: 1; min-width: 160px; }
.wf-stat-pill {
  display: flex; align-items: baseline; gap: 4px;
  background: var(--hd-bg); border-radius: 999px; padding: 3px 9px 3px 11px;
  font-size: 10px; color: var(--hd-muted); white-space: nowrap;
}
.wf-stat-pill .n { font-size: 13px; font-weight: 800; color: var(--hd-text); }
.wf-stat-pill.active .n { color: var(--hd-blue); }
.wf-stat-pill.resigned .n { color: var(--hd-danger); }
.wf-stat-pill.resigned-year .n { color: var(--hd-danger); }
.wf-stat-pill.accounts .n { color: var(--hd-teal); }
.wf-blocks { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 900px) { .wf-blocks { grid-template-columns: 1fr; } }
.wf-block-title {
  display: flex; justify-content: space-between; font-size: 10px; font-weight: 700;
  color: var(--hd-muted); text-transform: uppercase; letter-spacing: 0.04em;
  margin-bottom: 6px; padding-bottom: 4px; border-bottom: 1px solid var(--hd-border);
}
/* Diverging bar per unit: active headcount grows right from a center line (accent-to-teal
   gradient), resigned-this-year grows left (red) - both share one scale so the two lengths
   are honestly comparable, and each carries its own number (inside the bar when there's room,
   just outside the tip when the value is too small to hold a label).
   Label column is max-content, sized to the longest label actually present in that block - short
   department names (e.g. "HR Dept") get a narrow column so the bar gets more room, a block with
   one long name (e.g. "Systems Control & Technology Development Dept") widens automatically for
   just that block. .wf-unit-row-div is display:contents so each row's label+track become direct
   items of this one shared grid (same column widths/center-line position on every row) rather than
   each row measuring its own column independently. */
.wf-unit-list { display: grid; grid-template-columns: max-content 1fr; align-items: center; column-gap: 8px; row-gap: 3px; }
.wf-unit-row-div { display: contents; }
.wf-unit-label {
  font-size: 10.5px; font-weight: 600; color: var(--hd-text); white-space: nowrap;
  max-width: 280px; overflow: hidden; text-overflow: ellipsis;
}
/* Head Office org-chart ordering (js/workforce-overview.js's computeOfficeHierarchyRows) - a unit
   that has its own sub-units reads bolder/darker (same weight the block already gives an active-
   headcount number), and the "└" tree-guide glyph before a child row's name reads as an
   indent/rank marker without needing SVG connector lines. */
.wf-unit-parent-label { font-weight: 800; }
.wf-unit-tree-guide { color: var(--hd-muted); font-weight: 400; }
.wf-div-track { display: flex; align-items: center; height: 15px; }
.wf-div-half { flex: 1; display: flex; align-items: stretch; height: 100%; min-width: 0; }
.wf-div-half.wf-div-left { justify-content: flex-end; }
.wf-div-half.wf-div-right { justify-content: flex-start; }
.wf-div-center { width: 2px; height: 100%; background: var(--hd-border); flex: 0 0 auto; }
.wf-div-fill { display: flex; align-items: center; justify-content: center; border-radius: 3px; min-width: 3px; }
.wf-div-fill.wf-div-fill-red { background: var(--hd-danger); }
.wf-div-num-in { font-size: 9px; font-weight: 800; color: #fff; padding: 0 5px; white-space: nowrap; }
.wf-div-num-out { font-size: 9px; font-weight: 800; padding: 0 4px; white-space: nowrap; }
.wf-legend { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; margin: 0 0 10px; padding: 6px 10px; background: #f8fafc; border: 1px solid var(--hd-border); border-radius: 8px; }
.wf-legend-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: var(--hd-text-muted, #555); }
.wf-legend-swatch { width: 12px; height: 12px; border-radius: 3px; flex: 0 0 auto; }

/* Admin Dashboard landing page (admin/dashboard.html) - exception-first cards per blueprint. */
.dash-kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 4px; }
.dash-stub-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.dash-stub-card {
  background: var(--hd-card); border: 1px solid var(--hd-border); border-radius: var(--hd-radius);
  padding: 16px 18px; text-align: center; color: var(--hd-muted);
}
.dash-stub-card .dash-stub-icon { font-size: 26px; margin-bottom: 8px; opacity: 0.6; }
.dash-stub-card .dash-stub-title { font-size: 13px; font-weight: 700; color: var(--hd-text); margin-bottom: 4px; }
.dash-stub-card .dash-stub-tag { display: inline-block; margin-top: 10px; padding: 3px 10px; border-radius: 999px; background: #fef3c7; color: #92400e; font-size: 10.5px; font-weight: 700; }

/* max-width:100% on every flex:1 pane below (.split-right here, .materials-main,
   .split-even > div) - the same fix as .app-main, for the same reason: found auditing mobile/
   landscape widths, a flex:1 + min-width:0 item still sizes itself off its CONTENT's preferred
   width (a wide table, an unwrappable row) rather than the space the flex layout actually gave
   it, once that content wants more than the item's share - min-width:0 alone doesn't stop it,
   only capping the item's own max-width does. Anywhere a "row that stacks into a column on
   mobile" is added later needs the same max-width:100% on its flexible child(ren). */
.split-layout { display: flex; gap: 16px; align-items: flex-start; }
.split-left { flex: 0 0 360px; }
.split-left .card { margin-bottom: 14px; }
.split-right {
  flex: 1;
  min-width: 0;
  max-width: 100%;
  max-height: calc(100vh - 180px);
  overflow-y: auto;
  padding-right: 6px;
}
.split-folder-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 14px;
  border-radius: 10px;
  cursor: pointer;
  margin-bottom: 4px;
  border: 1px solid transparent;
}
.split-folder-item:hover { background: #f4f6f9; }
.split-folder-item.active { background: #e3ecf6; border-color: var(--hd-blue); color: var(--hd-blue-dark); font-weight: 600; }
@media (max-width: 860px) {
  .split-layout { flex-direction: column; }
  .split-left { width: 100%; flex: none; }
  .split-right { max-height: none; overflow-y: visible; padding-right: 0; }
}

/* .materials-layout is a permanent two-column row: .materials-main (Library tree) flexes to fill
   the remaining width, .materials-sidebar (Add training material form) is a fixed-width column
   pinned to the right with position:sticky so it stays in view while the tree scrolls - always
   visible, no hover/click-to-reveal pill anymore. See materials.html for the markup/JS. */
.materials-layout { display: flex; align-items: flex-start; gap: 14px; }
.materials-main { flex: 1; min-width: 0; max-width: 100%; }
.materials-sidebar { flex: 0 0 300px; width: 300px; position: sticky; top: 12px; max-height: calc(100vh - 24px); overflow-y: auto; }
.materials-main .split-left { flex: 0 0 230px; }
.materials-main .split-right { flex: 1; }
.lib-sidebar-tab { display: none; }
.lib-sidebar-panel { display: block; position: static; width: 100%; max-height: none; overflow-y: visible; }
.lib-sidebar-panel .card.compact-form { box-shadow: 0 1px 4px rgba(0,0,0,0.08); }
@media (max-width: 860px) {
  /* No room for a fixed side column on narrow screens - stack instead. */
  .materials-layout { flex-direction: column; }
  .materials-sidebar { position: static; width: 100%; flex: none; max-height: none; }
}

.split-even { display: flex; gap: 16px; align-items: flex-start; }
.split-even > div { flex: 1; min-width: 0; max-width: 100%; }
.split-even .sticky-panel { position: sticky; top: 12px; max-height: calc(100vh - 24px); overflow-y: auto; }
@media (max-width: 960px) {
  .split-even { flex-direction: column; }
  .split-even .sticky-panel { position: static; max-height: none; }
}

.compact-form { max-width: 1000px; }
.compact-form label { margin: 8px 0 3px; font-size: 11.5px; }
.compact-form input[type="text"],
.compact-form select,
.compact-form textarea {
  padding: 7px 10px;
  font-size: 13px;
  border-radius: 8px;
  width: 100%;
  box-sizing: border-box;
}
.compact-form textarea { min-height: 32px; }
.compact-form input[type="file"] { max-width: 100%; }

.split-3col { display: flex; gap: 16px; align-items: flex-start; }
.split-3col > .split-col {
  flex: 1;
  min-width: 0;
  max-height: calc(100vh - 180px);
  overflow-y: auto;
  padding-right: 6px;
}
.split-3col > .split-col:first-child { flex: 0 0 320px; }
.split-3col.equal-3col > .split-col:first-child { flex: 1; }
.split-3col > .split-col > h4 { margin-top: 0; }
@media (max-width: 1100px) {
  .split-3col { flex-direction: column; }
  .split-3col > .split-col { width: 100%; flex: none; max-height: none; overflow-y: visible; padding-right: 0; }
}

.center-screen {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.card {
  background: var(--hd-card);
  border: 1px solid var(--hd-border);
  border-radius: var(--hd-radius);
  padding: 18px;
  margin-bottom: 14px;
  box-shadow: 0 1px 3px rgba(20,30,50,0.04);
}

.card h2, .card h3 { margin-top: 0; }

.stack { display: flex; flex-direction: column; gap: 10px; }

/* Read-only label/value display grid, e.g. an employee's own profile info. */
/* .app-main shrink-to-fits its content instead of filling the shell. On a desktop nobody sees it:
   .container's own max-width (1180px) is narrower than the space available, so the shrink lands on
   1180 and looks right. On a phone it lands on whatever the content happens to measure - and pages
   whose content is naturally narrow end up hugging the left edge with the rest of the screen empty.
   Measured at a 540px viewport: employee/birthdays.html got 323px and employee/welcome.html 407px,
   so the birthday hero and the unit cards covered barely half the screen, while employee/leave.html
   (whose form fields are intrinsically wide) filled all 525px and looked fine - which is why this
   only ever showed up on some pages.
   width:100% makes it fill on every page. It is a no-op wherever the layout was already correct:
   the container inside is still capped at its own max-width, so the desktop view does not move. */
.app-main { width: 100%; }

.info-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px 16px; }
.info-field { padding: 8px 10px; background: #f8fafc; border-radius: 8px; }
/* Opt-in for a single long-text field (e.g. an address) to span every column in its row, so it
   reads on one line instead of wrapping inside a narrow grid cell like every other field. */
.info-field-full { grid-column: 1 / -1; }
.info-field-full .info-value { white-space: nowrap; overflow-x: auto; }
.info-field .info-label { font-size: 10.5px; color: var(--hd-muted); text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 3px; }
.info-field .info-value { font-size: 13.5px; font-weight: 600; word-break: break-word; }
.info-section-title { font-size: 12px; font-weight: 700; color: var(--hd-muted); text-transform: uppercase; letter-spacing: 0.03em; margin: 16px 0 8px; }
.info-section-title:first-child { margin-top: 0; }

/* Card-per-section profile layout (employee/profile.html) - each section of the personnel record
   gets its own tinted card with a colored accent bar + icon badge, rather than one long flat list,
   so a long read-only record stays visually easy to scan and doesn't feel like a plain form dump.
   Accent color alternates between the two brand colors (--hd-accent set inline per section) for
   rhythm without introducing new colors that would clash with the rest of the app. */
.info-section {
  background: #fff;
  border: 1px solid var(--hd-border);
  border-left: 4px solid var(--hd-accent, var(--hd-blue));
  border-radius: 12px;
  padding: 16px 18px;
  margin-bottom: 14px;
  box-shadow: 0 2px 6px rgba(18,56,133,0.05);
}
.info-section-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.info-section-icon {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; background: color-mix(in srgb, var(--hd-accent, var(--hd-blue)) 14%, #fff);
}
.info-section-head .info-section-title { margin: 0; }

/* Polished per-request card - employee/leave.html and employee/resignation.html's own "My
   requests" history lists, per explicit request ("thiết kế trình bày thật chuyên nghiệp nhất - và
   đẹp nhất" for the two most-used employee forms). Unlike .info-section's fixed brand-color accent
   bar, --rc-accent is set inline per card from the request's own status level (see accentForLevel()
   in both pages) so the state reads at a glance - amber still open, red returned, teal/green done -
   without having to find and read the small badge text first. */
.request-card {
  background: #fff;
  border: 1px solid var(--hd-border);
  border-left: 4px solid var(--rc-accent, var(--hd-muted));
  border-radius: 12px;
  padding: 14px 16px;
  margin-bottom: 12px;
  box-shadow: 0 2px 8px rgba(18,56,133,0.05);
}
.request-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.request-card-code { font-weight: 700; font-size: 13.5px; color: var(--hd-text); }
.request-card-type { color: var(--hd-muted); font-weight: 500; }
.request-card-head .badge { margin-left: auto; }
.request-card-stat { display: flex; align-items: baseline; gap: 6px; margin: 8px 0 4px; }
.request-card-stat .n { font-size: 24px; font-weight: 800; color: var(--hd-blue); line-height: 1; }
.request-card-stat .u { font-size: 11.5px; color: var(--hd-muted); }
.request-card-range { font-size: 12.5px; color: var(--hd-text); margin: 2px 0; }
.request-card-meta { font-size: 11px; color: var(--hd-muted); margin: 6px 0 0; }
.request-card-tag { display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; font-weight: 700; padding: 2px 9px; border-radius: 999px; background: #fdecea; color: var(--hd-danger); margin: 6px 6px 0 0; }
.request-card-note { font-size: 11.5px; color: var(--hd-muted); margin: 6px 0 0; padding: 7px 9px; background: #f8fafc; border-radius: 8px; }
.request-card-note.warn { color: var(--hd-danger); background: #fdecea; }
.request-card-note strong { color: var(--hd-text); }
/* "Waiting on <name>" highlight - per explicit request ("phan Cho duyet hay cho biet Ten nguoi duyet
   tiep theo trong bang de nhan su viet") - a pending request's card names the exact person who needs
   to act next, not just a generic "Pending approval" status, so the employee knows whose court the
   ball is in without having to ask HR. */
.request-card-next { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; font-size: 12.5px; font-weight: 700; color: var(--hd-blue); background: #eef2fb; border-radius: 8px; padding: 7px 10px; margin: 8px 0 0; }
.request-card-next .lbl { font-weight: 500; color: var(--hd-muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; }
.request-card-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.request-card-actions .btn-sm, .request-card-actions summary.btn-sm { width: auto; }
.request-card details { margin-top: 8px; }
.request-card details summary { cursor: pointer; font-size: 11.5px; font-weight: 600; color: var(--hd-blue); list-style: none; }
.request-card details summary::-webkit-details-marker { display: none; }
.request-card details summary::before { content: "▸ "; }
.request-card details[open] summary::before { content: "▾ "; }

label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin: 12px 0 6px;
  color: var(--hd-muted);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
textarea,
select {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--hd-border);
  border-radius: 10px;
  font-size: 16px;
  background: #fff;
  color: var(--hd-text);
}

textarea { min-height: 80px; resize: vertical; }

/* The rule above lists input types one by one, and the list has holes: an <input> with NO type
   attribute (which is a text field) and input[type="date"] were never in it, so they never got
   width:100%, the 10px radius, the padding or the 16px font - they render at the browser's own
   default size. Measured on employee/leave.html at 502px wide: the grid cell is 433px and the
   name / staff code / unit fields sit at 202px inside it, the two date pickers at 136px. On a
   desktop the cell is only ~210px so nobody noticed; on a phone the cell is the full screen and
   half-width boxes look unfinished. Their default ~13px font also makes iOS zoom the page on focus,
   the same problem the .emp-picker-input rule below deals with.
   Fixed at phone width only: the desktop layout of every admin table and filter row is built around
   the current widths, and this is a presentation fix for phones, not a reason to move those. */
@media (max-width: 760px) {
  input:not([type]),
  input[type="date"], input[type="time"], input[type="datetime-local"],
  input[type="month"], input[type="week"],
  input[type="tel"], input[type="search"], input[type="url"] {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 14px;
    border: 1px solid var(--hd-border);
    border-radius: 10px;
    font-size: 16px;
    background: #fff;
    color: var(--hd-text);
  }
}

button, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: 12px;
  padding: 13px 18px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  background: var(--hd-blue);
  color: #fff;
  width: 100%;
}
button:active { background: var(--hd-blue-dark); }
button:disabled { opacity: 0.55; cursor: not-allowed; }

.btn-secondary { background: #e9eef5; color: var(--hd-blue); }
.btn-danger { background: var(--hd-danger); }
.btn-outline { background: transparent; color: var(--hd-blue); border: 1px solid var(--hd-blue); }
.btn-sm { padding: 6px 12px; font-size: 12.5px; width: auto; }
/* Header role-switch link ("Admin Panel" / "My employee view" / "My work") - plain light-gray text,
   no border/box, per explicit request. Scoped to this one link only (not a global .btn-outline
   change, which is reused across hundreds of unrelated buttons app-wide). */
#role-switch-link.btn-outline { color: var(--hd-muted); border: none; background: none; }
/* Small action buttons (Start/Review/Retake/etc.) read the EN/vi pair as one line, same trick as
   .badge below - the default stacked bi-en/bi-vi layout was making these pills nearly twice as
   tall as they need to be in dense list rows. */
.btn-sm .bi-en { display: inline; }
.btn-sm .bi-vi { display: inline; font-size: 0.85em; }
.btn-block-group { display: flex; flex-wrap: wrap; gap: 10px; }
.btn-block-group > * { min-width: 0; }

.muted { color: var(--hd-muted); font-size: 13px; }
.error-text { color: var(--hd-danger); font-size: 13px; margin-top: 8px; }
.success-text { color: var(--hd-success); font-size: 13px; margin-top: 8px; }

.badge {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  background: #e3ecf6;
  color: var(--hd-blue);
  white-space: nowrap;
}
/* Bilingual text inside a badge always reads as one line (EN / vi), never stacked - badges are too
   narrow for the default stacked bi-en/bi-vi layout, which was wrapping into 3+ broken lines. */
.badge .bi-en { display: inline; }
.badge .bi-vi { display: inline; font-size: 0.85em; }
.badge.level-1 { background: #fdecea; color: #c0392b; }
.badge.level-2 { background: #fdf3e3; color: #b9770e; }
.badge.level-3 { background: #eef7e6; color: #4c8a2c; }
.badge.level-4 { background: #e3f2ee; color: #12897d; }
.badge.level-5 { background: #e9e3f7; color: #5b3fa6; }

.list-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 0;
  border-bottom: 1px solid var(--hd-border);
  gap: 10px;
}
.list-item:last-child { border-bottom: none; }

.materials-block { margin: 2px 0 6px 20px; padding-left: 10px; border-left: 2px solid var(--hd-border); }
/* Scoped to the Materials page's merged folder tree only - keeps rows compact without affecting
   the shared .split-folder-item/.org-row/.test-level-item classes used on other pages. */
#folder-list .split-folder-item { padding: 6px 10px; margin-bottom: 2px; }
#folder-list .org-row { padding: 5px 10px; margin-bottom: 3px; font-size: 12.5px; }
#folder-list .test-level-item { padding: 3px 8px; }
#folder-list .material-row-main { padding: 4px 0; }
.material-row { border-bottom: 1px solid var(--hd-border); }
.material-row:last-child { border-bottom: none; }
.material-row-main {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
  flex-wrap: nowrap;
}
.material-row-title {
  flex: 1 1 auto;
  min-width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}
.material-row-badge { flex: 0 0 auto; padding: 2px 8px; font-size: 11px; }
.material-row-actions { flex: 0 0 auto; display: flex; gap: 4px; margin-left: auto; }
.attach-detail {
  padding: 2px 0 10px 16px;
  margin: 0 0 6px 2px;
  border-left: 2px solid var(--hd-border);
}
@media (max-width: 860px) {
  .material-row-main { flex-wrap: wrap; }
  .material-row-title { white-space: normal; min-width: 100%; }
  .material-row-actions { margin-left: 0; }
}

/* Employee header nav: pills inline in the header bar next to Log out, mirrors .admin-header/.admin-nav. */
.app-header.employee-header { justify-content: flex-start; gap: 16px; padding: 6px 16px; min-height: 0; }
.employee-header .logo-badge { height: 32px; width: auto; border-radius: 0; }
.employee-nav { display: flex; gap: 6px; overflow-x: auto; flex: 1 1 0%; min-width: 0; }
.employee-nav a {
  padding: 7px 18px; border-radius: 999px; white-space: nowrap; flex: 0 0 auto;
  background: rgba(0,0,0,0.045); color: var(--hd-text); font-size: 12.5px; font-weight: 600;
}
.employee-nav a.active { background: var(--hd-blue); color: #fff; }
.employee-header .link-btn { flex: 0 0 auto; width: auto; }

.progress-bar {
  height: 8px;
  background: var(--hd-border);
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: 18px;
}
.progress-bar > div {
  height: 100%;
  background: var(--hd-teal);
  transition: width 0.25s ease;
}

.option-btn {
  display: block;
  width: 100%;
  text-align: left;
  padding: 14px 16px;
  border-radius: 12px;
  border: 2px solid var(--hd-border);
  background: #fff;
  color: var(--hd-text);
  font-size: 15px;
  margin-bottom: 10px;
  font-weight: 500;
}
.option-btn.selected {
  border-color: var(--hd-blue);
  background: #eaf1fa;
  color: var(--hd-blue-dark);
}
.option-btn.correct { border-color: var(--hd-success); background: #eaf7f0; }
.option-btn.incorrect { border-color: var(--hd-danger); background: #fbeceb; }

.top-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  overflow-x: auto;
  position: sticky;
  top: var(--header-height);
  z-index: 8;
  background: var(--hd-bg);
  padding: 10px 0;
}
.top-tabs a {
  padding: 8px 14px;
  border-radius: 999px;
  background: #e9eef5;
  color: var(--hd-blue);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.top-tabs a.active { background: var(--hd-blue); color: #fff; }

.sub-tabs { display: flex; gap: 8px; margin-bottom: 16px; overflow-x: auto; }
.sub-tabs a {
  padding: 8px 14px;
  border-radius: 999px;
  background: #e9eef5;
  color: var(--hd-blue);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.sub-tabs a.active { background: var(--hd-blue); color: #fff; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
/* Denser row height for tables that don't need the default 8px vertical padding (e.g. admin/leave.html's
   routing-rule/unit-manager/request-list tables) - narrows just the vertical padding, keeps horizontal. */
.table-compact th, .table-compact td { padding-top: 3px; padding-bottom: 3px; }

/* Searchable "name (staff code)" employee picker (admin/leave.html's Managers by unit/project table) -
   a text input plus an absolutely-positioned filtered-results dropdown, so admin can type instead of
   scrolling a several-hundred-row <select>. */
.emp-picker { position: relative; min-width: 160px; }
.emp-picker-input { width: 100%; font-size: 12px; }

/* iOS Safari zooms the whole page in whenever a form control smaller than 16px takes focus, and it
   does not zoom back out - the person is left pinching the layout back to size after every tap.
   Every control in this app is 16px by default (see the `textarea, select` rule above); a handful
   of pages then shrink specific ones for density, which is fine on a mouse and costly on a phone.
   Those are restored to 16px at phone width only, so nothing about the desktop layout moves.
   44px is the usual minimum comfortable touch target.
   Deliberately NOT applied to the in-grid inputs on employee/wea-bonus.html (.wea-score-input is
   52px wide, .wea-notes-input 120px): those live inside a horizontally-scrolling score table where
   16px text would break the grid apart, and a zoom on an already-scrolling table costs less than a
   broken one. */
@media (max-width: 760px) {
  .emp-picker-input { font-size: 16px; min-height: 44px; }
}
.emp-picker-results {
  display: none; position: absolute; z-index: 20; top: 100%; left: 0; margin-top: 2px;
  width: 220px; max-height: 200px; overflow-y: auto; background: #fff;
  border: 1px solid var(--hd-border); border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.12);
}
.emp-picker-opt { padding: 6px 10px; font-size: 12px; cursor: pointer; border-bottom: 1px solid var(--hd-border); }
.emp-picker-opt:last-child { border-bottom: none; }
.emp-picker-opt:hover { background: #eef1f6; }
.emp-picker-empty { padding: 8px 10px; font-size: 12px; color: var(--hd-muted); }
tr.f-summary-row:hover { background: #eef1f6; }
tr.f-detail-row td { padding: 14px 12px; }
th, td { text-align: left; padding: 8px 6px; border-bottom: 1px solid var(--hd-border); }
th { color: var(--hd-muted); font-size: 12px; text-transform: uppercase; }

/* A synced proxy scrollbar pinned to the bottom of the viewport, so the wide roster table's
   horizontal scroll is always reachable without first scrolling down past every row. */
.sticky-hscroll { position: fixed; bottom: 0; height: 14px; overflow-x: auto; overflow-y: hidden; z-index: 500; display: none; }
.sticky-hscroll > div { height: 1px; }

/* The base `table { width: 100% }` rule stretches this table to fill #roster-scroll-wrap's full
   width, which - since most columns only carry a min-width, not a fixed width - hands the leftover
   space to the browser to distribute as extra gaps between columns instead of keeping them snug.
   width:auto lets the table size itself to its actual column widths; any leftover space collects
   after the last column instead of being spread out between every one. */
#roster-table { width: auto; }
/* border-collapse:collapse (the base `table` rule) shares each border between adjacent cells,
   which - combined with position:sticky on the header cells - lets a sliver of the row scrolling
   underneath visibly peek through right above the sticky header during scroll, in some browsers.
   border-collapse:separate gives every cell its own border, closing that gap. */
#roster-table { border-collapse: separate; border-spacing: 0; }
/* table-layout:fixed makes each column obey its <colgroup> <col> width exactly (auto layout would
   otherwise widen a column to fit its widest cell's content, ignoring the col width) - required for
   user-driven column resizing (the .f-col-resize drag handles below) to actually take effect.
   Content that no longer fits a narrowed column is clipped with an ellipsis instead of overflowing
   into the next cell. */
#roster-table { table-layout: fixed; }
/* Padding/overflow/ellipsis now come from the generic .f-resizable-table rule below (js/resizable-table.js
   adds that class to every table it wires up, including this one) so the shared row-height handle's
   --f-row-pad-y variable can control this table's row height too, instead of being locked to a fixed value. */
#roster-table th, #roster-table td { font-size: 12px; }
#roster-table th { position: relative; }
/* Drag handle on the right edge of each resizable header cell. Widened past the cell's own border
   (rather than sized to it) so it's easy to grab without needing pixel-perfect aim. */
.f-col-resize { position: absolute; right: -4px; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 2; user-select: none; }
.f-col-resize:hover, .f-col-resize.resizing { background: var(--hd-blue); opacity: 0.35; }

/* Generic resizable-table treatment (js/resizable-table.js) - applied via JS (classList.add) to
   every wide admin table (Employees roster, Results, Framework matrix, Tests question tables,
   Account admin list) so column-resize and row-height behave identically everywhere instead of
   being reimplemented per page. #roster-table's own rules above stay in place for the extra
   sticky-header/scroll-wrap treatment specific to that page. */
.f-resizable-table { width: auto; border-collapse: separate; border-spacing: 0; table-layout: fixed; }
.f-resizable-table th, .f-resizable-table td {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding-top: var(--f-row-pad-y, 4px); padding-bottom: var(--f-row-pad-y, 4px);
}
.f-resizable-table th { position: relative; }
/* Shared row-height/density drag handle (js/resizable-table.js setupRowHeightResize) - one per
   table, adjusts every row's padding at once via the --f-row-pad-y custom property rather than
   resizing a single row, and is pinned to the top-right corner of its wrapper card. */
.f-row-height-handle {
  position: absolute; top: 6px; right: 8px; width: 26px; height: 18px; cursor: row-resize;
  border-radius: 4px; background: var(--hd-border); display: flex; align-items: center;
  justify-content: center; font-size: 11px; color: var(--hd-muted); user-select: none; z-index: 5;
}
.f-row-height-handle:hover, .f-row-height-handle.resizing { background: var(--hd-blue); color: #fff; }
/* #roster-scroll-wrap already has overflow-x:auto for the horizontal-scroll feature - per the CSS
   overflow spec, setting only one axis to non-visible forces the other to compute as "auto" too,
   turning this into its own scroll container. A sticky thead's containing block is the nearest
   such scroll container, and since this one has no bounded height it never actually scrolls
   vertically on its own (the page scrolls it instead), so top:0 alone would never "stick" - it
   needs a real internal vertical scroll to stick relative to. --roster-wrap-max-height is set from
   JS to the remaining viewport height below the frozen controls area (whose own height changes as
   panels toggle open/closed), turning this into a bounded, independently-scrolling list. */
/* #roster-scroll-wrap inherits .card's padding:18px, but as the sticky thead's scrolling ancestor,
   that top padding becomes a permanent ~19px gap between the box's visible top edge and where
   top:0 actually sticks (sticky offsets are relative to the padding edge, not the border edge) -
   scrolled rows pass through that gap and appear to bleed in above the "frozen" header. Zeroing
   the top padding (keeping the sides/bottom for visual breathing room) removes the gap entirely. */
#roster-scroll-wrap { padding-top: 0; max-height: var(--roster-wrap-max-height, 60vh); overflow-y: auto; }
#roster-table thead th { position: sticky; top: 0; z-index: 4; background: #fff; text-align: center; }

/* Employees page top controls (title/buttons/summary/search-filter/HR action list) compacted -
   language (English/Vietnamese/Korean) is now controlled globally by the [data-lang] rules below,
   not locked here. */
#employees-quick-controls p.muted br { display: none; }
#employees-quick-controls label { margin: 6px 0 3px; font-size: 12px; }
#employees-quick-controls p.muted { margin: 2px 0 6px; }
#employees-quick-controls input[type="text"],
#employees-quick-controls select {
  padding: 7px 10px;
  font-size: 13px;
  border-radius: 8px;
}

tr.group-row td { font-size: 12px; padding: 10px 6px 6px; border-bottom: 2px solid var(--hd-text); }
tr.f-competency-row:hover td { border-bottom-color: var(--hd-text); }
tr.f-competency-row.active td { border-bottom: 2px solid var(--hd-text); font-weight: 600; }
#matrix-table { white-space: nowrap; }
#matrix-table td:nth-child(2), #matrix-table th:nth-child(2) { white-space: normal; min-width: 220px; }

.tests-3col > .split-col { flex: 1; min-width: 0; }

/* Stretch all 3 columns to equal height so their cards extend down together instead of stopping short. */
.split-3col.tests-3col { align-items: stretch; }
.tests-3col > .split-col { display: flex; flex-direction: column; }
.tests-3col > .split-col > .card:last-child { flex: 1; }
@media (max-width: 1100px) {
  .split-3col.tests-3col { align-items: flex-start; }
  .tests-3col > .split-col > .card:last-child { flex: none; }
}

.test-list-item { padding: 7px 8px; margin-bottom: 1px; gap: 8px; }
.test-list-item .test-item-info { min-width: 0; }
.test-list-item .test-item-code { font-size: 10.5px; font-weight: 700; color: var(--hd-muted); letter-spacing: 0.3px; }
.test-list-item.active .test-item-code { color: var(--hd-blue); }
.test-list-item .test-item-name { font-size: 12.5px; }
.test-list-item .test-item-name .bi-en,
.test-list-item .test-item-name .bi-vi { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.test-list-item .test-item-name .bi-vi { font-size: 0.85em; }
.test-list-item .test-item-btn { padding: 4px 8px; font-size: 11px; flex: 0 0 auto; }

.test-level-sublist { margin: 0 0 4px 12px; padding-left: 8px; border-left: 2px solid var(--hd-border); }
.test-level-item { cursor: pointer; padding: 5px 8px; font-size: 11.5px; border-left: 2px solid transparent; color: var(--hd-muted); }
.test-level-item:hover { border-left-color: var(--hd-border); }
.test-level-item.active { border-left-color: var(--hd-blue); color: var(--hd-blue-dark); font-weight: 700; }

.org-row {
  padding: 9px 10px; font-size: 13.5px; font-weight: 700; cursor: pointer;
  border-left: 3px solid transparent; border-radius: 8px; margin-bottom: 5px;
  background: #e9eef8; color: var(--hd-blue-dark);
}
.org-row .muted { font-weight: 400; }
.org-row:hover { border-left-color: var(--hd-blue); }
.org-row.active { border-left-color: var(--hd-blue); background: #dbe6f7; }
/* Minimal variant for informational, non-selectable rows (org-unit tree, project list) - just a
   name + a light detail, no pill background, no bold, no click-target highlight, since there is
   no "selected" state to indicate here (Edit is a separate explicit button, not row-click). */
.org-row-plain {
  background: none; font-weight: 400; border-radius: 0;
  border-left: none; border-bottom: 1px solid var(--hd-border);
  padding: 8px 4px; margin-bottom: 0;
}
.org-row-plain:hover { border-left-color: transparent; background: none; }
.org-row-plain strong { font-weight: 600; }
tr.jt-row.active td { border-bottom: 2px solid var(--hd-text); font-weight: 600; }

.level-question-group { margin-bottom: 6px; }
.level-group-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 4px 6px;
  border-bottom: 2px solid var(--hd-text);
  font-weight: 700;
  font-size: 13px;
  margin-top: 14px;
}
.level-question-group:first-child .level-group-header { margin-top: 0; }

#level-tree details { margin-bottom: 2px; }
#level-tree summary { cursor: pointer; padding: 6px 2px; font-size: 12px; font-weight: 700; list-style-position: outside; }
#level-tree .tree-track > summary { color: var(--hd-blue-dark); }
#level-tree details details summary { font-weight: 600; font-size: 12px; padding-left: 4px; }
#level-tree ul { list-style: none; margin: 0; padding-left: 16px; }
#level-tree .tree-leaf { cursor: pointer; padding: 5px 4px; font-size: 12.5px; border-left: 2px solid transparent; }
#level-tree .tree-leaf:hover { border-left-color: var(--hd-border); }
#level-tree .tree-leaf.active { border-left-color: var(--hd-blue); font-weight: 700; color: var(--hd-blue-dark); }
#level-tree .tree-onboarding { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--hd-border); }

.empty-state { text-align: center; padding: 40px 16px; color: var(--hd-muted); }
.empty-state .icon { font-size: 40px; margin-bottom: 8px; }

.spinner {
  width: 22px; height: 22px;
  border: 3px solid rgba(255,255,255,0.4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

.bi-en {
  display: block;
  font-weight: inherit;
}
.bi-vi {
  display: block;
  font-size: 0.8em;
  font-weight: 400;
  color: var(--hd-muted);
  line-height: 1.3;
}
button .bi-vi, .btn .bi-vi { color: rgba(255,255,255,0.75); }
button.btn-secondary .bi-vi, button.btn-outline .bi-vi { color: var(--hd-muted); }
.badge .bi-vi { color: inherit; opacity: 0.75; }
.bi-inline { display: inline; }
.bi-inline .bi-en { display: inline; }
.bi-inline .bi-vi { display: inline; font-size: 0.85em; color: var(--hd-muted); }

/* Language switching (js/i18n.js sets data-lang on <html> from the user's saved choice via the
   flag switcher). Exactly one of bi-en/bi-vi is shown at a time - a real single-active-language
   switch, not the old "always show both" bilingual display, so this overrides every context-
   specific display rule above (badge/btn-sm/bi-inline/nav/etc.) with !important rather than trying
   to keep each of them independently in sync. Defaults to English when no language has been chosen yet. */
html:not([data-lang]) .bi-vi,
html[data-lang="en"] .bi-vi { display: none !important; }
html[data-lang="vi"] .bi-en { display: none !important; }
/* Per explicit request ("khi toi chuyen sang co Viet Nam thi chu khong hien ro") - every .bi-vi
   color/font-size/weight rule above (the base .bi-vi rule, button/.btn-secondary/.btn-outline/.badge/
   .bi-inline variants) was written for its role as the SECONDARY annotation in the default bilingual
   view: small, muted, stacked under the primary .bi-en text. Once data-lang="vi" hides .bi-en above
   and makes .bi-vi the ONLY visible text, it needs to read as PRIMARY text instead - full size, full
   color, inherited weight - not the dimmed secondary treatment, which is what made Vietnamese text
   hard to read app-wide (headers, buttons, badges, sidebar, everywhere .bi-en/.bi-vi is used). One
   !important reset here covers every context at once, same reasoning as the two rules just above. */
html[data-lang="vi"] .bi-vi {
  font-size: 1em !important;
  font-weight: inherit !important;
  color: inherit !important;
  opacity: 1 !important;
}

/* Flag-icon language switcher, placed next to Log out in the header. */
.lang-switcher { display: flex; gap: 4px; align-items: center; margin-right: 8px; flex: 0 0 auto; }
.lang-switcher button {
  width: auto; padding: 0; display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 0; box-shadow: none;
  cursor: pointer; opacity: 0.55; filter: grayscale(40%);
}
.lang-switcher button svg { display: block; border-radius: 0; }
.lang-switcher button:hover { opacity: 0.85; }
.lang-switcher button.active { opacity: 1; filter: none; background: none; border: 0; box-shadow: none; }
.lang-switcher button:focus-visible { outline: 2px solid var(--hd-blue); outline-offset: 3px; }

.no-copy { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.no-copy iframe { print-color-adjust: exact; }
@media print {
  .no-copy { display: none !important; }
}

.watermark-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  display: flex;
  flex-wrap: wrap;
  align-content: space-around;
  justify-content: space-around;
  opacity: 0.09;
  transform: rotate(-25deg) scale(1.3);
  z-index: 5;
}
.watermark-overlay span {
  font-size: 14px;
  font-weight: 500;
  color: #000;
  text-align: center;
  white-space: nowrap;
  line-height: 1.3;
}

/* Per explicit request ("Logo phai hinh Vuong... thiet ke that chuyen nghiep nhat") - the brand mark
   on the auth screens (login/register/index splash) is a crisp square, not the rounded/squircle
   crop the old 18px radius (28% of the 64px box) produced - a corporate logo lockup reads as
   deliberately square, softened just enough (10% radius) to not look harsh, with a subtle shadow
   for depth against the plain background. Renamed from .logo-circle since that name no longer
   matched the shape. */
/* Auth screens: the margin-free original icon (icons/handong-logo-icon.png), sat close above the
   HANDONG E&C name (user request 2026-10-16). Unaltered - sized by height only. */
.logo-mark {
  height: 64px; width: auto; max-width: 100%;
  display: block;
  margin: 0 auto 10px;
  object-fit: contain;
}

/* Personnel content panels (personnel.html) - one visible at a time, switched by the app sidebar's
   #panel-* hash links now (the page used to have its own internal nav column here; removed since
   HR Operations already serves that purpose). */
.hr-content { min-width: 0; }
.hr-panel { display: none; }
.hr-panel.active { display: block; }
.hr-kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.hr-kpi-tile { background: var(--hd-card); border: 1px solid var(--hd-border); border-radius: var(--hd-radius); padding: 14px 16px; }
.hr-kpi-tile .hr-kpi-value { font-size: 26px; font-weight: 800; color: var(--hd-blue); line-height: 1.2; }
.hr-kpi-tile .hr-kpi-label { font-size: 12px; color: var(--hd-muted); margin-top: 4px; }
.hr-bar-row { display: flex; align-items: center; gap: 10px; font-size: 12px; margin-bottom: 8px; }
.hr-bar-row .hr-bar-label { flex: 0 0 140px; color: var(--hd-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hr-bar-row .hr-bar-track { flex: 1; height: 10px; background: var(--hd-bg); border-radius: 999px; overflow: hidden; }
.hr-bar-row .hr-bar-fill { height: 100%; background: var(--hd-teal); border-radius: 999px; }
.hr-bar-row .hr-bar-count { flex: 0 0 28px; text-align: right; font-weight: 700; }
.hr-stub { text-align: center; padding: 56px 20px; color: var(--hd-muted); }
.hr-stub .hr-stub-icon { font-size: 40px; margin-bottom: 12px; opacity: 0.6; }
.hr-stub .hr-stub-title { font-size: 16px; font-weight: 700; color: var(--hd-text); margin-bottom: 6px; }
.hr-stub .hr-stub-desc { font-size: 13px; max-width: 480px; margin: 0 auto; line-height: 1.5; }
.hr-stub .hr-stub-tag { display: inline-block; margin-top: 14px; padding: 4px 12px; border-radius: 999px; background: #fef3c7; color: #92400e; font-size: 11px; font-weight: 700; }

/* Shared document-template layout: compact form above, full-width A4 preview below. */
.document-template-workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  width: 100%;
}
.document-template-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  width: 100%;
  min-width: 0;
}
.document-template-section {
  min-width: 0;
  border: 1px solid var(--hd-border);
  border-radius: var(--hd-radius);
  background: var(--hd-card);
}
.document-template-preview {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--hd-border);
  border-radius: var(--hd-radius);
  background: var(--hd-card);
  padding: 12px;
}
.document-template-preview > h3 {
  margin: 0 0 10px;
  color: var(--hd-text);
  font-size: 17px;
}
.document-template-preview-shell {
  width: 100%;
  min-width: 0;
  overflow-x: auto;
  overflow-y: visible;
  display: block;
  padding: 18px 10px;
  background: #dbe0e6;
  border-radius: calc(var(--hd-radius) - 3px);
}
@media (max-width: 900px) {
  .document-template-preview { padding: 8px; }
}

/* New-hire welcome-card TA confirmation chip (offer list, migration_v183) - the checkmark and its
   exact timestamp are always visible, never only on hover, matching this app's other approval
   chips. */
.nhw-confirmed-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}
.nhw-posted-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

/* Phones and tablets: iOS Safari gives date/time inputs an intrinsic minimum width wider than a
   half-width grid cell, which pushed fields off the screen on the leave and resignation forms
   (explicit request 2026-09-30: check every form). Strip the native sizing app-wide so each
   date/time box follows its own container. */
@media (max-width: 780px) {
  input[type="date"], input[type="datetime-local"], input[type="time"], input[type="month"] {
    -webkit-appearance: none; appearance: none; min-width: 0; max-width: 100%; box-sizing: border-box; text-align: left;
  }
  input[type="date"]::-webkit-date-and-time-value, input[type="datetime-local"]::-webkit-date-and-time-value,
  input[type="time"]::-webkit-date-and-time-value, input[type="month"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
}
/* Shared My Requests navigation; original forms retain their layout and access checks. */
.my-request-tabs { display:flex; align-items:center; flex-wrap:wrap; gap:12px 20px; margin:0 0 18px; }
.my-request-tabs h2 { margin:0; font-size:22px; line-height:1.3; color:#30218c; }
.my-request-tabs nav { display:flex; flex-wrap:wrap; gap:8px; }
.my-request-tab { display:inline-flex; align-items:center; padding:9px 15px; border:1px solid #c5c7ef; border-radius:999px; color:#30218c; background:#fff; font-size:13px; line-height:1.25; text-decoration:none; }
.my-request-tab:hover { background:#f0effc; }
.my-request-tab.active { background:#352093; border-color:#352093; color:#fff; font-weight:600; }
.my-request-tab:focus-visible { outline:2px solid #168b99; outline-offset:3px; }
.my-request-tab[hidden] { display:none !important; }
.workspace-tabs-shell { padding-bottom:0; }
@media print { .my-request-tabs { display:none; } }

/* Phone layout for every tab bar in the app, User and Admin: an even grid of icon tiles, like an
   app home screen (explicit request 2026-10-05: "trình bày đều đẹp gọn - giống các Icon trên app
   điện thoại... Tôi không thích roll sang ngang. Mục nào có thông báo sẽ tự động hiển thị"). Every
   option is visible at once - no sideways scrolling. js/mobile-tabs.js adds the icon to each tile
   and picks the column count (2-4) so rows come out even; a tile with something waiting carries a
   red count badge. Measured at 390px before the first redesign: My Approvals wrapped to 3 rows of
   pills (121px), Attendance 3 rows (124px), Contract center a 2x2 grid of text (95px).
   Desktop keeps its own tab styles. The id-weighted :is() list outranks each page's own <style>
   rules; display is never forced with !important, so a tab hidden by its page (permissions,
   [hidden], inline display:none) stays hidden. */
.hd-tab-ico { display: none; pointer-events: none; }
@media (max-width: 768px) {
  body :is(#appr-tabs, #ladder-tabs, #track-tabs, #chart-scope-tabs, #line-mode-tabs, #view-tabs,
    .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs, .ov-tabs, .lp-tabs,
    .cp-tabs, .contract-center-tabs):not(.no-tiles):not([hidden]) {
    display: grid;
    grid-template-columns: repeat(var(--hd-tab-cols, 4), minmax(0, 1fr)) !important;
    gap: 8px !important;
    width: auto !important;
    max-width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    padding: 2px 0 !important;
    overflow: visible !important;
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
  }
  body :is(#appr-tabs, #ladder-tabs, #track-tabs, #chart-scope-tabs, #line-mode-tabs, #view-tabs,
    .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs, .ov-tabs, .lp-tabs,
    .cp-tabs, .contract-center-tabs):not(.no-tiles) > :is(a, button):not([hidden]) {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    width: auto !important;
    min-width: 0 !important;
    height: auto !important;
    min-height: 86px !important;
    margin: 0 !important;
    padding: 10px 4px 9px !important;
    white-space: normal !important;
    overflow-wrap: anywhere;
    font-size: 11px !important;
    font-weight: 600 !important;
    line-height: 1.25 !important;
    letter-spacing: 0 !important;
    text-align: center !important;
    text-decoration: none !important;
    border-radius: 16px !important;
    transition: background-color .15s ease, color .15s ease, border-color .15s ease, transform .1s ease;
    -webkit-tap-highlight-color: transparent;
  }
  body :is(#appr-tabs, #ladder-tabs, #track-tabs, #chart-scope-tabs, #line-mode-tabs, #view-tabs,
    .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs, .ov-tabs, .lp-tabs,
    .cp-tabs, .contract-center-tabs):not(.no-tiles) > :is(a, button):not([hidden]):active { transform: scale(.97); }
  body :is(#appr-tabs, #ladder-tabs, #track-tabs, #chart-scope-tabs, #line-mode-tabs, #view-tabs,
    .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs, .ov-tabs, .lp-tabs,
    .cp-tabs, .contract-center-tabs):not(.no-tiles) > :is(a, button):not(.active):not(.is-active):not([aria-current="page"]) {
    background: #fff !important;
    color: #262b45 !important;
    border: 1px solid #e3e5f2 !important;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .05) !important;
  }
  body :is(#appr-tabs, #ladder-tabs, #track-tabs, #chart-scope-tabs, #line-mode-tabs, #view-tabs,
    .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs, .ov-tabs, .lp-tabs,
    .cp-tabs, .contract-center-tabs):not(.no-tiles) > :is(a, button):is(.active, .is-active, [aria-current="page"]) {
    background: #352093 !important;
    color: #fff !important;
    border: 1px solid #352093 !important;
    box-shadow: 0 6px 14px rgba(53, 32, 147, .25) !important;
  }

  /* The icon: a soft rounded square, white-on-tint when the tile is selected. */
  .hd-tab-ico {
    display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
    width: 40px; height: 40px; border-radius: 12px; background: #f0effc; color: #352093;
  }
  .hd-tab-ico svg { width: 21px; height: 21px; }
  :is(.active, .is-active, [aria-current="page"]) > .hd-tab-ico { background: rgba(255, 255, 255, .18); color: #fff; }

  /* Something waiting: red count badge (sidebar's unread-notification badge on page tabs, the
     pending-approval count on My Approvals) pinned to the tile's corner; a plain dot when the
     queue only knows "has items". */
  body :is(#appr-tabs, .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs,
    .ov-tabs, .lp-tabs, .cp-tabs, .contract-center-tabs):not(.no-tiles) > :is(a, button) :is(.sidebar-badge, .hd-tab-badge) {
    position: absolute !important; top: 5px !important; right: 6px !important; margin: 0 !important;
    min-width: 19px; height: 19px; padding: 0 5px; border-radius: 10px;
    display: inline-flex; align-items: center; justify-content: center;
    background: #e5484d !important; color: #fff !important; font-size: 10.5px; font-weight: 700; line-height: 1;
    box-shadow: 0 0 0 2px #fff;
  }
  body :is(#appr-tabs, .appr-tabs) .appr-tab-dot {
    position: absolute; top: 8px; right: 9px; width: 9px !important; height: 9px !important; margin: 0 !important;
    background: #e5484d !important; box-shadow: 0 0 0 2px #fff;
  }
  body :is(#appr-tabs, .appr-tabs) .hd-tab-badge ~ .appr-tab-dot,
  body :is(#appr-tabs, .appr-tabs) .appr-tab-dot:has(~ .hd-tab-badge) { display: none; }

  /* Recruitment Center keeps its tabs beside the heading with display:flex !important; on a phone
     they drop under the heading as the same tile grid. */
  body .recruit-top-row { flex-wrap: wrap !important; }
  body .recruit-top-row .recruit-tabs:not([hidden]) { display: grid !important; flex: 1 1 100% !important; width: 100% !important; }

  /* Group title + its tiles: title on its own line, tiles full width right under it. */
  .my-request-tabs { flex-direction: column; align-items: stretch; gap: 10px; margin: 0 0 14px; }
  .my-request-tabs h2 { font-size: 17px; }
}

/* Phone forms and tables (explicit request 2026-10-05: "rà tiếp bảng và form trên điện thoại - đẹp,
   hiện đại, chuyên nghiệp nhất hiện nay"). Audit at 390px of 50 User + Admin pages: no page wider
   than the screen except Materials, but many Admin form controls below 16px (iOS zooms the page on
   focus) and under 38px tall (Recruitment 78, Personnel 15, Work reports 13...), nearly every small
   button under 34px, and list tables only reachable by sideways scrolling.
   - form controls outside tables: 14.5px text, 40px tall, soft focus ring (in-table grid inputs keep
     their compact size - a 16px font breaks score / timesheet grids apart);
   - field rows: js/mobile-tables.js re-flows rows of cramped fields into an even 2-up / 1-up grid;
   - small buttons: 36px touch height;
   - tables: list tables become cards, the rest scroll inside a rounded frame (js/mobile-tables.js).
   A4 document previews are never touched. Desktop unchanged. */
@media (max-width: 768px) {
  body :is(input:not([type]), input[type="text"], input[type="email"], input[type="password"], input[type="number"],
    input[type="tel"], input[type="search"], input[type="url"], input[type="date"], input[type="time"],
    input[type="datetime-local"], input[type="month"], input[type="week"], select, textarea):not(table *):not(.ol-page *):not(.pc-page *):not(.pr-page *):not(.bod-sheet *) {
    font-size: 14.5px !important;
    min-height: 40px;
    padding-top: 8px;
    padding-bottom: 8px;
    border-radius: 10px;
    box-sizing: border-box;
    max-width: 100%;
  }
  body textarea:not(table *) { min-height: 88px; }
  body :is(input, select, textarea):not([type="checkbox"]):not([type="radio"]):focus-visible {
    outline: none;
    border-color: #4b3bb8 !important;
    box-shadow: 0 0 0 3px rgba(75, 59, 184, .18) !important;
  }
  body label:not(table *) { font-size: 12px; color: #4a5568; }
  body .btn-sm:not(.ol-page *):not(.pc-page *):not(.pr-page *) { min-height: 34px; padding-top: 7px; padding-bottom: 7px; font-size: 12.5px; }

  /* Re-flowed field rows (class set by js/mobile-tables.js). */
  body .hd-fields { display: grid !important; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)) !important; gap: 10px 12px !important; flex-wrap: wrap; }
  body .hd-fields > * { min-width: 0 !important; width: auto !important; max-width: none !important; flex: none !important; grid-column: auto !important; margin: 0 !important; }
  body .hd-fields > .hd-field-wide { grid-column: 1 / -1 !important; }

  /* List tables as cards. */
  body table.hd-cards, body table.hd-cards > tbody, body table.hd-cards > tfoot { display: block; width: 100% !important; min-width: 0 !important; border: 0 !important; background: transparent !important; }
  body table.hd-cards > thead, body table.hd-cards tr:has(> th):not(:has(> td)) { display: none !important; }
  /* Display on rows / cells has zero specificity (:where), so a page rule that hides a filtered row
     or a column still wins. */
  :where(table.hd-cards) > :where(tbody, tfoot) > :where(tr), :where(table.hd-cards) > :where(tr) { display: block; }
  :where(table.hd-cards) :where(td) { display: block; }
  body table.hd-cards > tbody > tr, body table.hd-cards > tfoot > tr, body table.hd-cards > tr {
    position: relative; margin: 0 0 10px; padding: 10px 12px;
    background: #fff !important; border: 1px solid #e3e7ef; border-radius: 14px;
    box-shadow: 0 1px 2px rgba(16, 24, 40, .05);
  }
  body table.hd-cards > tfoot > tr { background: #f5f7fc !important; }
  /* Label pinned in a left gutter, the cell's own content (however many elements) flows on the
     right - multi-part cells such as "name + staff code" stay together. */
  body table.hd-cards td {
    position: relative !important;
    width: auto !important; min-width: 0 !important; max-width: none !important;
    padding: 5px 0 5px calc(36% + 10px) !important; border: 0 !important; background: transparent !important;
    text-align: left !important; white-space: normal !important; overflow-wrap: anywhere;
    font-size: 12.5px; line-height: 1.45; min-height: 24px;
  }
  body table.hd-cards td::before {
    content: attr(data-label); position: absolute; left: 0; top: 6px; width: 36%;
    color: #6b7686; font-size: 11px; font-weight: 600; line-height: 1.35; white-space: normal;
  }
  body table.hd-cards td[data-label=""] { padding-left: 0 !important; }
  body table.hd-cards td[data-label=""]::before { content: none; }
  body table.hd-cards td:empty, body table.hd-cards td.hd-card-index { display: none; }
  body table.hd-cards td.hd-card-title {
    padding: 0 0 8px !important; margin-bottom: 4px; border-bottom: 1px dashed #e4e8f0 !important;
    font-size: 13.5px; font-weight: 700; color: #1d2340;
  }
  body table.hd-cards td.hd-card-title::before { display: none; }
  body table.hd-cards td.hd-card-full { padding-left: 0 !important; text-align: center !important; color: #6b7686; }
  body table.hd-cards td.hd-card-full::before { display: none; }
  body table.hd-cards td :is(button, .btn-sm, a.btn-sm) { width: auto; margin: 2px 4px 2px 0; }

  /* Tables that stay tables: their own rounded scroll frame instead of widening the page. */
  body .hd-table-scroll {
    max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain;
    border: 1px solid #e3e7ef; border-radius: 12px; background: #fff; margin: 0 0 12px;
  }
  body .hd-table-scroll > table { margin: 0; }
}

/* "Home" (app home screen, employee/home.html) at the top of the employee drawer: phones only, same
   breakpoint as the drawer itself. */
.app-sidebar .sidebar-mobile-only { display: none !important; }
@media (max-width: 900px) { .app-sidebar .sidebar-mobile-only { display: flex !important; } }

/* App home screen (explicit request 2026-10-05: "khi User mở ra sẽ hiển thị các Icon của các thư
   mục lớn trước tiên, sau khi ấn vào các Icon sẽ vào các thư mục làm việc cụ thể ... Icon tiên tiến
   nhất hiện nay, đẹp chuyên nghiệp nhất"). The folders are read from the sidebar this page has just
   rendered, so permissions, hidden features and badges are exactly the sidebar's own. */
.hd-home { padding-top: 14px; }
.hd-home-hero {
  position: relative; overflow: hidden; display: flex; align-items: center; gap: 14px;
  padding: 18px 18px 20px; margin: 0 0 22px; border-radius: 22px; color: #fff;
  background: linear-gradient(135deg, #2b1d8f 0%, #3d2bb3 45%, #0f8a8a 100%);
  box-shadow: 0 14px 30px -14px rgba(43, 29, 143, .55);
}
.hd-home-hero::before, .hd-home-hero::after {
  content: ""; position: absolute; border-radius: 50%; background: rgba(255, 255, 255, .08); pointer-events: none;
}
.hd-home-hero::before { width: 220px; height: 220px; right: -70px; top: -90px; }
.hd-home-hero::after { width: 140px; height: 140px; right: 60px; bottom: -80px; background: rgba(255, 255, 255, .06); }
.hd-home-avatar {
  position: relative; z-index: 1; flex: 0 0 auto; width: 58px; height: 58px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  background: rgba(255, 255, 255, .18); box-shadow: 0 0 0 3px rgba(255, 255, 255, .35);
  font-size: 20px; font-weight: 800; letter-spacing: .02em;
}
.hd-home-avatar img { width: 100%; height: 100%; object-fit: cover; object-position: center 25%; display: block; }
/* With a real photo: larger, crisp white ring and a soft drop shadow. */
.hd-home-avatar.has-photo { width: 64px; height: 64px; background: #fff; box-shadow: 0 0 0 3px #fff, 0 8px 18px rgba(10, 8, 40, .28); }
.hd-home-avatar:focus-visible { outline: 3px solid rgba(255, 255, 255, .7); outline-offset: 3px; }
.hd-home-greet { position: relative; z-index: 1; min-width: 0; }
.hd-home-greet small { display: block; font-size: 12.5px; font-weight: 600; opacity: .85; }
.hd-home-greet h1 { margin: 2px 0 3px; font-size: 21px; line-height: 1.2; color: #fff; overflow-wrap: anywhere; }
.hd-home-greet p { margin: 0; font-size: 12.5px; opacity: .88; line-height: 1.35; }
.hd-home-date {
  position: absolute; z-index: 1; top: 14px; right: 14px; padding: 4px 10px; border-radius: 999px;
  background: rgba(255, 255, 255, .16); font-size: 11px; font-weight: 700; letter-spacing: .02em;
}
.hd-home-title { display: flex; align-items: baseline; justify-content: space-between; margin: 0 2px 12px; }
.hd-home-title h2 { margin: 0; font-size: 16px; color: #1d2340; }
.hd-home-title span { font-size: 12px; color: #6b7686; }
/* App home icon tiles (employee/home.html "My workspace", admin/home.html folders + page sheet).
   2026-10-17 refresh (approved Before/After preview): Modern minimalist - same navy and rounded-square
   frame; 60px phone / 64px tablet / 66px desktop, Lucide glyphs 26-27px, solid navy + soft shadow and
   hairline edge (glass sheen removed), subtle hover / press / keyboard-focus states, labels max 2 lines. */
.hd-home-grid { --hd-tile: 60px; --hd-tile-r: 16px; --hd-glyph: 26px; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px 6px; margin: 0 0 26px; }
@media (max-width: 340px) { .hd-home-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 600px) { .hd-home-grid { --hd-tile: 64px; --hd-tile-r: 17px; --hd-glyph: 27px; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 18px 12px; } }
@media (min-width: 1024px) { .hd-home-grid { --hd-tile: 66px; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 22px 16px; } }
.hd-app {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 9px;
  min-height: 44px; padding: 6px 2px 4px; border-radius: 14px; outline: none;
  text-decoration: none; color: #262b45; -webkit-tap-highlight-color: transparent;
}
.hd-app-icon {
  position: relative; width: var(--hd-tile); height: var(--hd-tile); border-radius: var(--hd-tile-r);
  display: flex; align-items: center; justify-content: center; color: #fff;
  background: var(--c1, #123885); /* solid brand navy - locked by test-sidebar-black-text / test-admin-home-icons */
  box-shadow: 0 1px 2px rgba(15, 30, 70, .10), 0 6px 14px -6px rgba(18, 56, 133, .40), inset 0 0 0 1px rgba(255, 255, 255, .10);
  transition: transform .18s cubic-bezier(.2, .8, .2, 1), box-shadow .18s ease;
}
.hd-app-icon::before { content: none; display: none; }
.hd-app-icon svg { width: var(--hd-glyph); height: var(--hd-glyph); stroke-width: 1.85; }
.hd-app:active .hd-app-icon { transform: scale(.95); transition-duration: .08s; }
@media (hover: hover) {
  .hd-app:hover .hd-app-icon { transform: translateY(-2px); box-shadow: 0 2px 4px rgba(15, 30, 70, .10), 0 12px 22px -8px rgba(18, 56, 133, .50), inset 0 0 0 1px rgba(255, 255, 255, .14); }
  .hd-app:hover .hd-app-label { color: #123885; }
}
.hd-app:focus-visible .hd-app-icon { box-shadow: 0 0 0 3px #fff, 0 0 0 5px rgba(18, 56, 133, .55); }
.hd-app:focus-visible .hd-app-label { color: #123885; }
/* Never split a word ("Announcemen-t"): a long single word may use the 5px either side. Max 2 balanced
   lines; min-height = two lines so every tile (and the grey placeholder) has the same height. */
.hd-app-label {
  width: calc(100% + 10px); margin: 0 -5px; min-height: 2.6em; text-align: center; font-size: 12px; font-weight: 600;
  line-height: 1.3; letter-spacing: -.005em; text-wrap: balance; overflow-wrap: normal; word-break: normal; hyphens: manual;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; transition: color .18s ease;
}
.hd-app-badge {
  position: absolute; top: -5px; right: -5px; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: #ff3b30; color: #fff; font-size: 11px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
  box-shadow: 0 0 0 2px #f4f6fb;
}
.hd-home-empty { color: #6b7686; font-size: 13px; }
@media (prefers-reduced-motion: reduce) { .hd-app-icon, .hd-app-label { transition: none; } }

/* Admin app home: tapping a folder opens a bottom sheet with that folder's pages as smaller icons,
   like opening a folder on a phone home screen (admin/home.html). */
.hd-sheet-backdrop { position: fixed; inset: 0; z-index: 1200; background: rgba(15, 18, 38, .42); opacity: 0; pointer-events: none; transition: opacity .2s ease; }
.hd-sheet-backdrop.open { opacity: 1; pointer-events: auto; }
.hd-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1201; max-height: 82vh; overflow-y: auto;
  padding: 10px 18px calc(22px + var(--safe-bottom, 0px)); background: #f7f8fc;
  border-radius: 24px 24px 0 0; box-shadow: 0 -12px 30px rgba(15, 18, 38, .22);
  transform: translateY(105%); transition: transform .26s cubic-bezier(.2, .8, .2, 1);
}
.hd-sheet.open { transform: translateY(0); }
.hd-sheet-grip { width: 42px; height: 5px; border-radius: 3px; background: #cfd4e2; margin: 0 auto 12px; }
.hd-sheet-head { display: flex; align-items: center; gap: 12px; margin: 0 0 16px; }
.hd-sheet-head .hd-app-icon { width: 46px; height: 46px; border-radius: 13px; flex: 0 0 auto; }
.hd-sheet-head .hd-app-icon svg { width: 23px; height: 23px; }
.hd-sheet-head h3 { margin: 0; font-size: 17px; color: #1d2340; }
.hd-sheet-head small { display: block; color: #6b7686; font-size: 12px; margin-top: 2px; }
.hd-sheet-close { margin-left: auto; width: 34px !important; height: 34px; min-height: 0 !important; padding: 0 !important; border-radius: 50% !important; background: #e8ebf3 !important; color: #4a5568 !important; font-size: 18px !important; }
.hd-sheet .hd-home-grid { margin-bottom: 4px; }
.hd-sheet .hd-app-icon { width: 54px; height: 54px; border-radius: 15px; }
.hd-sheet .hd-app-icon svg { width: 25px; height: 25px; }
@media (min-width: 769px) {
  .hd-sheet { left: 50%; right: auto; top: 50%; bottom: auto; width: 640px; max-width: calc(100vw - 48px); border-radius: 24px; padding-bottom: 24px; transform: translate(-50%, -46%) scale(.97); opacity: 0; pointer-events: none; transition: transform .2s ease, opacity .2s ease; }
  .hd-sheet.open { transform: translate(-50%, -50%); opacity: 1; pointer-events: auto; }
  .hd-sheet-grip { display: none; }
}
@media (prefers-reduced-motion: reduce) { .hd-sheet, .hd-sheet-backdrop { transition: none; } }
/* Admin folders are <button>s (they open the sheet): undo the app-wide button look. */
button.hd-app, button.hd-app:active { width: auto; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; color: #262b45; font: inherit; cursor: pointer; box-shadow: none; }
/* App home placeholders while the folder list is being finalised (js/home-grid.js). */
.hd-app.is-skel .hd-app-icon { background: linear-gradient(90deg, #eceef5 0%, #f7f8fc 50%, #eceef5 100%); background-size: 200% 100%; box-shadow: none; animation: hd-skel 1.2s linear infinite; }
.hd-app.is-skel .hd-app-icon::before { display: none; }
.hd-app.is-skel .hd-app-label { width: 64%; height: 10px; min-height: 0; margin: 2px auto calc(2.5em - 12px); border-radius: 5px; background: #eceef5; }
@keyframes hd-skel { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .hd-app.is-skel .hd-app-icon { animation: none; } }

/* Phone bottom bar (js/bottom-nav.js): Home, Notifications, E-learning, Settings - always in reach at
   the bottom on phones (drawer breakpoint), hidden on desktop. Frosted white, safe-area aware. */
.hd-bottom-nav { display: none; }
@media (max-width: 900px) {
  .hd-bottom-nav {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 1100;
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
    background: rgba(255, 255, 255, .92); -webkit-backdrop-filter: saturate(180%) blur(14px); backdrop-filter: saturate(180%) blur(14px);
    border-top: 1px solid rgba(20, 24, 50, .08); box-shadow: 0 -6px 20px rgba(20, 24, 50, .07);
  }
  body.has-bottom-nav .app-main { padding-bottom: calc(80px + env(safe-area-inset-bottom, 0px)); }
  .hd-bn-item, button.hd-bn-item, button.hd-bn-item:active {
    position: relative; flex: 1 1 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    width: auto; min-height: 52px; margin: 0; padding: 4px 2px; border: 0; border-radius: 14px; background: none; box-shadow: none;
    color: #6b7286; font: inherit; font-size: 11px; font-weight: 600; line-height: 1.1; text-decoration: none; cursor: pointer;
    -webkit-tap-highlight-color: transparent; transition: color .15s ease, background-color .15s ease;
  }
  .hd-bn-item svg { width: 24px; height: 24px; transition: transform .15s ease; }
  .hd-bn-item:active svg { transform: scale(.9); }
  .hd-bn-item.active { color: #352093; background: #f0effc; }
  .hd-bn-badge {
    position: absolute; top: 2px; left: calc(50% + 4px); min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
    display: inline-flex; align-items: center; justify-content: center;
    background: #ff3b30; color: #fff; font-size: 10.5px; font-weight: 800; box-shadow: 0 0 0 2px #fff;
  }
  .hd-bn-badge[hidden] { display: none; }
}
/* Notification sheet (opened from the bell). */
.hd-notif-readall, button.hd-notif-readall { width: auto; min-height: 0; margin: -6px 0 10px; padding: 6px 12px; border: 0; border-radius: 999px; background: #eef0fa; color: #352093; font-size: 12.5px; font-weight: 700; }
.hd-notif-readall[hidden] { display: none; }
.hd-notif-list { display: flex; flex-direction: column; gap: 8px; }
.hd-notif-group { margin: 6px 2px 0; font-size: 11.5px; font-weight: 700; color: #6b7686; }
.hd-notif-group:first-child { margin-top: 0; }
a.hd-notif-item { text-decoration: none; color: inherit; }
.hd-notif-task { border-color: #f5cf8f !important; background: #fffaf0 !important; }
.hd-notif-task .hd-notif-dot { background: #e07b1f; }
.hd-notif-item, button.hd-notif-item, button.hd-notif-item:active {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; min-height: 0; margin: 0; padding: 11px 12px; text-align: left;
  border: 1px solid #e6e9f2; border-radius: 14px; background: #fff; color: #1d2340; font: inherit; box-shadow: 0 1px 2px rgba(16, 24, 40, .04); cursor: pointer;
}
.hd-notif-dot { flex: 0 0 auto; width: 9px; height: 9px; margin-top: 5px; border-radius: 50%; background: #ff3b30; }
.hd-notif-body { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.hd-notif-body strong { font-size: 13.5px; line-height: 1.3; overflow-wrap: anywhere; }
.hd-notif-body span { font-size: 12.5px; color: #4a5568; line-height: 1.35; overflow-wrap: anywhere; }
.hd-notif-body small { font-size: 11px; color: #8a93a6; }
.hd-notif-empty { padding: 26px 10px 18px; text-align: center; color: #8a93a6; }
.hd-notif-empty svg { width: 34px; height: 34px; opacity: .55; }
.hd-notif-empty p { margin: 8px 0 0; font-size: 13px; }

/* Phone type scale (explicit request 2026-10-06: "trong app điện thoại bạn để cỡ chữ nhỏ vừa phù hợp
   trang"). Without a body size, every plain paragraph / card text inherited the browser's 16px and
   h2/h3 their 24px/18.7px defaults - oversized on a 390px screen. Compact, consistent scale on
   phones only; desktop untouched. Form controls / tables / cards are sized in the blocks above
   (14.5px / 12.5px); iOS focus-zoom on <16px inputs is prevented in js/supabaseClient.js. */
@media (max-width: 768px) {
  body { font-size: 13.5px; line-height: 1.45; }
  :where(.app-main) h1 { font-size: 19px; }
  :where(.app-main) h2 { font-size: 17px; }
  :where(.app-main) h3 { font-size: 15px; }
  :where(.app-main) h4 { font-size: 13.5px; }
}

/* EN / VI flags on phones (explicit request 2026-10-06: "trên app điện thoại bạn phải để cờ tiếng anh
   và cờ tiếng Việt"): always in the top bar next to Log out, finger-sized. */
@media (max-width: 768px) {
  .app-header .lang-switcher { display: flex; gap: 4px; margin-right: 6px; }
  .app-header .lang-switcher button { padding: 7px 6px; min-height: 0; }
  .app-header .lang-switcher button svg { width: 22px; height: 15px; }
}

/* =====================================================================================================
   DESIGN SYSTEM - Clean · Modern · Compact · Professional (explicit request 2026-10-07: "thiết kế toàn
   bộ giao diện app theo phong cách hiện đại tối giản và chuyên nghiệp ... UI clean gọn dễ nhìn, hạn chế
   chi tiết và màu sắc không cần thiết ... Spacing đồng nhất, tận dụng khoảng trắng").
   One layer, last in the file, so every page follows it without touching page code:
   - neutral greys + ONE accent (Handong navy); no gradients / heavy shadows on chrome and controls
   - spacing scale 4 / 8 / 12 / 16 / 24 px; radius 12 (surfaces) / 8 (controls)
   - system font (no download), 14px body, 600 headings, sentence-case table headers
   Phone sizes keep their own rules (the phone blocks above use higher specificity / media queries);
   desktop-only typography lives in the min-width block below.
   ===================================================================================================== */
:root {
  --hd-bg: #f6f7f9;
  --hd-border: #e5e7eb;
  --hd-text: #1f2937;
  --hd-muted: #6b7280;
  --hd-radius: 12px;
  --ds-surface: #ffffff;
  --ds-subtle: #f3f4f6;
  --ds-line: #eef0f3;
  --ds-control: #d6d9de;
  --ds-accent: #123885;
  --ds-accent-hover: #0e2c68;
  --ds-accent-soft: #eef2fb;
  --ds-ring: 0 0 0 3px rgba(18, 56, 133, .14);
  --ds-r: 12px;
  --ds-r-sm: 8px;
  --ds-1: 4px; --ds-2: 8px; --ds-3: 12px; --ds-4: 16px; --ds-5: 24px;
}
html, body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body { background: var(--hd-bg); color: var(--hd-text); }
a { color: var(--ds-accent); }

/* Sidebar selection uses a soft background, never a blue text override. */
.app-header { box-shadow: none; border-bottom: 1px solid var(--hd-border); }
.app-sidebar {
  --sidebar-surface: #ffffff;
  --sidebar-hover: var(--ds-subtle);
  --sidebar-active: var(--ds-accent-soft);
  --sidebar-text: #000;
  --sidebar-muted: #000;
  border-right: 1px solid var(--hd-border);
}
.sidebar-link.active, .sidebar-flat-link.active { color: var(--sidebar-text); font-weight: 400; }
.app-sidebar :is(.sidebar-section-head, .sidebar-flat-link, .sidebar-link, .sidebar-divider, .sidebar-collapse-btn) { color: var(--sidebar-text); font-weight: 400; }
.app-sidebar :is(.bi-en, .bi-vi) { color: inherit; }
.sidebar-section-icon { color: #4b5563; }
.app-sidebar.collapsed:hover { box-shadow: 0 8px 24px rgba(16, 24, 40, .10); }

/* Surfaces: border only, no drop shadow; one radius; consistent inner spacing. */
.card { border: 1px solid var(--hd-border); border-radius: var(--ds-r); box-shadow: none; padding: var(--ds-4) 18px; margin-bottom: var(--ds-4); }
.info-section { border: 1px solid var(--hd-border); border-left-width: 1px; border-radius: var(--ds-r); box-shadow: none; }
.info-section-icon { background: var(--ds-subtle); }
.info-field { background: #f9fafb; border-radius: var(--ds-r-sm); }
.request-card { border-left-width: 3px; border-radius: var(--ds-r); box-shadow: none; }
.request-card-next { background: var(--ds-accent-soft); }

/* Controls */
label { font-size: 12.5px; font-weight: 500; color: #4b5563; margin: 10px 0 5px; }
button, .btn {
  border-radius: var(--ds-r-sm);
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0;
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease, filter .15s ease;
}
button:hover:not(:disabled), .btn:hover { filter: brightness(.95); }
button:focus-visible, .btn:focus-visible, a:focus-visible { outline: none; box-shadow: var(--ds-ring); }
.btn-secondary { background: #ffffff; color: #1f2937; border: 1px solid var(--ds-control); }
.btn-outline { background: #ffffff; color: var(--ds-accent); border: 1px solid #c9d3e6; }
.btn-danger { background: #dc2626; color: #fff; }
.btn-sm { padding: 6px 12px; font-size: 12.5px; border-radius: 7px; }
.badge { font-weight: 600; font-size: 11.5px; padding: 2px 9px; border-radius: 999px; }
.muted { color: var(--hd-muted); }

/* Tables: sentence-case headers, hairline rows. */
th { text-transform: none; letter-spacing: 0; font-weight: 600; color: #6b7280; }
th, td { border-bottom-color: var(--ds-line); }

/* Tab bars: solid accent for the selected tab (was a navy->teal gradient). */
.contract-center-tabs { background: var(--ds-subtle); border-color: var(--hd-border); }
.contract-center-tab.active { background: var(--ds-accent); box-shadow: none; }

/* Desktop typography + form fields (phones keep the compact phone scale defined above). */
@media (min-width: 769px) {
  body { font-size: 14px; line-height: 1.5; }
  :where(.app-main) h1 { font-size: 22px; font-weight: 650; letter-spacing: -.01em; }
  :where(.app-main) h2 { font-size: 19px; font-weight: 650; letter-spacing: -.01em; }
  :where(.app-main) h3 { font-size: 16px; font-weight: 600; }
  :where(.app-main) h4 { font-size: 14px; font-weight: 600; }
  input[type="text"], input[type="email"], input[type="password"], input[type="number"], textarea, select {
    padding: 9px 12px;
    border: 1px solid var(--ds-control);
    border-radius: var(--ds-r-sm);
    font-size: 14px;
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus, input[type="number"]:focus,
  input[type="date"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input:not([type]):focus, textarea:focus, select:focus {
    outline: none;
    border-color: var(--ds-accent);
    box-shadow: var(--ds-ring);
  }
  .container { padding-top: var(--ds-4); padding-left: var(--ds-5); padding-right: var(--ds-5); }
}

/* Page stylesheets (recruitment, total rewards, org chart, attendance grids, ... 17 files) still set
   uppercase table headers of their own - the design system's sentence-case header wins everywhere in
   the app, except the printable documents (offer letter, contracts, probation form, decision sheets),
   which keep the layout of their paper originals. */
.app-main th:not(:where(.ol-page, .pc-page, .pr-page, .a4-page, .bod-sheet) th) { text-transform: none !important; letter-spacing: 0 !important; }

/* Page palettes mapped onto the design system (phase 2, 2026-10-07): the page stylesheets keep their
   layout; only their own accents / heavy header fills are brought to the shared neutral + navy scheme.
   "html body" / html:root raise specificity over the page <style> blocks that load after this file. */
html:root {
  --wr-green: var(--ds-accent); --wr-green-dark: var(--ds-accent-hover); --wr-soft: var(--ds-accent-soft); --wr-line: var(--hd-border);
  --mail-accent: var(--ds-accent); --mail-line: var(--hd-border); --mail-soft: #f9fafb;
}
html body :is(.tr-tabs, .lp-tabs) button.active { background: var(--ds-accent); color: #fff; }
html body :is(.tr-tabs, .lp-tabs) button:not(.active) { background: var(--ds-subtle); color: #374151; }
/* Total Rewards tables: neutral header rows; the income group keeps one accent, no red / dark blue fills. */
html body :is(.tr-summary-table, .tr-support-matrix) th { background: #f3f4f6; color: #1f2937; }
html body :is(.tr-summary-table, .tr-support-matrix) thead tr:nth-child(2) th { background: #f9fafb; color: #4b5563; }
html body .tr-summary-table th.tr-income-head { background: var(--ds-accent); color: #fff; }
html body .tr-summary-table thead tr:nth-child(2) th.tr-income-sub { background: var(--ds-accent-soft); color: var(--ds-accent); }
html body .tr-long-block h4 { background: #f3f4f6; color: #1f2937; }
html body .tr-long-total h4 { background: var(--ds-accent); color: #fff; }
html body .tr-long-table thead th { background: #f9fafb; color: #374151; }
html body .tr-long-total .tr-long-table thead th { background: var(--ds-accent-soft); color: var(--ds-accent); }
/* Work reports: flat KPI highlight + neutral trend bars, cards without drop shadow. */
html body .wr-card { box-shadow: none; border-radius: var(--ds-r); }
html body .wr-linked-kpis .wr-kpi-current { background: var(--ds-accent); border-color: var(--ds-accent); box-shadow: none; }
html body .wr-trend-item i { background: #c7d2e8; }
html body .wr-tab.active { box-shadow: 0 1px 2px rgba(16, 24, 40, .06); }
/* Notice banners (My profile): solid colours instead of gradients. */
html body #birthday-banner { background: #db2777; }
html body #new-hire-banner { background: var(--ds-accent); }
html body #probation-review-banner { background: #d97706; }
html body #probation-review-banner.is-waiting { background: var(--ds-accent); }
/* Recruitment quota groups and leave summary: flat tints. */
html body #quota-table tr.quota-group td { background: var(--ds-accent-soft); }
html body .lv-form .lv-summary { background: #f9fafb; }
html body .tr-summary-table th.tr-support-head { background: #f3f4f6; color: #1f2937; }

/* Row "more actions" menu (design system): keeps table rows to one or two visible actions. Markup:
   <details class="row-more"><summary>⋯</summary><div class="row-more-menu"><button>...</button></div></details>
   Closed on outside click / after picking an item by js/sidebar.js. */
details.row-more { position: relative; display: inline-block; }
details.row-more > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 28px; border: 1px solid var(--ds-control); border-radius: 7px; background: #fff;
  color: #4b5563; font-size: 16px; line-height: 1; letter-spacing: 1px;
}
details.row-more > summary::-webkit-details-marker { display: none; }
details.row-more[open] > summary, details.row-more > summary:hover { background: var(--ds-subtle); }
.row-more-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 60; min-width: 190px;
  display: flex; flex-direction: column; padding: 4px; background: #fff;
  border: 1px solid var(--hd-border); border-radius: 10px; box-shadow: 0 8px 24px rgba(16, 24, 40, .12);
}
html body .row-more-menu > button {
  width: 100%; justify-content: flex-start; margin: 0; padding: 7px 10px; border: 0 !important; border-radius: 7px;
  background: transparent !important; color: #1f2937 !important; font-size: 13px; font-weight: 500; box-shadow: none !important;
}
html body .row-more-menu > button:hover:not(:disabled) { background: var(--ds-subtle) !important; filter: none; }
html body .row-more-menu > button:disabled { opacity: .45; }
html body .row-more-menu > button:is(.offer-delete-btn, .danger, [class*="delete"]) { color: #dc2626 !important; }

/* Printing (request 2026-10-07: the phone bottom bar and the Notifications sheet were printed on top
   of the contract) - app chrome that lives outside .app-shell never goes to paper. */
@media print {
  .hd-bottom-nav, .hd-sheet, .hd-sheet-backdrop, #hd-notif-sheet, #hd-notif-backdrop,
  #app-sidebar-backdrop, #app-sidebar-spacer, #mobile-nav-toggle, #push-prompt-banner, .row-more-menu { display: none !important; }
  body { padding-bottom: 0 !important; }
}

/* Compact top bar (request 2026-10-16): menu button, logo, EN/VI flags and Log out all exactly the same
   height (--hd-hdr-ctl). The bottom bar keeps its original look and stays fixed (user request). */
@media screen {
  .app-header { --hd-hdr-ctl: 24px; }
  .app-header #mobile-nav-toggle, .app-header .logo-badge, .app-header .lang-switcher button, .app-header #logout-btn {
    height: var(--hd-hdr-ctl) !important; min-height: var(--hd-hdr-ctl); box-sizing: border-box; align-self: center;
  }
  .app-header #mobile-nav-toggle { width: var(--hd-hdr-ctl); }
  .app-header .logo-badge { width: auto !important; }
  .app-header .header-left { align-items: center; }
  .app-header .lang-switcher { align-items: center; }
  /* Flags fill the compact row like the logo: no white box around them; the chosen
     language stays full colour, the other keeps the existing dimmed look. */
  .app-header .lang-switcher { gap: 6px; }
  .app-header .lang-switcher button, .app-header .lang-switcher button.active {
    display: inline-flex; align-items: center; justify-content: center; padding: 0; width: auto;
    background: none; border: 0; box-shadow: none; border-radius: 0; overflow: hidden;
  }
  .app-header .lang-switcher button svg { width: calc(var(--hd-hdr-ctl) * 10 / 7); height: var(--hd-hdr-ctl); border-radius: 0; }
  .app-header #logout-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0 12px; line-height: 1; margin: 0; }
  /* Smaller flags + Log out (request 2026-10-18): one shared, lower height; the menu button and logo keep 24px. */
  .app-header { --hd-hdr-btn: 18px; }
  .app-header .lang-switcher button, .app-header #logout-btn { height: var(--hd-hdr-btn) !important; min-height: var(--hd-hdr-btn); }
  .app-header .lang-switcher { gap: 4px; }
  .app-header .lang-switcher button svg { width: calc(var(--hd-hdr-btn) * 10 / 7); height: var(--hd-hdr-btn); }
  .app-header #logout-btn { padding: 0 8px; font-size: 11px; font-weight: 500; }
}

/* Home hero (request 2026-10-16): the name line reserves ONE line, so the job title sits right under it
   instead of below an empty second line. */
.hd-home-greet h1 { min-height: 1.2em !important; }

/* Audit fixes 2026-10-16 (approved items 4 and 6) - technical only, look unchanged:
   4) Chat on phones / tablets: the page is a fixed-height column (100vh - header), so its message box
      sat under the bottom navigation bar. The column now also leaves room for that bar.
   6) Computer inventory pager arrows reach the 32px touch size on phones. */
@media (max-width: 900px) {
  body.has-bottom-nav .app-main:has(#chat-root) { padding-bottom: 0; }
  body.has-bottom-nav .container.full:has(#chat-root) { height: calc(100dvh - 56px - 70px - env(safe-area-inset-bottom, 0px)) !important; }
  [data-ci-prev], [data-ci-next] { min-width: 32px; min-height: 32px; }
}

/* Phone drawer flash (2026-10-17): #app-sidebar starts as an empty element and only gets .app-sidebar
   (with its off-screen transform + 0.22s transition) when js/sidebar.js renders it, so every page load
   slid the drawer from open to closed in front of the user. It now starts off-screen; opening and
   closing with the menu button work exactly as before. */
@media (max-width: 900px) {
  #app-sidebar { transform: translateX(-100%); }
  #app-sidebar.mobile-open { transform: translateX(0); }
}

/* Sub-icons inside the big folders (request 2026-10-17: "các Icon lớn tại trang User và admin giữ
   nguyên, nhưng các Icon con bạn giảm độ lớn và cỡ chữ nhỏ lại"): the home-screen folder tiles keep
   their size; the folder sheet (admin/home.html) and the phone page-tab tiles inside each folder get a
   smaller icon and label - compact and balanced. */
.hd-sheet .hd-home-grid { gap: 12px 6px; }
.hd-sheet .hd-app { gap: 6px; }
.hd-sheet .hd-app-icon { width: 44px; height: 44px; border-radius: 13px; }
.hd-sheet .hd-app-icon svg { width: 21px; height: 21px; }
.hd-sheet .hd-app-label { font-size: 11px; line-height: 1.25; min-height: 2.5em; font-weight: 500; }
.hd-sheet .hd-app-badge { top: -4px; right: -4px; min-width: 18px; height: 18px; font-size: 10px; }
@media (min-width: 769px) {
  .hd-sheet .hd-home-grid { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 16px 10px; }
}
@media (max-width: 768px) {
  body :is(#appr-tabs, #ladder-tabs, #track-tabs, #chart-scope-tabs, #line-mode-tabs, #view-tabs,
    .my-request-tabs nav, .appr-tabs, .sub-tabs, .recruit-tabs, .rp-tabs, .tr-tabs, .ov-tabs, .lp-tabs,
    .cp-tabs, .contract-center-tabs):not(.no-tiles) > :is(a, button):not([hidden]) {
    min-height: 70px !important;
    gap: 5px;
    padding: 8px 3px 7px !important;
    font-size: 10.5px !important;
    font-weight: 500 !important;
    border-radius: 14px !important;
  }
  .hd-tab-ico { width: 32px; height: 32px; border-radius: 10px; }
  .hd-tab-ico svg { width: 17px; height: 17px; }
}

/* Phone top bar: the menu button (#mobile-nav-toggle) is inserted by js/sidebar.js after the page
   loads, so the logo first painted at the left edge and then jumped 54px to the right on EVERY page
   (measured 2026-10-17 at 390px: logo x 16 -> 70 at ~0.9-2.1 s - "giật mạnh, lác màn hình" when
   opening a sub-folder). Until the button exists, the logo keeps exactly the room it will take:
   button 32px + its 6px margin + the header's 16px gap = 54px. */
@media (max-width: 900px) {
  .app-header:not(:has(#mobile-nav-toggle)) > :is(.header-left, .admin-header-left) { margin-left: 54px; }
}

/* Sub-folder icons in green (user colour 2026-10-17, #0B6E4F); the home-screen parent folder tiles keep
   their navy. Applies to the pages inside a folder: the admin folder sheet and the phone page-tab tiles. */
/* Parent folder tiles on both home screens (User "My workspace"/"Delegated admin access", Admin folders,
   the open folder's header icon) are green too since 2026-10-18 ("cùng màu xanh lá với thư mục con");
   the bottom bar (.hd-bn-item) is untouched. */
:is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app:not(.is-skel) .hd-app-icon,
#hd-sheet-icon,
#hd-sheet-grid .hd-app-icon { background: #0B6E4F !important; border-color: #0B6E4F !important; color: #fff; box-shadow: 0 1px 2px rgba(11, 110, 79, .12), 0 6px 14px -6px rgba(11, 110, 79, .40), inset 0 0 0 1px rgba(255, 255, 255, .10); }
@media (max-width: 768px) {
  body .hd-tab-ico { background: #0B6E4F; color: #fff; border-color: #0B6E4F; }
}
/* The selected page tile inside a folder is green too (user request 2026-10-17 "Ô đang chọn cũng chuyển
   luôn màu xanh lá"): green tile, white label, the icon a soft white square on it. Same selector weight
   as logo-icons.css's navy rule, declared later so it wins. */
@media (max-width: 768px) {
  html body :is(#appr-tabs,#ladder-tabs,#track-tabs,#chart-scope-tabs,#line-mode-tabs,#view-tabs,.my-request-tabs nav,.appr-tabs,.sub-tabs,.recruit-tabs,.rp-tabs,.tr-tabs,.ov-tabs,.lp-tabs,.cp-tabs,.contract-center-tabs):not(.no-tiles)>:is(a,button):is(.active,.is-active,[aria-current="page"]) {
    background: #0B6E4F !important; border-color: #0B6E4F !important; color: #fff !important;
    box-shadow: 0 4px 10px rgba(11, 110, 79, .22) !important;
  }
  html body :is(.active, .is-active, [aria-current="page"]) > .hd-tab-ico { background: rgba(255, 255, 255, .18); color: #fff; border-color: rgba(255, 255, 255, .5); }
}

/* Page intro sentences hidden (user request 2026-10-18: "ẩn các câu giải thích phía dưới các mục lớn
   này, vì tốn diện tích" - user and admin pages): the grey line right under a page-level heading.
   Only page-level (direct children of the page container), never inside a card, and never a line with
   an id (those carry live status text filled in by the page). The text stays in the HTML. */
.app-main :is(.container, #re-page, .workspace-tabs-shell) > :is(h2, h3) + p.muted:not([id]) { display: none; }
.app-main :is(.container, #re-page) > :is(h2, h3) { margin-bottom: 10px !important; }
/* Same when the heading sits in a title row with buttons (e.g. List of Resigned Employees). */
.app-main :is(.container, #re-page) > div:first-child:has(> :is(h2, h3)) + p.muted:not([id]) { display: none; }

/* Phone home - compact tiles (request 2026-10-18 "các ô chức năng gọn hơn, cỡ chữ gọn"): smaller icon frame,
   11px labels, tighter rows and a lower welcome card. Colours, shapes and the tablet/desktop sizes unchanged. */
@media (max-width: 599px) {
  .hd-home { padding-top: 10px; }
  html body .hd-home-hero { min-height: 104px; height: 104px; box-sizing: border-box; gap: 12px; padding: 14px 14px 15px; margin: 0 0 16px; border-radius: 18px; }
  html body .hd-home-avatar, html body .hd-home-avatar.has-photo { width: 52px; height: 52px; font-size: 17px; }
  .hd-home-greet small { font-size: 11.5px; }
  .hd-home-greet h1 { font-size: 18px; margin: 1px 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal; }
  .hd-home-greet p { font-size: 11.5px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
  .hd-home-date { top: 10px; right: 10px; padding: 3px 8px; font-size: 10.5px; }
  .hd-home-title { margin: 0 2px 8px; }
  .hd-home-title h2 { font-size: 14px; }
  .hd-home-title span { font-size: 11.5px; }
  .hd-home-grid { gap: 10px 4px; margin: 0 0 18px; } /* folder icons keep the original 60px (user 2026-10-19) */
  .hd-app { gap: 6px; padding: 4px 2px 2px; }
  .hd-app-label { width: 100%; margin: 0; font-size: 11px; font-weight: 500; line-height: 1.25; min-height: 2.5em; }
  .hd-app-badge { top: -4px; right: -4px; min-width: 18px; height: 18px; padding: 0 5px; font-size: 10px; }
  .hd-app.is-skel .hd-app-label { margin-bottom: calc(2.5em - 11px); }
}

/* Sidebar: one font and one size for every item, user and admin pages alike (request 2026-10-27).
   The expandable group heads are <button>s and took the browser's button font (Arial - it reads
   bigger than the links' system font), and the child links were 12.5px. */
.app-sidebar :is(.sidebar-section-head, .sidebar-flat-link, .sidebar-link, .sidebar-stub) { font-family: inherit; font-size: 13px; }
@media (max-width: 480px) {
  .app-sidebar :is(.sidebar-section-head, .sidebar-flat-link, .sidebar-link, .sidebar-stub) { font-size: 13.5px; }
}

/* Phone home screens - 2-column cards (user choice 2026-10-27, option "B"): a small green icon on the left,
   the full name on the right, in white rounded cards; the count badge stays on the icon corner and the
   whole card is the tap target. Phones only (the 4-across icon grid stays on tablets and computers).
   Covers the employee home ("My workspace" + delegated admin) and the admin home folders; the grey
   loading placeholders take the same card shape so nothing jumps when the real tiles arrive. */
@media (max-width: 599px) {
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) {
    --hd-tile: 38px; --hd-tile-r: 11px; --hd-glyph: 20px;
    grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  }
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app {
    flex-direction: row; align-items: center; justify-content: flex-start; gap: 10px;
    min-height: 56px; padding: 9px 10px; background: #fff; border: 1px solid #e4e8f1; border-radius: 14px;
    box-shadow: 0 4px 12px -10px rgba(18, 56, 133, .4); transition: transform .12s ease, box-shadow .12s ease;
  }
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app:active { transform: scale(.98); }
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app-icon { flex: 0 0 auto; }
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app-label {
    width: auto; flex: 1 1 auto; min-width: 0; margin: 0; min-height: 0; text-align: left;
    font-size: 12.5px; line-height: 1.25; color: #1d2340; overflow-wrap: anywhere;
  }
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app-badge { top: -4px; right: -4px; }
  html body :is(#hd-home-grid, #hd-home-admin-grid, #hd-home-mine-grid) .hd-app.is-skel .hd-app-label { width: 60%; height: 10px; margin: 0; }
}
