/* ============================================================================
   DTTASA Portal — responsive.css
   ----------------------------------------------------------------------------
   Centralised mobile-compatibility rules and shared interaction patterns.
   Loaded from every page via the standard `<link>` block alongside
   `utilities.css` and `style-shim.css`.

   Anything that should look the SAME across pages goes here:
     • Mobile breakpoints + touch-target sizing rules
     • Shared interaction patterns (chat rows, modal sheets, etc.)
     • Pointer/hover capability gates
     • Safe-area insets for iOS standalone PWA

   Anything PAGE-SPECIFIC stays in the page's own `css/<page>.css`.
   Anything PER-ELEMENT-INLINE that was extracted by tools/extract-inline-styles
   lives in `css/style-shim.css` (auto-generated, do not hand-edit).

   Rule of thumb: if the same selector would be useful on three or more pages,
   it belongs here.
   ============================================================================ */


/* ──────────────────────────────────────────────────────────────────────────
   Motion design tokens — enterprise animation vocabulary
   ──────────────────────────────────────────────────────────────────────────
   DTTASA's animation system is built on TWO curves only:
     • --ease-out    : the canonical entrance/exit curve. Decelerates into
                       its final position. Used for every UI entrance,
                       hover lift, sidebar slide, modal open, section
                       transition. If you're animating motion into view,
                       use this.
     • --ease-pulse  : the canonical breathing curve. Symmetric, smoother
                       than browser `ease-in-out` at the same endpoints.
                       Used for every infinite pulse, glow, attention
                       indicator, splash orb drift.

   Duration tokens are reference values. Existing tuned durations may stay
   inline; new code should prefer these tokens. Pulse durations should
   inherit --dur-pulse so we have one place to slow them all down.

   These tokens are declared globally on :root so every page (and every
   per-page css/<page>.css) inherits them. Per-page CSS may override the
   pulse duration locally if a specific surface needs faster/slower
   breathing, but the easing curves should NEVER be overridden — one
   curve vocabulary across the whole portal. */
:root{
  --ease-out:    cubic-bezier(.16,1,.3,1);
  --ease-pulse:  cubic-bezier(.4,0,.6,1);
  --dur-fast:    180ms;
  --dur-base:    280ms;
  --dur-slow:    480ms;
  --dur-pulse:   2400ms;
}

/* ──────────────────────────────────────────────────────────────────────────
   Accessibility — prefers-reduced-motion (WCAG 2.3.3 / vestibular safety)
   ──────────────────────────────────────────────────────────────────────────
   GLOBAL, canonical rule. responsive.css loads on 61/62 pages (incl. the
   public applicant forms that don't load shared-ui.css), so this is the one
   place that guarantees the WHOLE portal honours the OS "Reduce Motion"
   setting. Near-zero (0.01ms, not 0) keeps animationend/transitionend
   listeners + GSAP-adjacent flows firing — so behaviour is preserved, only
   the motion is removed. iteration-count:1 stops the ~380 infinite pulses/
   shimmers. Decorative motion → static; nothing functional breaks. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Battery + perf — pause every running animation while tab is hidden
   ──────────────────────────────────────────────────────────────────────────
   When the user switches tab or backgrounds the app on iOS, infinite pulses
   keep running and burn CPU/GPU/battery for no benefit. We toggle this class
   on <html> via the `visibilitychange` listener wired in `js/early-init.js`
   (loaded on every page). The * selector is only paid for when the class is
   present — on a visible tab the rule never matches. */
html.dttasa-tab-hidden *,
html.dttasa-tab-hidden *::before,
html.dttasa-tab-hidden *::after {
  animation-play-state: paused !important;
}

/* ──────────────────────────────────────────────────────────────────────────
   audit A1 — Re-animation jank guard.
   ──────────────────────────────────────────────────────────────────────────
   Board lists render items with a staggered entry animation applied inline
   (`animation:wgIn|pIn|scIn .3s … ${i*.05}s both`). Because the list is rebuilt
   via innerHTML inside every onSnapshot callback, those entry animations REPLAY
   on each data change — the whole list flickers/re-staggers. There is no shared
   render layer to gate, so once the page has settled we neutralise ONLY those
   staggered list-item entry keyframes (a stylesheet `!important` overrides the
   non-important inline `animation`). Newly-arriving rows then just appear without
   the stagger replay. Scope is deliberately narrow: modal/overlay entrances
   (fadeIn/slideIn/mIn) and every infinite pulse (blink/obActionPulse/…) are
   untouched, and the first paint (before `anims-settled`) animates normally.
   The class is added ~1.2s after load by js/early-init.js. */
body.dttasa-anims-settled [style*="animation:wgIn"],
body.dttasa-anims-settled [style*="animation: wgIn"],
body.dttasa-anims-settled [style*="animation:pIn"],
body.dttasa-anims-settled [style*="animation: pIn"],
body.dttasa-anims-settled [style*="animation:scIn"],
body.dttasa-anims-settled [style*="animation: scIn"] {
  animation: none !important;
}

/* ──────────────────────────────────────────────────────────────────────────
   Navigation-trail chip (audit R4) — "‹ Back to «prior page»"
   ──────────────────────────────────────────────────────────────────────────
   Injected into .hdr-left by js/nav-trail.js when the user arrived from a
   known non-dashboard same-origin page. Complements the Home button; glass/
   token styling to match .hdr-back-btn. Label hides at ≤640px (icon-only),
   matching the portal's existing header-compaction convention. */
.nav-trail-chip{
  display:inline-flex; align-items:center; gap:6px;
  padding:6px 12px; border-radius:8px;
  background:var(--panel); border:1px solid var(--border);
  font:inherit; font-size:12px; color:var(--t3); cursor:pointer;
  white-space:nowrap; max-width:220px;
  transition:background .25s var(--ease-out,ease), border-color .25s, color .25s;
}
.nav-trail-chip:hover{ background:var(--panel2); border-color:var(--bord2,var(--border)); color:var(--text); }
.nav-trail-chip span{ overflow:hidden; text-overflow:ellipsis; }
.nav-trail-chip i{ font-size:11px; opacity:.8; }
@media (max-width:640px){ .nav-trail-chip span{ display:none; } .nav-trail-chip{ max-width:none; } }

/* ──────────────────────────────────────────────────────────────────────────
   Keyboard focus ring — accessibility + design-system parity
   ──────────────────────────────────────────────────────────────────────────
   Browser default focus rings (blue Chrome outline) clash with the gold/glass
   visual language. Use `:focus-visible` so the ring appears ONLY when the
   user is keyboard-navigating, never on mouse clicks. The outline-offset +
   transition give the same gold-glow feel as hover, animated in 180ms.

   `outline` is used (not `box-shadow`) so it never clips at container edges
   and never shifts layout. Applies to every interactive surface used by the
   portal — buttons, nav items, form fields, anything tabbable. */
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.btn:focus-visible,
.mi:focus-visible,
.gi:focus-visible,
.gi-ta:focus-visible,
.ig:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--gold, #f0c832);
  outline-offset: 2px;
  transition: outline-offset 180ms var(--ease-out, cubic-bezier(.16,1,.3,1)),
              outline-color  180ms var(--ease-out, cubic-bezier(.16,1,.3,1));
}

/* Remove the legacy non-visible focus ring so mouse clicks don't trigger it. */
button:focus:not(:focus-visible),
a:focus:not(:focus-visible),
input:focus:not(:focus-visible),
select:focus:not(:focus-visible),
textarea:focus:not(:focus-visible),
.btn:focus:not(:focus-visible) {
  outline: none;
}

/* ──────────────────────────────────────────────────────────────────────────
   View Transition API — cross-page navigation cross-fade
   ──────────────────────────────────────────────────────────────────────────
   `js/early-init.js` `_navWithTransition` wraps every `dttasaNav.go/home/
   pageHome/back` call with `document.startViewTransition` on supporting
   browsers (Chrome 111+, iOS Safari 18+). These pseudo-elements style the
   outgoing/incoming root snapshots — same easing token used throughout the
   portal so cross-page nav feels native instead of "flash to white".

   Unsupported browsers skip the wrapper and behave identically to before
   (hard navigation) — graceful degradation. */
/* R5 (2026-05-30) — MODERN cross-document View Transitions. The single
   line below opts every same-origin full-page navigation (links, raw
   location.href, back/forward) into a native browser cross-fade — the
   Vercel/Linear page-fade aesthetic, NO JS wrapper. responsive.css loads
   in <head> on 61/62 pages, so the opt-in is present on both the outgoing
   and incoming document (required for cross-doc VT). Unsupported browsers
   (Firefox, Safari <18.2) ignore this at-rule and hard-cut exactly as
   before — pure progressive enhancement. */
@view-transition { navigation: auto; }

@supports (view-transition-name: root) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 220ms;
    animation-timing-function: var(--ease-out, cubic-bezier(.16,1,.3,1));
  }
}

/* Reduced-motion: the global `*` reduced-motion rule does NOT match the
   ::view-transition-* pseudo-elements (they're outside the document tree),
   so the page-fade must be disabled explicitly here for users who request
   reduced motion (WCAG 2.3.3 / vestibular safety). Navigation still works —
   it just hard-cuts instead of cross-fading. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   Skel → content arrival fade-up via @starting-style
   ──────────────────────────────────────────────────────────────────────────
   When async data lands and JS replaces a skeleton placeholder with the real
   element (typically activity-stream rows, applicant cards, recruitment
   pipeline tiles, EOM cards, broadcast list items, etc.) the new node
   should not snap in — it should fade up to feel "settled".

   `@starting-style` defines the initial-render values for a freshly inserted
   element. The browser then transitions to the rule's normal values using
   the listed `transition` properties. Pure CSS — fires automatically the
   moment the element enters the DOM. No JS observers, no MutationObserver,
   no per-callsite changes.

   Support: Chrome 117+ (Sept 2023), Firefox 129+ (Aug 2024), Safari 17.5+
   (May 2024). Older browsers ignore the rule and elements appear instantly
   — graceful degradation, no broken state.

   Convention: any new content surface that should arrive-fade-up adds the
   `.dttasa-arrive` class on its child elements (or use one of the named
   selectors below for surfaces already in production). */
@supports (transition-behavior: allow-discrete) {
  .ab-item,
  .dttasa-arrive {
    opacity: 1;
    transform: translateY(0);
    transition: opacity 240ms var(--ease-out, cubic-bezier(.16,1,.3,1)),
                transform 240ms var(--ease-out, cubic-bezier(.16,1,.3,1));
  }
  @starting-style {
    .ab-item,
    .dttasa-arrive {
      opacity: 0;
      transform: translateY(8px);
    }
  }
}


/* ──────────────────────────────────────────────────────────────────────────
   Touch-target minimums
   ──────────────────────────────────────────────────────────────────────────
   CLAUDE.md mandate: every tappable element must have a ≥44×44 hit area
   on touch devices. Use `.touch-target` as a wrapper class on small icons
   that don't naturally meet that size — invisible padding extends the tap
   zone without growing the visible footprint. */
.touch-target{
  min-width:44px;min-height:44px;
  display:inline-flex;align-items:center;justify-content:center;
}


/* ──────────────────────────────────────────────────────────────────────────
   Chat message row, delete control, and read-receipt meta line
   ──────────────────────────────────────────────────────────────────────────
   Used by the dashboard chat on index.html. Defined here (not in
   `css/index.css`) so the same look applies to any other future page that
   reuses these classes (e.g. an HR-Ops chat side-panel, a comms inbox). */
.chat-msg-row{padding:3px 0;}
.chat-msg-meta{
  display:flex;align-items:center;gap:4px;
  font-size:9px;color:var(--t3);margin-top:3px;
}
.chat-msg-meta .fa-check,
.chat-msg-meta .fa-check-double{font-size:10px;}
.chat-msg-del{
  /* Visually small (icon ~11px) but the button itself is a 44×44 touch
     target via padding — meets the touch-target rule above. The
     transparent excess area is invisible. */
  appearance:none;background:transparent;border:0;cursor:pointer;
  color:var(--red);opacity:.55;
  width:44px;height:44px;padding:0;margin:-12px -10px -12px 2px;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:11px;transition:opacity .15s,color .15s;
}
.chat-msg-del:hover,.chat-msg-del:focus{opacity:1;color:var(--red);outline:none;}

