/*
 * ╔══════════════════════════════════════════════════════════════╗
 * ║  MartPlus — SPA styles                                         ║
 * ║  Change the --theme-* ramp below to restyle the whole app.     ║
 * ╚══════════════════════════════════════════════════════════════╝
 *
 * THE THEME COLOUR HAS TWO JOBS and they need separate values:
 *
 *   --theme-color    a SURFACE — navbar, primary buttons, brand mark,
 *                    avatars. Anything sitting ON it uses
 *                    --theme-contrast.
 *   --theme-ink      the same hue used as TEXT / ICONS on white or on
 *                    --theme-light. It carries its own contrast, so it
 *                    is a version of the hue that reads on white.
 *
 * FLAT COLOUR, NO GRADIENTS. The brand is #360185, a deep violet that
 * scores 14.0:1 against white on its own — so painted surfaces are the
 * flat colour and depth comes from hover states, not from a sweep.
 * (The previous red ramp only managed 4.0:1 flat, which is why it had
 * to be a gradient at all. That constraint is gone; do not reintroduce
 * gradients here.)
 *
 * ON A DARK SURFACE, HOVER LIGHTENS. #360185 is already near the bottom
 * of the scale, so the old rgba(0,0,0,.20) darkening was invisible on
 * it. Nav tabs wash with white instead — see .nl:hover.
 */
:root {
    /* ACCENT — the one saturated colour. Used sparingly: primary buttons, the
       active nav pill, links, focus, chart bars, the loader. Everything else in
       the interface is white, near-white or grey. */
    --theme-color:    #360185;  /* Brand violet — 14.0:1 on white */
    --theme-dark:     #290165;  /* Button + surface hovers */
    --theme-mid:      #2F0174;  /* Between the two */
    --theme-light:    #F4EDFF;  /* Tint — row hovers, soft badges, focus glow */
    --theme-light2:   #E1CFFC;  /* Deeper tint — soft borders, disabled fills */
    --theme-muted:    #7E47D1;  /* Muted accent */
    --theme-contrast: #FFFFFF;  /* ON --theme-color */
    --theme-ink:      #4A0FA8;  /* The hue as text on white — 10.9:1 */

    /* NEUTRALS carry the layout. The chrome is white on a near-white page and is
       separated by hairlines, not by shadow — every panel edge is one 1px --border
       and nothing casts a shadow except a hovered primary button. */
    --body-bg:        #F7F7F7;  /* The page behind the cards */
    --card-bg:        #FFFFFF;
    --surface-alt:    #F9FAFB;  /* Table heads, inset strips, hover rows */
    --border:         #E6EAED;  /* The only divider in the app */
    --text-primary:   #212B36;  /* Headings, table-head labels, input text */
    --text-secondary: #646B72;  /* Body copy and table cells */
    --text-muted:     #74748F;  /* Captions, placeholders, meta - 4.5:1 on white */
    --navy:           #092C4C;  /* Secondary solid — a weightier neutral button */

    /* STATUS — flat fills for solid chips, and a matching wash for soft ones. */
    /* Each status is a TRIO: a saturated fill for chips and icon plates, a pale
       wash behind them, and a darker -ink for the small text that sits on the wash.
       The fill is too light to read as 11px type - success on its own wash is only
       2.4:1 - so the ink is what any label actually uses. */
    --success:  #3EB780;  --success-soft: #EEFAF1;  --success-ink: #1E7A4E;
    --danger:   #E11B1B;  --danger-soft:  #FFEDE9;  --danger-ink:  #C41414;
    --warning:  #FFCA18;  --warning-soft: #FFF8E4;  --warning-ink: #8A5D00;
    --info:     #155EEF;  --info-soft:    #EDF2FE;  --info-ink:    #155EEF;
    --danger-line: #FFC9BE;  --success-line: #C7EBD8;  /* Borders for the washes */

    /* GEOMETRY — three radii, and that is the whole vocabulary. */
    --r-sm: 5px;                /* Buttons, inputs, badges */
    --r-md: 8px;                /* Cards, modals, panels */
    --r-pill: 50px;             /* Nav pills, toggles */

    --topbar-h: 60px;
    --navbar-h: 46px;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
    font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--body-bg);
    color: var(--text-primary);
    font-size: 14px;
    line-height: 1.5;
}

