/* ══════════════════════════════════════════════════════════════
   MOTION TOKENS — "Snappy" (chosen in Motion Lab, Nov 2 2026; slowed ~25% Nov 3
   after the user said it felt a bit fast: 120/220/300/650 -> 150/280/380/800)
   Quick, with a tiny spring on small things. Every shared animation reads
   these; change a value here and the whole app moves together.
   (Named --motion-*: the Motion Lab preview uses its own --m-* names.)
   ══════════════════════════════════════════════════════════════ */
:root {
    --motion-fast:   150ms;   /* taps, exits, hovers */
    --motion-base:   280ms;   /* toasts, menus, page change, rows arriving */
    --motion-slow:   380ms;   /* dialogs, panels, larger moves */
    --motion-count:  800ms;   /* numbers counting */
    --motion-dist:   10px;    /* how far things travel when they appear */
    --motion-enter:  cubic-bezier(.2, .8, .2, 1);     /* fast start, soft stop */
    --motion-exit:   cubic-bezier(.4, 0, 1, 1);       /* quick, gets out of the way */
    --motion-spring: cubic-bezier(.34, 1.45, .64, 1); /* tiny overshoot: badges, bell */
}

/* static/css/hp-restyle.css
 * Restyles the existing sidebar (.app-sidebar) and toasts (.toast-notification)
 * with the "hp" design tokens. HTML and behaviour stay as they are.
 * Loaded in templates/base.html right after base.css.
 * To rebrand, change only --hp-fill, --hp-fill-press and --hp-accent (light + dark).
 */

/* ---------- Tokens: light ---------- */
/* Colours are the original green palette from base.css (Oct 2026: users found
   the brown theme hard to read); the hp layout and sizes stay. */
:root {
    --hp-fill: #2A9D5C;
    --hp-fill-press: #248850;
    --hp-on-fill: #FFFFFF;
    --hp-accent: #2A9D5C;
    --hp-soft: #CDEBD9;
    --hp-tint: #EEF3F0;

    --hp-bg: #FFFFFF;
    --hp-bg-2: #F0F4F2;
    --hp-card: #FFFFFF;
    --hp-input: #FFFFFF;
    --hp-line: #E8EEEB;
    --hp-divider: #DDE8E2;
    --hp-text: #1C1C1C;
    --hp-muted: #6B6B6B;

    --hp-ok: #4CAF50;
    --hp-ok-soft: #E8F5E9;
    --hp-ok-ink: #2E7D32;
    --hp-on-ok: #FFFFFF;     /* text/tick on a green fill */
    --hp-warn: #FF9800;
    --hp-warn-soft: #FFF3E0;
    --hp-warn-ink: #B45309;
    --hp-danger: #E0434F;
    --hp-danger-soft: #FDECEE;
    --hp-badge: #FFB320;

    --hp-shadow: 0 4px 14px rgba(26, 46, 34, .12);
    --hp-shadow-sm: 0 2px 8px rgba(26, 46, 34, .08);
    --accent-glow: rgba(42, 157, 92, .22);

    --hp-radius: 13px;
    --radius-sm: 10px;
    --radius-lg: 18px;
    --radius-xl: 22px;
}

/* ---------- Tokens: dark (screen only, print stays light) ---------- */
@media screen {
    :root[data-theme="dark"] {
        --hp-fill: #818CF8;
        --hp-fill-press: #6F7BF0;
        --hp-on-fill: #111111;
        --hp-accent: #818CF8;
        --hp-soft: rgba(129, 140, 248, .35);
        --hp-tint: #262626;

        --hp-bg: #1C1C1C;
        --hp-bg-2: #111111;
        --hp-card: #1C1C1C;
        --hp-input: #262626;
        --hp-line: #2E2E2E;
        --hp-divider: #2A2A2A;
        --hp-text: #EDEDED;
        --hp-muted: #A0A0A0;

        --hp-ok-soft: rgba(76, 175, 80, .18);
        --hp-ok-ink: #8BD48F;
        --hp-warn-soft: rgba(255, 152, 0, .18);
        --hp-warn-ink: #FFC46B;
        --hp-danger-soft: rgba(224, 67, 79, .2);

        --hp-shadow: 0 4px 14px rgba(0, 0, 0, .28);
        --hp-shadow-sm: 0 2px 8px rgba(0, 0, 0, .2);
        --accent-glow: rgba(129, 140, 248, .22);
    }
}

/* ══════════════════════════════════════════════
   SIDEBAR: the original dark sidebar (green in light mode, near-black in dark),
   using base.css's --sidebar-* tokens; the hp shapes stay.
══════════════════════════════════════════════ */
.app-sidebar {
    background: var(--sidebar-bg);
    border-right: 1px solid var(--sidebar-dark);
}

.sidebar-logo,
.sidebar-footer { border-color: rgba(255, 255, 255, .10); }
.sidebar-divider { border-top-color: rgba(255, 255, 255, .10); }

.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .18); }

/* Collapse button on the sidebar edge */
.sidebar-toggle-btn {
    background: var(--hp-card);
    border-color: var(--hp-line);
    color: var(--hp-muted);
    box-shadow: var(--hp-shadow-sm);
}
.sidebar-toggle-btn:hover {
    background: var(--hp-fill);
    border-color: var(--hp-fill);
    color: var(--hp-on-fill);
}

/* Section labels */
.sidebar-nav-label,
body.sidebar-collapsed .sidebar-nav-label::before { color: var(--sidebar-text); opacity: .75; }

/* Nav items: soft text -> light wash on hover -> brighter wash when active */
.sidebar-nav-item {
    color: var(--sidebar-text);
    border-radius: var(--hp-radius);
    transition: all .2s;
}
.sidebar-nav-item:hover {
    background: var(--sidebar-hover);
    color: var(--sidebar-text-bright);
}
.sidebar-nav-item.active {
    background: rgba(255, 255, 255, .16);
    color: var(--sidebar-text-bright);
    box-shadow: none;
}

/* Icons sit plainly inside the item (no chip behind them) */
.sidebar-nav-icon,
.sidebar-nav-item:hover .sidebar-nav-icon,
.sidebar-nav-item.active .sidebar-nav-icon {
    background: transparent;
    color: inherit;
}

.sidebar-nav-item.danger:hover,
.sidebar-nav-item.danger:hover .sidebar-nav-icon {
    background: rgba(224, 67, 79, .22);
    color: #FFB4BA;
}
.sidebar-nav-item.danger:hover .sidebar-nav-icon { background: transparent; }

.sidebar-nav-badge.gold { background: var(--hp-badge); color: #1C1C1C; }

/* Footer: user */
.sidebar-user-avatar {
    width: 36px;
    height: 36px;
    background: rgba(255, 255, 255, .12);
    border: 2px solid rgba(255, 255, 255, .22);
    color: var(--sidebar-text-bright);
    font-size: .9rem;
    transition: border-color .2s;
}
.sidebar-user:hover .sidebar-user-avatar { border-color: var(--sidebar-active); }
.sidebar-user-name { color: var(--sidebar-text-bright); }
.sidebar-user-role { color: var(--sidebar-text); }

/* Mobile hamburger */
.sidebar-mobile-toggle {
    background: var(--hp-fill);
    color: var(--hp-on-fill);
    border-radius: var(--hp-radius);
    box-shadow: 0 4px 12px var(--accent-glow);
}
.sidebar-mobile-toggle:hover { background: var(--hp-fill-press); }

/* ══════════════════════════════════════════════
   TOASTS  (showToast in templates/_base_scripts.html)
   The card stays neutral; only the icon carries the colour.
══════════════════════════════════════════════ */
#toast-container {
    top: 20px !important;
    left: 50% !important;
    right: auto !important;
    transform: translateX(-50%) !important;
    z-index: 2147483647 !important;
    width: min(340px, calc(100vw - 32px));
    align-items: center !important;
}