/* Desktop with a real pointer: keep the original "appears on hover" feel so
   the chat doesn't look cluttered. Mobile / touch always shows it. */
@media (hover:hover) and (pointer:fine){
  .chat-msg-del{opacity:0;transition:opacity .15s;}
  .chat-msg-row:hover .chat-msg-del{opacity:.7;}
  .chat-msg-row:hover .chat-msg-del:hover{opacity:1;}
}


/* ──────────────────────────────────────────────────────────────────────────
   Safe-area insets — iOS standalone PWA
   ──────────────────────────────────────────────────────────────────────────
   Pages can opt-in by adding `.safe-bottom` to a sticky footer or
   `.safe-top` to a sticky header. Avoids the iOS home-indicator overlap. */
.safe-bottom{padding-bottom:max(12px,env(safe-area-inset-bottom));}
.safe-top{padding-top:max(0px,env(safe-area-inset-top));}


/* ──────────────────────────────────────────────────────────────────────────
   Mobile readability — minimum legible font sizes on phones
   ──────────────────────────────────────────────────────────────────────────
   Users reported text was straining their eyes on mobile (2026-05-18).
   The CLAUDE.md tokens (13/14/15/18 px) are reasonable on desktop but feel
   tight on a 320–540 px phone screen. We bump common small-text patterns
   up by 1–2 px below the 540 px breakpoint, and force inputs to 16 px so
   iOS Safari stops auto-zooming when a field is focused.

   Targeted bumps only — we don't blanket-resize the document, which would
   knock card layouts off their grids. Selectors aim at the small-text
   classes used across pages.

   Cascade: these rules carry `!important` because the inline shim classes
   (`.s-…`) generated by `tools/extract-inline-styles.mjs` ALSO carry
   `!important` (they had to, to preserve the original inline-style
   priority). Without `!important` here the per-element shim wins and our
   mobile-readability bumps silently fail. */

@media (max-width:540px){
  /* Base body text — bump conservatively. */
  body{font-size:14px !important;}

  /* Form inputs — 16 px is the iOS Safari threshold below which Safari
     auto-zooms when the field receives focus. That zoom is jarring on a
     PWA where the viewport is meta-locked. 16 px on textareas + inputs
     stops it cold. */
  input, textarea, select, button{font-size:16px !important;}

  /* Common small-text utility / pattern classes used across pages. */
  .u-fs9-13, .u-fs10, .u-fs11{font-size:13px !important;}
  .u-fs12, .u-fs13{font-size:14px !important;}

  /* Labels, captions, helper text. */
  label, .label, .mlbl, .form-label, .field-label,
  .form-hint, .form-help, .helper-text, .helper, small{font-size:13px !important;}

  /* Table cells and key/value pair rows. */
  td, th, .dtbl td, .dtbl th, .cell, .row-meta{font-size:13px !important;}

  /* Badges and pill chips can stay slightly smaller but not tiny. */
  .pip, .sbadge, .pill, .chip, .tag{font-size:12px !important;}

  /* Section / panel headings. */
  .sec-head, .panel-title, .card-title{font-size:16px !important;}
  h1{font-size:22px !important;}
  h2{font-size:19px !important;}
  h3{font-size:17px !important;}
  h4, h5, h6{font-size:15px !important;}

  /* Chat message bubbles + meta line (centralised above) — keep readable. */
  .chat-msg-meta{font-size:11px !important;}
  .chat-msg-meta .fa-check,
  .chat-msg-meta .fa-check-double{font-size:12px !important;}
}

@media (max-width:400px){
  /* Slightly more aggressive on very small phones. */
  body{font-size:14.5px !important;}
  h1{font-size:21px !important;}
  h2{font-size:18px !important;}
}


/* ──────────────────────────────────────────────────────────────────────────
   Apply Credit to Cell — published shift action (SA / Head of HR only)
   ──────────────────────────────────────────────────────────────────────────
   Small gold "hand holding dollar" icon in the corner of every published
   timed-shift cell. Opens a modal that draws N hours from the user's
   banked credit and shortens the published shift by N hours. */