/* ── BOOT SPLASH ─────────────────────────────────────────────── */
.boot-splash { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
/* A ring of 16 dots whose radius tapers as it travels round, so the ring reads as
   a comet chasing its own tail. Drawn as one element: the dots are box-shadow
   copies of a zero-sized circle, so there is no extra markup and the whole thing
   inherits the accent. The tapering size — not opacity — is what gives it depth. */
.spinner {
    width: 0; height: 0; border-radius: 50%;
    margin: 19px;   /* half the 38px the shadow ring occupies, so it centres */
    box-shadow:
        0px -15px 0 4.2px var(--theme-color), 5.74px -13.86px 0 3.96px var(--theme-color), 10.61px -10.61px 0 3.72px var(--theme-color),
        13.86px -5.74px 0 3.48px var(--theme-color), 15px 0px 0 3.24px var(--theme-color), 13.86px 5.74px 0 3px var(--theme-color),
        10.61px 10.61px 0 2.76px var(--theme-color), 5.74px 13.86px 0 2.52px var(--theme-color), 0px 15px 0 2.28px var(--theme-color),
        -5.74px 13.86px 0 2.04px var(--theme-color), -10.61px 10.61px 0 1.8px var(--theme-color), -13.86px 5.74px 0 1.56px var(--theme-color),
        -15px 0px 0 1.32px var(--theme-color), -13.86px -5.74px 0 1.08px var(--theme-color), -10.61px -10.61px 0 0.84px var(--theme-color),
        -5.74px -13.86px 0 0.6px var(--theme-color);
    animation: spin 1.25s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── TOP BAR ─────────────────────────────────────────────────── */
#topbar {
    position: fixed; top: 0; left: 0; right: 0;
    height: var(--topbar-h);
    background: #fff; border-bottom: 1px solid var(--border);
    display: flex; align-items: center; padding: 0 1.5rem; gap: 1rem; z-index: 50;
}
.brand-link { display: flex; align-items: center; gap: 10px; text-decoration: none; flex-shrink: 0; }
.brand-icon {
    width: 38px; height: 38px; border-radius: var(--r-md); background: var(--theme-color);
    display: flex; align-items: center; justify-content: center;
    color: var(--theme-contrast); font-weight: 800; font-size: 16px;
}
.brand-name { font-size: 1.0625rem; font-weight: 800; color: var(--text-primary); line-height: 1.15; }
.brand-sub  { font-size: 0.6875rem; font-weight: 600; color: var(--text-muted); }

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 0.5rem; }

.user-chip {
    display: flex; align-items: center; gap: 7px;
    padding: 4px 10px 4px 4px; border-radius: var(--r-pill);
    cursor: pointer; transition: background 0.15s; border: 1px solid var(--border);
}
.user-chip:hover { background: var(--surface-alt); border-color: var(--theme-light2); }
.u-avatar {
    width: 28px; height: 28px; border-radius: 50%;
    background: var(--theme-color); color: var(--theme-contrast);
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 0.72rem; flex-shrink: 0;
}
.u-name { font-size: 0.8125rem; font-weight: 700; color: var(--text-primary); line-height: 1.15; }
.u-role { font-size: 0.6875rem; font-weight: 600; color: var(--text-muted); }

/* ── NAVBAR ──────────────────────────────────────────────────── */
#navbar {
    position: fixed; top: var(--topbar-h); left: 0; right: 0;
    height: var(--navbar-h); background: var(--card-bg);
    border-bottom: 1px solid var(--border);
    z-index: 40; display: flex; align-items: stretch; padding: 0 1.25rem; gap: 2px;
}
.ni { position: relative; display: flex; align-items: center; }
/* The nav is a white bar of grey PILLS; only the current section is filled with the
   accent. Nothing else in the chrome is coloured, so the filled pill is the single
   loudest thing on screen and always answers "where am I".
   .nl is a fixed-height pill but .ni stays full-bar height — the dropdowns hang off
   .ni with top:100%, so shrinking it would float them halfway up the bar. */
.nl {
    display: flex; align-items: center; gap: 7px;
    padding: 0 13px; height: 32px; border-radius: var(--r-pill);
    color: var(--text-secondary); text-decoration: none;
    font-size: 0.8125rem; font-weight: 600;
    border: none; background: none; cursor: pointer; white-space: nowrap;
    transition: background 0.15s, color 0.15s;
}
.nl:hover { background: var(--theme-light); color: var(--theme-ink); }
.nl.active { background: var(--theme-color); color: var(--theme-contrast); }
.nl.active .chev { opacity: 0.9; }
.nl svg { width: 16px; height: 16px; flex-shrink: 0; }
.chev { width: 14px; height: 14px; opacity: 0.7; }