.toast-notification,
[data-theme="dark"] .toast-notification {
    --toast-ink: var(--hp-muted);
    --toast-soft: var(--hp-bg-2);
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-width: 0;
    max-width: none;
    box-sizing: border-box;
    margin-bottom: 10px;
    padding: 11px 12px 11px 11px;
    background: var(--hp-card);
    color: var(--hp-text);
    border: 1px solid var(--hp-line);
    border-radius: 14px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .14), 0 2px 6px rgba(0, 0, 0, .06);
    animation: hpToastIn var(--motion-base) var(--motion-enter) both;
}
.toast-notification.success { --toast-ink: var(--hp-ok);     --toast-soft: var(--hp-ok-soft); }
.toast-notification.error   { --toast-ink: var(--hp-danger); --toast-soft: var(--hp-danger-soft); }
.toast-notification.warning { --toast-ink: var(--hp-warn);   --toast-soft: var(--hp-warn-soft); }

.toast-notification.removing { animation: hpToastOut var(--motion-fast) var(--motion-exit) forwards; }

/* Icon */
.toast-notification .toast-icon,
[data-theme="dark"] .toast-notification .toast-icon {
    position: relative;
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 50%;
    border: none;
    background: var(--toast-soft);
    color: var(--toast-ink);
    animation: hpToastPop .5s cubic-bezier(.34, 1.8, .5, 1) .08s both;
}
.toast-notification .toast-icon::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid var(--toast-ink);
    opacity: 0;
    animation: hpToastRing .7s ease-out .2s both;
}
.toast-notification .toast-icon svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.toast-notification.success .toast-icon path,
.toast-notification.error .toast-icon path {
    stroke-dasharray: 30;
    stroke-dashoffset: 30;
    animation: hpToastDraw .4s ease-out .32s forwards;
}
.toast-notification.error .toast-icon path + path { animation-delay: .44s; }
.toast-notification.error .toast-icon svg   { animation: hpToastShake .4s ease-in-out .75s; }
.toast-notification.warning .toast-icon svg { animation: hpToastBounce .6s ease-in-out .45s; }

/* Text */
.toast-notification .toast-title,
[data-theme="dark"] .toast-notification .toast-title {
    font-size: var(--fs-body);
    font-weight: 600;
    line-height: 1.3;
    margin-bottom: 0;
    color: var(--hp-text);
}
.toast-notification .toast-message,
[data-theme="dark"] .toast-notification .toast-message {
    font-size: var(--fs-btn);
    font-weight: 500;
    line-height: 1.4;
    margin-top: 2px;
    color: var(--hp-muted);
    overflow-wrap: anywhere;
}

/* Close */
.toast-notification .toast-close,
[data-theme="dark"] .toast-notification .toast-close {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    font-size: 18px;
    color: var(--hp-muted);
    background: transparent;
}
.toast-notification .toast-close:hover,
[data-theme="dark"] .toast-notification .toast-close:hover {
    background: var(--hp-bg-2);
    color: var(--hp-text);
}

/* Progress (also the timer; pauses on hover) */
.toast-notification .toast-progress,
[data-theme="dark"] .toast-notification .toast-progress {
    height: 3px;
    border-radius: 0;
    background: var(--hp-line);
}
.toast-notification:hover .toast-progress { animation-play-state: paused; }

@keyframes hpToastIn  { from { opacity: 0; transform: translateY(calc(var(--motion-dist) * -1)) scale(.96); } }
@keyframes hpToastOut { to { opacity: 0; transform: translateY(calc(var(--motion-dist) * -.6)) scale(.97); } }
@keyframes hpToastPop { from { transform: scale(0) rotate(-45deg); } }
@keyframes hpToastRing {
    0%   { transform: scale(1); opacity: .6; }
    100% { transform: scale(1.7); opacity: 0; }
}
@keyframes hpToastDraw { to { stroke-dashoffset: 0; } }
@keyframes hpToastShake {
    0%, 100% { transform: translateX(0); }
    20%, 60% { transform: translateX(-3px); }
    40%, 80% { transform: translateX(3px); }
}
@keyframes hpToastBounce {
    0%, 100% { transform: translateY(0); }
    30%      { transform: translateY(-3px); }
    60%      { transform: translateY(0); }
    80%      { transform: translateY(-1.5px); }
}

@media (max-width: 768px) {
    #toast-container { top: 60px !important; }
}

/* Reduced motion: no animation, icon fully drawn */
@media (prefers-reduced-motion: reduce) {
    .toast-notification,
    .toast-notification.removing,
    .toast-notification .toast-icon,
    .toast-notification .toast-icon::after,
    .toast-notification .toast-icon svg,
    .toast-notification .toast-icon path,
    .toast-notification .toast-progress { animation: none !important; }
    .toast-notification .toast-icon path { stroke-dashoffset: 0 !important; }
}

/* ══════════════════════════════════════════════
   PAGES: point the app's existing tokens (base.css) at the hp tokens,
   so every page that uses var(--bg-surface), var(--blue)... follows.
   Fills with text on them use --hp-fill / --hp-on-fill directly.
══════════════════════════════════════════════ */
:root {
    --bg-card:        var(--hp-card);
    --bg-base:        var(--hp-card);
    --bg-surface:     var(--hp-card);
    --bg-raised:      var(--hp-bg-2);
    --bg-hover:       var(--hp-tint);
    --border:         var(--hp-line);
    --border-bright:  color-mix(in srgb, var(--hp-line) 75%, var(--hp-muted));

    --text-primary:   var(--hp-text);
    --text-secondary: color-mix(in srgb, var(--hp-text) 55%, var(--hp-muted));
    --text-muted:     var(--hp-muted);

    --accent:         var(--hp-accent);
    --accent-dim:     var(--hp-fill-press);
    --blue:           var(--hp-accent);
    --blue-glow:      color-mix(in srgb, var(--hp-accent) 13%, transparent);
    --cyan:           var(--hp-accent);
    --cyan-glow:      color-mix(in srgb, var(--hp-accent) 13%, transparent);
    --gold:           var(--hp-warn);
    --gold-glow:      var(--hp-warn-soft);
    --red:            var(--hp-danger);
    --red-glow:       var(--hp-danger-soft);

    --page-bg:        var(--hp-bg-2);
    --page-bg-img:    none;
    --navbar-bg:      var(--hp-bg);
    --footer-bg:      var(--hp-bg);
    --footer-border:  var(--hp-line);

    --tooltip-bg:     var(--hp-text);
    --tooltip-text:   var(--hp-bg);
    --shadow-color:   rgba(26, 46, 34, .12);
    --card-shadow:    var(--hp-shadow-sm);

    /* --sidebar-* keep their base.css values (the dark sidebar) */

    --m3-primary:           var(--hp-accent);
    --m3-primary-container: var(--hp-tint);
    --m3-surface-low:       var(--hp-card);
    --m3-surface-high:      color-mix(in srgb, var(--hp-accent) 6%, var(--hp-card));
    --m3-outline:           var(--hp-line);
}
@media screen {
    :root[data-theme="dark"] {
        --accent-dim:   color-mix(in srgb, var(--hp-accent) 14%, transparent);
        --tooltip-bg:   var(--hp-card);
        --tooltip-text: var(--hp-text);
        --shadow-color: rgba(0, 0, 0, .28);
    }
}

body {
    background: var(--hp-bg-2);
    color: var(--hp-text);
    transition: background-color .3s, color .3s;
}
::selection { background: var(--hp-soft); color: var(--hp-text); }
* { scrollbar-width: thin; scrollbar-color: var(--hp-line) transparent; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--hp-line); border-radius: 8px; }

/* ---------- Top bar ---------- */
.app-topbar,
.app-topbar.m3-scrolled {
    background: var(--hp-bg);
    border-bottom: 1px solid var(--hp-line);
}
.app-topbar-left h1 { color: var(--hp-text); }
.app-topbar-subtitle { color: var(--hp-muted); }

.topbar-icon-btn { color: var(--hp-muted); }
.topbar-icon-btn:hover,
.topbar-icon-btn:active,
.topbar-icon-btn:focus,
.topbar-icon-btn.show {
    background: var(--hp-tint);
    color: var(--hp-text);
    transform: none;
}
[data-theme="dark"] :is(.topbar-icon-btn:hover, .topbar-icon-btn:active, .topbar-icon-btn:focus, .topbar-icon-btn.show) {
    background: var(--hp-card);
}
body:not(.sidebar-collapsed) #sidebarCollapseToggle { background: var(--hp-tint); color: var(--hp-accent); }

