@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap');

:root {
  /* Webmores brand — matched to the real webmores.co site: bright yellow #FEED01 + black + a warm
     off-white, not a designed-from-scratch palette. Sampled directly off the live site (computed
     styles, not guessed from a screenshot): #feed01 is the dominant hero/section background and
     the only accent color in real use; body copy runs on #f8f7f5 with #e5e3db dividers; every
     clickable element (the CONTACT button, the small circular arrow icons) is solid black with
     white text — never yellow-with-white-text, which is why --primary below stays a near-black
     tone (safe for white text on top) and the yellow lives in --accent/--nav-accent instead, used
     for highlights, tags, and gradient accents rather than button fills. */
  --bg: #f8f7f5;
  --card-bg: #ffffff;
  --border: #e5e3db;
  --text: #1a1912;
  --muted: #6e6b5e;
  --ink: #101010;
  --ink-soft: #232323;
  --primary: #141311;
  --primary-2: #322f27;
  --primary-dark: #000000;
  --primary-soft: #fff6c2;
  --accent: #feed01;
  --danger: #ef4444;
  --danger-soft: #fef2f2;
  --success: #10b981;
  --success-soft: #ecfdf5;
  --warn: #f59e0b;
  --warn-soft: #fffbeb;
  --radius: 12px;
  --radius-lg: 18px;
  --nav-accent: #feed01;
  --nav-accent-soft: rgba(254, 237, 1, 0.16);
  --shadow-sm: 0 1px 2px rgba(20, 18, 12, 0.06);
  --shadow-md: 0 4px 18px rgba(20, 18, 12, 0.10), 0 1px 3px rgba(20, 18, 12, 0.07);
  --shadow-lg: 0 14px 36px rgba(20, 18, 12, 0.18), 0 2px 8px rgba(20, 18, 12, 0.10);
  --gradient-brand: linear-gradient(90deg, var(--primary), var(--primary-2));
  --gradient-brand-3: linear-gradient(90deg, var(--primary), var(--primary-2), var(--accent));
  /* "Plain white surface" colors — form fields, buttons, filter pills, calendar cells — kept as
     their own variables (rather than hardcoded #fff) purely so dark mode below can swap them. */
  --input-bg: #ffffff;
  --surface-alt: #f5f3ee;
  --track-bg: #ece9df;
  /* Plain link/wording text color — kept separate from --primary (which stays near-black, sized
     for buttons/badges) specifically so dark mode can swap ONLY the wording to a legible tone
     below, without touching any brand-colored UI. */
  --link-color: var(--primary);
}

/* ============ Dark mode ============ *
 * Two ways in: the OS/browser preference (prefers-color-scheme), or an explicit choice from the
 * toggle button in header.ejs — which stamps data-theme="dark"/"light" on <html> and always wins
 * over the system setting. Only the tokens that actually need to change are redefined; every rule
 * in this file already reads colors from variables, so the whole app repaints from these two blocks
 * alone. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #17150f;
    --card-bg: #221f18;
    --border: #3c392e;
    --text: #f3f1e7;
    --muted: #b3ae9c;
    /* --primary itself (near-black) would vanish on a dark page, so wording/badge-text that reads
       against the dark background switches to the brand yellow instead — buttons/gradients keep
       their own fixed near-black fill either way, since a dark button reads fine on light OR dark
       pages without needing to change. */
    --primary-dark: #feed01;
    --primary-soft: rgba(254, 237, 1, 0.16);
    --danger: #f87171;
    --danger-soft: rgba(239, 68, 68, 0.18);
    --success: #34d399;
    --success-soft: rgba(16, 185, 129, 0.18);
    --warn: #fbbf24;
    --warn-soft: rgba(245, 158, 11, 0.18);
    --input-bg: #241f17;
    --surface-alt: #1e1b14;
    --track-bg: #2c2820;
    /* Plain wording (project titles, links, the "▸" expand marker) rendered in the brand yellow
       everywhere would be overwhelming at that scale — swapped to a neutral warm off-white
       instead. Smaller accent text (tags, table headers, hover states) still gets the yellow via
       --primary-dark above. */
    --link-color: #e7e4d6;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
    --shadow-md: 0 4px 18px rgba(0, 0, 0, 0.38), 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.32);
  }
}
:root[data-theme="dark"] {
  --bg: #17150f;
  --card-bg: #221f18;
  --border: #3c392e;
  --text: #f3f1e7;
  --muted: #b3ae9c;
  --primary-dark: #feed01;
  --primary-soft: rgba(254, 237, 1, 0.16);
  --danger: #f87171;
  --danger-soft: rgba(239, 68, 68, 0.18);
  --success: #34d399;
  --success-soft: rgba(16, 185, 129, 0.18);
  --warn: #fbbf24;
  --warn-soft: rgba(245, 158, 11, 0.18);
  --input-bg: #241f17;
  --surface-alt: #1e1b14;
  --track-bg: #2c2820;
  --link-color: #e7e4d6;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 4px 18px rgba(0, 0, 0, 0.38), 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.32);
}

* { box-sizing: border-box; }

/* overflow-x: clip (not hidden) on purpose, paired with an explicit overflow-y: visible —
   "hidden" on either axis silently forces the OTHER axis to compute as "auto" per the CSS overflow
   spec, which turns html/body into a scroll container of their own and breaks position:sticky for
   the sidebar below (on both desktop and mobile, since sticky needs to track the page's own
   scroll, not a nested one it got shoved into). "clip" doesn't carry that side effect, so it blocks
   the same accidental horizontal overflow while leaving vertical scrolling/sticky untouched. */
html { overflow-x: clip; overflow-y: visible; }
body {
  margin: 0;
  font-family: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.5;
  overflow-x: clip;
  overflow-y: visible;
  max-width: 100vw;
}

/* Safety net so an unexpectedly wide element (a long link, an embed, a fixed-width field) never
   forces the whole page to scroll sideways on a phone — it clips instead. Actual wide content
   like tables gets its own scroll box (.table-scroll below, and the existing checklist/calendar
   wraps) so nothing important becomes unreachable. */
img, iframe, video { max-width: 100%; height: auto; }

h1, h2, h3 { font-weight: 800; letter-spacing: -0.01em; }

a { color: var(--link-color); text-decoration: none; transition: color 0.15s ease; }
a:hover { text-decoration: underline; color: var(--primary-dark); }

.container {
  max-width: none;
  margin: 0;
  padding: 24px 32px 60px;
  flex: 1 1 auto;
  min-width: 0;
}

/* App shell: left sidebar + main content, side by side on desktop */
.app-shell {
  display: flex;
  align-items: flex-start;
  min-height: 100vh;
}