/* Nav dropdown */
.nd {
    position: absolute; top: 100%; left: 0; min-width: 220px;
    background: #fff; border: 1px solid var(--border); border-radius: var(--r-md);
    box-shadow: 0 8px 28px rgba(0,0,0,0.12); z-index: 200; overflow: hidden;
    opacity: 0; visibility: hidden; transform: translateY(-6px); transition: all 0.15s;
}
.ni:hover .nd { opacity: 1; visibility: visible; transform: translateY(0); }
.nd-header {
    padding: 0.5rem 1rem 0.35rem; font-size: 0.68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted);
    border-bottom: 1px solid var(--border); background: var(--body-bg);
}
.ndi {
    display: flex; align-items: center; gap: 9px; padding: 0.6rem 1rem;
    font-size: 0.84rem; color: var(--text-primary); text-decoration: none;
    cursor: pointer; transition: background 0.1s; background: none; border: none; width: 100%;
}
.ndi:hover { background: var(--theme-light); color: var(--theme-ink); }
.ndi svg { width: 15px; height: 15px; flex-shrink: 0; color: var(--text-muted); }
.ndi:hover svg { color: var(--theme-ink); }
.nd-divider { height: 1px; background: var(--border); }

/* ── MAIN ────────────────────────────────────────────────────── */
#main-content { padding-top: calc(var(--topbar-h) + var(--navbar-h)); min-height: 100vh; }
.page-content { padding: 1.5rem 2rem; animation: fadeUp 0.2s ease; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }

.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.25rem; gap: 1rem; flex-wrap: wrap; }
.page-title { font-size: 1.4rem; font-weight: 700; color: var(--text-primary); display: flex; align-items: center; gap: 8px; }
.page-subtitle { font-size: 0.8rem; color: var(--text-secondary); margin-top: 2px; }

/* ── STAT CARDS ──────────────────────────────────────────────── */
.stat-card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--r-md); padding: 1.15rem 1.25rem; display: flex; align-items: center; gap: 1rem; }
.stat-icon { width: 46px; height: 46px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center; flex-shrink: 0; background: var(--theme-light); color: var(--theme-color); }
.stat-icon svg { width: 22px; height: 22px; }
.stat-value { font-size: 1.5rem; font-weight: 800; line-height: 1; margin-bottom: 3px; color: var(--text-primary); }
.stat-label { font-size: 0.8125rem; font-weight: 600; color: var(--text-secondary); }