.tlb { border-radius: var(--radius-sm); }
.tlb:hover { background: var(--hp-tint); color: var(--hp-text); }
.tlb.active { background: var(--hp-fill); color: var(--hp-on-fill); }
.topbar-notif-badge { background: var(--hp-danger); color: var(--hp-on-fill); }
[data-theme="dark"] .topbar-notif-badge { color: var(--hp-text); }

/* ---------- Cards: hp card (thin line + soft shadow) ---------- */
html :is( .stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card) {
    background: var(--hp-card);
    border: 1px solid var(--hp-line);
    border-radius: var(--hp-radius);
    box-shadow: var(--hp-shadow-sm);
}
html :is( .stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card):hover { border-color: var(--hp-line); }

/* ---------- Buttons ---------- */
.btn { border-radius: var(--hp-radius); }
html .btn-primary {
    background: var(--hp-fill);
    border-color: var(--hp-fill);
    color: var(--hp-on-fill);
}
html .btn-primary:hover,
html .btn-primary:focus,
html .btn-primary:active,
html .btn-primary.active {
    background: var(--hp-fill-press);
    border-color: var(--hp-fill-press);
    color: var(--hp-on-fill);
}
html .btn-primary:focus-visible { box-shadow: 0 0 0 3px var(--accent-glow); }
html .btn-outline-primary { color: var(--hp-accent); border-color: var(--hp-accent); background: transparent; }
html .btn-outline-primary:hover,
html .btn-outline-primary.active { background: var(--hp-fill); border-color: var(--hp-fill); color: var(--hp-on-fill); }

/* ---------- Inputs ---------- */
.form-control, .form-select {
    background: var(--hp-input);
    border-color: var(--hp-line);
    color: var(--hp-text);
}
.form-control:focus, .form-select:focus,
.app-content :is(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]), select, textarea):focus {
    background: var(--hp-input);
    border-color: var(--hp-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--hp-accent) 18%, transparent);
    outline: none;
}
.form-check-input:checked { background-color: var(--hp-fill); border-color: var(--hp-fill); }

/* ---------- Menus, dialogs, tables ---------- */
.dropdown-menu { border: 1px solid var(--hp-line); background: var(--hp-card); box-shadow: var(--hp-shadow); }
.dropdown-item:hover, .dropdown-item:focus { background: var(--hp-tint); color: var(--hp-text); }
[data-theme="dark"] :is(.dropdown-item:hover, .dropdown-item:focus) { background: var(--hp-bg-2); }
.modal-content, #confirm-modal-box { background: var(--hp-card); border: 1px solid var(--hp-line); border-radius: var(--radius-xl); }
.table { --bs-table-bg: transparent; color: var(--hp-text); }
.table thead th { background: var(--hp-bg-2); color: var(--hp-muted); border-bottom: 1px solid var(--hp-line); }
.table > :not(caption) > * > * { border-bottom-color: var(--hp-divider); }
.table-hover > tbody > tr:hover > * { background: var(--hp-tint); color: var(--hp-text); --bs-table-accent-bg: transparent; }
[data-theme="dark"] .table-hover > tbody > tr:hover > * { background: var(--hp-bg-2); }
.page-link { color: var(--hp-accent); }
a { color: var(--hp-accent); }

/* Bootstrap draws a 2px currentColor line between thead and tbody */
.table > :not(:first-child) { border-top: 1px solid var(--hp-line); }

/* Switches: base.css "input { max-width:100% }" squeezed them to 2px
   inside their zero-width .form-switch wrapper */
.form-switch .form-check-input { max-width: none; flex-shrink: 0; }
.form-switch .form-check-input:checked { background-color: var(--hp-fill) !important; border-color: var(--hp-fill) !important; }

/* Toast frame + timer bar (MemoFlow does not load base.css, so it lives here too) */
.toast-notification { position: relative; overflow: hidden; pointer-events: auto; white-space: normal; }
.toast-notification .toast-content { flex: 1; min-width: 0; }
.toast-notification .toast-close { display: flex; align-items: center; justify-content: center; flex-shrink: 0; border: none; padding: 0; cursor: pointer; line-height: 1; }
.toast-notification .toast-progress {
    position: absolute; left: 0; right: 0; bottom: 0;
    transform-origin: left;
    animation: hpToastProg var(--toast-dur, 5000ms) linear forwards;
}
@keyframes hpToastProg { from { transform: scaleX(1); } to { transform: scaleX(0); } }

/* ══════════════════════════════════════════════
   MEMOFLOW (templates/memoflow/base.html)
   Same tokens; MemoFlow keeps its own theme switch (localStorage "mf-theme").
══════════════════════════════════════════════ */
:root {
    --green:          var(--hp-ok);
    --green-glow:     var(--hp-ok-soft);
    --purple-dim:     color-mix(in srgb, var(--purple) 12%, transparent);
    --bg-surface-alt: var(--hp-card);
    --primary-color:  var(--hp-accent);
    --success-color:  var(--hp-ok);
    --warning-color:  var(--hp-warn);
    --danger-color:   var(--hp-danger);
}

.mf-navbar {
    background: var(--hp-bg);
    border-bottom: 1px solid var(--hp-line);
    box-shadow: none;
}
.mf-logo-text span { color: var(--hp-accent); }

.mf-icon-btn,
.mf-search-inner {
    background: var(--hp-card);
    border-color: var(--hp-line);
    color: var(--hp-muted);
    border-radius: var(--hp-radius);
    box-shadow: var(--hp-shadow-sm);
}
.mf-icon-btn:hover {
    background: var(--hp-tint);
    color: var(--hp-text);
    border-color: var(--hp-line);
    transform: none;
    box-shadow: var(--hp-shadow-sm);
}
[data-theme="dark"] .mf-icon-btn:hover { background: var(--hp-bg-2); }
.mf-icon-btn.active { background: var(--hp-fill); color: var(--hp-on-fill); border-color: var(--hp-fill); }

.mf-sidebar {
    background: var(--hp-bg);
    border-right: 1px solid var(--hp-line);
}
.mf-sidebar-label { color: var(--hp-muted); }
.mf-sidebar-divider { background: var(--hp-divider); border-color: var(--hp-divider); }
.mf-sidebar-nav a {
    color: var(--hp-muted);
    border-radius: var(--hp-radius);
    transition: all .2s;
}
.mf-sidebar-nav a:hover { background: var(--hp-tint); color: var(--hp-text); }
[data-theme="dark"] .mf-sidebar-nav a:hover { background: var(--hp-card); }
.mf-sidebar-nav a.active {
    background: var(--hp-fill);
    color: var(--hp-on-fill);
    box-shadow: 0 4px 12px var(--accent-glow);
}
/* Private memos keep their amber, as tokens */
.mf-sidebar-nav a.mf-private-link { color: var(--hp-warn-ink); }
.mf-sidebar-nav a.mf-private-link:hover { color: var(--hp-warn-ink); background: var(--hp-warn-soft); }
.mf-sidebar-nav a.mf-private-link.active { color: var(--hp-warn-ink); background: var(--hp-warn-soft); box-shadow: none; }

.mf-notif-dropdown { background: var(--hp-card); border-color: var(--hp-line); box-shadow: var(--hp-shadow); }

/* MemoFlow toast container: same place and width as the main app's */
.toast-container {
    top: 72px;
    z-index: 2147483647;
    width: min(340px, calc(100vw - 32px));
    gap: 0;
}