.cell-apply-credit-btn{
  position:absolute;top:4px;right:4px;z-index:3;
  width:22px;height:22px;border-radius:6px;
  appearance:none;cursor:pointer;
  background:rgba(212,175,55,.12);border:1px solid rgba(212,175,55,.35);
  color:var(--gold,#f0c832);
  display:inline-flex;align-items:center;justify-content:center;
  font-size:11px;transition:.15s;opacity:.0;
}
.alloc-cell{position:relative;}
.alloc-cell:hover .cell-apply-credit-btn,
.cell-apply-credit-btn:focus{opacity:1;}
.cell-apply-credit-btn:hover{background:rgba(212,175,55,.28);border-color:var(--gold,#f0c832);}
@media (hover:none){
  /* Touch devices — always-visible at lower opacity so admins can tap. */
  .cell-apply-credit-btn{opacity:.85;width:26px;height:26px;font-size:12px;}
}

.cellc-modal-overlay{
  position:fixed;inset:0;z-index:99999;
  background:rgba(10,14,8,.85);backdrop-filter:blur(10px);
  display:flex;align-items:center;justify-content:center;padding:24px;
  font-family:'DM Sans',sans-serif;
}
.cellc-modal-card{
  background:#172213;border:1px solid var(--gold,#f0c832);border-radius:14px;
  max-width:540px;width:100%;color:var(--text,#f2f7ee);
  box-shadow:0 24px 60px rgba(0,0,0,.5);
}
.cellc-modal-head{padding:22px 24px 14px;border-bottom:1px solid var(--border,rgba(255,255,255,.21));}
.cellc-modal-title{font-family:'Cinzel',serif;font-size:15px;letter-spacing:2.5px;color:var(--gold,#f0c832);margin-bottom:8px;}
.cellc-modal-sub{font-size:13px;color:var(--t2,rgba(242,247,238,.88));line-height:1.55;}
.cellc-modal-body{padding:18px 24px;}
.cellc-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;font-size:13px;}
.cellc-row span:first-child{color:var(--t3,rgba(242,247,238,.62));}
.cellc-mono{font-family:'IBM Plex Mono',monospace;color:var(--text,#f2f7ee);}
.cellc-credit{color:var(--green,#4cd657);font-weight:700;}
.cellc-dim{color:var(--t3,rgba(242,247,238,.62));font-weight:400;}
.cellc-input-row{margin:14px 0 8px;display:flex;flex-direction:column;gap:6px;}
.cellc-input-row label{font-size:12px;color:var(--t2,rgba(242,247,238,.88));font-weight:600;}
.cellc-input-row input{
  appearance:none;background:rgba(255,255,255,.08);border:1px solid var(--border,rgba(255,255,255,.21));
  border-radius:8px;padding:10px 12px;font-size:16px;color:var(--text,#f2f7ee);
  font-family:'IBM Plex Mono',monospace;
}
.cellc-input-row input:focus{outline:none;border-color:var(--gold,#f0c832);background:rgba(212,175,55,.08);}
.cellc-preview{
  background:rgba(212,175,55,.08);border:1px solid rgba(212,175,55,.3);
  border-radius:8px;padding:10px 12px;font-size:13px;line-height:1.5;
  color:var(--text,#f2f7ee);margin-bottom:14px;
}
.cellc-label{display:block;font-size:12px;color:var(--t2,rgba(242,247,238,.88));font-weight:600;margin-bottom:6px;}
.cellc-modal-body textarea{
  width:100%;background:rgba(255,255,255,.06);border:1px solid var(--border,rgba(255,255,255,.21));
  border-radius:8px;padding:10px 12px;font-size:14px;color:var(--text,#f2f7ee);
  font-family:'DM Sans',sans-serif;resize:vertical;min-height:60px;
  box-sizing:border-box;
}
.cellc-modal-body textarea:focus{outline:none;border-color:var(--gold,#f0c832);}
.cellc-err{color:var(--red,#ff4848);font-size:12px;margin-top:8px;min-height:18px;}
.cellc-modal-actions{
  padding:14px 24px 20px;border-top:1px solid var(--border,rgba(255,255,255,.21));
  display:flex;gap:12px;justify-content:flex-end;
}
.cellc-modal-actions .btn{min-width:120px;}

/* ──────────────────────────────────────────────────────────────────────────
   Required-field error shake — reusable highlight for inputs/textareas
   that fail validation. The shake makes the warning unmissable; the red
   border + tinted background is applied inline so it stays visible after
   the animation ends (until the user starts typing again). */
.field-error-shake{
  animation: dttasa-shake-x 0.45s cubic-bezier(.36,.07,.19,.97);
}
@keyframes dttasa-shake-x {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); }
  40%, 60% { transform: translateX(4px); }
}

/* Cell-credit modal error text — keep loud + bold so the warning isn't
   easily missed under the textarea. */
.cellc-err{font-weight:600;}

/* ──────────────────────────────────────────────────────────────────────────
   HR-view back button — visible only when public referee/HR-detail forms
   open in Capacitor PWA (window.open(_blank) routes to the same view in
   iOS WebView, leaving the HR user stranded without a navigation chrome).
   The button is positioned top-left, gold-on-dark, easy to thumb-tap. */
.rf-hr-back-btn{
  position:fixed;top:max(16px,env(safe-area-inset-top));left:16px;z-index:9999;
  display:inline-flex;align-items:center;gap:8px;
  padding:10px 16px;border-radius:10px;
  background:rgba(212,175,55,.18);color:var(--gold,#f0c832);
  text-decoration:none;font-weight:700;font-size:13px;
  border:1px solid rgba(212,175,55,.4);
  box-shadow:0 6px 18px rgba(0,0,0,.35);
  font-family:'DM Sans',sans-serif;
  transition:.15s;
}
.rf-hr-back-btn:hover,.rf-hr-back-btn:focus{
  background:rgba(212,175,55,.32);
  outline:none;
  transform:translateY(-1px);
}
@media (max-width:540px){
  .rf-hr-back-btn{padding:9px 12px;font-size:12px;}
  .rf-hr-back-btn span{display:none;}
}

/* ──────────────────────────────────────────────────────────────────────────
   HR-decision radio rows — applicant-ref-details-form
   The labels have class `.s-rpubrhw` (hashed from Phase 4 extractor).
   When a radio inside is checked, highlight the parent label so the user
   has clear visual feedback for their selection. Uses :has() — supported
   on all modern Chromium / Safari / Firefox versions on the target users'
   devices (iOS Safari ≥ 15.4). */
label.s-rpubrhw:has(input[type="radio"]:checked){
  background:rgba(212,175,55,.10) !important;
  border-color:rgba(212,175,55,.55) !important;
  box-shadow:0 0 0 2px rgba(212,175,55,.18), inset 0 1px 0 rgba(255,255,255,.06) !important;
}
label.s-rpubrhw:has(input[type="radio"]:checked) strong{
  text-shadow:0 0 8px rgba(212,175,55,.25);
}
label.s-rpubrhw:has(input[type="radio"][value="approve"]:checked){
  background:rgba(34,197,94,.12) !important;
  border-color:rgba(34,197,94,.5) !important;
  box-shadow:0 0 0 2px rgba(34,197,94,.18) !important;
}
label.s-rpubrhw:has(input[type="radio"][value="reject"]:checked){
  background:rgba(239,68,68,.12) !important;
  border-color:rgba(239,68,68,.5) !important;
  box-shadow:0 0 0 2px rgba(239,68,68,.18) !important;
}
label.s-rpubrhw:has(input[type="radio"][value="more-info"]:checked){
  background:rgba(245,158,11,.12) !important;
  border-color:rgba(245,158,11,.5) !important;
  box-shadow:0 0 0 2px rgba(245,158,11,.18) !important;
}
label.s-rpubrhw{transition:background .2s, border-color .2s, box-shadow .2s;}

/* "Credit already applied" status pill — replaces the Apply Credit button
   on a draft-week row once a credit application is on file for this week.
   Non-interactive (no button), green-tinted to communicate "done". */
.rec-applied-status{
  display:inline-flex;align-items:center;gap:6px;
  font-size:11px;font-weight:600;
  background:rgba(76,214,87,.10);
  border:1px solid rgba(76,214,87,.32);
  color:var(--green,#4cd657);
  padding:5px 10px;border-radius:6px;
}
.rec-applied-status i{font-size:11px;}
@media (max-width:540px){
  .cellc-modal-card{max-width:calc(100vw - 32px);}
  .cellc-modal-actions{flex-direction:column-reverse;}
  .cellc-modal-actions .btn{width:100%;}
}

/* ════════════════════════════════════════════════════════════════
   Centralised mobile button sizing.
   ════════════════════════════════════════════════════════════════
   Per-page CSS had a habit of bricking every action button to
   width:100% + min-height:44px on small viewports, which produced
   the "really big buttons" feel — three actions per card became
   three full-width 50px-tall blocks.

   Standardise: on ≤640px, action buttons flex-fit their content,
   wrap to a second line only when they overflow, and have a
   comfortable but not oversized min-height. Pages can still force
   width:100% on specific containers (modal CTAs, hero buttons)
   where it's the right call.
   ════════════════════════════════════════════════════════════════ */
@media (max-width:640px){
  /* Default touch sizing — 38px clears Apple HIG 44pt minimum once
     padding is added. Use !important sparingly: only on the size to
     beat per-page 44px overrides that drove the oversized feel.
     Padding + font-size also tighten because the base portal-wide
     `.btn` is a chunky pill (padding:13px 26px; letter-spacing:2px)
     that reads too large on iPhone. */
  body .btn:not(.btn-xs):not(.btn-sm){
    min-height:38px;
    padding:8px 16px!important;
    font-size:11px!important;
    letter-spacing:1.2px!important;
  }
  body .btn-sm{
    min-height:32px;
    padding:6px 12px!important;
    font-size:10.5px!important;
    letter-spacing:.9px!important;
  }
  body .btn-xs{
    min-height:26px;
    padding:4px 9px!important;
    font-size:10px!important;
    letter-spacing:.6px!important;
  }
  /* Section header utility classes use `.sec-lbl` for the title and a
     hashed flex-row container. Tighten the title font on mobile so the
     "ADD NOTE" gold button doesn't look bigger than the heading. */
  body .sec-lbl{font-size:13px;letter-spacing:1.2px;}

  /* Generic action-row pattern across the portal: any flex/grid row
     of buttons that previously forced full-width stacking gets a
     side-by-side flex-wrap behaviour instead. Buttons grow but never
     stretch to the full row alone. */
  body .card-actions:not(.btn-full-row),
  body .action-row:not(.btn-full-row),
  body .row-actions:not(.btn-full-row),
  body .actions:not(.btn-full-row),
  body .action-bar:not(.btn-full-row){
    display:flex!important;
    flex-wrap:wrap;
    gap:6px;
  }
  body .card-actions:not(.btn-full-row) .btn,
  body .action-row:not(.btn-full-row)  .btn,
  body .row-actions:not(.btn-full-row) .btn,
  body .actions:not(.btn-full-row)     .btn{
    flex:1 1 auto;
    min-width:fit-content;
    width:auto;
    justify-content:center;
  }
  /* Rota-style action bars: don't let buttons grow to fill the row —
     they look oversized on mobile when only 1–2 buttons are visible.
     Keep content-width so the "Publish" / "Save Draft" pills sit at
     their natural compact size. */
  body .action-bar:not(.btn-full-row) .btn{
    flex:0 1 auto;
    min-width:fit-content;
    width:auto;
    justify-content:center;
  }
}

/* ════════════════════════════════════════════════════════════════
   Centralised notification-panel overflow guard.
   Header bells across the portal (#notif-panel on IT board, .sys-
   notif-panel on dashboards, etc.) are absolute-positioned to the
   bell button itself. The bell typically sits mid-header on mobile,
   so a 310-320px panel extending in either direction overflows the
   viewport — half the panel is off-screen and the user can't read
   it. Switch to `position:fixed` on small viewports so the panel
   docks to the viewport edge with a viewport-wide max-width.
   ════════════════════════════════════════════════════════════════ */
@media (max-width:820px){
  body .notif-panel,
  body #notif-panel,
  body .sys-notif-panel,
  body #sys-notif-panel{
    position:fixed!important;
    top:calc(var(--hdh, 66px) + 8px)!important;
    right:10px!important;
    left:10px!important;
    width:auto!important;
    max-width:calc(100vw - 20px)!important;
    max-height:calc(100vh - var(--hdh, 66px) - 24px)!important;
    overflow-y:auto;
  }
}

/* ════════════════════════════════════════════════════════════════
   PORTAL-WIDE SCROLLBAR — wider, contrasting, never-disappearing
   ────────────────────────────────────────────────────────────────
   Default macOS / iOS scrollbars are 5–8px wide and auto-hide, which
   made the page scrollbar nearly invisible and hard to grab. These
   rules apply to every page that uses the document scroll plus any
   overflow:auto container that doesn't explicitly opt out via
   `scrollbar-width: none`. Pages that hide scrollbars on purpose
   (eg. .ac-nav, hidden chat lists) keep their override because
   inline `scrollbar-width: none` has higher specificity than these
   defaults.
   ════════════════════════════════════════════════════════════════ */
:root{
  /* Reusable tokens so individual pages can theme via these vars */
  --diag-scroll-w:        12px;
  --scroll-thumb-bg:      rgba(240,200,50,0.32);
  --scroll-thumb-hover:   rgba(240,200,50,0.55);
  --scroll-thumb-active:  rgba(240,200,50,0.78);
  --scroll-track-bg:      rgba(0,0,0,0.20);
}
/* Firefox + future-standard */
*{
  scrollbar-width: auto;
  scrollbar-color: var(--scroll-thumb-bg) var(--scroll-track-bg);
}
/* Honour explicit hide-the-scrollbar opt-outs */
[style*="scrollbar-width: none"],
[style*="scrollbar-width:none"]{ scrollbar-width: none; }

/* WebKit (Chrome / Safari / Edge / Capacitor WKWebView) */
*::-webkit-scrollbar{
  width:  var(--diag-scroll-w);
  height: var(--diag-scroll-w);
}
*::-webkit-scrollbar-track{
  background: var(--scroll-track-bg);
  border-radius: 12px;
}
*::-webkit-scrollbar-thumb{
  background: var(--scroll-thumb-bg);
  border-radius: 12px;
  border: 2px solid transparent;
  background-clip: padding-box;
  transition: background .25s ease;
  min-height: 40px;     /* prevents a single tiny page from giving a 12px-tall thumb */
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--scroll-thumb-hover);
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:active {
  background: var(--scroll-thumb-active);
  background-clip: padding-box;
}
*::-webkit-scrollbar-corner { background: transparent; }
/* Touch / mobile — slightly narrower so it doesn't cover content but still grabbable */
@media (max-width: 540px){
  :root{ --diag-scroll-w: 10px; }
}
@media (hover: none){
  /* On touch devices the thumb defaults higher-contrast since hover never fires */
  *::-webkit-scrollbar-thumb{ background: var(--scroll-thumb-hover); background-clip: padding-box; }
}

/* ════════════════════════════════════════════════════════════════
   MODAL CLOSE (X) BUTTON — enterprise 44×44 touch target
   ────────────────────────────────────────────────────────────────
   Page-level CSS sized close buttons at 30/32/34px which is below
   Apple/Material's 44px minimum target. The result: users often
   missed the X and clicked the backdrop, or the press had no
   visible feedback. These rules apply portal-wide AND override
   smaller per-page rules via :not() / higher specificity where
   needed (the `body &` prefix wins the cascade for stand-alone
   class selectors of equal weight).
   ════════════════════════════════════════════════════════════════ */
/* ════════════════════════════════════════════════════════════════
   X-button overlap protection — every modal title / sub-title in
   the portal must clear the absolute-positioned close button on
   the top-right (44px wide, 14px from the right edge → reserve
   66px clear). Without this rule the title text extends under the
   X and clicks on the title's right edge can register on the X.
   Applies portal-wide so any new modal automatically gets the
   protection. Universal — no per-page exceptions.
   ════════════════════════════════════════════════════════════════ */
/* 2026-05-28 — bumped reserve from 72px → 88px. The X is 44px wide at
   right:16px → occupies 60px of right-edge real estate. 72px gave only
   12px of breathing room; on the coordinator volunteer drawer the modal
   title shows the user's full name with a leading icon and that 12px gap
   wasn't enough. 88px gives a comfortable 28px buffer that visibly clears
   on every modal in the portal. Mobile bumps to 76px (X grows to 46×46
   per the rule at line 637 → 62px of edge real estate). */
body .modal-box .modal-title,
body .modal-box .modal-sub,
body .modal-box .mhr-modal-title,
body .modal-box .mhr-modal-sub,
body .modal-box .pres-modal-title,
body .modal-box .sd-modal-title,
body .modal-box .hpr-modal-title,
body .modal-box .ov-modal-title,
body .modal-box [data-modal-title],
body .modal-overlay .modal-title,
body .modal-overlay .modal-sub,
body .modal-box .modal-hd,
body .modal-box .drawer-title,
body .modal-box .drawer-sub {
  padding-right: 88px;
  box-sizing: border-box;
}
/* Defensive body-content protection — any first-child inside the modal
   bodies that might extend a hero / banner up to where the X sits gets
   the same right-edge reserve. Coordinator + VMEM detail drawers have
   hero blocks with names + avatars + status pips that can otherwise
   crowd the X on narrow widths. */
body #coord-vd-body, body #coord-td-body, body #vm-td-body,
body #coord-vd-body > .vd-hero, body #coord-vd-body > .vd-hero:first-child,
body .modal-box .vd-hero:first-child,
body .modal-box [class*="-hero"]:first-child {
  box-sizing: border-box;
}
body .modal-box .vd-hero:first-child,
body .modal-box [class*="-hero"]:first-child {
  padding-right: 72px;
}
/* X close button — explicit z-index so any scrolling body content or
   absolutely-positioned hero pip can never overlap on top of it. */
body .modal-close,
body .mhr-modal-close,
body .pres-modal-close,
body .sd-close,
body .hpr-close,
body .ov-close,
body .diag-detail-modal-close,
body .x-close,
body .modal-x,
body [data-modal-close],
body .btn-close,
body .close-btn {
  z-index: 6;
}
/* Body content tables — ensure the first row in the training-detail modal
   never sits flush against the title row where the X lives. */
body #coord-td-body table.coord-td-table,
body #vm-td-body table.coord-td-table {
  margin-top: 4px;
}
@media (max-width: 540px) {
  body .modal-box .modal-title,
  body .modal-box .modal-sub,
  body .modal-box .mhr-modal-title,
  body .modal-box .mhr-modal-sub,
  body .modal-box .pres-modal-title,
  body .modal-box .sd-modal-title,
  body .modal-box .hpr-modal-title,
  body .modal-box .ov-modal-title,
  body .modal-box [data-modal-title],
  body .modal-overlay .modal-title,
  body .modal-overlay .modal-sub,
  body .modal-box .modal-hd,
  body .modal-box .drawer-title,
  body .modal-box .drawer-sub {
    padding-right: 76px;
  }
  body .modal-box .vd-hero:first-child,
  body .modal-box [class*="-hero"]:first-child {
    padding-right: 60px;
  }
}

/* Position DEFAULT — low specificity (0,1,0), deliberately NOT `body`-prefixed.
   Read-audit 2026-05-30: `position: relative` previously lived INSIDE the
   high-specificity `body .modal-close{}` block below (0,1,1) and overrode every
   page's own `.modal-close{position:absolute;top;right}` (0,1,0), so corner-X
   buttons across the whole portal dropped into normal flow and collided with the
   modal title (VMEM, comms, exec, hr-ops, leave, ops-dashboard, sa-control,
   it-board, grant, sggrant, all-org-doc, …). Declaring the default here at
   (0,1,0) lets each page's own absolute placement win the specificity tie (page
   CSS loads after responsive.css), fixing every corner modal at once — while
   flex-header X buttons that set NO page position (safeguarding `.modal-hdr`,
   volunteer-board welfare drawer) keep `relative` and stay correct in their flex
   row. The ::after touch-pad has a positioned parent either way. */
.modal-close,
.mhr-modal-close,
.pres-modal-close,
.sd-close,
.hpr-close,
.ov-close,
.diag-detail-modal-close,
.x-close,
.modal-x,
[data-modal-close],
.btn-close,
.close-btn {
  position: relative;
}

body .modal-close,
body .mhr-modal-close,
body .pres-modal-close,
body .sd-close,
body .hpr-close,
body .ov-close,
body .diag-detail-modal-close,
body .x-close,
body .modal-x,
body [data-modal-close],
body .btn-close,
body .close-btn{
  min-width: 44px;
  min-height: 44px;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: background .2s ease, color .2s ease, transform .12s ease, border-color .2s ease;
}
/* Invisible touch-pad that extends the hit-box another 4px each side so
   tapping near (not on) the X still registers. Doesn't expand visible
   chrome, only the hit area. */
body .modal-close::after,
body .mhr-modal-close::after,
body .pres-modal-close::after,
body .sd-close::after,
body .hpr-close::after,
body .ov-close::after,
body .diag-detail-modal-close::after,
body .x-close::after,
body .modal-x::after,
body [data-modal-close]::after,
body .btn-close::after,
body .close-btn::after{
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: inherit;
}
/* Press feedback so the user knows the tap landed even on slow networks */
body .modal-close:active,
body .mhr-modal-close:active,
body .pres-modal-close:active,
body .sd-close:active,
body .hpr-close:active,
body .ov-close:active,
body .diag-detail-modal-close:active,
body .x-close:active,
body .modal-x:active,
body [data-modal-close]:active,
body .btn-close:active,
body .close-btn:active{
  transform: scale(0.92);
  background: rgba(255,72,72,0.18);
  color: #ff5773;
}
/* Hover state on devices that have one */
@media (hover: hover){
  body .modal-close:hover,
  body .mhr-modal-close:hover,
  body .pres-modal-close:hover,
  body .sd-close:hover,
  body .hpr-close:hover,
  body .ov-close:hover,
  body .diag-detail-modal-close:hover,
  body .x-close:hover,
  body .modal-x:hover,
  body [data-modal-close]:hover,
  body .btn-close:hover,
  body .close-btn:hover{
    background: rgba(255,72,72,0.14);
    color: #ff7088;
    border-color: rgba(255,72,72,0.45);
  }
}
/* Mobile — slightly bigger so it's unmissable on small screens */
@media (max-width: 540px){
  body .modal-close,
  body .mhr-modal-close,
  body .pres-modal-close,
  body .sd-close,
  body .hpr-close,
  body .ov-close,
  body .diag-detail-modal-close,
  body .x-close,
  body .modal-x,
  body [data-modal-close],
  body .btn-close,
  body .close-btn{
    min-width: 46px;
    min-height: 46px;
    width: 46px;
    height: 46px;
    font-size: 19px;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   WEATHER CHIP — shared component for index + dept dashboard headers.
   Source: js/weather-chip.js (calls getWeather Cloud Function).
   ──────────────────────────────────────────────────────────────────────── */
.weather-chip-slot {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.wch-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 36px;
  padding: 0 12px 0 11px;
  background: rgba(212,175,55,.08);
  border: 1px solid rgba(212,175,55,.28);
  border-radius: 999px;
  color: #f0c832;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .3px;
  cursor: pointer;
  transition: background .25s cubic-bezier(.16,1,.3,1), border-color .25s, transform .25s;
  -webkit-tap-highlight-color: transparent;
}
.wch-pill:hover {
  background: rgba(212,175,55,.16);
  border-color: rgba(212,175,55,.55);
  transform: translateY(-1px);
}
.wch-pill i { font-size: 13px; }
.wch-temp { line-height: 1; }
.wch-pill-error {
  background: rgba(255,72,72,.08);
  border-color: rgba(255,72,72,.3);
  color: #ff4848;
  cursor: default;
}
.wch-pill-loading {
  background: rgba(255,255,255,.05);
  border-color: rgba(255,255,255,.18);
  color: rgba(242,247,238,.6);
  cursor: default;
}
.wch-pop {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 200px;
  max-width: 280px;
  background: #0d150c;
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 14px;
  padding: 14px 16px;
  box-shadow: 0 20px 48px rgba(0,0,0,.55);
  z-index: 1200;
  display: none;
  animation: wchPopIn .22s cubic-bezier(.16,1,.3,1);
}
.wch-pop.open { display: block; }
@keyframes wchPopIn {
  from { opacity: 0; transform: translateY(-6px) scale(.97); }
  to   { opacity: 1; transform: none; }
}
.wch-pop-loc {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: rgba(240,200,50,.85);
  margin-bottom: 10px;
}
.wch-pop-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 11px;
  margin-bottom: 11px;
  border-bottom: 1px solid rgba(255,255,255,.07);
}
.wch-pop-icon {
  font-size: 28px;
  color: #f0c832;
  width: 32px; text-align: center;
}
.wch-pop-temp {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 22px;
  font-weight: 700;
  color: #f2f7ee;
  line-height: 1;
}
.wch-pop-cond {
  font-size: 12px;
  color: rgba(242,247,238,.7);
  margin-top: 4px;
}
.wch-pop-meta {
  display: flex; gap: 14px; flex-wrap: wrap;
  font-size: 11.5px;
  color: rgba(242,247,238,.7);
  margin-bottom: 9px;
}
.wch-pop-meta i { color: rgba(212,175,55,.7); margin-right: 4px; }
.wch-pop-foot {
  font-size: 10.5px;
  color: rgba(242,247,238,.45);
  letter-spacing: .3px;
}

@media (max-width: 640px) {
  .wch-pill {
    height: 34px;
    padding: 0 10px;
    font-size: 12px;
  }
  .wch-pop {
    right: -8px;
    min-width: 220px;
    max-width: calc(100vw - 28px);
  }
}
@media (max-width: 400px) {
  /* Tighten further on tiny phones — keep just the temp visible */
  .wch-pill { padding: 0 9px; }
}

/* ════════════════════════════════════════════════════════════════════
   WEATHER ANIMATIONS — shared across index.html dashboard widget AND
   hr-assistant.html World Clock tiles. Pure CSS keyframes.
   ════════════════════════════════════════════════════════════════════ */
.wx-fx {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.wx-fx-sun {
  position: absolute; top: -22px; right: -22px;
  width: 110px; height: 110px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffe27a 0%, #ffb830 55%, transparent 72%);
  box-shadow: 0 0 50px rgba(255,184,48,.55), 0 0 80px rgba(255,184,48,.28);
  animation: wxSunPulse 5s ease-in-out infinite, wxSunDrift 28s linear infinite;
}
@keyframes wxSunPulse { 0%,100% { transform: scale(1); filter: brightness(1); } 50% { transform: scale(1.07); filter: brightness(1.12); } }
@keyframes wxSunDrift { 0% { transform-origin: center; } 100% { transform: rotate(360deg); } }
.wx-fx-moon {
  position: absolute; top: 10px; right: 14px;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #f4f4ff 0%, #b6bdd5 60%, #5a608a 100%);
  box-shadow: inset -8px -4px 0 #303759, 0 0 30px rgba(180,200,255,.35);
}
.wx-fx-star {
  position: absolute;
  width: 2px; height: 2px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 4px rgba(255,255,255,.7);
  animation: wxTwinkle 2.4s ease-in-out infinite;
}
@keyframes wxTwinkle { 0%,100% { opacity: .3; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.2); } }
.wx-fx-cloud {
  position: absolute;
  background: radial-gradient(ellipse 50% 60% at 50% 60%, #f4f6fa 0%, #c3ccd9 65%, transparent 75%);
  border-radius: 50%;
  filter: blur(.3px);
  opacity: .82;
}
.wx-fx-cloud-1 { width: 120px; height: 42px; top: 18px; left: -50px;  animation: wxCloudDrift 22s linear infinite; }
.wx-fx-cloud-2 { width: 90px;  height: 34px; top: 52px; left: -40px;  animation: wxCloudDrift 32s linear infinite; }
.wx-fx-cloud-3 { width: 150px; height: 50px; top: 84px; left: -80px;  animation: wxCloudDrift 26s linear infinite reverse; }
@keyframes wxCloudDrift { 0% { transform: translateX(0); } 100% { transform: translateX(340px); } }
.wx-fx-rain { background: linear-gradient(180deg, transparent, rgba(8,18,35,.10)); }
.wx-fx-drop {
  position: absolute;
  width: 1.6px; height: 12px;
  background: linear-gradient(to bottom, rgba(180,210,250,0), rgba(180,210,250,.85));
  border-radius: 1px;
  animation: wxRainFall 0.9s linear infinite;
}
.wx-fx-drop.heavy { width: 2.2px; height: 18px; }
@keyframes wxRainFall {
  0%   { transform: translate(0, -20px); opacity: 0; }
  20%  { opacity: 1; }
  100% { transform: translate(-4px, 130%); opacity: .6; }
}
.wx-fx-flake {
  position: absolute;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 4px rgba(255,255,255,.85);
  opacity: .9;
  animation: wxFlakeFall 6s linear infinite;
}
@keyframes wxFlakeFall {
  0%   { transform: translate(0, -20px) rotate(0deg); opacity: 0; }
  10%  { opacity: 1; }
  100% { transform: translate(-30px, 140%) rotate(360deg); opacity: .7; }
}
.wx-fx-thunder-cloud {
  position: absolute; top: 0; right: -30px;
  width: 180px; height: 80px;
  background: radial-gradient(ellipse 70% 80% at 50% 70%, #4b5374 0%, #2b314e 65%, transparent 75%);
  border-radius: 50%;
  opacity: .85;
}
.wx-fx-flash {
  position: absolute;
  inset: 0;
  background: rgba(255,235,160,0);
  animation: wxFlash 6s steps(1) infinite;
}
@keyframes wxFlash {
  0%, 9%, 11%, 14%, 100% { background: rgba(255,235,160,0); }
  10%, 13%              { background: rgba(255,235,160,.65); }
}
.wx-fx-fog { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 0%, rgba(220,225,235,.12) 35%, rgba(220,225,235,.10) 55%, transparent 100%); }
.wx-fx-fog-band {
  position: absolute;
  left: -40%; width: 180%; height: 22px;
  background: linear-gradient(90deg, transparent, rgba(220,225,235,.32), transparent);
  filter: blur(2px);
}
.wx-fx-fog-band.b1 { top: 30%; animation: wxFogDrift 18s linear infinite; }
.wx-fx-fog-band.b2 { top: 55%; animation: wxFogDrift 24s linear infinite reverse; }
.wx-fx-fog-band.b3 { top: 75%; animation: wxFogDrift 30s linear infinite; }
@keyframes wxFogDrift { 0% { transform: translateX(0); } 100% { transform: translateX(40%); } }

/* ════════════════════════════════════════════════════════════════════
   DASHBOARD WEATHER CARD (index.html — after the welcome section)
   Big animated card showing the signed-in user's local weather.
   ════════════════════════════════════════════════════════════════════ */
.dash-weather-card {
  position: relative;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 22px;
  align-items: stretch;
  padding: 22px 24px;
  margin: 16px 0 18px;
  background: linear-gradient(155deg, rgba(91,170,255,.18), rgba(255,255,255,.04) 60%, rgba(0,0,0,.16));
  border: 1px solid rgba(91,208,255,.30);
  border-radius: 22px;
  overflow: hidden;
  isolation: isolate;
  box-shadow: 0 18px 48px rgba(0,0,0,.25), 0 0 0 1px rgba(91,208,255,.08) inset;
  min-height: 180px;
  animation: dwcIn .7s cubic-bezier(.16,1,.3,1) both;
}
@keyframes dwcIn { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }
.dash-weather-card.is-night { background: linear-gradient(155deg, rgba(30,45,90,.50), rgba(0,0,0,.36) 70%, rgba(0,0,0,.50)); border-color: rgba(120,150,220,.30); }
.dash-weather-card.wx-Rain, .dash-weather-card.wx-Drizzle { background: linear-gradient(155deg, rgba(60,100,150,.26), rgba(0,0,0,.30)); }
.dash-weather-card.wx-Thunderstorm { background: linear-gradient(155deg, rgba(60,60,110,.35), rgba(0,0,0,.40)); }
.dash-weather-card.wx-Snow { background: linear-gradient(155deg, rgba(170,200,240,.22), rgba(0,0,0,.18)); }
.dash-weather-card .dwc-left, .dash-weather-card .dwc-right { position: relative; z-index: 1; }

.dwc-loc {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: .5px;
  color: rgba(255,255,255,.78);
  margin-bottom: 12px;
}
.dwc-loc i { color: #5bd0ff; margin-right: 5px; }
.dwc-temp-row { display: flex; align-items: center; gap: 14px; margin-bottom: 8px; }
.dwc-icon { font-size: 46px; color: #ffd55e; filter: drop-shadow(0 4px 12px rgba(255,213,94,.4)); }
.dash-weather-card.is-night .dwc-icon { color: #cad9ff; filter: drop-shadow(0 4px 12px rgba(200,217,255,.4)); }
.dwc-temp { font-family: 'IBM Plex Mono', monospace; font-size: 46px; font-weight: 700; color: #fff; line-height: 1; text-shadow: 0 2px 10px rgba(0,0,0,.4); }
.dwc-cond { font-size: 14px; font-weight: 500; color: rgba(255,255,255,.82); margin-top: 4px; }
.dwc-hilo { font-family: 'IBM Plex Mono', monospace; font-size: 13px; color: rgba(255,255,255,.78); margin-top: 6px; }
.dwc-hilo .hi { color: #ff9e7a; }
.dwc-hilo .lo { color: #7ec3ff; }
.dwc-hilo .precip { color: #b6dcff; margin-left: 8px; }

.dwc-right {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 18px;
  align-content: center;
}
.dwc-stat {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  color: rgba(255,255,255,.85);
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap;
}
.dwc-stat i { color: #5bd0ff; font-size: 12px; }
.dwc-stat-uv { grid-column: span 2; padding-top: 4px; border-top: 1px solid rgba(255,255,255,.10); margin-top: 4px; }
.dwc-stat-uv i { color: #ffd55e; }
.dwc-updated {
  grid-column: span 2;
  font-size: 10.5px;
  color: rgba(255,255,255,.45);
  margin-top: 6px;
  letter-spacing: .3px;
}

@media (max-width: 640px) {
  .dash-weather-card { grid-template-columns: 1fr; padding: 18px 18px; min-height: 0; gap: 14px; }
  .dwc-temp { font-size: 38px; }
  .dwc-icon { font-size: 38px; }
  .dwc-right { grid-template-columns: 1fr 1fr 1fr; gap: 8px 12px; }
  .dwc-stat-uv { grid-column: span 3; }
  .dwc-updated { grid-column: span 3; }
}

/* ── Dashboard weather card — click-to-expand forecast ─────────── */
.dash-weather-card {
  grid-template-areas:
    "left right"
    "expanded expanded";
  cursor: pointer;
}
.dash-weather-card .dwc-left  { grid-area: left; }
.dash-weather-card .dwc-right { grid-area: right; }
.dash-weather-card .dwc-expanded {
  grid-area: expanded;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height .5s cubic-bezier(.16,1,.3,1), opacity .35s cubic-bezier(.16,1,.3,1), margin-top .4s ease, padding-top .4s ease;
  position: relative;
  z-index: 1;
}
.dash-weather-card.is-expanded { cursor: default; }
.dash-weather-card.is-expanded .dwc-expanded {
  max-height: 900px;
  opacity: 1;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,.12);
}
.dwc-toggle {
  position: absolute;
  top: 12px; right: 14px;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.16);
  color: rgba(255,255,255,.78);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background .25s, transform .35s cubic-bezier(.16,1,.3,1), color .25s;
  z-index: 2;
}
.dwc-toggle:hover { background: rgba(255,255,255,.16); color: #fff; }
.dash-weather-card.is-expanded .dwc-toggle { transform: rotate(180deg); background: rgba(91,208,255,.20); color: #fff; }

.dwc-strip-head {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.6px;
  color: rgba(255,255,255,.65);
  text-transform: uppercase;
  margin: 12px 0 10px;
}
.dwc-strip-head:first-child { margin-top: 0; }

/* Hourly strip — 12 cells horizontally scrollable */
.dwc-hourly {
  display: flex; gap: 10px;
  overflow-x: auto;
  padding-bottom: 6px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,.2) transparent;
}
.dwc-hourly::-webkit-scrollbar { height: 4px; }
.dwc-hourly::-webkit-scrollbar-track { background: transparent; }
.dwc-hourly::-webkit-scrollbar-thumb { background: rgba(255,255,255,.18); border-radius: 2px; }
.dwc-h-cell {
  flex: 0 0 68px;
  text-align: center;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.10);
  border-radius: 12px;
  padding: 10px 0 8px;
  transition: transform .25s cubic-bezier(.16,1,.3,1), border-color .25s, background .25s;
}
.dwc-h-cell:hover { transform: translateY(-2px); border-color: rgba(91,208,255,.35); background: rgba(91,208,255,.10); }
.dwc-h-cell .h-time   { font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: rgba(255,255,255,.7); letter-spacing: .3px; }
.dwc-h-cell .h-icon   { font-size: 17px; color: #ffd55e; margin: 6px 0 2px; }
.dash-weather-card.is-night .dwc-h-cell .h-icon { color: #cad9ff; }
.dwc-h-cell .h-temp   { font-family: 'IBM Plex Mono', monospace; font-size: 15px; font-weight: 700; color: #fff; }
.dwc-h-cell .h-precip { font-size: 10px; color: #7ec3ff; margin-top: 3px; }

/* 7-day strip — rows with hi-lo gradient */
.dwc-daily {
  display: flex; flex-direction: column; gap: 6px;
}
.dwc-d-row {
  display: grid;
  grid-template-columns: 78px 26px 1fr 46px 14px 46px;
  gap: 10px;
  align-items: center;
  padding: 9px 12px;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 11px;
  transition: background .2s, border-color .2s;
}
.dwc-d-row:hover { background: rgba(255,255,255,.08); border-color: rgba(91,208,255,.20); }
.dwc-d-row .d-day   { font-size: 13px; font-weight: 600; color: #fff; }
.dwc-d-row .d-icon  { font-size: 15px; color: #ffd55e; text-align: center; }
.dash-weather-card.is-night .dwc-d-row .d-icon { color: #ffd55e; }
.dwc-d-row .d-range {
  height: 5px; border-radius: 3px;
  background: linear-gradient(to right, #7ec3ff 0%, #ffd55e 50%, #ff9e7a 100%);
  opacity: .55;
}
.dwc-d-row .d-lo, .dwc-d-row .d-hi {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  font-weight: 600;
}
.dwc-d-row .d-lo { color: #7ec3ff; text-align: right; }
.dwc-d-row .d-hi { color: #ff9e7a; }
.dwc-d-row .d-precip {
  grid-column: 1 / -1;
  font-size: 11px;
  color: #b6dcff;
  padding-left: 90px;
  margin-top: -3px;
}

/* Sun / moon / wind summary line at the bottom of the expanded panel */
.dwc-sunline {
  display: flex; gap: 22px; flex-wrap: wrap;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid rgba(255,255,255,.10);
  font-size: 12px;
  color: rgba(255,255,255,.7);
}
.dwc-sunline i { color: #ffd55e; margin-right: 5px; }
.dwc-sunline b { font-family: 'IBM Plex Mono', monospace; color: #fff; font-weight: 600; }

@media (max-width: 640px) {
  .dash-weather-card { grid-template-areas: "left" "right" "expanded"; }
  .dwc-toggle { top: 10px; right: 10px; width: 28px; height: 28px; }
  .dwc-h-cell { flex: 0 0 60px; }
  .dwc-d-row { grid-template-columns: 60px 20px 1fr 36px 12px 36px; gap: 8px; }
  .dwc-d-row .d-precip { padding-left: 64px; }
}

/* ── Live dot next to the location label ───────────────────────── */
.dwc-loc .dwc-live-dot {
  display: inline-block;
  width: 7px; height: 7px;
  margin-left: 8px;
  border-radius: 50%;
  background: #4ee598;
  box-shadow: 0 0 0 0 rgba(78,229,152,.55);
  animation: dwcLivePulse 2.4s cubic-bezier(.16,1,.3,1) infinite;
  vertical-align: middle;
}
@keyframes dwcLivePulse {
  0%   { box-shadow: 0 0 0 0 rgba(78,229,152,.55); transform: scale(.92); }
  70%  { box-shadow: 0 0 0 9px rgba(78,229,152,0); transform: scale(1.18); }
  100% { box-shadow: 0 0 0 0 rgba(78,229,152,0); transform: scale(.92); }
}

/* ── Next-hour precipitation banner ────────────────────────────── */
.dwc-nexthour {
  padding: 10px 14px;
  background: linear-gradient(90deg, rgba(91,208,255,.18), rgba(91,208,255,.04));
  border: 1px solid rgba(91,208,255,.32);
  border-radius: 12px;
  font-size: 13px;
  color: #e0f1ff;
  margin-bottom: 14px;
}
.dwc-nexthour i { color: #7ec3ff; margin-right: 8px; }
.dwc-nexthour b { color: #fff; font-weight: 700; font-family: 'IBM Plex Mono', monospace; }

/* ── Active weather alerts ─────────────────────────────────────── */
.dwc-alerts { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.dwc-alert {
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid;
  font-size: 13px;
  line-height: 1.5;
}
.dwc-alert-extreme  { background: rgba(255,89,115,.20); border-color: rgba(255,89,115,.55); color: #ffd2db; }
.dwc-alert-severe   { background: rgba(255,89,115,.15); border-color: rgba(255,89,115,.40); color: #ffd2db; }
.dwc-alert-moderate { background: rgba(255,179,71,.18); border-color: rgba(255,179,71,.42); color: #ffe7c5; }
.dwc-alert-minor,
.dwc-alert-unknown,
.dwc-alert-advisory { background: rgba(91,208,255,.14); border-color: rgba(91,208,255,.36); color: #d8efff; }
.dwc-alert-head {
  display: flex; align-items: center; gap: 8px;
  font-weight: 700;
}
.dwc-alert-head i { color: inherit; }
.dwc-alert-sev {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 1.2px;
  padding: 2px 7px;
  background: rgba(0,0,0,.18);
  border-radius: 5px;
}
.dwc-alert-title { flex: 1; }
.dwc-alert-area, .dwc-alert-src {
  font-size: 11.5px;
  opacity: .8;
  margin-top: 4px;
  padding-left: 24px;
}

/* Warn variant of the live dot — shown when weather feed is unavailable */
.dwc-live-dot.dwc-live-dot-warn { background: #ffb347; box-shadow: 0 0 0 0 rgba(255,179,71,.55); animation: dwcLiveWarnPulse 2.4s cubic-bezier(.16,1,.3,1) infinite; }
@keyframes dwcLiveWarnPulse {
  0%   { box-shadow: 0 0 0 0 rgba(255,179,71,.55); transform: scale(.92); }
  70%  { box-shadow: 0 0 0 9px rgba(255,179,71,0); transform: scale(1.18); }
  100% { box-shadow: 0 0 0 0 rgba(255,179,71,0); transform: scale(.92); }
}

/* ── Weather chip popover — RICH version (matches dashboard widget) ── */
.wch-pop.wch-pop-rich {
  position: absolute;
  top: calc(100% + 8px); right: 0;
  width: min(320px, calc(100vw - 16px));
  background: linear-gradient(155deg, rgba(91,170,255,.20), rgba(11,18,24,.92) 70%);
  border: 1px solid rgba(91,208,255,.36);
  border-radius: 18px;
  padding: 0;
  box-shadow: 0 22px 56px rgba(0,0,0,.6), 0 0 0 1px rgba(91,208,255,.08) inset;
  z-index: 1200;
  overflow: hidden;
  isolation: isolate;
}
.wch-pop.wch-pop-rich.is-night { background: linear-gradient(155deg, rgba(30,45,90,.50), rgba(0,0,0,.85)); border-color: rgba(120,150,220,.40); }
.wch-pop.wch-pop-rich.wx-Rain, .wch-pop.wch-pop-rich.wx-Drizzle { background: linear-gradient(155deg, rgba(60,100,150,.30), rgba(0,0,0,.85)); }
.wch-pop.wch-pop-rich.wx-Thunderstorm { background: linear-gradient(155deg, rgba(60,60,110,.40), rgba(0,0,0,.90)); }
.wch-pop.wch-pop-rich.wx-Snow { background: linear-gradient(155deg, rgba(170,200,240,.28), rgba(0,0,0,.85)); }
.wch-pop.wch-pop-rich .wx-fx { position: absolute; inset: 0; z-index: 0; border-radius: 18px; }
.wch-pop-inner { position: relative; z-index: 1; padding: 14px 16px; }
.wch-pop-loc-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.wch-pop-loc-text { font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; color: rgba(255,255,255,.82); letter-spacing: .3px; }
.wch-pop-loc-text i { color: #5bd0ff; margin-right: 5px; }
.wch-pop-live-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #4ee598; box-shadow: 0 0 0 0 rgba(78,229,152,.55); animation: dwcLivePulse 2.4s cubic-bezier(.16,1,.3,1) infinite; }
.wch-pop-rich .wch-pop-row { display: flex; align-items: center; gap: 14px; padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid rgba(255,255,255,.10); }
.wch-pop-rich .wch-pop-icon { font-size: 36px; color: #ffd55e; filter: drop-shadow(0 3px 9px rgba(255,213,94,.35)); }
.wch-pop-rich.is-night .wch-pop-icon { color: #cad9ff; filter: drop-shadow(0 3px 9px rgba(200,217,255,.35)); }
.wch-pop-rich .wch-pop-temp { font-family: 'IBM Plex Mono', monospace; font-size: 32px; font-weight: 700; color: #fff; line-height: 1; }
.wch-pop-rich .wch-pop-cond { font-size: 12px; color: rgba(255,255,255,.78); margin-top: 4px; }
.wch-pop-hilo { font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; color: rgba(255,255,255,.7); margin-top: 4px; }
.wch-pop-hilo .hi { color: #ff9e7a; }
.wch-pop-hilo .lo { color: #7ec3ff; }
.wch-pop-nh { padding: 8px 12px; background: rgba(91,208,255,.16); border: 1px solid rgba(91,208,255,.30); border-radius: 10px; font-size: 11.5px; color: #d8efff; margin-bottom: 12px; }
.wch-pop-nh i { color: #7ec3ff; margin-right: 6px; }
.wch-pop-nh b { color: #fff; font-family: 'IBM Plex Mono', monospace; }
.wch-pop-hourly { display: flex; gap: 6px; overflow-x: auto; margin-bottom: 12px; padding-bottom: 4px; scrollbar-width: none; }
.wch-pop-hourly::-webkit-scrollbar { display: none; }
.wch-h-cell { flex: 0 0 50px; text-align: center; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10); border-radius: 9px; padding: 6px 0 5px; }
.wch-h-time { font-family: 'IBM Plex Mono', monospace; font-size: 9.5px; color: rgba(255,255,255,.65); }
.wch-h-icon { font-size: 13px; color: #ffd55e; margin: 3px 0 1px; }
.wch-pop-rich.is-night .wch-h-icon { color: #cad9ff; }
.wch-h-temp { font-family: 'IBM Plex Mono', monospace; font-size: 12px; font-weight: 700; color: #fff; }
.wch-pop-rich .wch-pop-meta { display: flex; gap: 12px; flex-wrap: wrap; font-size: 11px; color: rgba(255,255,255,.7); padding-top: 10px; border-top: 1px solid rgba(255,255,255,.10); }
.wch-pop-rich .wch-pop-meta i { color: #5bd0ff; margin-right: 4px; }
.wch-pop-rich .wch-pop-foot { font-size: 10px; color: rgba(255,255,255,.45); margin-top: 7px; letter-spacing: .3px; }
.wch-alert { padding: 7px 10px; border-radius: 9px; border: 1px solid; font-size: 11.5px; margin-bottom: 10px; line-height: 1.4; }
.wch-alert i { margin-right: 6px; }
.wch-alert-extreme, .wch-alert-severe { background: rgba(255,89,115,.18); border-color: rgba(255,89,115,.42); color: #ffd2db; }
.wch-alert-moderate { background: rgba(255,179,71,.18); border-color: rgba(255,179,71,.42); color: #ffe7c5; }
.wch-alert-minor, .wch-alert-unknown, .wch-alert-advisory { background: rgba(91,208,255,.14); border-color: rgba(91,208,255,.36); color: #d8efff; }

/* ──────────────────────────────────────────────────────────────────
   Universal modal-title / modal-sub padding so the absolute-positioned
   .modal-close X button never overlaps the text. Applies on every page
   that uses .modal-overlay / .modal-box (every modal in the portal).
   Higher specificity than individual page CSS, no !important needed.
   ────────────────────────────────────────────────────────────────── */
.modal-overlay .modal-title,
.modal-overlay .modal-sub,
.modal-box     .modal-title,
.modal-box     .modal-sub {
  padding-right: 56px;
}
@media (max-width: 540px) {
  .modal-overlay .modal-title,
  .modal-overlay .modal-sub,
  .modal-box     .modal-title,
  .modal-box     .modal-sub {
    padding-right: 48px;
  }
}

/* ──────────────────────────────────────────────────────────────────
   Shared header clock + temperature chip — `.hdr-wclock`.
   Mounted on every page that includes `js/hdr-wclock.js`. WAT time
   + Benin-City temperature via Open-Meteo. Glass design language.
   ────────────────────────────────────────────────────────────────── */
.hdr-wclock {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14);
  color: rgba(242,247,238,.88);
  font-family: var(--mono, 'IBM Plex Mono', monospace);
  font-size: 12px;
  line-height: 1;
  font-weight: 600;
  letter-spacing: .04em;
  white-space: nowrap;
  user-select: none;
}
.hdr-wclock i { color: var(--gold, #f0c832); font-size: 11px; }
.hdr-wclock-sep { color: rgba(242,247,238,.35); margin: 0 2px; }

@media (max-width: 820px) {
  .hdr-wclock { padding: 6px 10px; font-size: 11px; }
}
@media (max-width: 540px) {
  /* On narrow phones the chip collapses to time-only — temp hidden. */
  .hdr-wclock .hdr-wclock-sep,
  .hdr-wclock .hdr-wclock-temp,
  .hdr-wclock > i.fa-cloud-sun { display: none; }
}

/* ════════════════════════════════════════════════════════════════
   SCROLL PERFORMANCE (2026-05-26)
   ────────────────────────────────────────────────────────────────
   Momentum scrolling on touch devices + scroll-chaining containment
   on nested scroll containers. No visual change. Pairs with the
   per-page backdrop-filter removals on sticky chrome (hr-ops-monitor
   header / section-nav / KPI tiles) that eliminated the per-frame
   re-blur that caused "page hangs while scrolling".
   ════════════════════════════════════════════════════════════════ */
html, body { -webkit-overflow-scrolling: touch; }

/* Nested scroll regions: momentum + don't chain the scroll to the page
   behind them (stops the "stuck/rubber-banding" feel inside drawers,
   modals, notification panels, and wide tables). */
.snp-body, .snp-hr-body, .modal-body, .pres-modal-box,
[id$="-drawer"], [id$="-drawer-body"],
.grid-scroll, .rota-scroll, .table-scroll, .dtbl-wrap, .tz-combo-list {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ============================================================================
   DTTASA AI Assistant — enterprise chat panel (js/support-assistant.js)
   Glassmorphism + gold treatment + cubic-bezier(.16,1,.3,1) motion. Tokens:
   --gold/--gold2/--gglow/--gdim/--void/--panel/--text/--t2/--t3/--border.
   ============================================================================ */
.dsa-panel{position:fixed;right:24px;bottom:24px;bottom:calc(24px + env(safe-area-inset-bottom));z-index:9001;width:400px;max-width:calc(100vw - 32px);height:580px;max-height:calc(100vh - 100px);display:none;flex-direction:column;border:1px solid rgba(240,200,50,.22);border-radius:20px;overflow:hidden;background:linear-gradient(165deg,rgba(30,46,27,.97),rgba(12,17,9,.985));backdrop-filter:blur(22px);-webkit-backdrop-filter:blur(22px);box-shadow:0 30px 80px -12px rgba(0,0,0,.7),inset 0 0 0 1px rgba(255,255,255,.05),0 0 50px -10px var(--gglow,rgba(212,175,55,.3))}
.dsa-panel::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--gold,#f0c832),var(--gold2,#f7d94e),var(--gold,#f0c832),transparent);opacity:.85;z-index:2}
.dsa-panel.show{display:flex;animation:dsaIn .42s cubic-bezier(.16,1,.3,1) both}
@keyframes dsaIn{from{opacity:0;transform:translateY(24px) scale(.94)}to{opacity:1;transform:none}}
.dsa-head{position:relative;display:flex;align-items:center;gap:11px;padding:15px 14px 14px;border-bottom:1px solid rgba(240,200,50,.14);background:linear-gradient(180deg,rgba(240,200,50,.10),transparent)}
.dsa-av{position:relative;flex:0 0 auto;width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at 50% 38%,rgba(30,46,27,.9),rgba(12,17,9,.97));border:1.5px solid var(--gold,#f0c832);box-shadow:0 0 0 1px rgba(240,200,50,.28),0 0 18px -2px var(--gglow,rgba(212,175,55,.5));animation:dsaPulse 3s ease-in-out infinite;overflow:visible}
.dsa-av img{width:100%;height:100%;object-fit:cover;border-radius:50%}
.dsa-av i{font-size:17px;color:var(--gold,#f0c832)}
.dsa-av::before{content:'';position:absolute;top:-7px;left:50%;width:2px;height:7px;transform:translateX(-50%);background:var(--gold,#f0c832);border-radius:1px}
.dsa-av::after{content:'';position:absolute;top:-11px;left:50%;width:6px;height:6px;transform:translateX(-50%);border-radius:50%;background:var(--gold2,#f7d94e);box-shadow:0 0 8px var(--gold,#f0c832);animation:blink 2s ease infinite}
@keyframes dsaPulse{0%,100%{box-shadow:0 0 0 1px rgba(240,200,50,.4),0 0 16px -2px var(--gglow,rgba(212,175,55,.45))}50%{box-shadow:0 0 0 1px rgba(240,200,50,.6),0 0 26px 1px var(--gglow,rgba(212,175,55,.65))}}
.dsa-head-meta{flex:1;min-width:0}
.dsa-head-title{font-family:var(--disp,'Cinzel',serif);font-size:15px;font-weight:700;letter-spacing:.3px;color:var(--text,#f2f7ee);line-height:1.1}
.dsa-head-sub{font-family:var(--body,'DM Sans',sans-serif);font-size:10.5px;color:var(--t3,rgba(242,247,238,.6));margin-top:3px;display:flex;align-items:center;gap:5px}
.dsa-pip{width:6px;height:6px;border-radius:50%;background:var(--green,#4cd657);box-shadow:0 0 0 2px rgba(76,214,87,.25);animation:blink 2.4s ease infinite}
.dsa-head-actions{display:flex;align-items:center;gap:6px}
.dsa-ticket-link{display:inline-flex;align-items:center;gap:5px;background:rgba(255,255,255,.06);border:1px solid var(--border,rgba(255,255,255,.21));color:var(--t2,rgba(242,247,238,.85));font-family:var(--body,'DM Sans',sans-serif);font-size:11px;font-weight:600;padding:6px 10px;border-radius:9px;cursor:pointer;transition:all .25s cubic-bezier(.16,1,.3,1)}
.dsa-ticket-link:hover{border-color:var(--gold,#f0c832);color:var(--gold,#f0c832);background:var(--gdim,rgba(212,175,55,.12))}
.dsa-close{flex:0 0 auto;width:28px;height:28px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.05);border:none;border-radius:50%;color:var(--t2,rgba(242,247,238,.7));font-size:18px;line-height:1;cursor:pointer;transition:all .25s ease}
.dsa-close:hover{background:rgba(255,72,72,.2);color:#ff4848}
.dsa-notice{padding:9px 15px;font-size:10.5px;color:var(--t3,rgba(242,247,238,.55));background:rgba(0,0,0,.18);border-bottom:1px solid rgba(255,255,255,.06);display:flex;gap:7px;align-items:center}
.dsa-notice i{color:var(--gold,#f0c832)}
.dsa-msgs{flex:1;overflow-y:auto;padding:16px 14px;display:flex;flex-direction:column;gap:12px;scrollbar-width:thin;scrollbar-color:rgba(240,200,50,.3) transparent}
.dsa-msgs::-webkit-scrollbar{width:6px}.dsa-msgs::-webkit-scrollbar-thumb{background:rgba(240,200,50,.3);border-radius:3px}
.dsa-msg{max-width:86%;padding:10px 13px;font-family:var(--body,'DM Sans',sans-serif);font-size:13px;line-height:1.55;word-break:break-word;animation:dsaMsgIn .4s cubic-bezier(.16,1,.3,1) both}
@keyframes dsaMsgIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.dsa-user{align-self:flex-end;background:linear-gradient(135deg,rgba(240,200,50,.28),rgba(247,217,78,.13));border:1px solid rgba(240,200,50,.42);color:var(--text,#f2f7ee);border-radius:15px 15px 4px 15px}
.dsa-bot{align-self:flex-start;background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.10);color:var(--t2,rgba(242,247,238,.92));border-radius:15px 15px 15px 4px}
.dsa-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.dsa-chip{display:inline-flex;align-items:center;gap:5px;padding:6px 10px;border-radius:20px;background:var(--gdim,rgba(212,175,55,.12));border:1px solid rgba(240,200,50,.4);color:var(--gold,#f0c832);font-size:11px;font-weight:600;text-decoration:none;transition:all .25s cubic-bezier(.16,1,.3,1)}
.dsa-chip:hover{background:rgba(240,200,50,.22);transform:translateY(-1px)}
.dsa-esc{margin-top:7px;font-size:11.5px;color:var(--t3,rgba(242,247,238,.6))}
.dsa-esc-btn{margin-top:10px;display:inline-flex;align-items:center;gap:6px;background:linear-gradient(135deg,rgba(240,200,50,.2),rgba(247,217,78,.1));border:1px solid var(--gold,#f0c832);color:var(--gold,#f0c832);font-family:var(--body,'DM Sans',sans-serif);font-size:12px;font-weight:600;padding:8px 12px;border-radius:10px;cursor:pointer;transition:all .25s cubic-bezier(.16,1,.3,1)}
.dsa-esc-btn:hover{background:rgba(240,200,50,.28);transform:translateY(-1px)}
.dsa-dots{display:inline-flex;gap:5px;padding:2px 0}
.dsa-dots i{width:7px;height:7px;border-radius:50%;background:var(--gold,#f0c832);display:inline-block;animation:dsaBounce 1.3s infinite ease-in-out both}
.dsa-dots i:nth-child(1){animation-delay:-.24s}.dsa-dots i:nth-child(2){animation-delay:-.12s}
@keyframes dsaBounce{0%,80%,100%{transform:scale(.5);opacity:.4}40%{transform:scale(1);opacity:1}}
.dsa-input{display:flex;gap:8px;padding:12px;border-top:1px solid rgba(255,255,255,.08);background:linear-gradient(180deg,transparent,rgba(0,0,0,.25))}
.dsa-q{flex:1;padding:11px 14px;border-radius:12px;border:1px solid var(--border,rgba(255,255,255,.21));background:rgba(255,255,255,.05);color:var(--text,#f2f7ee);font-family:var(--body,'DM Sans',sans-serif);font-size:14px;transition:border-color .25s,box-shadow .25s}
.dsa-q:focus{outline:none;border-color:var(--gold,#f0c832);box-shadow:0 0 0 3px var(--gdim,rgba(212,175,55,.14))}
.dsa-send{flex:0 0 auto;width:44px;height:44px;border-radius:12px;border:none;background:linear-gradient(135deg,var(--gold2,#f7d94e),var(--gold,#f0c832));color:#19230a;cursor:pointer;font-size:15px;display:flex;align-items:center;justify-content:center;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
.dsa-send:hover{transform:translateY(-2px);box-shadow:0 6px 18px -4px var(--gglow,rgba(212,175,55,.6))}
.dsa-send:disabled{opacity:.5;cursor:not-allowed;transform:none}
.dsa-tf-title{font-family:var(--disp,'Cinzel',serif);font-size:13px;font-weight:700;color:var(--gold,#f0c832);display:flex;align-items:center;gap:7px;margin-bottom:9px}
.dsa-tf-lbl{display:block;font-size:11px;color:var(--t3,rgba(242,247,238,.6));margin:7px 0 3px}
.dsa-tf-in,.dsa-tf-ta{width:100%;box-sizing:border-box;background:rgba(255,255,255,.05);border:1px solid var(--border,rgba(255,255,255,.21));border-radius:10px;padding:9px 11px;color:var(--text,#f2f7ee);font-family:var(--body,'DM Sans',sans-serif);font-size:13px;resize:none;transition:border-color .25s,box-shadow .25s}
.dsa-tf-in:focus,.dsa-tf-ta:focus{outline:none;border-color:var(--gold,#f0c832);box-shadow:0 0 0 3px var(--gdim,rgba(212,175,55,.14))}
.dsa-tf-row{display:flex;gap:8px;margin-top:10px}
.dsa-tf-cancel{flex:0 0 auto;background:transparent;border:1px solid var(--border,rgba(255,255,255,.21));color:var(--t2,rgba(242,247,238,.85));border-radius:10px;padding:9px 13px;font-size:12px;cursor:pointer;font-family:var(--body,'DM Sans',sans-serif);transition:all .25s ease}
.dsa-tf-cancel:hover{border-color:rgba(255,255,255,.4)}
.dsa-tf-submit{flex:1;background:linear-gradient(135deg,var(--gold2,#f7d94e),var(--gold,#f0c832));border:none;color:#19230a;border-radius:10px;padding:9px 13px;font-size:12px;font-weight:700;cursor:pointer;font-family:var(--body,'DM Sans',sans-serif);transition:transform .25s cubic-bezier(.16,1,.3,1)}
.dsa-tf-submit:hover{transform:translateY(-1px)}
.dsa-tf-submit:disabled{opacity:.5;cursor:not-allowed;transform:none}
.dsa-tf-ok{color:var(--green,#4cd657);font-size:13px;line-height:1.5;text-align:center;padding:6px 0}
.dsa-tf-ok i{font-size:26px;display:block;margin-bottom:7px}
.dsa-tf-ref{font-family:var(--mono,'IBM Plex Mono',monospace);font-size:12px;color:var(--gold,#f0c832);margin-top:6px}
@media(max-width:540px){.dsa-panel{right:8px;left:8px;width:auto;bottom:8px;height:calc(100vh - 76px);border-radius:18px}}

/* ── Contract Renewal v2 — signing-chain stepper + in-flight panel (centralised; used on HR monitor + signing page) ── */
.renew-stepper{display:inline-flex;align-items:center;gap:0;margin-top:4px;vertical-align:middle}
.renew-stepper .rs-node{width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:9px;font-weight:800;letter-spacing:.2px;border:1.5px solid var(--border,rgba(255,255,255,.21));background:rgba(255,255,255,.06);color:var(--t3,rgba(242,247,238,.62));position:relative}
.renew-stepper .rs-node:not(:last-child){margin-right:18px}
.renew-stepper .rs-node:not(:last-child)::after{content:"";position:absolute;left:100%;top:50%;width:18px;height:2px;background:var(--border,rgba(255,255,255,.21));transform:translateY(-50%)}
.renew-stepper .rs-done{background:var(--green,#4cd657);border-color:var(--green,#4cd657);color:#0c1109}
.renew-stepper .rs-done:not(:last-child)::after{background:var(--green,#4cd657)}
.renew-stepper .rs-active{background:var(--gold,#f0c832);border-color:var(--gold,#f0c832);color:#0c1109;animation:rsPulse 1.6s cubic-bezier(.16,1,.3,1) infinite}
@keyframes rsPulse{0%,100%{box-shadow:0 0 0 0 rgba(240,200,50,.5)}50%{box-shadow:0 0 0 5px rgba(240,200,50,0)}}
.renew-panel{background:rgba(240,200,50,.06);border:1px solid var(--gglow,rgba(212,175,55,.3));border-radius:12px;padding:14px 16px;margin-bottom:14px}
.renew-panel-title{font-size:13px;font-weight:700;color:var(--gold,#f0c832);margin-bottom:10px;display:flex;align-items:center;gap:8px}
.renew-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:8px 0;border-top:1px solid var(--border,rgba(255,255,255,.14))}
.renew-row:first-of-type{border-top:0}
.renew-row-name{font-size:13px;font-weight:600;color:var(--text,#f2f7ee);min-width:160px;flex:1}
.renew-row-status{font-size:11px;font-weight:700;color:var(--gold,#f0c832);text-transform:uppercase;letter-spacing:.4px}

/* Contract-renewal in-flight panel — staggered row entrance (enterprise polish) */
.renew-panel .renew-row{animation:cvIn .4s cubic-bezier(.16,1,.3,1) both;}
.renew-panel .renew-row:nth-child(2){animation-delay:.05s}
.renew-panel .renew-row:nth-child(3){animation-delay:.10s}
.renew-panel .renew-row:nth-child(4){animation-delay:.15s}
.renew-panel .renew-row:nth-child(n+5){animation-delay:.2s}

/* ════════════════════════════════════════════════════════════════════════════
   PREMIUM UI KIT (2026-06-07) — reusable enterprise glass / facet / diamond
   surfaces + entrance animations, distilled from the Recruitment Pipeline
   redesign. Use on ANY page; design tokens (--gold,--gdim,--gglow,--panel,
   --border,--t3,--disp,--ease) resolve from that page's own :root.

   Atoms:   .pm-glass · .pm-facet · .pm-dia (hover sheen)
   Cards:   .pm-card (glass facet + hover lift + sheen)
   KPIs:    .pm-kpis (grid) > .pm-kpi  (.pm-kn number · .pm-kl label · .pm-ki icon)
   Drawer:  #x{...} + .pm-drawer / .pm-scrim  (use pmSlideIn / pmScrimIn)
   Motion:  .pm-anim-rise · .pm-anim-card · .pm-stagger>*  ·  keyframes pm*
   Easing:  always cubic-bezier(.16,1,.3,1)
   ════════════════════════════════════════════════════════════════════════════ */
.pm-glass{background:var(--panel);border:1px solid var(--border);border-radius:18px;backdrop-filter:blur(14px) saturate(1.2);-webkit-backdrop-filter:blur(14px) saturate(1.2);box-shadow:0 10px 34px -8px rgba(0,0,0,.34),inset 0 1px 0 rgba(255,255,255,.10)}
.pm-facet{background:linear-gradient(160deg,rgba(255,255,255,.16),rgba(255,255,255,.04) 42%,var(--panel)),linear-gradient(320deg,var(--gdim),transparent 60%);border:1px solid rgba(255,255,255,.22)}
.pm-dia{position:relative;overflow:hidden}
.pm-dia::after{content:"";position:absolute;top:-60%;left:-70%;width:42%;height:220%;pointer-events:none;background:linear-gradient(100deg,transparent,rgba(255,255,255,.14),rgba(255,255,255,.03),transparent);transform:rotate(9deg);transition:left .75s cubic-bezier(.16,1,.3,1)}
.pm-dia:hover::after{left:150%}

.pm-card{position:relative;overflow:hidden;
  background:linear-gradient(160deg,rgba(255,255,255,.13),rgba(255,255,255,.035) 42%,var(--panel)),linear-gradient(320deg,var(--gdim),transparent 60%);
  border:1px solid rgba(255,255,255,.20);border-radius:16px;
  box-shadow:0 8px 26px -12px rgba(0,0,0,.42),inset 0 1px 0 rgba(255,255,255,.08);
  transition:transform .3s cubic-bezier(.16,1,.3,1),border-color .3s,box-shadow .3s}
.pm-card::after{content:"";position:absolute;top:-60%;left:-70%;width:42%;height:220%;pointer-events:none;z-index:0;background:linear-gradient(100deg,transparent,rgba(255,255,255,.13),rgba(255,255,255,.03),transparent);transform:rotate(9deg);transition:left .75s cubic-bezier(.16,1,.3,1)}
.pm-card:hover{border-color:var(--gglow);transform:translateY(-3px);box-shadow:0 18px 44px -12px rgba(0,0,0,.5),0 0 0 1px var(--gglow) inset}
.pm-card:hover::after{left:150%}
.pm-card > *{position:relative;z-index:1}

.pm-kpis{display:grid;gap:12px}
.pm-kpi{position:relative;overflow:hidden;padding:15px 16px;border-radius:16px;
  background:linear-gradient(160deg,rgba(255,255,255,.16),rgba(255,255,255,.04) 42%,var(--panel)),linear-gradient(320deg,var(--gdim),transparent 60%);
  border:1px solid rgba(255,255,255,.22);
  box-shadow:0 10px 30px -10px rgba(0,0,0,.34),inset 0 1px 0 rgba(255,255,255,.10);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  animation:pmKpiIn .5s cubic-bezier(.16,1,.3,1) both}
.pm-kpi:nth-child(2){animation-delay:.05s}.pm-kpi:nth-child(3){animation-delay:.1s}
.pm-kpi:nth-child(4){animation-delay:.15s}.pm-kpi:nth-child(5){animation-delay:.2s}
.pm-kn{font-family:var(--disp);font-weight:700;font-size:26px;line-height:1}
.pm-kl{font-size:10.5px;letter-spacing:1px;text-transform:uppercase;color:var(--t3);font-weight:700;margin-top:6px}
.pm-ki{position:absolute;top:12px;right:13px;font-size:15px;opacity:.5}

/* Right-side slide-in drawer + scrim (apply pm-drawer to the panel, pm-scrim to the overlay) */
.pm-scrim{background:rgba(5,9,5,.52);-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);animation:pmScrimIn .32s cubic-bezier(.16,1,.3,1) both}
.pm-drawer{background:linear-gradient(165deg,var(--base),var(--deep));border-left:1px solid var(--border);box-shadow:-28px 0 80px rgba(0,0,0,.6);will-change:transform;animation:pmSlideIn .52s cubic-bezier(.16,1,.3,1) both}

/* Entrance helpers + keyframes */
.pm-anim-rise{animation:pmRise .6s cubic-bezier(.16,1,.3,1) both}
.pm-anim-card{animation:pmCardIn .5s cubic-bezier(.16,1,.3,1) both}
.pm-stagger > *{animation:pmCardIn .5s cubic-bezier(.16,1,.3,1) both}
.pm-stagger > *:nth-child(1){animation-delay:.06s}.pm-stagger > *:nth-child(2){animation-delay:.12s}.pm-stagger > *:nth-child(3){animation-delay:.18s}.pm-stagger > *:nth-child(4){animation-delay:.24s}.pm-stagger > *:nth-child(5){animation-delay:.30s}.pm-stagger > *:nth-child(n+6){animation-delay:.36s}
@keyframes pmKpiIn{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes pmCardIn{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes pmRise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
@keyframes pmSlideIn{from{transform:translateX(102%);opacity:.55}60%{opacity:1}to{transform:none;opacity:1}}
@keyframes pmScrimIn{from{opacity:0}to{opacity:1}}
@keyframes pmSecIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

/* ════ Premium overlay-modal depth (centralised, 2026-06-08) ════
   Every page's overlay modal gets premium glass depth + a refined border/radius.
   Background is NOT changed here (preserves light/dark readability); the major dark
   pages already carry the full facet modal bg. The X-clearance + z-index rules above
   already stop the close (X) button overlapping the title text. */
.modal-overlay .modal-card, .modal-box, .modal-sheet {
  box-shadow:0 32px 90px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.08) !important;
  border-radius:20px !important;
}
.modal-overlay .modal-card { border:1px solid rgba(255,255,255,.18) !important; }
@media (max-width:640px){ .modal-overlay .modal-card, .modal-box, .modal-sheet { border-radius:16px !important; } }

/* ════ MAIL ENGINE live panel (me-*) — shared SA Control + IT Board (2026-06-10) ════
   Premium provider counters for the mail router (Resend → Trigger Email).
   Used by js/mail-engine-panel.js. Mobile-first to 320px. */
.me-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;margin-bottom:14px}
.me-card{padding:16px 18px 14px;border-radius:16px}
.me-card.me-active{border-color:var(--gglow);box-shadow:0 14px 40px -14px rgba(0,0,0,.5),0 0 0 1px var(--gglow) inset}
.me-card-top{display:flex;align-items:center;gap:9px;min-width:0}
.me-name{font-family:var(--disp);font-weight:700;font-size:15px;letter-spacing:.6px;color:var(--text)}
.me-active-chip{margin-left:auto;font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:1.5px;color:var(--gold);background:var(--gdim);border:1px solid var(--gglow);border-radius:20px;padding:3px 9px;text-shadow:0 0 8px var(--gglow);white-space:nowrap}
.me-sub{font-size:11px;color:var(--t3);margin:3px 0 12px;letter-spacing:.3px}
.me-bar-row{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.me-bar-lbl{font-family:var(--mono);font-size:10px;letter-spacing:1px;text-transform:uppercase;color:var(--t3);width:44px;flex:none}
.me-bar{flex:1;height:7px;border-radius:6px;background:rgba(255,255,255,.09);overflow:hidden;min-width:0}
.me-bar-fill{height:100%;border-radius:6px;transition:width .6s cubic-bezier(.16,1,.3,1)}
.me-fill-green{background:linear-gradient(90deg,#2e8d3a,var(--green));box-shadow:0 0 10px rgba(76,214,87,.4)}
.me-fill-gold{background:linear-gradient(90deg,#b08d1e,var(--gold));box-shadow:0 0 10px var(--gglow)}
.me-fill-red{background:linear-gradient(90deg,#8d1e1e,var(--red));box-shadow:0 0 10px rgba(255,72,72,.4)}
.me-bar-num{font-family:var(--mono);font-size:11.5px;font-weight:700;color:var(--t2);flex:none;min-width:54px;text-align:right}
.me-foot{margin-top:6px;border-top:1px solid rgba(255,255,255,.08);padding-top:8px;min-height:18px}
.me-ok{font-size:11px;color:var(--t3)}
.me-err{font-size:11px;color:var(--red);display:inline-flex;align-items:flex-start;gap:6px;line-height:1.4;word-break:break-word}
.me-empty{padding:18px;text-align:center;color:var(--t3);font-size:13px}
.me-log-wrap{border-radius:16px;padding:14px 16px}
.me-log-hdr{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:1.6px;text-transform:uppercase;color:var(--gold);margin-bottom:10px}
.me-log-sub{margin-left:auto;color:var(--t3);font-weight:400;letter-spacing:.6px;text-transform:none}
.me-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
.me-tbl th{text-align:left;font-family:var(--mono);font-size:10px;letter-spacing:1px;text-transform:uppercase;color:var(--t3);padding:6px 10px;border-bottom:1px solid var(--border)}
.me-tbl td{padding:8px 10px;border-bottom:1px solid rgba(255,255,255,.06);color:var(--t2);vertical-align:top}
.me-tbl tr:hover td{background:var(--gdim)}
.me-subj{word-break:break-word}
.me-st{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;border-radius:12px;padding:2px 8px;white-space:nowrap}
.me-st-sent{color:var(--green);background:rgba(76,214,87,.12);border:1px solid rgba(76,214,87,.3)}
.me-st-error{color:var(--red);background:rgba(255,72,72,.12);border:1px solid rgba(255,72,72,.3)}
.me-st-queued{color:var(--gold);background:var(--gdim);border:1px solid var(--gglow)}
.me-st-bounced{color:var(--red);background:rgba(255,72,72,.12);border:1px solid rgba(255,72,72,.3)}
.me-st-complained{color:#ff9a3d;background:rgba(255,154,61,.12);border:1px solid rgba(255,154,61,.3)}
.me-st-suppressed{color:#c06cff;background:rgba(192,108,255,.12);border:1px solid rgba(192,108,255,.35)}
.me-fetch-btn{margin-left:10px}
.me-fetch-note{font-size:12.5px;padding:8px 12px;border-radius:10px;margin-bottom:10px;display:flex;align-items:center;gap:8px}
.me-fetch-ok{color:var(--green);background:rgba(76,214,87,.1);border:1px solid rgba(76,214,87,.28)}
.me-fetch-warn{color:#ffb055;background:rgba(255,154,61,.1);border:1px solid rgba(255,154,61,.3)}
@media(max-width:540px){
  .me-grid{grid-template-columns:1fr}
  .me-tbl thead{display:none}
  .me-tbl tr{display:block;border-bottom:1px solid var(--border);padding:8px 0}
  .me-tbl td{display:flex;gap:10px;border-bottom:none;padding:3px 6px}
  .me-tbl td::before{content:attr(data-l);font-family:var(--mono);font-size:9.5px;letter-spacing:1px;text-transform:uppercase;color:var(--t3);width:64px;flex:none;padding-top:2px}
}

/* ════════════════════════════════════════════════════════════════════
   UNIVERSAL BACKGROUND SCROLL LOCK  (VP 2026-07-26)
   --------------------------------------------------------------------
   Requirement: "overlays must never allow background page to scroll
   when an overlay is opened."

   Driven by js/scroll-lock.js, which adds .dtt-scroll-locked to BOTH
   <html> and <body> whenever a viewport-covering fixed layer is on
   screen, and removes it when the last one closes.

   WHY !important
   --------------
   Five pages already set `document.body.style.overflow='hidden'` inline
   and clear it to '' on close (all-org-doc, ddcp-v5, diagnostics,
   mobile-ui). An inline style beats a class, so without !important a
   page that clears its own inline lock while another overlay is still
   open would let the background scroll again. With it, the class is
   authoritative and the two mechanisms cannot disagree.

   WHY BOTH html AND body
   ----------------------
   iOS Safari propagates the viewport scroll to whichever of the two is
   the scrolling element, and that differs by page depending on whether
   the page sets height:100% on html,body (my-desk.css does, index does
   not). Locking both covers every combination.

   WHY NOT position:fixed ON BODY
   ------------------------------
   That is the more aggressive technique, but this portal puts
   `position:fixed` on #hdr and `position:sticky` on the rails of nearly
   every page. Making <body> a fixed block re-parents the containing
   block for all of them and visibly reflows the layout. overflow:hidden
   plus overscroll-behavior:none is correct on iOS 14+ and in the
   Capacitor WKWebView build, and cannot reflow anything.
   ════════════════════════════════════════════════════════════════════ */
html.dtt-scroll-locked,
body.dtt-scroll-locked {
  overflow: hidden !important;
  /* Stops the scroll chain reaching the page, and kills iOS rubber-band
     bounce behind the overlay. */
  overscroll-behavior: none !important;
  /* Belt and braces on iOS: even with overflow:hidden, touch-dragging the
     background could still pan in older WebKit. */
  -webkit-overflow-scrolling: auto !important;
  /* touch-action must NOT be `none` here: that would also kill scrolling
     INSIDE the overlay on touch devices, because the overlay is a
     descendant of <body>. `pan-x pan-y` is left alone deliberately. */
}

/* Scrollbar-gutter compensation.
   On desktop engines with classic space-taking scrollbars, hiding the
   overflow reclaims ~15px and the whole page jumps sideways. scroll-lock.js
   measures the real gutter and publishes it as --dtt-sbw, so we pad it back.
   On mobile and on overlay-scrollbar engines the variable is never set and
   the fallback of 0px means nothing changes. */
body.dtt-scroll-locked {
  padding-right: var(--dtt-sbw, 0px) !important;
}
/* The portal-standard fixed header spans the full viewport width, so it
   needs the same compensation or it shifts while the body does not. */
html.dtt-scroll-locked #hdr {
  padding-right: calc(20px + var(--dtt-sbw, 0px));
}

/* An overlay's own scroll container must keep working, and must not chain
   its scroll back out to the page when it reaches its end. Applies to the
   portal's overlay card conventions plus the new pages. */
html.dtt-scroll-locked .modal-card,
html.dtt-scroll-locked .modal-box,
html.dtt-scroll-locked [role="dialog"] > * {
  overscroll-behavior: contain;
}