/* Left sidebar navigation */
.sidebar {
  background: #000000;
  border-right: none;
  box-shadow: 6px 0 28px rgba(15, 14, 10, 0.16);
  width: 230px;
  flex: 0 0 230px;
  min-height: 100vh;
  position: sticky;
  top: 0;
  align-self: flex-start;
  display: flex;
  flex-direction: column;
  z-index: 10;
}
.sidebar::before {
  content: '';
  display: block;
  height: 4px;
  width: 100%;
  background: var(--gradient-brand-3);
  flex: 0 0 auto;
}
.sidebar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 18px 14px;
}
.brand {
  display: inline-flex;
  align-items: center;
}
.brand-logo-img {
  height: 22px;
  width: auto;
  display: block;
  /* Logo file is black-on-transparent; the sidebar is dark, so flip it to white. */
  filter: brightness(0) invert(1);
}
.brand:hover { text-decoration: none; opacity: 0.82; }
.nav { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px; flex: 1 1 auto; overflow-y: auto; }
.nav a { color: #c7c3b4; font-size: 14px; font-weight: 500; padding: 9px 10px; border-radius: 8px; transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease; }
.nav a:hover { color: var(--nav-accent); background: var(--ink-soft); text-decoration: none; }
.nav a.nav-active { color: var(--nav-accent); background: var(--ink-soft); font-weight: 700; box-shadow: inset 3px 0 0 var(--nav-accent); }
.nav a.nav-active:hover { color: var(--nav-accent); }
/* batch80: click-to-expand grouped sections ("Project", "Finance", "Management", "Human
   Resource") — now a native <details>/<summary> element (same zero-JS accordion pattern as
   .login-group below) instead of an always-open <div>. Server-rendered `open` attribute (see
   partials/header.ejs) means the group containing the current page starts expanded and every
   other group starts collapsed; clicking the title (<summary>) toggles it locally. */
.nav-group { display: flex; flex-direction: column; gap: 2px; margin: 6px 0 2px; }
.nav-group-title {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px 2px;
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: #8a8570;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.nav-group-title::-webkit-details-marker { display: none; }
.nav-group-title::marker { content: ''; }
.nav-group-title::before { content: '▸'; font-size: 10px; color: #8a8570; transition: transform 0.15s ease; }
.nav-group[open] > .nav-group-title::before { content: '▾'; }
.nav-group-title:hover { color: #c7c3b4; }
.nav-group-title:hover::before { color: #c7c3b4; }
/* batch80 fix: `<details>` blockifies its flex-item children in theory, but relying on that
   alone left the anchors as inline boxes in at least one real-world browser this shipped to —
   links wrapped two-to-a-row instead of stacking, and an active link's highlight hugged just its
   text instead of spanning the row (compare "Dashboard"/"Calendar" above, which are plain <a>
   siblings of <nav>, not inside a <details>, and were never affected). Forcing `display: block`
   here removes any dependency on the parent's flex behavior being interpreted correctly. */
.nav-group a { display: block; padding-left: 24px; font-size: 13.5px; }
.nav-toggle {
  display: none;
  background: none;
  border: 1px solid #4a463a;
  color: #fff;
  font-size: 18px;
  line-height: 1;
  padding: 6px 10px;
  border-radius: 8px;
  cursor: pointer;
  margin-left: auto;
}
/* Site-wide search — sits in the dark sidebar just below the logo row (see header.ejs), replacing
   the old per-page search box in .page-topbar plus every page/section's own "search this list"
   input. Styled for the sidebar's black background rather than the light card surfaces the
   .page-search input/button pair (still defined below, now otherwise unused) were built for. */
.sidebar-search { display: flex; align-items: center; gap: 6px; padding: 0 18px 14px; margin: 0; }
.sidebar-search input[type="search"] {
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid #4a463a;
  color: #fff;
  font-size: 13.5px;
  padding: 8px 10px;
  border-radius: 8px;
  flex: 1;
  min-width: 0;
  outline: none;
}
.sidebar-search input[type="search"]::placeholder { color: #8a8570; }
.sidebar-search input[type="search"]:focus { border-color: var(--nav-accent); }
.sidebar-search button {
  background: none;
  border: 1px solid #4a463a;
  color: #fff;
  font-size: 14px;
  line-height: 1;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
}
.sidebar-search button:hover { border-color: var(--nav-accent); }
/* batch134: the as-you-type quick-pick list for the sidebar search box — see footer.ejs's
   wm-live-search script for the fetch/render logic. batch139: this used to be a dropdown squeezed
   under the search box, clipped to the narrow sidebar's own width ("remove the search result as
   dropdown, add to right side search result instead") — it's now a fixed panel docked to the right
   edge of the viewport instead, wide enough to actually read a result's sub-line, and independent
   of the sidebar's own width/scroll since position:fixed anchors to the viewport, not the
   .sidebar-search-wrap parent it still happens to live inside in the markup. */
.sidebar-search-wrap { position: relative; }
.sidebar-search-dropdown {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 360px;
  max-width: 92vw;
  z-index: 200;
  background: #23211a;
  border-left: 1px solid #4a463a;
  box-shadow: -10px 0 32px rgba(0, 0, 0, 0.35);
  overflow-y: auto;
  padding: 0 0 16px;
}
.sidebar-search-dropdown .wm-lsd-panel-header {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  background: #23211a;
  border-bottom: 1px solid #4a463a;
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
}
.sidebar-search-dropdown .wm-lsd-panel-close {
  background: none;
  border: 1px solid #4a463a;
  color: #fff;
  border-radius: 6px;
  width: 26px;
  height: 26px;
  line-height: 1;
  cursor: pointer;
  flex: 0 0 auto;
}
.sidebar-search-dropdown .wm-lsd-panel-close:hover { border-color: var(--nav-accent); }
.sidebar-search-dropdown .wm-lsd-group-label {
  padding: 12px 16px 4px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #8a8570;
}
.sidebar-search-dropdown a.wm-lsd-item {
  display: block;
  padding: 9px 16px;
  color: #fff;
  text-decoration: none;
  font-size: 13.5px;
  line-height: 1.35;
}
.sidebar-search-dropdown a.wm-lsd-item:hover,
.sidebar-search-dropdown a.wm-lsd-item.wm-lsd-active { background: rgba(255, 255, 255, 0.08); }
.sidebar-search-dropdown .wm-lsd-item-sub { display: block; font-size: 11.5px; color: #8a8570; margin-top: 2px; }
.sidebar-search-dropdown .wm-lsd-more,
.sidebar-search-dropdown .wm-lsd-empty {
  display: block;
  padding: 9px 16px;
  font-size: 12.5px;
  color: #b8b39f;
}
.sidebar-search-dropdown a.wm-lsd-more { color: var(--nav-accent); text-decoration: none; }
.sidebar-search-dropdown a.wm-lsd-more:hover { text-decoration: underline; }
/* A backdrop behind the panel so it reads as a focused overlay rather than content floating loose
   over the page — click it to dismiss, same as clicking anywhere else outside the panel. */
.wm-lsd-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.25);
  z-index: 190;
}
@media (max-width: 760px) {
  .sidebar-search-dropdown { width: 100vw; max-width: 100vw; }
}
/* Row holding the "Last updated" timestamp + page-refresh button at the top of every logged-in
   page's content — see header.ejs. margin-left:auto on .wm-last-updated (the timestamp, first of
   the two) pins both of them together to the right of this row. */
.page-topbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
.wm-last-updated { white-space: nowrap; }
/* batch380: Last updated + refresh live in the sidebar, above "Active now" */
.wm-side-refresh { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 18px 8px; color: #b0ab98; font-size: 11.5px; }
.wm-side-refresh .wm-refresh-btn { background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.18); color: #d6d2c2; font-size: 13px; padding: 5px 8px; border-radius: 8px; box-shadow: none; flex: none; }
.wm-side-refresh .wm-refresh-btn:hover { color: #FEED01; border-color: #FEED01; }
/* EN / 中文 language switch, beside "Active now" */
.wm-lang { margin-left: auto; display: inline-flex; border: 1px solid rgba(255,255,255,.22); border-radius: 999px; overflow: hidden; flex: none; }
.wm-lang-btn { background: transparent; border: 0; color: #d6d2c2; font: inherit; font-size: 11px; font-weight: 700; padding: 3px 9px; cursor: pointer; line-height: 1.3; }
.wm-lang-btn.wm-lang-on { background: #FEED01; color: #03040F; }
.wm-lang-btn:focus-visible { outline: 2px solid #FEED01; outline-offset: -2px; }
.wm-refresh-btn {
  background: var(--card-bg);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 16px;
  line-height: 1;
  padding: 9px 12px;
  border-radius: 9px;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.wm-refresh-btn:hover { color: var(--primary); border-color: var(--primary); transform: rotate(90deg); }
/* Site search — now sits at the top of each page's own content, not the sidebar (see header.ejs) */
.page-search { display: flex; align-items: center; gap: 0; max-width: 420px; margin-bottom: 0; }
.page-search input[type="search"] {
  background: var(--input-bg);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 14px;
  padding: 9px 12px;
  border-radius: 9px 0 0 9px;
  width: auto;
  flex: 1;
  min-width: 0;
  outline: none;
  margin: 0;
}
.page-search input[type="search"]:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(20, 18, 12, 0.14);
  z-index: 1;
  position: relative;
}
.page-search button {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-left: none;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  padding: 9px 14px;
  border-radius: 0 9px 9px 0;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.page-search button:hover { color: var(--link-color); border-color: var(--primary); }
.topbar-user { display: flex; align-items: center; gap: 10px; font-size: 14px; padding: 14px 18px; border-top: 1px solid rgba(255,255,255,0.08); flex-wrap: wrap; }
.user-name { color: #c7c3b4; }
.topbar-user .link-btn { color: #c7c3b4; }
.topbar-user .link-btn:hover { color: var(--nav-accent); }
.topbar-user .user-name:hover { color: var(--nav-accent); text-decoration: underline; }

.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.role-admin { background: var(--ink); color: var(--accent); }
.role-staff { background: var(--success-soft); color: var(--success); }
.role-customer { background: #e7f0ff; color: #2454b8; }
.role-super_staff { background: var(--primary-soft); color: var(--primary-dark); }
/* Batch153: the six new system roles */
.role-director, .role-management_manager { background: var(--ink); color: var(--accent); }
.role-developer_manager, .role-social_media_manager, .role-head_of_department { background: var(--primary-soft); color: var(--primary-dark); }
.role-operation { background: var(--success-soft); color: var(--success); }

.link-btn {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 14px;
  padding: 0;
  transition: color 0.15s ease;
}
.link-btn:hover { color: var(--primary-dark); text-decoration: underline; }
/* batch257: small, tidy "Hide" pill used on every project section header */
.hide-btn { display: inline-flex; align-items: center; gap: 4px; padding: 1px 9px; font-size: 11.5px; line-height: 1.6; font-weight: 600; color: var(--muted); background: transparent; border: 1px solid var(--border, rgba(0,0,0,.14)); border-radius: 999px; cursor: pointer; transition: background .15s ease, color .15s ease, border-color .15s ease; }
.hide-btn::before { content: ""; width: 10px; height: 10px; background: currentColor; opacity: .75; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3l18 18M10.6 5.1A10.9 10.9 0 0 1 12 5c6 0 10 7 10 7a17.6 17.6 0 0 1-3.2 4M6.6 6.6A17.4 17.4 0 0 0 2 12s4 7 10 7a10 10 0 0 0 4.4-1'/%3E%3C/svg%3E") center/contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3l18 18M10.6 5.1A10.9 10.9 0 0 1 12 5c6 0 10 7 10 7a17.6 17.6 0 0 1-3.2 4M6.6 6.6A17.4 17.4 0 0 0 2 12s4 7 10 7a10 10 0 0 0 4.4-1'/%3E%3C/svg%3E") center/contain no-repeat; }
.hide-btn:hover { background: var(--primary-soft, rgba(0,0,0,.05)); color: var(--primary-dark, #222); border-color: var(--primary-dark, rgba(0,0,0,.3)); }

/* Cards */
.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 20px 22px;
  margin-bottom: 20px;
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.card h2, .card h1 { margin-top: 0; }

.grid {
  display: grid;
  gap: 16px;
}
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
/* batch245: a grid cell may shrink below its content's natural width (otherwise a wide table inside one cell pushes the card past the screen / clips its neighbour) */
.grid > * { min-width: 0; }
@media (max-width: 960px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  .grid-3, .grid-2, .grid-4 { grid-template-columns: 1fr; }
}

.stat-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 18px 20px;
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.stat-card:hover { box-shadow: var(--shadow-lg); transform: translateY(-2px); }
.stat-card .stat-value {
  font-size: 28px;
  font-weight: 800;
  background: var(--gradient-brand-3);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  display: inline-block;
}
.stat-card .stat-label { color: var(--muted); font-size: 13px; text-transform: uppercase; letter-spacing: 0.03em; font-weight: 600; }
/* batch147: a .stat-card can also be an <a> (My Tasks — each card jumps to its matching list
   further down the page) — reset link defaults so it still looks exactly like the plain-div
   version everywhere else that uses this class, just with a pointer cursor as the extra hint. */
a.stat-card { display: block; text-decoration: none; color: inherit; cursor: pointer; }

/* Forms */
form label {
  display: block;
  margin-bottom: 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--muted);
}
form input, form select, form textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 9px;
  font-size: 14px;
  font-family: inherit;
  color: var(--text);
  background: var(--input-bg);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
form textarea { resize: vertical; min-height: 80px; }
form input:focus, form select:focus, form textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(20, 18, 12, 0.14);
}
/* Password field with an inline eye toggle (login + passcode gate — see views/login.ejs). The
   input itself still matches the plain "form input" rule above for its border/padding/width;
   this wrapper only exists to position the eye button inside it. */
.wm-pw-field { position: relative; }
.wm-pw-field input { padding-right: 40px !important; }
.wm-pw-toggle-btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  color: var(--muted);
  padding: 5px 7px;
  border-radius: 6px;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.wm-pw-toggle-btn:hover { color: var(--primary-dark); background: var(--surface-alt); }

.checkbox-list { display: flex; flex-wrap: wrap; gap: 10px; font-weight: 400; color: var(--text); }
.checkbox-list label { display: flex; align-items: center; gap: 6px; font-weight: 400; color: var(--text); margin-bottom: 0; }
.checkbox-list input { width: auto; margin: 0; }

.btn {
  display: inline-block;
  padding: 9px 18px;
  border-radius: 9px;
  border: 1px solid transparent;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn-primary { background: var(--gradient-brand); color: #fff; border: none; box-shadow: 0 3px 10px rgba(20, 18, 12, 0.3); }
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 8px 20px rgba(20, 18, 12, 0.38); color: #fff; text-decoration: none; }
.btn-secondary { background: var(--card-bg); border-color: var(--border); color: var(--text); box-shadow: var(--shadow-sm); }
.btn-secondary:hover { border-color: var(--primary); color: var(--primary-dark); box-shadow: var(--shadow-md); text-decoration: none; }
.btn-danger { background: var(--card-bg); border-color: #f9c9c9; color: var(--danger); }
.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); text-decoration: none; }
.btn-sm { padding: 5px 11px; font-size: 12.5px; }

/* Tables */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); vertical-align: top; }
th { color: var(--primary-dark); font-weight: 700; font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.02em; }
thead { background: var(--primary-soft); }
tr:last-child td { border-bottom: none; }
tbody tr:hover { background: rgba(20, 18, 12, 0.035); }

/* Status badges */
.status { display: inline-block; padding: 2px 9px 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 700; }
.status::before { content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: currentColor; margin-right: 5px; vertical-align: middle; opacity: 0.85; }
.status-on_track, .status-active, .status-done { background: var(--success-soft); color: var(--success); }
.status-at_risk, .status-on_hold { background: var(--warn-soft); color: var(--warn); }
.status-blocked, .status-cancelled { background: var(--danger-soft); color: var(--danger); }

.progress-bar {
  background: var(--track-bg);
  border-radius: 999px;
  height: 8px;
  width: 140px;
  overflow: hidden;
}
.progress-bar-fill { background: var(--gradient-brand-3); height: 100%; }

.score { font-weight: 800; }
.score-5, .score-4 { color: var(--success); }
.score-3 { color: var(--warn); }
.score-2, .score-1 { color: var(--danger); }

/* Auth page background — the brand's own "Branding & Identity" slide (public/img/brand/login-bg.jpg),
   sized to cover the full screen. No video/overlay on top of it anymore — just this one image. */
body:has(.auth-wrap) {
  background: #F8F8F6 url('/img/brand/login-bg.jpg') center center / cover no-repeat;
  min-height: 100vh;
  position: relative;
}
body:has(.auth-wrap) .container { max-width: none; padding: 0; min-height: 100vh; position: relative; z-index: 1; }
.auth-wrap { display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 24px; }
.auth-logo { display: block; max-width: 210px; width: 100%; height: auto; margin: 0 auto 16px; }
.auth-seasonal {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: -4px auto 16px;
}
.auth-seasonal img { width: 34px; height: 34px; object-fit: contain; flex: 0 0 auto; }
.auth-seasonal span {
  font-size: 12px;
  font-weight: 700;
  color: var(--primary-dark);
  background: var(--primary-soft);
  padding: 4px 11px;
  border-radius: 999px;
  white-space: nowrap;
}
.auth-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 36px 32px 32px;
  width: 100%;
  max-width: 380px;
  position: relative;
  overflow: hidden;
}
.auth-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 5px;
  background: var(--gradient-brand-3);
}
.auth-card h1 {
  font-size: 22px;
  margin-bottom: 4px;
  font-weight: 800;
  background: var(--gradient-brand-3);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  display: inline-block;
}
.muted { color: var(--muted); font-size: 14px; }
.demo-creds {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--muted);
}
.demo-creds code { background: var(--primary-soft); color: var(--primary-dark); padding: 1px 6px; border-radius: 5px; font-weight: 600; }

.alert { padding: 10px 14px; border-radius: 9px; font-size: 13.5px; margin-bottom: 14px; font-weight: 600; }
.alert-error { background: var(--danger-soft); color: var(--danger); }
.alert-success { background: var(--success-soft); color: var(--success); }

.section-title { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }

/* batch169: project pages — every section is a click-to-open dropdown, closed by default; only the Task Checklist
   starts open. The class on <html> is set by an inline script on those pages before the sections are parsed, so
   there is no flash of open content. The first child of each card is its title bar. */
html.proj-collapsible [data-section-key] > :first-child { cursor: pointer; user-select: none; }
html.proj-collapsible [data-section-key]:not(.sec-open):not([data-section-key="checklist"]) > :not(:first-child),
html.proj-collapsible [data-section-key="checklist"].sec-closed > :not(:first-child) { display: none !important; }
html.proj-collapsible [data-section-key]:not(.sec-open):not([data-section-key="checklist"]),
html.proj-collapsible [data-section-key="checklist"].sec-closed { padding-bottom: 14px; }
html.proj-collapsible [data-section-key]:not(.sec-open):not([data-section-key="checklist"]) > :first-child,
html.proj-collapsible [data-section-key="checklist"].sec-closed > :first-child { margin-bottom: 0; }
html.proj-collapsible [data-section-key]:not(.sec-open):not([data-section-key="checklist"]) > :first-child :is(h1, h2, h3),
html.proj-collapsible [data-section-key="checklist"].sec-closed > :first-child :is(h1, h2, h3) { margin-bottom: 0; }
.sec-chev { display: inline-block; width: 1.1em; margin-right: 4px; color: var(--muted); font-size: 0.8em; transition: transform .15s ease; vertical-align: middle; }
[data-section-key].sec-open .sec-chev, [data-section-key="checklist"]:not(.sec-closed) .sec-chev { transform: rotate(90deg); }
.sec-bar { display: flex; gap: 8px; align-items: center; margin: -6px 0 14px; font-size: 12.5px; color: var(--muted); flex-wrap: wrap; }
.sec-bar .link-btn { font-size: 12.5px; }
.empty-state { color: var(--muted); font-size: 14px; padding: 20px 0; text-align: center; }
.feedback-item { background: var(--surface-alt); border-radius: 9px; padding: 10px 12px; margin-top: 8px; font-size: 13.5px; border: 1px solid var(--border); }
.feedback-item .meta { color: var(--muted); font-size: 12px; margin-top: 4px; }
.inline-form { display: flex; gap: 8px; align-items: flex-end; }
.tag { font-size: 12px; color: var(--primary-dark); background: var(--primary-soft); font-weight: 600; padding: 2px 8px; border-radius: 999px; }

/* Checklist */
.checklist-section-title { margin: 18px 0 8px; font-size: 14px; color: var(--text); font-weight: 700; }
.checklist-section-title:first-of-type { margin-top: 0; }
.checklist-table-wrap { overflow-x: auto; margin-bottom: 4px; }
.checklist-table { min-width: 720px; }
.checklist-table th, .checklist-table td { padding: 6px 8px; }
.checklist-table input[type="text"], .checklist-table input[type="date"], .checklist-table input[type="number"] {
  margin-top: 0;
  padding: 5px 7px;
  font-size: 13px;
}
.checklist-table tr.row-done { background: var(--success-soft); }
.checklist-table tr.row-hold { opacity: .62; background: repeating-linear-gradient(135deg, transparent 0 8px, rgba(0,0,0,.035) 8px 16px); }
.tag.tag-hold { background: #fff3d6; color: #8a5a00; }
/* batch85: a completed task's own label used to get a strikethrough (text-decoration: line-through)
   right through the middle of the words — the user asked for the text to stay fully readable and
   let the tick itself (below, styled green via accent-color) be the only "this is done" signal. */
.checklist-table tr.task-overdue { background: var(--danger-soft); }
.checklist-table select { margin-top: 0; padding: 5px 7px; font-size: 13px; }
/* batch85: native checkbox rendered green-on-check by default (accent-color), instead of relying on
   struck-through text, as the one "done" indicator for a checklist row. */
.checklist-table input[type="checkbox"] { accent-color: var(--success); width: 16px; height: 16px; cursor: pointer; }
/* Drag-to-reorder handle — the first column of every checklist row (see checklist-row.ejs). batch139:
   draggable="true" now lives on this <td> alone, not the whole <tr> — dragging used to kick off from
   any plain cell (empty table whitespace, a cell's own padding, even an unfocused select), which made
   it too easy to accidentally start reordering a row while just trying to click into it. The row is
   still found via e.target.closest('tr[data-checklist-item]') in checklist.ejs's drag handlers, since
   that walks up from wherever inside the row the drag actually started. */
.checklist-drag-handle { cursor: grab; color: var(--muted); text-align: center; width: 22px; user-select: none; }
.checklist-table tr.checklist-row-dragging { opacity: 0.35; }
.checklist-table tr.checklist-drag-over { box-shadow: inset 0 2px 0 var(--primary); }
.checklist-section { margin-bottom: 6px; }
.checklist-add-item-row input[type="text"] { margin-top: 0; padding: 6px 8px; font-size: 13px; }
.checklist-save-flash { transition: opacity 0.4s ease; }

/* Hosting & Domain — tighter than the default table so a row (label, platform, link, period,
   status, cost/billing) reads as one glance instead of a wide sprawl. */
.hosting-table th, .hosting-table td { padding: 8px 10px; font-size: 13.5px; white-space: nowrap; }
.hosting-table td:last-child, .hosting-table th:last-child { white-space: normal; }
.hosting-table .tag { margin-left: 4px; }

/* My Pending Tasks (staff dashboard) */
.task-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 13.5px; }
.task-row:last-child { border-bottom: none; }
/* batch86: on My Tasks (staff/admin) only, .task-row is nested one level deeper inside .task-item so
   a per-task "log an update" disclosure can sit underneath it without disturbing the standalone
   .task-row used elsewhere (e.g. the dashboard's own top-5 preview widget, which has no updates UI
   and keeps its own border/padding exactly as before). */
.task-item { border-bottom: 1px solid var(--border); padding: 10px 0; }
.task-item:last-child { border-bottom: none; }
.task-item .task-row { padding: 0; border-bottom: none; }
.task-updates summary { font-size: 12px; cursor: pointer; }
.task-due { font-size: 12px; white-space: nowrap; }
.task-due-overdue { color: var(--danger); font-weight: 700; }
.task-due-soon { color: var(--warn); font-weight: 700; }
.hidden-form { display: none; }
form select[multiple] { min-height: 90px; }
details summary { font-size: 13.5px; }
details summary::marker { color: var(--muted); }

/* Filter tabs (Projects: All / Pending / Completed) */
.filter-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.filter-tab { padding: 5px 13px; border-radius: 999px; font-size: 13px; color: var(--muted); border: 1px solid var(--border); background: var(--card-bg); transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease; }
.filter-tab:hover { border-color: var(--primary); color: var(--primary-dark); text-decoration: none; }
.filter-tab-active { background: var(--gradient-brand); color: #fff; border-color: transparent; font-weight: 700; box-shadow: 0 3px 10px rgba(20, 18, 12, 0.28); }
.filter-tab-active:hover { color: #fff; }
.filter-tab-active .muted { color: #fff; opacity: 0.8; }

/* Credential verified toggle + inline password show/hide */
.verify-badge {
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--muted);
  border-radius: 999px;
  padding: 3px 11px;
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.15s ease;
}
.verify-badge:hover { border-color: var(--primary); }
.verify-badge-on { background: var(--success-soft); color: var(--success); border-color: #bbf0d4; font-weight: 700; }
.pw-toggle { display: inline-flex; align-items: center; gap: 7px; }
.pw-value { background: var(--primary-soft); color: var(--primary-dark); padding: 1px 7px; border-radius: 5px; font-size: 13px; }
.pw-toggle-btn { font-size: 12px; }

/* Meeting summaries */
.meeting-item { padding: 14px 0; border-bottom: 1px solid var(--border); font-size: 14px; }
.meeting-item:last-child { border-bottom: none; }
.meeting-action-items { margin-top: 10px; padding: 10px 12px; background: var(--primary-soft); border-radius: 9px; font-size: 13.5px; }

/* Activity feed */
.activity-feed { list-style: none; margin: 0; padding: 0; }
.activity-feed li { padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 13.5px; }
.activity-feed li:last-child { border-bottom: none; }

/* Logins overview — collapsible per-project groups */
.login-group summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  list-style: none;
  border-radius: 8px;
  transition: background-color 0.15s ease;
}
.login-group summary:hover { background: var(--primary-soft); margin: -4px -6px; padding: 4px 6px; }
.login-group summary::-webkit-details-marker { display: none; }
.login-group summary::before { content: '▸'; color: var(--link-color); font-size: 12px; }
.login-group[open] summary::before { content: '▾'; }

/* ============ Responsive ============ */

/* Any table not already in its own scroll box (.checklist-table-wrap, .calendar-wrap) gets
   wrapped in one of these automatically by footer.ejs — so a wide table (Projects, Users, KPI,
   Activity Log, etc.) scrolls sideways inside its card on a phone instead of forcing the whole
   page to scroll, squeezing illegibly, or getting cut off. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Without this, `table { width: 100% }` (below) shrinks the table down to fit a narrow phone
   screen, which is what was forcing every header/cell to wrap character-by-character ("TE AM",
   "STAT US") instead of the wrapper actually scrolling sideways. Giving the table a floor width
   means it can no longer shrink past that point — so on a phone it overflows its wrapper instead,
   and .table-scroll's overflow-x:auto lets the user swipe/scroll right to see the rest, the same
   way the Checklist and Calendar tables already behave. */
.table-scroll table { width: auto; min-width: 760px; }
.table-scroll th { white-space: nowrap; }

/* Tablet: still comfortable at 3 columns down to ~960px, then ease to 2 */
@media (max-width: 960px) {
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}

/* Phone/small tablet: collapsible hamburger nav, stacked grids, roomier tap targets */
@media (max-width: 760px) {
  .container { padding: 16px 14px 48px; }
  .app-shell { display: block; }
  .sidebar {
    width: 100%;
    flex: none;
    min-height: auto;
    position: sticky;
    border-right: none;
    box-shadow: 0 4px 18px rgba(15, 14, 10, 0.16);
  }
  .sidebar-top { padding: 10px 14px; }
  .nav-toggle { display: inline-block; }
  .nav {
    display: none;
    flex-direction: column;
    gap: 2px;
    width: auto;
    background: var(--ink-soft);
    border-radius: 10px;
    padding: 6px 10px;
    margin: 0 14px 8px;
    overflow-y: visible;
  }
  .nav.nav-open { display: flex; }
  .nav a { padding: 9px 10px; border-bottom: 1px solid rgba(255,255,255,0.06); border-radius: 0; }
  .nav a:last-child { border-bottom: none; }
  .topbar-user { flex-wrap: wrap; }
  .page-search { max-width: none; }
  .page-search input[type="search"] { flex: 1; width: auto; }

  .grid-3, .grid-2, .grid-4 { grid-template-columns: 1fr; }
  .card { padding: 16px; }
  h1 { font-size: 22px; }
  .section-title { flex-wrap: wrap; gap: 8px; }
  .inline-form { flex-wrap: wrap; }
  .inline-form label { flex: 1 1 100%; }
  .btn { padding: 10px 16px; }
  .btn-sm { padding: 7px 12px; }
  table { font-size: 13px; }
  .filter-tabs { width: 100%; }
  .stat-card .stat-value { font-size: 24px; }

  /* Fields with an inline min-width (assignee multi-selects, admin note boxes, sop-timeline/
     project-types inputs) are sized for desktop rows sitting side by side; on a narrow phone that
     min-width can force the field wider than the screen. Dropping it lets the existing
     width:100% rule take over so every field fits. */
  input, select, textarea { min-width: 0; }

  /* Long unbroken text — a full URL, email, or credential value — wraps instead of pushing the
     table/card wider than the screen. */
  td, .card { overflow-wrap: break-word; word-break: break-word; }
}

/* Very small phones: tighten further, let long tables scroll rather than squeeze */
@media (max-width: 420px) {
  .auth-card { padding: 26px 20px; }
  .grid { gap: 12px; }
}

/* Calendar (renewals + task deadlines month view) */
.calendar-wrap { overflow-x: auto; }
.calendar-table { min-width: 760px; table-layout: fixed; border-collapse: separate; border-spacing: 4px; }
.calendar-table th { text-align: center; padding: 6px 4px; font-size: 12px; }
.calendar-table thead { background: none; }
.cal-cell {
  vertical-align: top;
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 6px;
  height: 92px;
  overflow-y: auto;
  background: var(--card-bg);
}
.cal-cell.cal-out-month { background: var(--surface-alt); color: var(--muted); }
.cal-cell.cal-out-month .cal-day-num { color: var(--muted); }
.cal-cell.cal-today { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(254, 237, 1, 0.35) inset; }
.cal-day-num { font-size: 12px; font-weight: 700; color: var(--text); margin-bottom: 3px; }
.cal-today .cal-day-num { color: var(--primary-dark); }
.cal-chip {
  display: block;
  font-size: 10.5px;
  line-height: 1.35;
  padding: 2px 5px;
  border-radius: 5px;
  margin-bottom: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-decoration: none;
}
.cal-chip:hover { text-decoration: none; filter: brightness(0.96); }
.cal-chip-overdue { background: var(--danger-soft); color: var(--danger); font-weight: 700; }
.cal-chip-today { background: var(--warn-soft); color: var(--warn); font-weight: 700; }
.cal-chip-upcoming { background: var(--primary-soft); color: var(--primary-dark); }
.cal-chip-renewal { background: rgba(34, 211, 238, 0.14); color: #0e7490; }
.cal-chip-done { background: var(--success-soft); color: var(--success); }
/* batch128: Public Holiday (company-wide, always the same look) and Leave (pending vs approved) */
.cal-chip-holiday { background: rgba(254, 237, 1, 0.22); color: #7a6a00; font-weight: 700; }
.cal-chip-leave-pending { background: var(--warn-soft); color: var(--warn); }
.cal-chip-post { background: rgba(244, 143, 177, 0.22); color: #ad1457; font-weight: 600; }
.cal-dot.cal-chip-post { background: #ec407a; }
.cal-chip-shoot { background: rgba(30, 136, 229, 0.16); color: #0d5ea8; font-weight: 600; }
.cal-chip-shoot-notion { background: rgba(3, 4, 15, 0.12); color: #03040F; font-weight: 600; }
.cal-dot.cal-chip-shoot { background: #1e88e5; }
.cal-chip-leave-approved { background: rgba(155, 89, 182, 0.14); color: #6c3483; }
.cal-pic { opacity: 0.75; font-style: italic; }
.cal-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 4px; vertical-align: middle; }
.cal-dot.cal-chip-overdue { background: var(--danger); }
.cal-dot.cal-chip-today { background: var(--warn); }
.cal-dot.cal-chip-upcoming { background: var(--primary); }
.cal-dot.cal-chip-renewal { background: #0e7490; }
.cal-dot.cal-chip-done { background: var(--success); }
.cal-dot.cal-chip-holiday { background: #d4af00; }
.cal-dot.cal-chip-leave-approved { background: #6c3483; }
@media (max-width: 760px) {
  .cal-cell { height: 78px; }
  /* batch130: the grid's own 760px min-width (7 columns × ~108px, needed on desktop so a chip's
     project title/label has room to read) meant a phone only ever showed 2-3 day columns at a time
     before needing a horizontal swipe — awkward for something that's meant to be read as "this
     week" at a glance. Shrinking the per-column footprint here (and further under 420px below) gets
     most of a week on-screen at once; the "Listing for [month]" section further down the page (flat,
     no horizontal scroll at all) remains the fully-detailed fallback either way. */
  .calendar-table { min-width: 560px; border-spacing: 3px; }
  .cal-chip { font-size: 10px; padding: 2px 4px; }
}
@media (max-width: 420px) {
  .calendar-table { min-width: 480px; }
  .cal-cell { height: 66px; padding: 4px; }
  .cal-day-num { font-size: 11px; margin-bottom: 2px; }
  .cal-chip { font-size: 9px; padding: 1px 4px; margin-bottom: 2px; }
}

/* Admin live activity toast — bottom-left, pops on any page except Activity Log itself */
#wm-activity-toasts {
  position: fixed;
  left: 14px;
  bottom: 14px;
  z-index: 9999;
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  max-width: 300px;
  pointer-events: none;
}
.wm-toast {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: linear-gradient(160deg, #262319, var(--ink));
  color: #fff;
  border-left: 3px solid var(--accent);
  border-radius: 10px;
  padding: 10px 14px;
  text-decoration: none;
  box-shadow: var(--shadow-lg);
  font-size: 12.5px;
  line-height: 1.4;
  animation: wm-toast-in 0.25s ease-out;
}
/* Same fix as .wm-notif-item above: this is an <a> tag too, so the generic a:hover rule would
   otherwise turn its text near-black on hover, invisible against this toast's own dark background. */
.wm-toast:hover { background: linear-gradient(160deg, #2e2a1f, var(--ink-soft)); color: #e5e3db; }
.wm-toast-success { border-left-color: #2ecc71; }
.wm-toast-user { font-weight: 700; color: var(--accent); font-size: 12px; }
.wm-toast-action { color: #fff; }
.wm-toast-out { animation: wm-toast-out 0.35s ease-in forwards; }
@keyframes wm-toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes wm-toast-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(10px); }
}
@media (max-width: 480px) {
  #wm-activity-toasts { left: 8px; right: 8px; bottom: 8px; max-width: none; }
}

/* Bell-icon notification dropdown (see partials/header.ejs, near the sidebar's role/name/logout
   row) — overdue/due-soon checklist tasks, renewals, and "just hit 100%" project completions.
   Sits at the bottom of the sidebar, so the panel opens UPWARD (bottom: 100%) to stay on-screen
   instead of running off the bottom of the viewport. */
.wm-notif-bell { position: relative; display: inline-flex; }
.wm-notif-bell-btn {
  position: relative;
  background: none;
  border: none;
  cursor: pointer;
  color: #d6d2c2;
  font-size: 17px;
  line-height: 1;
  padding: 4px 6px;
  border-radius: 8px;
}
.wm-notif-bell-btn:hover { background: rgba(255,255,255,0.08); }
.wm-notif-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}
.wm-notif-dropdown {
  position: absolute;
  bottom: 100%;
  left: 0;
  margin-bottom: 8px;
  width: 340px;
  max-width: calc(100vw - 32px);
  max-height: 70vh;
  overflow-y: auto;
  background: linear-gradient(160deg, #262319, var(--ink));
  color: #fff;
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  z-index: 1000;
  font-size: 13px;
}
.wm-notif-section { padding: 10px 14px; border-bottom: 1px solid rgba(255,255,255,0.08); }
.wm-notif-section:last-child { border-bottom: none; }
.wm-notif-section-title { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: #b0ab98; margin-bottom: 6px; }
.wm-notif-item { display: block; padding: 6px 0; text-decoration: none; color: #fff; border-top: 1px solid rgba(255,255,255,0.06); }
.wm-notif-item:first-child { border-top: none; }
/* Without this, the generic "a:hover { color: var(--primary-dark) }" rule elsewhere in this file
   (higher specificity than the plain .wm-notif-item color above) takes over on hover — and since
   --primary-dark is near-black in light mode, that made the item text turn invisible against this
   dropdown's own dark background. Pinned to a light grey here instead so it stays legible. */
.wm-notif-item:hover, .wm-notif-item:hover .wm-notif-item-label { color: #e5e3db; }
.wm-notif-item:hover .wm-notif-item-label { text-decoration: underline; }
.wm-notif-item-label { font-weight: 600; }
.wm-notif-item-meta { font-size: 11.5px; color: #d6d2c2; margin-top: 2px; }
@media (max-width: 480px) {
  .wm-notif-dropdown { width: calc(100vw - 32px); }
}

/* "Project completed" celebration popup (see partials/footer.ejs) — full-screen dark backdrop,
   a falling confetti/emoji layer behind a centered message card. No auto-dismiss: it's removed
   only by the × button (or a click on the backdrop itself), per how this was asked for. */
.wm-celebrate-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 8, 4, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  overflow: hidden;
  animation: wm-celebrate-fade-in 0.2s ease-out;
}
.wm-celebrate-confetti { position: absolute; inset: 0; pointer-events: none; }
.wm-confetti-piece {
  position: absolute;
  top: -10%;
  will-change: transform, opacity;
  animation-name: wm-confetti-fall;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes wm-confetti-fall {
  0%   { transform: translateY(0) rotate(0deg); opacity: 0.95; }
  100% { transform: translateY(115vh) rotate(360deg); opacity: 0.85; }
}
.wm-celebrate-card {
  position: relative;
  background: var(--card-bg);
  color: var(--text);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 40px 36px 34px;
  max-width: 420px;
  width: calc(100% - 32px);
  text-align: center;
  animation: wm-celebrate-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.wm-celebrate-close {
  position: absolute;
  top: 10px;
  right: 12px;
  background: none;
  border: none;
  font-size: 26px;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 8px;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.wm-celebrate-close:hover { color: var(--text); background: var(--primary-soft); }
.wm-celebrate-emoji { font-size: 44px; line-height: 1; margin-bottom: 6px; }
.wm-celebrate-title { margin: 0 0 8px; font-size: 21px; }
.wm-celebrate-body { margin: 0; color: var(--muted); font-size: 14.5px; }
@keyframes wm-celebrate-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes wm-celebrate-pop {
  from { opacity: 0; transform: scale(0.9) translateY(6px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
@media (max-width: 480px) {
  .wm-celebrate-card { padding: 32px 22px 28px; }
  .wm-celebrate-title { font-size: 18px; }
}

/* Light/dark mode toggle — fixed top-right on every page (see header.ejs) */
.theme-toggle {
  position: fixed;
  top: 14px;
  right: 14px;
  z-index: 1000;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--card-bg);
  color: var(--text);
  font-size: 17px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  transition: background-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.theme-toggle:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
@media (max-width: 760px) {
  .theme-toggle { top: 8px; right: 8px; width: 32px; height: 32px; font-size: 14px; }
}

/* Light/dark mode toggle — logged-in variant, sitting inline right beside the sidebar logo
   instead of floating over the page (see header.ejs) — the sidebar is always dark-themed
   regardless of the chosen theme, so this uses the same fixed light-on-dark colors as the
   hamburger button next to it, not the theme variables. */
.theme-toggle-inline {
  background: none;
  border: 1px solid #4a463a;
  color: #fff;
  font-size: 14px;
  line-height: 1;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  margin-left: 10px;
  flex: none;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.theme-toggle-inline:hover { background: rgba(255, 255, 255, 0.1); transform: translateY(-1px); }

/* Batch155: overdue warnings (1 / 3 / 7 days late) and Assign Task progress bars */
.od-badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 700; }
.od-warn { background: #fff3cd; color: #8a6100; }
.od-high { background: #ffd9b3; color: #8a3b00; }
.od-critical { background: #c0392b; color: #fff; }
.od-banner { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 12px; margin-bottom: 12px; font-weight: 600; }
.od-banner-warn { background: #fff3cd; color: #8a6100; }
.od-banner-high { background: #ffd9b3; color: #8a3b00; }
.od-banner-critical { background: #c0392b; color: #fff; font-size: 16px; }
.od-banner-critical a, .od-banner-high a, .od-banner-warn a { color: inherit; text-decoration: underline; }
.at-bar { height: 8px; border-radius: 6px; background: rgba(0,0,0,.1); overflow: hidden; min-width: 90px; }
.at-bar > span { display: block; height: 100%; background: #2e9e5b; }
.at-task { border: 1px solid var(--border, #e3e0d4); border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; }
.at-head { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; align-items: flex-start; }
.at-head-main { flex: 1 1 260px; min-width: 0; overflow-wrap: anywhere; }
.at-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.at-people, .table-scroll table.at-people { width: 100%; min-width: 0; table-layout: auto; }
.table-scroll table.at-people th { white-space: normal; }
.at-p-name { width: 200px; }
.at-p-bar { width: 170px; }
.at-p-pct { width: 56px; white-space: nowrap; }
@media (max-width: 760px) {
  .at-task { padding: 10px 12px; }
  .at-actions { width: 100%; }
  .at-people, .at-people tbody { display: block; }
  .at-people tr { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 4px 10px; align-items: center; padding: 8px 0; border-top: 1px solid var(--border, #e3e0d4); }
  .at-people tr:first-child { border-top: 0; }
  .at-people td { display: block; width: auto; padding: 0; border: 0; }
  .at-p-name { grid-column: 1 / -1; width: auto; }
  .at-p-bar { grid-column: 1; width: auto; }
  .at-p-pct { grid-column: 2; width: auto; text-align: right; }
  .at-p-status { grid-column: 1 / -1; }
  .at-bar { min-width: 0; }
}
.at-task-od-critical { border-color: #c0392b; box-shadow: 0 0 0 2px rgba(192,57,43,.25); }
.at-task-od-high { border-color: #e08a3c; }

/* batch155c: Director dashboard — the three overdue tiers in one row */
.od-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.od-tile { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 12px; text-decoration: none; font-weight: 600; transition: transform .1s, box-shadow .1s; }
.od-tile:hover { transform: translateY(-1px); box-shadow: 0 3px 10px rgba(0,0,0,.15); }
.od-tile-n { font-size: 30px; font-weight: 800; line-height: 1; min-width: 36px; text-align: center; }
.od-tile-t { font-size: 13.5px; line-height: 1.3; }
.od-tile-critical { background: #c0392b; color: #fff; }
.od-tile-high { background: #ffd9b3; color: #8a3b00; }
.od-tile-warn { background: #fff3cd; color: #8a6100; }
@media (max-width: 760px) { .od-tiles { grid-template-columns: 1fr; } }


/* batch186: hide / show the left menu (desktop; on a phone the hamburger already does this) */
.sb-show-btn { display: none; }
@media (min-width: 761px) {
  html.sb-hidden .sidebar { display: none; }
  html.sb-hidden .sb-show-btn {
    display: inline-flex; align-items: center; justify-content: center;
    position: fixed; top: 12px; left: 12px; z-index: 60; width: 38px; height: 38px;
    background: #000; color: #fff; border: 1px solid rgba(255,255,255,0.25); border-radius: 8px;
    font-size: 18px; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.3);
  }
  .sb-show-btn:hover { background: #222; }
}
@media (max-width: 760px) { .sb-hide-btn { display: none; } }

/* batch227: Feedback/Status / Remark / Note boxes wrap words and grow taller with their content
   (the one-line inputs are swapped for auto-sizing textareas by a script in partials/footer.ejs). */
textarea.wm-wrap-field {
  display: block; width: 100%; box-sizing: border-box; min-height: 0; height: auto;
  resize: none; overflow: hidden; line-height: 1.4;
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: normal;
}
form textarea.wm-wrap-field { min-height: 0; }
.checklist-table textarea.wm-wrap-field, .hosting-table textarea.wm-wrap-field { margin-top: 0; padding: 5px 7px; font-size: 13px; }
/* columns follow the length of the content: Feedback/Status and Remark columns get a fair minimum
   and are allowed to take more room instead of staying a fixed 160px sliver */
.checklist-table th:nth-last-child(3), .checklist-table th:nth-last-child(2) { min-width: 150px; }
.checklist-table th:nth-child(3) { min-width: 160px; }
.checklist-table th:nth-child(4) { min-width: 104px; }
.checklist-table th:nth-child(5), .checklist-table th:nth-child(6), .checklist-table th:nth-child(8) { min-width: 96px; }
.checklist-table th:nth-child(7) { min-width: 58px; }
.checklist-table { min-width: 1000px; }
.table-scroll td, .hosting-table td:last-child { overflow-wrap: anywhere; }
.so-remark { overflow-wrap: anywhere; }
/* read-only remark / note text shown in table cells wraps too */
.fc-remark .fv, .status-remark-text { white-space: pre-wrap; overflow-wrap: anywhere; }

/* batch235 — Recurring Tasks: full-width table, responsive form grid, edit panel as a full-width row */
.table-scroll table.rt-table { width: 100%; min-width: 960px; }
.rt-table td { vertical-align: top; }
.rt-edit-row[hidden] { display: none; }
.rt-edit-row > td { background: var(--card-bg, #fff); padding: 14px 16px; }
.rt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px 16px; align-items: start; margin-bottom: 12px; }
.rt-grid > label, .rt-grid > div > label { display: block; margin: 0; }
.rt-grid .rt-wide { grid-column: 1 / -1; }
.rt-grid input[type=text], .rt-grid input[type=number], .rt-grid select { width: 100%; box-sizing: border-box; }
.rt-days { display: flex; gap: 8px 16px; flex-wrap: wrap; }
.rt-days label { margin: 0; display: flex; align-items: center; gap: 5px; font-weight: 400; }
.rt-days input { width: auto; margin: 0; }
.rt-edit-actions { display: flex; gap: 8px; }
@media (max-width: 700px) { .rt-grid { grid-template-columns: 1fr; } }

/* batch400: locked menu entries (Human Resource / KPI) */
.nav-locked { display:block; padding:8px 12px; margin:2px 0; border-radius:8px; opacity:.7; cursor:not-allowed; font-size:14px; color:#b4b4c0; user-select:none; overflow-wrap:anywhere; }