/* ══════════════════════════════════════════════
   STATUS BADGES: soft tonal pills instead of solid fills.
   --sb-<colour> is the pill background and --sb-<colour>-on its text, so every
   badge that uses them (all pages + MemoFlow) changes here.
   --sbc-<colour> keeps solid versions for charts (Chart.js needs plain colours).
══════════════════════════════════════════════ */
:root {
    --sb-green:  #E8F5E9; --sb-green-on:  #2E7D32;
    --sb-red:    #FDECEE; --sb-red-on:    #B42833;
    --sb-amber:  #FFF3E0; --sb-amber-on:  #B45309;
    --sb-orange: #FDEBDD; --sb-orange-on: #B4471B;
    --sb-blue:   #E8EEFA; --sb-blue-on:   #2F5DB3;
    --sb-teal:   #E0F2EF; --sb-teal-on:   #0F766E;
    --sb-purple: #F0EAFB; --sb-purple-on: #6D3FC0;
    --sb-gray:   #EFEDEC; --sb-gray-on:   #5F5F5F;

    --sbc-green: #4CAF50; --sbc-red: #E0434F; --sbc-amber: #FF9800; --sbc-orange: #F07B3F;
    --sbc-blue: #5B7FD6; --sbc-teal: #26A69A; --sbc-purple: #8E6CD8; --sbc-gray: #9E9E9E;
}
@media screen {
    :root[data-theme="dark"] {
        --sb-green:  rgba(76, 175, 80, .18);   --sb-green-on:  #8BD48F;
        --sb-red:    rgba(224, 67, 79, .2);    --sb-red-on:    #F5A0A7;
        --sb-amber:  rgba(255, 152, 0, .18);   --sb-amber-on:  #FFC46B;
        --sb-orange: rgba(240, 123, 63, .2);   --sb-orange-on: #FFAD85;
        --sb-blue:   rgba(120, 150, 230, .2);  --sb-blue-on:   #AFC4F6;
        --sb-teal:   rgba(45, 212, 191, .16);  --sb-teal-on:   #7FE0D2;
        --sb-purple: rgba(167, 139, 250, .18); --sb-purple-on: #CBB8FC;
        --sb-gray:   rgba(181, 186, 203, .16); --sb-gray-on:   #C9CDDA;

        --sbc-green: #66BB6A; --sbc-red: #EF5A65; --sbc-amber: #FFA726; --sbc-orange: #FF8A50;
        --sbc-blue: #7C9AE6; --sbc-teal: #4DB6AC; --sbc-purple: #A78BFA; --sbc-gray: #A9AEBE;
    }
}

/* Count badges stay solid so numbers pop */
.sidebar-nav-badge,
.topbar-notif-badge {
    background: var(--hp-danger);
    color: var(--hp-on-fill);
    border-color: var(--hp-danger);
}
[data-theme="dark"] :is(.sidebar-nav-badge, .topbar-notif-badge) { color: var(--hp-bg); }
.sidebar-nav-item.active .sidebar-nav-badge { background: var(--hp-on-fill); color: var(--hp-fill); }

/* ══════════════════════════════════════════════
   STAT / KPI CARDS: neutral hp card; only the number and a round icon carry
   the card's colour (--k = soft, --k-on = ink, set by each page).
   :not(#hp) adds ID weight so this beats each page's own "SOLID KPI" !important block.
══════════════════════════════════════════════ */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp),
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp):hover {
    background: var(--hp-card) !important;
    border: 1px solid var(--hp-line) !important;
    border-radius: var(--hp-radius) !important;
    box-shadow: var(--hp-shadow-card) !important;
    color: var(--hp-text) !important;
    transform: none !important;
}
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) *:not(.m3-ink-host):not(.m3-ripple) {
    color: var(--hp-text) !important;
    opacity: 1 !important;
}
/* Labels and hints: muted */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="headline"], [class*="label"], [class*="lbl"], [class*="title"], [class*="sub"], [class*="hint"], [class*="desc"]):not(#hp),
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="headline"], [class*="label"], [class*="lbl"], [class*="title"], [class*="sub"], [class*="hint"], [class*="desc"]):not(#hp) * {
    color: var(--hp-muted) !important;
}
/* The number: the card's ink colour */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="num"], [class*="value"], [class*="val"], [class*="amount"], [class*="big"], [class*="count"]):not(#hp) {
    color: var(--k-on, var(--hp-text)) !important;
}
/* Icon: soft circle in the card's colour */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) [class*="icon"]:not(#hp) {
    background: var(--k, var(--hp-tint)) !important;
    border-color: transparent !important;
    border-radius: 50% !important;
}
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) [class*="icon"]:not(#hp),
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) [class*="icon"]:not(#hp) * {
    color: var(--k-on, var(--hp-accent)) !important;
}
/* Pills inside a card */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="pill"], [class*="badge"]):not(#hp) {
    background: var(--k, var(--hp-tint)) !important;
    color: var(--k-on, var(--hp-accent)) !important;
    border-color: transparent !important;
}
/* Clickable filter cards: selected state */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card).active:not(#hp) {
    outline: 2px solid var(--k-on, var(--hp-accent)) !important;
    outline-offset: 2px;
}

/* ══════════════════════════════════════════════
   TOP BAR BUTTONS: round, card-coloured, soft shadow
══════════════════════════════════════════════ */
.topbar-icon-btn {
    width: 38px;
    height: 38px;
    background: var(--hp-card);
    border: 1px solid var(--hp-line) !important;
    border-radius: 50% !important;
    box-shadow: var(--hp-shadow-sm);
    color: var(--hp-muted);
    transition: background-color .2s, color .2s, box-shadow .2s, transform .2s;
}
.topbar-icon-btn.wide {
    width: auto;
    height: 38px;
    padding: 0 .95rem;
    border-radius: 999px !important;
}
.topbar-icon-btn:hover,
.topbar-icon-btn:focus-visible,
.topbar-icon-btn.show {
    background: var(--hp-tint);
    color: var(--hp-text);
    box-shadow: var(--hp-shadow);
    transform: translateY(-1px);
}
[data-theme="dark"] :is(.topbar-icon-btn:hover, .topbar-icon-btn:focus-visible, .topbar-icon-btn.show) { background: var(--hp-bg-2); }
.topbar-icon-btn:active { transform: none; box-shadow: var(--hp-shadow-sm); }
/* Language switch: one pill holding EN · ខ្មែរ */
.topbar-lang-toggle {
    height: 38px;
    padding: 0 5px;
    background: var(--hp-card);
    border: 1px solid var(--hp-line);
    border-radius: 999px;
    box-shadow: var(--hp-shadow-sm);
}
.topbar-lang-toggle .tlb { border-radius: 999px; padding: .32rem .6rem; }

/* MemoFlow top bar: same round buttons */
.mf-icon-btn { border-radius: 50% !important; }
.mf-icon-btn:hover { box-shadow: var(--hp-shadow); transform: translateY(-1px); }
.mf-search-inner { border-radius: 999px !important; }

/* ══════════════════════════════════════════════
   TYPE: Kantumruy Pro for English + Khmer (same as the POS system).
   Weights: 400 body/cells/inputs · 500 buttons/tabs/menu · 600 labels/headers/names/badges
            700 titles/prices/totals/big numbers.
   Scale:   32 stat numbers · 22 page title · 18 card/section headings · 16 prices, totals,
            primary button · 15 body, cells, inputs, item names · 14 buttons, tabs, secondary
            · 13 captions, badges, small labels. (One step up from the POS scale: user wanted bigger text.)
   Khmer keeps its tuned sizes in base.css (html[lang="km"] … !important), which sit on the
   same steps (14 / 13 / 12px).
══════════════════════════════════════════════ */
:root {
    --font: 'Kantumruy Pro', 'Segoe UI', system-ui, sans-serif;
    --fs-stat: 32px;
    --fs-title: 22px;   /* page title; 28px made the top bar too tall */
    --fs-head: 18px;
    --fs-price: 16px;
    --fs-body: 15px;
    --fs-btn: 14px;
    --fs-cap: 13px;
}
body {
    font-family: var(--font);
    font-size: var(--fs-body);
    font-weight: 400;
    letter-spacing: .2px;
    color: var(--hp-text);          /* #1F1F1F in light mode; follows dark mode */
}
button, input, select, textarea { font-family: inherit; letter-spacing: inherit; }

/* 22 / 700: page title (one per page), same in English and Khmer */
html .app-topbar-left h1,
html .mf-navbar-title h1,
html[lang="km"] .app-topbar-left h1,
html[lang="km"] .mf-navbar-title h1 {
    font-size: var(--fs-title) !important;
    font-weight: 700 !important;
    letter-spacing: .2px !important;
    line-height: 1.3 !important;
    margin: 0 !important;
    color: var(--hp-text);
}
/* 13 / 500: secondary text */
html .app-topbar-subtitle,
html .mf-navbar-subtitle,
html :is(.text-muted, small.text-muted) {
    font-size: var(--fs-btn);
    font-weight: 500;
    color: var(--hp-muted) !important;
}