/* ── CARDS ───────────────────────────────────────────────────── */
.card { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.card-header { padding: 1rem 1.25rem; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
/* A card title is a HEADING, not a label: dark, 16px, sentence case. The old
   uppercase letter-spaced grey micro-caption made every panel look like a form
   fieldset and left nothing on the page acting as a heading. */
.card-title { font-size: 1rem; font-weight: 700; color: var(--text-primary); letter-spacing: 0; text-transform: none; }
.card-body { padding: 1.25rem; }

/* ── BUTTONS ─────────────────────────────────────────────────── */
/* One button geometry, three weights of emphasis. Every button is 13px/600 on a
   5px radius - the difference between them is FILL, never size or shape.
   The primary carries a wide, very soft drop of its own colour; it is the only
   shadow anywhere in the interface, which is what makes it read as raised. */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 7px 13px; border-radius: var(--r-sm); font-size: 0.8125rem; font-weight: 600;
    line-height: 1.45; cursor: pointer; border: 1px solid transparent;
    transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s;
    text-decoration: none; white-space: nowrap;
}
.btn svg { width: 16px; height: 16px; flex-shrink: 0; }
.btn-primary { background: var(--theme-color); border-color: var(--theme-color); color: var(--theme-contrast); box-shadow: 0 4px 20px rgba(54, 1, 133, 0.15); }
.btn-primary:hover { background: var(--theme-dark); border-color: var(--theme-dark); box-shadow: 0 4px 20px rgba(54, 1, 133, 0.28); }
.btn-outline { background: transparent; color: var(--theme-color); border-color: var(--theme-color); }
.btn-outline:hover { background: var(--theme-color); color: var(--theme-contrast); }
/* A weightier neutral than the outline, for the second half of a paired action. */
.btn-navy { background: var(--navy); border-color: var(--navy); color: #fff; box-shadow: 0 4px 20px rgba(9, 44, 76, 0.15); }
.btn-navy:hover { background: #061E36; border-color: #061E36; }
/* The quiet default - Cancel, Export, Filter. White on a hairline, exactly like an
   input, so a row of them recedes and the one primary button stands alone.
   The class name is kept: it has 80+ call sites. */
.btn-outline-gray { background: var(--card-bg); color: var(--text-secondary); border-color: var(--border); }
.btn-outline-gray:hover { background: var(--surface-alt); border-color: var(--theme-light2); color: var(--theme-ink); }
/* Destructive actions stay RED, and with a violet brand that is a real signal
   rather than a near-miss: a delete cannot be mistaken for a confirm. */
.btn-danger { background: var(--danger); border-color: var(--danger-ink); color: #fff; box-shadow: 0 4px 20px rgba(225, 27, 27, 0.15); }
.btn-danger:hover { background: #B81414; border-color: #B81414; }
.btn-sm { padding: 4px 10px; font-size: 0.75rem; }
.btn-sm svg { width: 14px; height: 14px; }
.btn-icon { padding: 6px; border-radius: var(--r-sm); }
.btn[disabled] { opacity: 0.55; cursor: not-allowed; box-shadow: none; }

/* ── TABLES ──────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
/* The head is a tinted strip with DARK sentence-case labels - heavier than the
   cells it sits above, so the eye starts there. (It used to be pale uppercase
   micro-type, which made the head lighter than its own data.) */
thead th {
    padding: 9px 1rem; text-align: left; font-size: 0.8125rem; font-weight: 700;
    text-transform: none; letter-spacing: 0; color: var(--text-primary);
    background: var(--surface-alt); border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
tbody td { padding: 11px 1rem; font-size: 0.875rem; color: var(--text-secondary); border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
/* Row hover is a NEUTRAL wash, not a tint of the accent - on a list of 50 rows an
   accent-coloured hover competes with the accent-coloured primary button. */
tbody tr:hover td { background: var(--surface-alt); }

/* ── BADGES ──────────────────────────────────────────────────── */
/* SOFT chips: a pale wash of the status colour with the status colour as text.
   A table of 50 rows each carrying a saturated pill is a Christmas tree - the wash
   keeps the row readable while the colour still classifies it at a glance. Every
   pair is the same hue, so they read as one family. */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 4px 9px; border-radius: var(--r-sm); font-size: 0.6875rem; font-weight: 700; line-height: 1.3; white-space: nowrap; }
.badge-active  { background: var(--success-soft); color: var(--success-ink); }
.badge-inactive{ background: var(--danger-soft);  color: var(--danger-ink); }
.badge-system  { background: var(--info-soft);    color: var(--info); }
.badge-custom  { background: var(--theme-light);  color: var(--theme-ink); }
.badge-dev     { background: var(--warning-soft); color: var(--warning-ink); }
.badge-muted   { background: var(--surface-alt);  color: var(--text-secondary); }
/* The solid counterparts, for the rare chip that must shout (cart counts, alerts). */
.badge-solid   { background: var(--theme-color); color: #fff; }
.badge-solid-danger { background: var(--danger); color: #fff; }

/* ── FORMS ───────────────────────────────────────────────────── */
.form-group { margin-bottom: 1rem; }
.form-label { display: block; font-size: 0.8125rem; font-weight: 600; color: var(--text-primary); margin-bottom: 6px; }
.form-control {
    width: 100%; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
    font-size: 0.875rem; font-family: inherit; color: var(--text-primary); background: #fff; outline: none;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.form-control::placeholder { color: var(--text-muted); }
/* Focus is the accent plus a wide, very faint halo of the same hue - the input
   itself only shifts by one hairline, so a focused field never jumps the layout. */
.form-control:focus { border-color: var(--theme-color); box-shadow: 0 0 0 3px rgba(54, 1, 133, 0.08); }
.form-control:disabled { background: var(--surface-alt); color: var(--text-muted); cursor: not-allowed; }
textarea.form-control { min-height: 84px; resize: vertical; }
select.form-control { cursor: pointer; }

/* ── MODALS ──────────────────────────────────────────────────── */
.modal-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 100;
    display: flex; align-items: center; justify-content: center; padding: 1rem;
    opacity: 0; visibility: hidden; transition: all 0.2s;
}
.modal-overlay.show { opacity: 1; visibility: visible; }
.modal {
    background: #fff; border-radius: var(--r-md); width: 100%; max-width: 560px; max-height: 90vh;
    overflow: hidden; display: flex; flex-direction: column;
    box-shadow: 0 20px 60px rgba(0,0,0,0.18);
    transform: scale(0.96) translateY(8px); transition: all 0.2s;
}
.modal-overlay.show .modal { transform: scale(1) translateY(0); }
.modal-lg { max-width: 700px; }
.modal-sm { max-width: 420px; }
.modal-header {
    padding: 1rem 1.25rem; border-bottom: 1px solid var(--border);
    display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; background: #fff;
}
.modal-title { font-size: 1rem; font-weight: 700; color: var(--text-primary); }
.modal-close {
    width: 28px; height: 28px; border-radius: var(--r-sm); border: none; background: transparent; cursor: pointer;
    display: flex; align-items: center; justify-content: center; color: var(--text-muted); font-size: 1rem; transition: all 0.15s;
}
.modal-close:hover { background: var(--danger-soft); color: var(--danger-ink); }
.modal-body { padding: 1.5rem; overflow-y: auto; flex: 1; }
.modal-footer { padding: 0.875rem 1.5rem; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 0.5rem; flex-shrink: 0; }

/* ── PAGINATION ──────────────────────────────────────────────── */
.pagination { display: flex; align-items: center; gap: 3px; padding: 0.875rem 1.25rem; border-top: 1px solid var(--border); flex-wrap: wrap; }
.page-btn {
    min-width: 32px; height: 32px; border-radius: var(--r-sm); border: 1px solid var(--border);
    background: #fff; cursor: pointer; font-size: 0.8125rem; font-weight: 600; font-family: inherit;
    color: var(--text-secondary); transition: all 0.15s; padding: 0 8px;
}
.page-btn:hover { background: var(--theme-light); color: var(--theme-ink); border-color: var(--theme-light2); }
.page-btn.active { background: var(--theme-color); color: var(--theme-contrast); border-color: var(--theme-color); }
.page-btn.disabled { opacity: 0.35; cursor: not-allowed; pointer-events: none; }

/* ── DROPDOWNS ───────────────────────────────────────────────── */
.dropdown { position: relative; display: inline-block; }
.dd-menu {
    position: absolute; right: 0; top: calc(100% + 6px); min-width: 190px;
    background: #fff; border: 1px solid var(--border); border-radius: var(--r-md);
    box-shadow: 0 8px 28px rgba(0,0,0,0.08); z-index: 200; overflow: hidden;
    opacity: 0; visibility: hidden; transform: translateY(-4px); transition: all 0.15s;
}
.dd-menu.show { opacity: 1; visibility: visible; transform: translateY(0); }
.dd-item {
    display: flex; align-items: center; gap: 8px; padding: 0.6rem 1rem;
    font-size: 0.875rem; color: var(--text-primary); text-decoration: none; cursor: pointer;
    transition: background 0.1s; border: none; background: none; width: 100%; text-align: left;
}
.dd-item:hover { background: var(--theme-light); color: var(--theme-ink); }
/* The user menu was the ONE icon context in the app with no size rule, so its glyphs
   had no intrinsic width and stretched to fill the flex row — Change Password rendered
   at 85px and Sign Out at 110px, against 15-16px everywhere else. Sized to match
   .ndi svg, the nav dropdown it is the twin of. */
.dd-item svg { width: 15px; height: 15px; flex-shrink: 0; color: var(--text-muted); }
.dd-item:hover svg { color: var(--theme-ink); }
/* Restores the red the muted rule above would otherwise take off Sign Out. */
.dd-item.danger svg, .dd-item.danger:hover svg { color: var(--danger-ink); }
.dd-item.danger { color: var(--danger-ink); }
.dd-item.danger:hover { background: var(--danger-soft); color: var(--danger-ink); }
.dd-divider { height: 1px; background: var(--border); }

/* ── AVATARS ─────────────────────────────────────────────────── */
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--theme-color); color: var(--theme-contrast); display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.75rem; flex-shrink: 0; }

/* ── TOAST ───────────────────────────────────────────────────── */
#toast-container { position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 9999; display: flex; flex-direction: column; gap: 8px; }
.toast { background: #fff; border: 1px solid var(--border); border-radius: var(--r-md); padding: 0.8rem 1.1rem; box-shadow: 0 6px 24px rgba(0,0,0,0.08); display: flex; align-items: center; gap: 10px; min-width: 260px; font-size: 0.875rem; animation: toastIn 0.3s ease; }
.toast-success { border-left: 4px solid var(--success); }
.toast-error { border-left: 4px solid var(--danger); }
.toast-info { border-left: 4px solid var(--theme-color); }
@keyframes toastIn { from { transform: translateX(110%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

/* ── CHECKBOX LIST ───────────────────────────────────────────── */
.perm-module { border: 1px solid var(--border); border-radius: var(--r-md); padding: 0.75rem 1rem; margin-bottom: 0.75rem; }
.perm-module-title { font-size: 0.8125rem; font-weight: 700; letter-spacing: 0; text-transform: none; color: var(--text-primary); margin-bottom: 0.5rem; }
.checkbox-group { display: flex; flex-wrap: wrap; gap: 7px; }
.checkbox-item { display: flex; align-items: center; gap: 6px; padding: 5px 11px; border: 1px solid var(--border); border-radius: var(--r-sm); cursor: pointer; font-size: 0.8125rem; transition: all 0.15s; user-select: none; }
.checkbox-item:hover { border-color: var(--theme-light2); background: var(--theme-light); }
.checkbox-item input[type="checkbox"] { accent-color: var(--theme-color); }

/* ── GRIDS ───────────────────────────────────────────────────── */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; }
.grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 1.1rem; }

/* ── EMPTY / LOADING ─────────────────────────────────────────── */
.empty-state { padding: 3rem; text-align: center; color: var(--text-muted); }
.empty-state svg { width: 48px; height: 48px; margin: 0 auto 1rem; opacity: 0.3; display: block; }
.table-loading { padding: 2.5rem; text-align: center; }
.table-loading .spinner { margin: 0 auto; }

/* ── TOOLBAR (search + filters above a table) ────────────────── */
.toolbar { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.toolbar .form-control { width: auto; min-width: 150px; }
.search-box { position: relative; }
.search-box input { padding-left: 2.1rem; min-width: 220px; }
.search-box svg { position: absolute; left: 0.7rem; top: 50%; transform: translateY(-50%); width: 16px; height: 16px; color: var(--text-muted); pointer-events: none; }

/* ── MISC ────────────────────────────────────────────────────── */
.muted { color: var(--text-muted); }
.text-theme { color: var(--theme-color); }
.fw-600 { font-weight: 600; }
.rows-per-page { display: flex; align-items: center; gap: 6px; font-size: 0.78rem; color: var(--text-secondary); margin-left: auto; }
.rows-per-page select { padding: 4px 7px; border: 1px solid var(--border); border-radius: var(--r-sm); font-size: 0.78rem; font-family: inherit; background: #fff; }

/* ── LOGIN ───────────────────────────────────────────────────── */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; background: var(--theme-color); }
.login-card { background: #fff; border-radius: var(--r-md); width: 100%; max-width: 400px; padding: 2.25rem; box-shadow: 0 20px 60px rgba(0,0,0,0.25); }
.login-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 1.5rem; }
.login-brand .brand-icon { width: 44px; height: 44px; font-size: 18px; }
.login-title { font-size: 1.25rem; font-weight: 800; color: var(--text-primary); }
.login-sub { font-size: 0.8rem; color: var(--text-muted); }
.login-hint { margin-top: 1.25rem; padding: 0.75rem 1rem; background: var(--theme-light); border-radius: var(--r-sm); font-size: 0.74rem; color: var(--text-secondary); line-height: 1.6; }
.login-hint code { background: #fff; padding: 1px 5px; border-radius: 4px; color: var(--theme-ink); font-weight: 700; }
.login-error { background: var(--danger-soft); color: var(--danger-ink); border: 1px solid #FFC9BE; border-radius: var(--r-sm); padding: 0.6rem 0.85rem; font-size: 0.8rem; margin-bottom: 1rem; }

@media (max-width: 900px) { .grid-4 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .grid-2,.grid-3,.grid-4 { grid-template-columns: 1fr; } .page-content { padding: 1rem; } .brand-sub { display: none; } }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #D4D9DE; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--theme-light2); }