/* 17 / 700: card and section headings */
html :is(#mainContent, main) :is(h2, h3, h4, h5):not(.modal-title),
html .card-title,
html :is(.card-header, [class*="card-header"], [class*="-head"]) :is(h4, h5, h6) {
    font-size: var(--fs-head);
    font-weight: 700;
    letter-spacing: .2px;
    line-height: 1.3;
}

/* 14 / 600: item / product names */
html :is(#mainContent, main) h6,
html :is([class*="item-name"], [class*="product-name"], .request-name, .req-title) {
    font-size: var(--fs-body);
    font-weight: 600;
    line-height: 1.3;
}

/* 14 / 400: body text, table cells, inputs */
html .table tbody td,
html table tbody td { font-size: var(--fs-body); font-weight: 400; }
html :is(.form-control, .form-select, textarea, input:not([type="checkbox"]):not([type="radio"])) {
    font-size: var(--fs-body);
    font-weight: 400;
}

/* 13 / 500: buttons, tabs, menu items */
html :is(.btn, .btn-sm, .nav-link, [role="tab"], [class*="filter-tab"], [class*="filter-btn"], .dropdown-item, .topbar-icon-btn.wide, .tlb),
html :is(.sidebar-nav-item, .sidebar-nav-item.active, .mf-sidebar-nav a, .mf-sidebar-nav a.active) {
    font-size: var(--fs-btn);
    font-weight: 500;
    letter-spacing: .2px;
}
/* 15 / 700: primary button label */
html .btn-primary {
    font-size: var(--fs-price);
    font-weight: 700;
    letter-spacing: .3px;
}

/* 15 / 700: prices and totals, digits lined up */
html :is([class*="total"], [class*="price"], [class*="amount"], [class*="grand"]):not(th):not(table):not(thead):not(tbody):not(tr):not([class*="card"]):not([class*="row"]):not([class*="wrap"]):not([class*="section"]):not([class*="label"]):not([class*="lbl"]) {
    font-size: var(--fs-price);
    font-weight: 700;
    letter-spacing: .3px;
    font-variant-numeric: tabular-nums;
}
html :is(td, [class*="num"], [class*="count"], [class*="qty"], [class*="value"]) { font-variant-numeric: tabular-nums; }

/* 12 / 600: captions, column headers, status badges, small labels */
/* Column headers on every table: 16 / 600 in the main text colour (brown in light
   mode, white in dark), so they read crisply. Same in English and Khmer. */
html .table thead th,
html table thead th {
    font-size: var(--fs-price) !important;   /* 16px */
    font-weight: 600 !important;
    letter-spacing: .2px !important;
    color: var(--hp-text) !important;
    /* On narrower screens a long header ("Days waiting") wraps to two lines between words
       instead of making the whole table wider than its card */
    white-space: normal !important;
    overflow-wrap: normal !important;
    line-height: 1.3 !important;
    vertical-align: middle;
}
html :is(.form-label, .form-group > label, .field-label, .sidebar-nav-label, .mf-sidebar-label) {
    font-size: var(--fs-cap);
    font-weight: 600;
    letter-spacing: .4px;
    color: var(--hp-muted);
}
html :is(.form-text, .help-text, .helptext, small) { font-size: var(--fs-cap); }
html :is(.badge, [class*="status-badge"], [class*="-badge"], [class*="-pill"]):not(.sidebar-nav-badge):not(.topbar-notif-badge):not(.mf-nav-badge):not(.mf-private-badge):not(.mf-approved-badge) {
    font-size: var(--fs-cap);
    font-weight: 600;
    letter-spacing: .2px;
}
html .sidebar-user-name { font-size: var(--fs-body); font-weight: 600; }
html .sidebar-user-role { font-size: var(--fs-cap); font-weight: 400; color: var(--hp-muted); }

/* Stat cards: 12/600 label · 32/700 number · 12 hint */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="headline"], [class*="label"], [class*="lbl"], [class*="title"]):not(#hp) {
    font-size: var(--fs-cap) !important;
    font-weight: 600 !important;
    letter-spacing: .4px !important;
}
html :is(.stat-card, .kpi-card, .db-kpi):not(#hp) :is([class*="num"], [class*="value"], [class*="val"], [class*="amount"], [class*="big"], [class*="count"]):not(#hp) {
    font-size: var(--fs-stat) !important;
    font-weight: 700 !important;
    letter-spacing: -.2px !important;
    line-height: 1.1 !important;
    font-variant-numeric: tabular-nums;
}
/* Request-detail metric cards hold words ("9 months, 1 week"), so they use the heading size */
html .metric-card:not(#hp) :is([class*="num"], [class*="value"], [class*="val"], [class*="amount"], [class*="big"]):not(#hp) {
    font-size: var(--fs-head) !important;
    font-weight: 700 !important;
}
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="sub"], [class*="hint"], [class*="desc"]):not(#hp) {
    font-size: var(--fs-cap) !important;
    font-weight: 500 !important;
}

/* ══════════════════════════════════════════════
   CONTAINER SHADOW: every card / panel gets the same soft lift.
   :not(#hp) outranks each page's own box-shadow rule.
══════════════════════════════════════════════ */
:root {
    --hp-shadow-card: 0 1px 3px rgba(26, 46, 34, .08), 0 6px 18px rgba(26, 46, 34, .10);
    --card-shadow: var(--hp-shadow-card);
}
@media screen {
    :root[data-theme="dark"] {
        --hp-shadow-card: 0 1px 3px rgba(0, 0, 0, .35), 0 6px 18px rgba(0, 0, 0, .28);
        --card-shadow: var(--hp-shadow-card);
    }
}
html :is(.stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card, .adv-card, .form-main, .db-kpi, .settings-nav, .upload-card, .workflow-card, .notif-card, .card):not(#hp),
html :is(.stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card, .adv-card, .form-main, .db-kpi, .settings-nav, .upload-card, .workflow-card, .notif-card, .card):not(#hp):hover {
    box-shadow: var(--hp-shadow-card);
}
/* Cards nested inside another card stay flat, so shadows don't stack */
html :is(.stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card, .adv-card, .form-main, .db-kpi, .settings-nav, .upload-card, .workflow-card, .notif-card, .card) :is(.stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card, .adv-card, .form-main, .db-kpi, .settings-nav, .upload-card, .workflow-card, .notif-card, .card):not(#hp),
html :is(.stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card, .adv-card, .form-main, .db-kpi, .settings-nav, .upload-card, .workflow-card, .notif-card, .card) :is(.stat-card, .main-card, .requests-card, .table-card, .form-card, .section-card, .side-card, .side-panel, .kpi-card, .metric-card, .lp-card, .rv-card, .rv-side-card, .rd-card, .li-card, .li-side-card, .ua-card, .ua-side-card, .cp-side-card, .da-side-card, .ft-side-card, .cat-card, .rc-card, .paid-card, .settings-card, .tab-content-card, .rejection-card, .memo-card, .mf-gm-card, .mf-gm-dept-card, .mf-gm-signers-card, .db-card, .info-card, .help-card, .history-card, .progress-card, .completion-card, .action-card, .report-card, .sidebar-card, .p-card, .identity-card, .danger-card, .qt-card, .pa-table-card, .po-table-card, .approved-summary-panel, .detail-card, .pricing-card, .da-card, .cp-card, .req-mobile-card, .filter-bar, .filter-tab-group, .toolbar-row, .pa-toolbar, .po-toolbar, .chart-card, .activity-card, .adv-card, .form-main, .db-kpi, .settings-nav, .upload-card, .workflow-card, .notif-card, .card):not(#hp):hover {
    box-shadow: none;
}

/* Root size: rem-based text is one step bigger (MemoFlow does not load base.css) */
html { font-size: 17px; }

/* Bigger labels: let stat-card labels wrap instead of being cut off with "…" */
html :is(.stat-card, .kpi-card, .db-kpi, .metric-card):not(#hp) :is([class*="headline"], [class*="label"], [class*="lbl"], [class*="title"]):not(#hp) {
    white-space: normal !important;
    overflow: visible !important;
    text-overflow: clip !important;
}

/* ══════════════════════════════════════════════
   MEMOFLOW: a bit more lift on containers and buttons.
   html:has(.mf-navbar) only matches MemoFlow pages; the main app keeps its shadow.
══════════════════════════════════════════════ */
html:has(.mf-navbar) {
    --hp-shadow-card: 0 2px 4px rgba(26, 46, 34, .10), 0 10px 26px rgba(26, 46, 34, .14);
    --hp-shadow-btn: 0 1px 2px rgba(26, 46, 34, .12), 0 4px 10px rgba(26, 46, 34, .12);
    --hp-shadow-btn-hover: 0 2px 4px rgba(26, 46, 34, .14), 0 8px 18px rgba(26, 46, 34, .16);
}
@media screen {
    html[data-theme="dark"]:has(.mf-navbar) {
        --hp-shadow-card: 0 2px 4px rgba(0, 0, 0, .40), 0 10px 26px rgba(0, 0, 0, .34);
        --hp-shadow-btn: 0 1px 2px rgba(0, 0, 0, .40), 0 4px 10px rgba(0, 0, 0, .30);
        --hp-shadow-btn-hover: 0 2px 4px rgba(0, 0, 0, .45), 0 8px 18px rgba(0, 0, 0, .38);
    }
}
/* Buttons (the segmented "This month / 6 months" switch gets one shadow as a group) */
html:has(.mf-navbar) :is(.btn:not(.btn-link):not(.btn-close), .mf-navbar-action-btn, .btn-filter-search, .ml-dd-btn, .m3-seg, .mf-icon-btn) {
    box-shadow: var(--hp-shadow-btn);
    transition: box-shadow .2s, transform .2s, background-color .2s, color .2s;
}
html:has(.mf-navbar) :is(.btn:not(.btn-link):not(.btn-close), .mf-navbar-action-btn, .btn-filter-search, .ml-dd-btn, .mf-icon-btn):hover {
    box-shadow: var(--hp-shadow-btn-hover);
    transform: translateY(-1px);
}
html:has(.mf-navbar) :is(.btn, .mf-navbar-action-btn, .btn-filter-search, .ml-dd-btn, .mf-icon-btn):active {
    box-shadow: var(--hp-shadow-btn);
    transform: none;
}
/* Filled (brand) buttons glow in their own colour */
html:has(.mf-navbar) :is(.btn-primary, .mf-navbar-action-btn.primary, .btn-filter-search):not(#hp) {
    box-shadow: 0 2px 4px var(--accent-glow), 0 6px 14px var(--accent-glow);
}
html:has(.mf-navbar) :is(.btn-primary, .mf-navbar-action-btn.primary, .btn-filter-search):not(#hp):hover {
    box-shadow: 0 3px 6px var(--accent-glow), 0 10px 22px var(--accent-glow);
}
/* The segment buttons sit inside the shadowed group, so they stay flat */
html:has(.mf-navbar) .m3-seg-btn { box-shadow: none; }
html:has(.mf-navbar) .ml-dd.open .ml-dd-btn { box-shadow: inset 0 0 0 1px var(--hp-accent), var(--hp-shadow-btn); }

/* ══════════════════════════════════════════════
   TOP BAR SHADOW (main app + MemoFlow): soft shadow under the bar,
   so it reads as a layer above the page when content scrolls under it.
══════════════════════════════════════════════ */
:root { --hp-shadow-bar: 0 1px 2px rgba(26, 46, 34, .06), 0 4px 14px rgba(26, 46, 34, .09); }
@media screen {
    :root[data-theme="dark"] { --hp-shadow-bar: 0 1px 2px rgba(0, 0, 0, .35), 0 4px 14px rgba(0, 0, 0, .28); }
}
html .app-topbar,
html .app-topbar.m3-scrolled,
html .mf-navbar {
    box-shadow: var(--hp-shadow-bar);   /* keeps each bar's own sticky position */
}

/* ══════════════════════════════════════════════
   FILTER DROPDOWNS: the chosen text stays on one line. Dropdowns in toolbars and filter
   bars size to their longest option instead of a fixed width (the 140px Dept filter
   wrapped "All Departments" onto two lines after the text got bigger).
══════════════════════════════════════════════ */
select:not([multiple]):not([size]) {
    white-space: nowrap;
    text-overflow: ellipsis;
}
html :is([class*="toolbar"], [class*="filter"]) select:not([multiple]):not([size]) {
    width: auto !important;
    min-width: 9rem;
    max-width: 100%;
}

/* ══════════════════════════════════════════════
   STAT CARDS: icon in the top-right corner, text on the left
   (Approved Requests, Reports; MemoFlow cards already work this way).
══════════════════════════════════════════════ */
html :is(.stat-card, .kpi-card):has(> [class*="icon"]):not(#hp) {
    flex-direction: row-reverse !important;
    align-items: flex-start !important;
    justify-content: space-between !important;
}
html :is(.stat-card, .kpi-card):has(> [class*="icon"]):not(#hp) > :not([class*="icon"]) {
    flex: 1;
    min-width: 0;
}


/* ══════════════════════════════════════════════
   ROUNDED FILTER BARS (Oct 26): every search box, filter dropdown and
   filter button is a pill, like the My Requests / Not Completed tabs.
   Only controls inside filter / toolbar / search areas; form inputs on
   create/edit pages keep their normal corners.
══════════════════════════════════════════════ */
/* Search boxes: icon on the left, so only the right side needs more room */
html :is(.toolbar-search, .table-search, .adv-search input, .db-tsearch input, .filter-query,
         .cat-srch, .catalog-panel-search, .oo-filter input, #mainContent input[type="search"]):not(#hp) {
    border-radius: 999px !important;
    padding-right: .9rem !important;
}
/* Dropdowns and plain filter inputs */
html :is(.toolbar-input:not(.toolbar-search), .adv-filter-select, .filter-input, .filter-select,
         .filter-date, .filter-bar .ml-dd-btn, .oo-filter select):not(#hp) {
    border-radius: 999px !important;
    padding-left: .9rem !important;
}
/* Filter buttons (Search, Clear, Fast-track, Export...) */
html :is(.filter-btn, .filter-btn-primary, .filter-btn-clear, .toolbar-btn, .toolbar-btn-clear,
         .toolbar-btn-fast, .btn-filter-search, .btn-filter-clear, .oo-filter button):not(#hp) {
    border-radius: 999px !important;
    padding-left: 1rem !important;
    padding-right: 1rem !important;
}

/* ══════════════════════════════════════════════
   LATE PRs PILL (top bar, next to the bell; PO + Purchasing Manager).
   Replaces the big dashboard banner. Phone: icon + number only.
══════════════════════════════════════════════ */
.topbar-late-pill {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    height: 38px;
    padding: 0 .95rem;
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--red) 40%, transparent);
    background: color-mix(in srgb, var(--red) 10%, var(--hp-card, var(--bg-surface)));
    color: var(--red);
    font-weight: 600;
    font-size: .875rem;
    white-space: nowrap;
    text-decoration: none;
}
.topbar-late-pill:hover { background: var(--red); border-color: var(--red); color: #fff; }
.topbar-late-pill i { font-size: 1.05rem; }
@media (max-width: 768px) {
    .topbar-late-pill { padding: 0 .7rem; height: 40px; }
    .topbar-late-pill span { font-size: 0; }
    .topbar-late-pill span::before { content: attr(data-n); font-size: .875rem; }
}

/* -- Count-up for [data-countup] numbers (window.hpCountUp in _base_scripts) --
   Drawn by CSS: an animated integer (@property) shown through a counter in
   ::after, over the real number, which stays in the DOM (screen readers, layout)
   with its glyphs made transparent. Changing textContent every frame instead made
   the browser restyle the whole page (its :has() rules), 80-120ms/frame on phones. */
@property --hp-cnt { syntax: '<integer>'; initial-value: 0; inherits: false; }
@keyframes hpCount { from { --hp-cnt: var(--from, 0); } to { --hp-cnt: var(--to); } }   /* --from: live update (hpCountTo) */
[data-countup].hp-counting {
    position: relative;
    -webkit-text-fill-color: transparent;
    counter-reset: hpcnt var(--hp-cnt);
    animation: hpCount var(--motion-count) var(--motion-enter) both paused;
}
[data-countup].hp-counting.hp-run { animation-play-state: running; }
[data-countup].hp-counting::after {
    content: counter(hpcnt);
    position: absolute; inset: 0;
    text-align: inherit; white-space: nowrap;
    -webkit-text-fill-color: currentColor;
}

/* ══════════════════════════════════════════════════════════════
   TAP FEEDBACK + BUSY BUTTONS (shared by every page)
   ══════════════════════════════════════════════════════════════
   Press: the tapped control shrinks to 97% while held, so a tap is felt
   at once. Uses the separate `scale` property, NOT transform: the theme
   sets `.btn:active { transform:none }` and some controls position
   themselves with transform, and `scale` combines with both untouched.
   No transition on purpose: press is instant, like a native app. */
:is(.btn:not(.btn-link):not(.btn-close), button.action-btn, .action-btn,
    .sort-btn, .toolbar-btn, .ar-tab, .oo-tab, .m-nav-item, .btn-view,
    .page-link, .mf-navbar-action-btn, .mf-icon-btn, .topbar-icon-btn):active:not(:disabled):not(.disabled):not(.is-busy) {
    scale: .96;   /* Snappy press depth */
}

/* Busy: set by hpSetBusy() in _base_scripts.html after a POST form is sent */
.is-busy, .is-busy:disabled { cursor: progress !important; opacity: .85; }
/* Label goes transparent (icons too, they use currentColor); size unchanged */
button.is-busy, button.is-busy * { color: transparent !important; }
.hp-btn-spin {
    position: absolute; top: 50%; left: 50%;
    width: 1.1em; height: 1.1em; margin: -.55em 0 0 -.55em;
    border: 2px solid; border-radius: 50%;   /* colour set from JS = label colour */
    animation: hpBtnSpin .6s linear infinite;
    pointer-events: none;
}
@keyframes hpBtnSpin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    :is(.btn, .action-btn, .sort-btn, .toolbar-btn, .ar-tab, .oo-tab, .m-nav-item, .btn-view, .page-link):active { scale: none; }
    .hp-btn-spin { animation-duration: 1.6s; }
}

/* Changed-row highlight: set once by flashChangedRow() in _base_scripts.html.
   An inset shadow paints over the cell background without touching layout,
   and wins over `background: ... !important` rules (animations can't). */
@keyframes hpRowFlash {
    /* fixed success green (not --accent: some themes make the accent indigo) */
    0%, 35% { box-shadow: inset 0 0 0 100vmax rgba(34, 197, 94, .26); }
    100%    { box-shadow: inset 0 0 0 100vmax transparent; }
}
tr.hp-row-flash > td,
table.m-cards tr.hp-row-flash,
.hp-row-flash:not(tr) { animation: hpRowFlash 1.6s ease-out; }
@media (prefers-reduced-motion: reduce) {
    tr.hp-row-flash > td, table.m-cards tr.hp-row-flash, .hp-row-flash:not(tr) { animation-duration: 2.4s; }
}

/* ══════════════════════════════════════════════════════════════
   MODALS: open in ONE quick step
   ══════════════════════════════════════════════════════════════
   Bootstrap fades the backdrop in (0.15s), WAITS for that transition to end,
   and only then starts the dialog's 0.3s slide - the dialog appeared ~0.3s
   after the tap and settled at ~0.5s, which read as lag. Bootstrap only waits
   on a CSS *transition*, so the backdrop now fades with an *animation*
   instead: it has no transition to wait for, and backdrop + dialog run
   together. Dialog: short fade + 12px rise. Phones keep their bottom-sheet
   slide (hp-mobile.css loads after this file and overrides the transform).
   Full-screen backdrop-filter blur was also removed from all overlays (it was
   repainted every frame of the open animation: 150ms frames at phone speed). */
.modal-backdrop.fade { transition: none; }
.modal-backdrop.show { animation: hpBackdropIn var(--motion-base) var(--motion-enter); }
@keyframes hpBackdropIn { from { opacity: 0; } }
.modal.fade { transition: opacity var(--motion-base) var(--motion-enter); }
.modal.fade .modal-dialog {
    transform: translateY(var(--motion-dist)) scale(.985);
    transition: transform var(--motion-slow) var(--motion-enter);
}
.modal.show .modal-dialog { transform: none; }

/* Custom overlays (confirm, command palette, shortcuts): dark layer fades in
   instead of popping; the box keeps its own short zoom-in */
#confirm-modal-overlay.active,
#command-palette-overlay.active,
#shortcuts-modal-overlay.active { animation: hpBackdropIn var(--motion-base) var(--motion-enter); }

@media (prefers-reduced-motion: reduce) {
    .modal.fade .modal-dialog { transform: none; transition: none; }
    .modal-backdrop.show, #confirm-modal-overlay.active { animation: none; }
}

/* ══════════════════════════════════════════════════════════════
   LIVE UPDATES (pulse in _base_scripts.html, rdLive on the request page)
   ══════════════════════════════════════════════════════════════ */
/* A count that just changed (bell, sidebar / bottom-bar badges) gives one small bump */
@keyframes hpBump { 0% { transform: scale(1); } 35% { transform: scale(1.28); } 70% { transform: scale(.94); } 100% { transform: scale(1); } }
.hp-bump { animation: hpBump calc(var(--motion-base) * 2) var(--motion-spring); }
#sidebarBellBtn.hp-bump { animation: hpBellRing calc(var(--motion-slow) * 2) var(--motion-enter); }
@keyframes hpBellRing { 0%, 100% { rotate: 0deg; } 20% { rotate: 14deg; } 40% { rotate: -11deg; } 60% { rotate: 7deg; } 80% { rotate: -4deg; } }
/* A new-notification toast opens its request when clicked */
.toast-notification.hp-toast-link { cursor: pointer; pointer-events: auto; }
.hp-toast-open { font-weight: 700; color: var(--accent); white-space: nowrap; }
/* Compact live toast: small icon, one-line title, one-line "PR-… · Open →" */
.toast-notification.hp-toast-compact { gap: 10px; padding: 8px 10px 8px 9px; }
.toast-notification.hp-toast-compact .toast-icon { width: 28px !important; height: 28px !important; }
.toast-notification.hp-toast-compact .toast-icon svg { width: 15px; height: 15px; }
.toast-notification.hp-toast-compact .toast-content { min-width: 0; }
.toast-notification.hp-toast-compact :is(.toast-title, .toast-message) {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.3; }
.toast-notification.hp-toast-compact .toast-message { margin-top: 1px; }
/* "Refresh" button inside a live-update toast (offered when the reader is busy) */
.toast-action { margin-left: .4rem; padding: .1rem .55rem; border-radius: 999px; border: 1px solid currentColor;
                background: transparent; color: var(--accent); font-weight: 700; font-size: inherit; cursor: pointer; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) { .hp-bump, #sidebarBellBtn.hp-bump { animation: none; } }

/* ══════════════════════════════════════════════════════════════
   PAGE CHANGE + THEME SWITCH TRANSITIONS (chosen in Motion Lab, Nov 2)
   View Transitions API: the browser animates snapshots, the live page
   never moves. Classes are set only while a transition runs
   (_base_scripts.html: navigateToPage -> vt-nav, setTheme -> vt-theme).
   ══════════════════════════════════════════════════════════════ */
/* Page change: only the content area moves; sidebar + topbar switch in place.
   Two ways in, same look:
     - sidebar / SPA links: same-document transition (navigateToPage)
     - every other link, row click, form redirect, Back: cross-document
       transition (@view-transition below; Chrome/Edge/Safari 18+)
   #mainContent gets its name ONLY while a transition runs (html.vt-nav, set by
   navigateToPage and by the pageswap/pagereveal listeners in base.html <head>).
   A permanent view-transition-name makes #mainContent a stacking context, which
   trapped every full-screen overlay inside it (image viewers, dialogs) UNDER the
   top bar - the Nov 3 "image size" bug. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
}
html.vt-nav #mainContent { view-transition-name: hp-main; }
html:not(.ml-on)::view-transition-old(root), html:not(.ml-on)::view-transition-new(root) { animation: none; }
::view-transition-group(hp-main) { animation-duration: 0s; }          /* no size morph */
::view-transition-old(hp-main) { animation: hpVtOut var(--motion-fast) var(--motion-exit) both; }
::view-transition-new(hp-main) { animation: hpVtFromLeft calc(var(--motion-slow) * 1.1) var(--motion-enter) both; }   /* ~420ms: user asked a bit slower (Nov 3) */
@keyframes hpVtFromLeft { from { opacity: 0; transform: translateX(calc(var(--motion-dist) * -1.6)); } }
@keyframes hpVtOut { to { opacity: 0; } }
/* Theme switch / Motion Lab: the whole page is one picture, content included */
html:is(.vt-theme, .ml-vt-circle, .ml-on) #mainContent { view-transition-name: none; }   /* belt and braces */

/* Theme switch: the new theme spreads in a circle from the click (clip-path set from JS) */
html.vt-theme::view-transition-old(root), html.vt-theme::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
html.vt-theme::view-transition-new(root) { z-index: 2; }

/* ══════════════════════════════════════════════════════════════
   IMAGE VIEWERS: the photo rises from the bottom and fades in (Nov 3)
   All six full-screen item-image viewers (quick view, request page,
   create / edit request, suggest item, quotation). Each shows by going
   from display:none to visible, so these animations replay on every open.
   "html body" outranks each page's own "#id img" rule. If the image is
   still downloading, _base_scripts.html replays the rise when it loads.
   ══════════════════════════════════════════════════════════════ */
html body :is(.qv-lightbox.show, #imgLightbox, #qtLightbox.open, #rcLbOv.open, #ciLbOv.open) {
    animation: hpLbFade var(--motion-base) var(--motion-enter) both;
}
html body :is(.qv-lightbox-img, #imgLightbox img, #qtLightbox img, #rcLbOv img, #ciLbOv img) {
    animation: hpLbRise calc(var(--motion-slow) * 1.2) var(--motion-enter) both;
}
@keyframes hpLbFade { from { opacity: 0; } }
@keyframes hpLbRise { from { opacity: 0; transform: translateY(min(16vh, 140px)) scale(.97); } }   /* a real slide up (Nov 3: 30px read as a fade) */
@media (prefers-reduced-motion: reduce) {
    html body :is(.qv-lightbox.show, #imgLightbox, #qtLightbox.open, #rcLbOv.open, #ciLbOv.open,
                  .qv-lightbox-img, #imgLightbox img, #qtLightbox img, #rcLbOv img, #ciLbOv img) { animation: none; }
}

/* ══════════════════════════════════════════════════════════════
   SIDEBAR MOTION (Nov 3, Snappy tokens)
   - one highlight ("ink") glides to the active item instead of each item
     painting its own background (_base_scripts.html: hpSidebarInk)
   - the item that just became active pops its icon once
   - hover nudges the icon a little to the right
   The ink lives inside .sidebar-nav, so it scrolls with the items.
   ══════════════════════════════════════════════════════════════ */
.sidebar-nav.has-ink { position: relative; }
.sb-ink {
    position: absolute; top: 0; left: 0; z-index: 0; pointer-events: none;
    border-radius: var(--hp-radius, 12px); background: rgba(255, 255, 255, .16);
    transition: transform var(--motion-base) var(--motion-spring),
                height var(--motion-base) var(--motion-spring),
                width var(--motion-base) var(--motion-enter),
                opacity var(--motion-fast) var(--motion-exit);
}
.sb-ink.no-anim { transition: none; }
.sidebar-nav.has-ink .sidebar-nav-item { position: relative; z-index: 1; }
.sidebar-nav.has-ink .sidebar-nav-item.active { background: transparent; }   /* the ink is the highlight */
.sidebar-nav-icon { transition: transform var(--motion-fast) var(--motion-enter); }
.sidebar-nav-item:hover .sidebar-nav-icon { transform: translateX(2px); }
@keyframes hpIconPop { 0% { transform: scale(1); } 40% { transform: scale(1.22); } 100% { transform: scale(1); } }
.sidebar-nav-item .sidebar-nav-icon.sb-pop { animation: hpIconPop calc(var(--motion-base) * 1.6) var(--motion-spring); }
@media (prefers-reduced-motion: reduce) {
    .sb-ink, .sidebar-nav-icon { transition: none; }
    .sidebar-nav-item .sidebar-nav-icon.sb-pop { animation: none; }
}

/* ══════════════════════════════════════════════════════════════
   DROPDOWN MENUS (Nov 3, Snappy): fade + small drop from the top with a
   tiny spring - the bell list, Bootstrap dropdowns, MemoFlow menus.
   Uses the separate `translate` / `scale` properties, NOT transform:
   Bootstrap (Popper) positions menus with an inline transform, which a
   transform animation would override and throw the menu out of place.
   (Bootstrap hides a menu instantly on close, so only opening animates.)
   ══════════════════════════════════════════════════════════════ */
/* Same feel as Motion Lab card 4: the fade on the smooth curve, the small
   drop + grow on the gentle spring, together; closing fades back out
   (a ghost copy left by _base_scripts.html, since Bootstrap hides instantly). */
@keyframes hpDropFade { from { opacity: 0; } }
@keyframes hpDropMove { from { translate: 0 calc(var(--motion-dist) * -.5); scale: .96; } }
@keyframes hpDropOut  { to { opacity: 0; translate: 0 calc(var(--motion-dist) * -.5); scale: .96; } }
.dropdown-menu.show,
.ml-dd.open .ml-dd-menu {
    animation: hpDropFade var(--motion-base) var(--motion-enter) both,
               hpDropMove var(--motion-base) var(--motion-spring) both;
    transform-origin: top center;
}
.dropdown-menu-end.show { transform-origin: top right; }
.hp-drop-ghost { animation: hpDropOut var(--motion-fast) var(--motion-exit) forwards; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .dropdown-menu.show, .ml-dd.open .ml-dd-menu { animation: none; } .hp-drop-ghost { display: none !important; } }

/* ══════════════════════════════════════════════════════════════
   SELECT DROPDOWN LISTS (filters, status, forms) — same feel as Motion
   Lab card 4 (Nov 3). The app already uses customizable selects
   (appearance: base-select, base.css), so the open list is a real pop-up
   (::picker(select)) that CSS can animate in AND out:
     open : fade on the smooth curve + small drop/grow on the gentle spring
     close: quick fade back up (display/overlay allow-discrete keep it
            rendered while it fades)
   Chrome/Edge 135+; other browsers keep their native list.
   ══════════════════════════════════════════════════════════════ */
@supports (appearance: base-select) {
    select:not([multiple]):not([size])::picker(select) {
        transform-origin: top center;
        opacity: 0; translate: 0 calc(var(--motion-dist) * -.5); scale: .96;
        transition: opacity var(--motion-fast) var(--motion-exit),
                    translate var(--motion-fast) var(--motion-exit),
                    scale var(--motion-fast) var(--motion-exit),
                    display var(--motion-fast) allow-discrete,
                    overlay var(--motion-fast) allow-discrete;
    }
    select:not([multiple]):not([size])::picker(select):popover-open {
        opacity: 1; translate: 0 0; scale: 1;
        transition: opacity var(--motion-base) var(--motion-enter),
                    translate var(--motion-base) var(--motion-spring),
                    scale var(--motion-base) var(--motion-spring),
                    display var(--motion-base) allow-discrete,
                    overlay var(--motion-base) allow-discrete;
    }
    @starting-style {
        select:not([multiple]):not([size])::picker(select):popover-open {
            opacity: 0; translate: 0 calc(var(--motion-dist) * -.5); scale: .96;
        }
    }
    /* the chevron turns with the same timing */
    select:not([multiple]):not([size])::picker-icon { transition: rotate var(--motion-base) var(--motion-spring); }
}
@media (prefers-reduced-motion: reduce) {
    select::picker(select), select::picker(select):popover-open { transition: none; }
}
