/* ===========================================================================
   School CRM — application styles
   Layered on Bootstrap 5. Only the shell and app-specific components live here;
   anything Bootstrap already does well is left to Bootstrap.

   Colour is defined once as tokens on :root and redefined for dark mode. No
   colour is hard-coded inside a component rule, so the dark theme is a token
   swap rather than a second stylesheet.
   =========================================================================== */

/* ---------------------------------------------------------------- theme ---

   Each colour is declared ONCE, as a light/dark pair, using light-dark().
   The previous shape listed the dark values again inside a media query, which
   meant every token had two homes and a change could land in one of them.

   Which half of each pair applies is decided entirely by `color-scheme`:

     :root                       light dark   -> follow the operating system
     :root[data-theme="light"]   light        -> the user chose light
     :root[data-theme="dark"]    dark         -> the user chose dark

   So the toggle sets one attribute and every token follows. The old block
   could not express an explicit choice at all: its dark values lived in a
   bare `@media (prefers-color-scheme: dark)`, which would have overridden a
   user who asked for light.
   ------------------------------------------------------------------------ */

:root {
    color-scheme: light dark;

    --sc-sidebar-w: 236px;
    --sc-topbar-h: 56px;
    --sc-radius: 10px;
    --sc-radius-sm: 7px;

    /* Surfaces */
    --sc-bg:        light-dark(#f5f7fa, #0d1117);
    --sc-surface:   light-dark(#ffffff, #161b22);
    --sc-surface-2: light-dark(#f8fafc, #1c2128);
    --sc-line:      light-dark(#e4e9f0, #2b323c);
    --sc-line-soft: light-dark(#eef2f7, #232931);

    /* Text */
    --sc-ink:   light-dark(#0f172a, #e6edf3);
    --sc-ink-2: light-dark(#475569, #b3bfcc);
    --sc-muted: light-dark(#6b7a8f, #8b98a8);

    /* Brand + semantic */
    --sc-brand:      light-dark(#2451d6, #6b96ff);
    --sc-brand-ink:  light-dark(#1a3fae, #8fb0ff);
    --sc-brand-soft: light-dark(#eef3ff, #1a2540);
    --sc-good:       light-dark(#157347, #46c07f);
    --sc-good-soft:  light-dark(#e7f6ed, #14301f);
    --sc-warn:       light-dark(#a16207, #d9a441);
    --sc-warn-soft:  light-dark(#fdf5e3, #33280f);
    --sc-bad:        light-dark(#b42318, #f0736a);
    --sc-bad-soft:   light-dark(#fdeceb, #3a1a18);

    /* A shadow that works on white is invisible on near-black, so the dark
       half is deeper rather than the same value at lower opacity. */
    --sc-shadow:    light-dark(0 1px 2px rgba(15, 23, 42, .05), 0 1px 2px rgba(0, 0, 0, .4));
    --sc-shadow-lg: light-dark(0 4px 16px rgba(15, 23, 42, .08), 0 4px 16px rgba(0, 0, 0, .5));

    --sc-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --sc-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* An explicit choice pins color-scheme, which is what makes light-dark()
   resolve one way regardless of the operating system. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

/* Pull Bootstrap's own surfaces onto our tokens.
   No longer inside a media query: the tokens already resolve per theme, so
   this applies in both and there is nothing to keep in step. */
.card, .modal-content, .dropdown-menu,
.form-control, .form-select, .input-group-text {
    background-color: var(--sc-surface);
    border-color: var(--sc-line);
    color: var(--sc-ink);
}

.form-control::placeholder { color: var(--sc-muted); }
.form-control:disabled, .form-control[readonly] { background-color: var(--sc-surface-2); }
.table { --bs-table-color: var(--sc-ink); --bs-table-bg: transparent; }
.dropdown-item { color: var(--sc-ink); }
.dropdown-item:hover, .dropdown-item:focus { background-color: var(--sc-surface-2); color: var(--sc-ink); }
.modal-header, .modal-footer { border-color: var(--sc-line); }
.btn-light { background-color: var(--sc-surface-2); border-color: var(--sc-line); color: var(--sc-ink); }
.text-muted { color: var(--sc-muted) !important; }

/* ---------------------------------------------------------------- base --- */

body {
    font-family: var(--sc-font);
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

body.app-body { margin: 0; background: var(--sc-bg); color: var(--sc-ink); }

a { color: var(--sc-brand); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--sc-brand-ink); }

h1, h2, h3, h4, h5 { color: var(--sc-ink); letter-spacing: -.01em; }

::selection { background: var(--sc-brand-soft); color: var(--sc-brand-ink); }

:focus-visible { outline: 2px solid var(--sc-brand); outline-offset: 2px; border-radius: 3px; }

.req { color: var(--sc-bad); font-weight: 600; }

/* ------------------------------------------------------------- sidebar --- */

.app-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sc-sidebar-w);
    background: var(--sc-surface);
    border-right: 1px solid var(--sc-line);
    display: flex;
    flex-direction: column;
    z-index: 1030;
    transition: transform .2s ease;
}

.sidebar-head {
    display: flex;
    align-items: center;
    gap: .625rem;
    height: var(--sc-topbar-h);
    padding: 0 1rem;
    border-bottom: 1px solid var(--sc-line);
    flex-shrink: 0;
}

.sidebar-logo {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--sc-brand), var(--sc-brand-ink));
    color: #fff;
    font-weight: 700;
    font-size: 12px;
    letter-spacing: .5px;
    flex-shrink: 0;
}

.sidebar-name { font-weight: 600; font-size: 14px; }

.sidebar-nav { padding: .625rem .5rem; overflow-y: auto; flex: 1; }

.sidebar-link {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .5rem .75rem;
    margin-bottom: 1px;
    border-radius: var(--sc-radius-sm);
    color: var(--sc-ink-2);
    text-decoration: none;
    font-weight: 500;
    transition: background .12s ease, color .12s ease;
}

.sidebar-link:hover { background: var(--sc-surface-2); color: var(--sc-ink); }
.sidebar-link.is-active { background: var(--sc-brand-soft); color: var(--sc-brand); font-weight: 600; }
.sidebar-icon { width: 18px; text-align: center; font-size: 15px; opacity: .9; flex-shrink: 0; }

/* ---------------------------------------------------------------- main --- */

.app-main { margin-left: var(--sc-sidebar-w); min-height: 100vh; display: flex; flex-direction: column; }

.app-topbar {
    position: sticky;
    top: 0;
    height: var(--sc-topbar-h);
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 0 1.25rem;
    background: var(--sc-surface);
    border-bottom: 1px solid var(--sc-line);
    z-index: 1020;
}

.topbar-title { font-size: 1rem; font-weight: 600; margin: 0; }

/* Search sits in the middle and takes the slack, so it grows on a wide screen
   and collapses out of the way on a narrow one. */
.topbar-search { position: relative; flex: 1; max-width: 26rem; margin: 0 auto; }

.topbar-search .form-control {
    padding-left: 2.125rem;
    border-radius: 9px;
    background: var(--sc-surface-2);
    border-color: transparent;
}

.topbar-search .form-control:focus {
    background: var(--sc-surface);
    border-color: var(--sc-brand);
}

.topbar-search-icon {
    position: absolute;
    left: .625rem;
    top: 50%;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    color: var(--sc-muted);
    pointer-events: none;
}

.topbar-search-icon svg { width: 15px; height: 15px; }

/* Never had styling: it held a single child and default block layout was
   enough. Adding the bell beside the user chip stacked them, because nothing
   was laying them out side by side. */
.topbar-right {
    display: flex;
    align-items: center;
    gap: .375rem;
    margin-left: auto;
    flex-shrink: 0;
}

/* --- theme menu --- */
.theme-menu { min-width: 11rem; }

.theme-menu .dropdown-item {
    display: flex;
    align-items: center;
    gap: .5rem;
}

.theme-menu .dropdown-item svg { width: 16px; height: 16px; flex-shrink: 0; }

/* The tick holds its space whether or not it is shown, so choosing a
   different option does not shift the menu under the pointer. */
.theme-tick { margin-left: auto; visibility: hidden; color: var(--sc-brand); font-weight: 700; }
.theme-menu .dropdown-item.is-active .theme-tick { visibility: visible; }
.theme-menu .dropdown-item.is-active { font-weight: 600; }

/* --- notification bell --- */
.topbar-bell {
    position: relative;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    color: var(--sc-ink-2);
    text-decoration: none;
    flex-shrink: 0;
}

.topbar-bell:hover { background: var(--sc-surface-2); color: var(--sc-ink); }
.topbar-bell svg { width: 18px; height: 18px; }

/* The count sits ON the bell rather than beside it: a number that can be two
   characters wide must not push the rest of the header around. */
.topbar-bell-count {
    position: absolute;
    top: 1px;
    right: 0;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--sc-bad);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* --- notification list --- */
.notif {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--sc-line);
}

.notif:last-child { border-bottom: 0; }

/* Unread is carried by a tint AND the bold title, never by colour alone. */
.notif-unread { background: var(--sc-brand-soft); }

.notif-icon {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 9px;
    background: var(--sc-surface-2);
    color: var(--sc-ink-2);
}

.notif-unread .notif-icon { background: var(--sc-surface); color: var(--sc-brand); }
.notif-icon svg { width: 16px; height: 16px; }
.notif-body { flex: 1; min-width: 0; }
.notif-go { flex-shrink: 0; }

/* Name over role, as on a badge — the role is the part people forget they are
   currently wearing, and it changes what the rest of the UI will let them do. */
.topbar-user { display: flex; align-items: center; gap: .5rem; text-align: left; }
.topbar-who  { flex-direction: column; line-height: 1.15; }
.topbar-name { font-size: 12.5px; font-weight: 600; }
.topbar-role { font-size: 10.5px; color: var(--sc-muted); font-weight: 500; }

@media (max-width: 767.98px) {
    .topbar-search { display: none; }
    .topbar-title { flex: 1; }
}

.app-content { flex: 1; padding: 1.25rem; max-width: 1440px; width: 100%; }

.app-footer {
    padding: .875rem 1.25rem;
    border-top: 1px solid var(--sc-line);
    color: var(--sc-muted);
    font-size: 12px;
}

.page-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: .75rem;
    margin-bottom: 1rem;
}

.page-head-title { display: flex; align-items: center; gap: .625rem; }
.page-head-sub { color: var(--sc-muted); font-size: 12.5px; margin: .125rem 0 0; }

.page-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1rem;
}

.form-section {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--sc-muted);
    margin: 0 0 .625rem;
}

/* -------------------------------------------------------------- avatar --- */

.avatar {
    display: inline-grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--sc-brand), var(--sc-brand-ink));
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    flex-shrink: 0;
}

.avatar-sm { width: 24px; height: 24px; font-size: 10px; }
.avatar-lg { width: 40px; height: 40px; font-size: 15px; }

/* --------------------------------------------------------------- cards --- */

.content-card {
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-radius: var(--sc-radius);
    box-shadow: var(--sc-shadow);
}

.content-card .card-header {
    background: transparent;
    border-bottom: 1px solid var(--sc-line);
    font-weight: 600;
    font-size: 13px;
    padding: .625rem .875rem;
}

.content-card .card-footer { background: transparent !important; border-top: 1px solid var(--sc-line); }

/* --------------------------------------------------------------- tiles --- */

.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: .75rem; }

.tile {
    position: relative;
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-left: 3px solid var(--sc-line);
    border-radius: var(--sc-radius);
    padding: .75rem .9375rem;
    box-shadow: var(--sc-shadow);
    transition: border-color .12s ease, transform .12s ease;
}

.tile-good { border-left-color: var(--sc-good); }
.tile-warn { border-left-color: var(--sc-warn); }
.tile-bad  { border-left-color: var(--sc-bad); }

.tile-label {
    color: var(--sc-muted);
    font-size: 11.5px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .03em;
    margin-bottom: .1875rem;
}

.tile-value {
    font-size: 1.4375rem;
    font-weight: 650;
    line-height: 1.15;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}

.tile-delta { font-size: 11.5px; margin-top: .1875rem; color: var(--sc-muted); }
.tile-delta.is-up { color: var(--sc-good); }
.tile-delta.is-down { color: var(--sc-bad); }

/* --------------------------------------------------------------- table --- */

.table { color: var(--sc-ink); margin-bottom: 0; }

.table > thead > tr > th {
    background: var(--sc-surface-2);
    border-bottom: 1px solid var(--sc-line);
    color: var(--sc-muted);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: .5rem .75rem;
    white-space: nowrap;
}

.table > tbody > tr > td { padding: .5rem .75rem; border-color: var(--sc-line-soft); }
.table-hover > tbody > tr:hover > * { background-color: var(--sc-surface-2); }

.link-strong { font-weight: 600; text-decoration: none; color: var(--sc-ink); }
.link-strong:hover { color: var(--sc-brand); text-decoration: underline; }

.cell-sub { color: var(--sc-muted); font-size: 11.5px; line-height: 1.35; }
.cell-person { display: flex; align-items: center; gap: .5rem; }

.empty-cell { text-align: center; color: var(--sc-muted); padding: 2rem 1rem; font-size: 13px; }

/* Numeric columns align on the decimal and never wrap. */
.num, .num-plain { font-variant-numeric: tabular-nums; white-space: nowrap; }
.num { font-weight: 600; }
.num-due   { color: var(--sc-bad); }
.num-clear { color: var(--sc-good); }
.num-void  { text-decoration: line-through; color: var(--sc-muted); font-weight: 400; }

.row-total > td { border-top: 1px solid var(--sc-line); font-weight: 650; }
.row-danger > td { background-color: var(--sc-bad-soft) !important; }
.row-muted > td { opacity: .55; }

/* --------------------------------------------------- states and empties --- */

.empty-state {
    background: var(--sc-surface);
    border: 1px dashed var(--sc-line);
    border-radius: var(--sc-radius);
    padding: 2.5rem 1.5rem;
    text-align: center;
}

.empty-icon {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--sc-surface-2);
    color: var(--sc-muted);
    font-size: 20px;
    margin-bottom: .75rem;
}

.state-card {
    display: flex;
    align-items: center;
    gap: .875rem;
    border: 1px solid var(--sc-line);
    border-radius: var(--sc-radius);
    padding: 1rem 1.125rem;
    background: var(--sc-surface);
}

.state-card p { font-size: 12.5px; color: var(--sc-muted); }

.state-icon {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    font-size: 16px;
    flex-shrink: 0;
}

.state-good { border-color: var(--sc-good); }
.state-good .state-icon { background: var(--sc-good-soft); color: var(--sc-good); }

.flash-stack .alert { padding: .625rem .875rem; font-size: 13px; border-radius: var(--sc-radius-sm); }

.detail-list { display: grid; grid-template-columns: minmax(90px, 38%) 1fr; gap: .3125rem .75rem; margin: 0; font-size: 12.5px; }
.detail-list dt { color: var(--sc-muted); font-weight: 500; }
.detail-list dd { margin: 0; color: var(--sc-ink); }

/* ------------------------------------------------------------- scores --- */

.score-pill {
    display: inline-block;
    min-width: 30px;
    padding: 1px 7px;
    border-radius: 20px;
    font-size: 11px;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.score-high { background: var(--sc-good-soft); color: var(--sc-good); }
.score-mid  { background: var(--sc-warn-soft); color: var(--sc-warn); }
.score-low  { background: var(--sc-surface-2); color: var(--sc-muted); }

/* ------------------------------------------------------------ timeline --- */

.timeline { list-style: none; margin: 0; padding: 0 0 0 1.25rem; border-left: 2px solid var(--sc-line); }
.timeline-item { position: relative; padding-bottom: 1rem; }
.timeline-item:last-child { padding-bottom: 0; }

.timeline-marker {
    position: absolute;
    left: -1.6rem;
    top: 4px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--sc-muted);
    border: 2px solid var(--sc-surface);
}

.timeline-call    { background: var(--sc-brand); }
.timeline-email   { background: #7c3aed; }
.timeline-sms     { background: #0891b2; }
.timeline-meeting { background: var(--sc-good); }
.timeline-note    { background: var(--sc-muted); }
.timeline-status_change { background: #ea580c; }

.timeline-content { line-height: 1.45; }

/* --------------------------------------------------------------- board --- */

/* auto-flow rather than a fixed count: the pipeline went from four statuses
   to six, and a hardcoded `repeat(4, ...)` silently stacked the extras into a
   second row instead of extending the board. */
.board {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(210px, 1fr);
    gap: .75rem;
    overflow-x: auto;
    padding-bottom: .5rem;
}

.board-column { background: var(--sc-surface-2); border: 1px solid var(--sc-line); border-radius: var(--sc-radius); }

.board-head { display: flex; justify-content: space-between; align-items: center; padding: .625rem .75rem; border-bottom: 1px solid var(--sc-line); }

.board-body { padding: .5rem; max-height: 65vh; overflow-y: auto; }

.board-card {
    display: block;
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-radius: var(--sc-radius-sm);
    padding: .5rem .625rem;
    margin-bottom: .5rem;
    text-decoration: none;
    color: inherit;
    box-shadow: var(--sc-shadow);
    transition: border-color .12s ease, transform .12s ease;
}

.board-card:hover { border-color: var(--sc-brand); transform: translateY(-1px); color: inherit; }
.board-card.is-overdue { border-left: 3px solid var(--sc-bad); }

/* -------------------------------------------------- funnel + stage track --- */

.funnel { display: flex; gap: .375rem; overflow-x: auto; padding-bottom: .25rem; }

.funnel-step {
    flex: 1 0 auto;
    min-width: 96px;
    background: var(--sc-brand-soft);
    border: 1px solid var(--sc-line);
    border-radius: var(--sc-radius-sm);
    padding: .5rem .625rem;
    text-align: center;
    text-decoration: none;
    color: inherit;
    transition: border-color .12s ease;
}

.funnel-step:hover { border-color: var(--sc-brand); color: inherit; }
.funnel-step.is-empty { background: var(--sc-surface-2); opacity: .6; }

.funnel-count { display: block; font-size: 1.125rem; font-weight: 700; color: var(--sc-brand); font-variant-numeric: tabular-nums; }
.funnel-label { display: block; font-size: 11px; color: var(--sc-muted); line-height: 1.25; }

.stage-track { display: flex; gap: .25rem; overflow-x: auto; padding-bottom: .25rem; }

.stage-node { flex: 1 0 auto; min-width: 92px; text-align: center; position: relative; padding-top: 4px; }

.stage-node:not(:last-child)::after {
    content: '';
    position: absolute;
    top: 15px;
    left: calc(50% + 13px);
    right: calc(-50% + 13px);
    height: 2px;
    background: var(--sc-line);
}

.stage-node.is-done::after { background: var(--sc-good); }

.stage-dot {
    position: relative;
    z-index: 1;
    display: inline-grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--sc-surface);
    border: 2px solid var(--sc-line);
    color: var(--sc-muted);
    font-size: 11px;
    font-weight: 700;
}

.stage-node.is-done .stage-dot    { background: var(--sc-good); border-color: var(--sc-good); color: #fff; }
.stage-node.is-current .stage-dot { background: var(--sc-brand); border-color: var(--sc-brand); color: #fff; }

.stage-name { display: block; margin-top: .25rem; font-size: 10.5px; line-height: 1.25; color: var(--sc-muted); }
.stage-node.is-current .stage-name { color: var(--sc-brand); font-weight: 600; }
.stage-node.is-done .stage-name { color: var(--sc-ink); }

/* ------------------------------------------------------------- preview --- */

/* Dry-run screens: promotion, invoice generation. */
.preview-stats { display: flex; gap: 1.5rem; flex-wrap: wrap; }
.preview-stats > div { display: flex; flex-direction: column; }
.preview-num { font-size: 1.75rem; font-weight: 650; line-height: 1; font-variant-numeric: tabular-nums; color: var(--sc-ink); }
.preview-label { font-size: 11.5px; color: var(--sc-muted); text-transform: uppercase; letter-spacing: .03em; margin-top: .1875rem; }
.preview-stats > .is-primary .preview-num { color: var(--sc-brand); }
.preview-stats > .is-muted { opacity: .55; }

/* ------------------------------------------------- guardians + remarks --- */

.guardian-card { border: 1px solid var(--sc-line); border-radius: var(--sc-radius-sm); padding: .625rem .75rem; margin-bottom: .5rem; }
.guardian-card:last-child { margin-bottom: 0; }

.remark-list { list-style: none; margin: 0; padding: 0; }
.remark-item { border-top: 1px solid var(--sc-line-soft); padding: .625rem 0; font-size: 12.5px; }
.remark-item:first-child { border-top: 0; padding-top: 0; }
.remark-head { display: flex; align-items: center; gap: .375rem; margin-bottom: .25rem; }

/* --------------------------------------------------------- credentials --- */

.credential-box { background: var(--sc-surface-2); border: 1px solid var(--sc-line); border-radius: var(--sc-radius-sm); padding: .875rem 1rem; }
.credential-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: .25rem 0; }
.credential-label { color: var(--sc-muted); font-size: 12px; }
.credential-row code { font-size: 14px; font-weight: 600; color: var(--sc-ink); font-family: var(--sc-mono); }

.permission-chips { display: flex; flex-wrap: wrap; gap: .25rem; }
.permission-chip { background: var(--sc-surface-2); border-radius: 4px; padding: 2px 6px; font-size: 11px; font-family: var(--sc-mono); color: var(--sc-muted); }

/* ---------------------------------------------------------------- auth --- */

body.auth-body {
    margin: 0;
    min-height: 100vh;
    display: grid;
    place-items: center;
    background:
        radial-gradient(1200px 500px at 15% -10%, var(--sc-brand-soft), transparent 60%),
        radial-gradient(900px 400px at 110% 110%, var(--sc-good-soft), transparent 55%),
        var(--sc-bg);
    padding: 1.5rem;
    color: var(--sc-ink);
}

.auth-shell { width: 100%; max-width: 404px; }
.auth-brand { text-align: center; margin-bottom: 1.25rem; }
.auth-brand-title { font-size: 1.5rem; font-weight: 700; color: var(--sc-brand); margin: 0 0 .25rem; }
.auth-brand-tag { color: var(--sc-muted); font-size: 13px; margin: 0; }

.auth-card {
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-radius: 14px;
    padding: 1.5rem;
    box-shadow: var(--sc-shadow-lg);
}

.auth-title { font-size: 1.125rem; font-weight: 650; margin: 0 0 .25rem; }
.auth-sub { color: var(--sc-muted); font-size: 13px; margin-bottom: 1.25rem; }
.auth-help { text-align: center; color: var(--sc-muted); font-size: 12px; margin: 1rem 0 0; }
.auth-env { text-align: center; color: var(--sc-muted); font-size: 11px; margin-top: 1rem; text-transform: uppercase; letter-spacing: .05em; }

/* -------------------------------------------------------------- errors --- */

body.error-body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: var(--sc-bg); color: var(--sc-ink); padding: 1.5rem; }

.error-shell { max-width: 620px; text-align: center; }
.error-code { font-size: 3.5rem; font-weight: 700; color: var(--sc-brand); line-height: 1; }
.error-title { font-size: 1.125rem; font-weight: 600; margin: .5rem 0 1.25rem; }
.error-actions { display: flex; gap: .5rem; justify-content: center; margin-bottom: 1.5rem; }
.error-ref { color: var(--sc-muted); font-size: 12px; }
.error-ref code { font-family: var(--sc-mono); }
.error-debug { text-align: left; margin-top: 2rem; background: var(--sc-surface); border: 1px solid var(--sc-line); border-radius: var(--sc-radius-sm); padding: 1rem; }
.error-debug pre { font-size: 11px; max-height: 300px; overflow: auto; margin: 0; color: var(--sc-ink-2); }

/* ------------------------------------------------------- print/receipt --- */

body.print-body { margin: 0; background: var(--sc-bg); color: var(--sc-ink); padding: 1.5rem; }

.print-toolbar { display: flex; gap: .5rem; justify-content: flex-end; max-width: 760px; margin: 0 auto .75rem; }

.print-sheet {
    max-width: 760px;
    margin: 0 auto;
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-radius: var(--sc-radius);
    padding: 2rem 2.25rem;
    box-shadow: var(--sc-shadow-lg);
}

.receipt-void {
    border: 2px solid var(--sc-bad);
    color: var(--sc-bad);
    text-align: center;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    padding: .5rem;
    border-radius: var(--sc-radius-sm);
    margin-bottom: 1.25rem;
}

.receipt-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1.5rem; flex-wrap: wrap; }
.receipt-school { font-size: 1.25rem; font-weight: 700; margin: 0 0 .25rem; }
.receipt-meta { color: var(--sc-muted); font-size: 12px; margin: 0; }
.receipt-stamp { text-align: right; }
.receipt-label { color: var(--sc-muted); font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; }
.receipt-no { font-size: 1.0625rem; font-weight: 700; font-family: var(--sc-mono); }
.receipt-value { font-size: .9375rem; font-weight: 600; }
.receipt-rule { border-color: var(--sc-line); opacity: 1; margin: 1.25rem 0; }
.receipt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 1.5rem; }

.receipt-table { width: 100%; border-collapse: collapse; margin-bottom: 1.25rem; }
.receipt-table td { padding: .5rem 0; border-bottom: 1px solid var(--sc-line-soft); font-size: 13px; }
.receipt-table .receipt-total td {
    border-top: 2px solid var(--sc-ink);
    border-bottom: 0;
    font-size: 1.0625rem;
    font-weight: 700;
    padding-top: .75rem;
    font-variant-numeric: tabular-nums;
}

.receipt-summary { display: flex; gap: 1.5rem; flex-wrap: wrap; padding: .875rem 1rem; background: var(--sc-surface-2); border-radius: var(--sc-radius-sm); }
.receipt-summary > div { display: flex; flex-direction: column; gap: .125rem; font-variant-numeric: tabular-nums; font-weight: 600; }
.receipt-summary .is-due > span:last-child { color: var(--sc-bad); }
.receipt-summary .is-clear > span:last-child { color: var(--sc-good); }

.receipt-foot { display: flex; justify-content: space-between; align-items: flex-end; gap: 1.5rem; margin-top: 2.5rem; }
.receipt-sign { text-align: center; }
.receipt-sign-line { width: 160px; border-top: 1px solid var(--sc-ink); margin-bottom: .25rem; }
.receipt-fineprint { text-align: center; margin-top: 1.5rem; font-size: 10.5px; }

@media print {
    /* Always print on white, whatever the viewer's theme. A receipt printed
       from dark mode wastes toner and is barely readable. */
    :root { color-scheme: light; }
    body.print-body { background: #fff !important; color: #000 !important; padding: 0; }
    .print-hide, .app-sidebar, .app-topbar, .app-footer { display: none !important; }
    .print-sheet { max-width: none; border: 0; box-shadow: none; border-radius: 0; padding: 0; background: #fff !important; }
    .receipt-meta, .receipt-label { color: #555 !important; }
    .receipt-summary { background: #f4f4f4 !important; }
    a { text-decoration: none; color: #000 !important; }
    @page { margin: 16mm; }
}


/* ------------------------------------------------------- attendance --- */

/* Compact status buttons: a teacher marks 60 rows, so the target has to be
   big enough to hit but small enough that the class fits on one screen. */
.attendance-grid .status-group .btn { min-width: 34px; padding: .1875rem .375rem; font-weight: 600; }
.attendance-grid .reason-input { max-width: 260px; }

.meter {
    position: relative;
    height: 18px;
    background: var(--sc-surface-2);
    border-radius: 9px;
    overflow: hidden;
    min-width: 90px;
}

.meter-fill { height: 100%; border-radius: 9px; transition: width .2s ease; }
.meter-fill.is-good { background: var(--sc-good); }
.meter-fill.is-warn { background: var(--sc-warn); }
.meter-fill.is-bad  { background: var(--sc-bad); }

.meter-label {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: 10.5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--sc-ink);
    /* Readable over both the filled and unfilled halves. */
    text-shadow: 0 0 3px var(--sc-surface), 0 0 3px var(--sc-surface);
}

.chronic-chip {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    background: var(--sc-bad-soft);
    border: 1px solid var(--sc-bad);
    border-radius: 20px;
    padding: .1875rem .625rem;
    font-size: 12px;
    text-decoration: none;
    color: var(--sc-ink);
}

.chronic-chip:hover { color: var(--sc-ink); filter: brightness(.97); }
.chronic-chip span { color: var(--sc-bad); font-weight: 700; font-variant-numeric: tabular-nums; }

.template-body {
    max-height: 8rem;
    overflow: auto;
    white-space: pre-wrap;
    background: var(--sc-surface-2);
    border-radius: var(--sc-radius-sm);
    padding: .5rem .625rem;
    margin: 0;
}


/* -------------------------------------------------------- timetable --- */

.timetable-grid { table-layout: fixed; min-width: 760px; }
.timetable-grid th { text-align: center; }

.tt-cell {
    height: 62px;
    vertical-align: top;
    position: relative;
    padding: .3125rem .375rem !important;
}

.tt-cell.is-empty { background: var(--sc-surface-2); }
.tt-subject { font-size: 12px; font-weight: 600; line-height: 1.25; }
.tt-teacher { font-size: 11px; color: var(--sc-muted); }
.tt-room    { font-size: 10.5px; color: var(--sc-muted); }

/* The remove control only appears on hover, so the grid stays readable. */
.tt-remove { position: absolute; top: 2px; right: 2px; opacity: 0; transition: opacity .12s ease; }
.tt-cell:hover .tt-remove { opacity: 1; }

.tt-remove-btn {
    border: 0;
    background: transparent;
    color: var(--sc-bad);
    font-size: 15px;
    line-height: 1;
    padding: 0 3px;
    cursor: pointer;
}

.tt-add {
    width: 100%;
    height: 100%;
    min-height: 48px;
    border: 1px dashed var(--sc-line);
    border-radius: var(--sc-radius-sm);
    background: transparent;
    color: var(--sc-muted);
    font-size: 16px;
    cursor: pointer;
}

.tt-add:hover { border-color: var(--sc-brand); color: var(--sc-brand); background: var(--sc-brand-soft); }

/* ----------------------------------------------------------- marks --- */

.marks-grid .mark-input { width: 84px; text-align: right; font-variant-numeric: tabular-nums; }
.marks-grid .grade-cell { min-width: 34px; display: inline-block; text-align: center; }

/* ---------------------------------------------------------- events --- */

.event-cancelled { opacity: .6; }
.event-cancelled .card-body h3 a { text-decoration: line-through; }


/* ---------------------------------------------------------- reports --- */

.report-card {
    display: flex;
    align-items: flex-start;
    gap: .875rem;
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-radius: var(--sc-radius);
    padding: 1rem 1.125rem;
    text-decoration: none;
    color: inherit;
    height: 100%;
    box-shadow: var(--sc-shadow);
    transition: border-color .12s ease, transform .12s ease;
}

.report-card:hover { border-color: var(--sc-brand); transform: translateY(-1px); color: inherit; }

.report-icon {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: var(--sc-radius-sm);
    background: var(--sc-brand-soft);
    color: var(--sc-brand);
    font-size: 17px;
    flex-shrink: 0;
}

.report-body { display: flex; flex-direction: column; gap: .1875rem; }

/* Horizontal funnel: label, bar, conversion figure. */
.funnel-row { display: grid; grid-template-columns: 150px 1fr 200px; gap: .75rem; align-items: center; margin-bottom: .5rem; }
.funnel-row-label { display: flex; flex-direction: column; }
.funnel-bar-track { background: var(--sc-surface-2); border-radius: var(--sc-radius-sm); height: 26px; overflow: hidden; }
.funnel-bar { height: 100%; background: linear-gradient(90deg, var(--sc-brand), var(--sc-brand-ink)); border-radius: var(--sc-radius-sm); transition: width .25s ease; }
.funnel-row-meta { font-size: 12px; display: flex; gap: .3125rem; align-items: baseline; flex-wrap: wrap; }

.mode-row { display: grid; grid-template-columns: 110px 1fr 100px; gap: .625rem; align-items: center; margin-bottom: .4375rem; }
.mode-label { font-size: 12.5px; }
.mode-row .num { text-align: right; font-size: 12.5px; }

/* ----------------------------------------------------------- portal --- */

/* The portal deliberately has no sidebar — a parent uses two or three screens,
   usually on a phone, and the staff navigation would only be noise. */
body.portal-body { margin: 0; background: var(--sc-bg); color: var(--sc-ink); }

.portal-header { background: var(--sc-surface); border-bottom: 1px solid var(--sc-line); position: sticky; top: 0; z-index: 1020; }

.portal-header-inner {
    max-width: 960px;
    margin: 0 auto;
    padding: .625rem 1rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}

.portal-brand { display: flex; align-items: center; gap: .5rem; font-weight: 600; text-decoration: none; color: var(--sc-ink); }
.portal-brand:hover { color: var(--sc-ink); }

.portal-main { max-width: 960px; margin: 0 auto; padding: 1.25rem 1rem 2rem; }
.portal-footer { max-width: 960px; margin: 0 auto; padding: 1rem; color: var(--sc-muted); font-size: 12px; text-align: center; }

.portal-stats { display: grid; grid-template-columns: 1fr 1fr; gap: .625rem; }

.portal-stats > div {
    background: var(--sc-surface-2);
    border-radius: var(--sc-radius-sm);
    padding: .625rem .75rem;
    display: flex;
    flex-direction: column;
    gap: .0625rem;
    border-left: 3px solid var(--sc-line);
}

.portal-stats > .is-good { border-left-color: var(--sc-good); }
.portal-stats > .is-warn { border-left-color: var(--sc-warn); }
.portal-stats > .is-bad  { border-left-color: var(--sc-bad); }

.portal-stat-label { font-size: 11px; color: var(--sc-muted); text-transform: uppercase; letter-spacing: .03em; }
.portal-stat-value { font-size: 1.125rem; font-weight: 650; font-variant-numeric: tabular-nums; }
.portal-stat-note  { font-size: 11px; color: var(--sc-muted); }

.portal-list { list-style: none; margin: 0; padding: 0; }
.portal-list li { padding: .75rem .875rem; border-bottom: 1px solid var(--sc-line-soft); }
.portal-list li:last-child { border-bottom: 0; }

.portal-tabs { border-bottom-color: var(--sc-line); }
.portal-tabs .nav-link { color: var(--sc-muted); border: 0; border-bottom: 2px solid transparent; padding: .5rem .875rem; font-size: 13px; font-weight: 500; }
.portal-tabs .nav-link:hover { color: var(--sc-ink); border-bottom-color: var(--sc-line); }
.portal-tabs .nav-link.active { color: var(--sc-brand); background: transparent; border-bottom-color: var(--sc-brand); font-weight: 600; }

@media (max-width: 575.98px) {
    .funnel-row { grid-template-columns: 1fr; gap: .25rem; }
    .funnel-row-meta { justify-content: flex-start; }
    .mode-row { grid-template-columns: 90px 1fr; }
    .mode-row .num { grid-column: 2; text-align: left; }
}


/* ---------------------------------------------------------- audit log --- */

.audit-action { font-size: 11px; color: var(--sc-ink-2); }
.audit-notable > td { background: var(--sc-warn-soft) !important; }

.audit-json {
    font-size: 10.5px;
    background: var(--sc-surface-2);
    border-radius: 4px;
    padding: .375rem .5rem;
    margin: .25rem 0 0;
    max-width: 460px;
    max-height: 160px;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-all;
    color: var(--sc-ink-2);
}

details > summary { cursor: pointer; list-style: revert; }


/* -------------------------------------------------------- dashboard --- */

.dash-greeting {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1rem;
}

.dash-hello { font-size: 1.25rem; font-weight: 650; margin: 0; letter-spacing: -.02em; }
.dash-date  { color: var(--sc-muted); font-size: 12.5px; margin: .125rem 0 0; }

.dash-allclear {
    font-size: 12px;
    color: var(--sc-good);
    background: var(--sc-good-soft);
    border-radius: 20px;
    padding: .1875rem .75rem;
    font-weight: 600;
}

/* The attention strip is a QUEUE OF WORK, worst first — not a status board.
   Every row links to the filtered list that resolves it. */
.attention {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
    gap: .625rem;
    margin-bottom: 1.25rem;
}

.attn {
    display: flex;
    align-items: center;
    gap: .75rem;
    background: var(--sc-surface);
    border: 1px solid var(--sc-line);
    border-radius: 12px;
    padding: .625rem .75rem;
    text-decoration: none;
    color: inherit;
    box-shadow: var(--sc-shadow);
    transition: border-color .12s ease, transform .12s ease;
}

.attn:hover { transform: translateY(-1px); color: inherit; }

.attn-icon {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 10px;
    background: var(--attn-tint);
    color: var(--attn-ink);
}

.attn-icon svg { width: 18px; height: 18px; }

.attn-body { display: flex; flex-direction: column; gap: .0625rem; min-width: 0; flex: 1; }
.attn-label  { font-size: 12.5px; font-weight: 600; color: var(--sc-ink); }
.attn-detail { font-size: 11px; color: var(--sc-muted); }

/* The count sits at the end as a chip: the eye scans the icons down the left,
   then the magnitudes down the right. */
.attn-count {
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
    padding: .3125rem .5rem;
    min-width: 1.75rem;
    text-align: center;
    border-radius: 7px;
    background: var(--attn-tint);
    color: var(--attn-ink);
}

/* Severity is carried by the tint, the count, the ordering AND the wording —
   never by colour alone. */
.attn-bad  { --attn-tint: var(--sc-bad-soft);   --attn-ink: var(--sc-bad); }
.attn-warn { --attn-tint: var(--sc-warn-soft);  --attn-ink: var(--sc-warn); }
.attn-info { --attn-tint: var(--sc-brand-soft); --attn-ink: var(--sc-brand); }

.attn-bad:hover  { border-color: var(--sc-bad); }
.attn-warn:hover { border-color: var(--sc-warn); }
.attn-info:hover { border-color: var(--sc-brand); }

/* Tile tones reuse the same left-edge language as the attention cards. */
.tile-plain { border-left-color: var(--sc-line); }

@media (max-width: 575.98px) {
    .attention { grid-template-columns: 1fr; }
    .dash-hello { font-size: 1.125rem; }
}


/* ------------------------------------------------------------- KPI cards --- */

/* Accent = IDENTITY, not performance. Pipeline is always blue and fees always
   amber, so the row is recognisable at a glance and a reader learns the
   positions. How a metric is *doing* is carried by .kpi-delta and its dot. */
/* PALETTE PROVENANCE — do not hand-edit the --kpi values.

   Validated with dataviz/scripts/validate_palette.js in card order
   (blue, green, violet, amber, magenta):
     light  #2a78d6,#0f7a4a,#5b4bc4,#b06f00,#c04a7d  ALL CHECKS PASS
     dark   #3987e5,#008300,#9085e9,#c98500,#d55181  ALL CHECKS PASS

   The dark half is re-stepped, NOT an automatic lightening: that first attempt
   landed at OKLCH L 0.70-0.75 and failed the validator's 0.48-0.67 dark band.
   The tints have to become low-chroma near-blacks or the whole row glows.

   Written as light-dark() pairs so each accent is declared once. The previous
   shape listed every dark value twice — in a media query and again under
   [data-theme="dark"] — which is two places for a validated hex to drift.

   The tints are backgrounds rather than marks, so they sit outside the
   categorical checks; the accent is what has to stay separable. */
.kpi-blue {
    --kpi:      light-dark(#2a78d6, #3987e5);
    --kpi-tint: light-dark(#eef4fd, #131e2e);
    --kpi-chip: light-dark(#dfeafb, #1b2b42);
}

.kpi-green {
    --kpi:      light-dark(#0f7a4a, #008300);
    --kpi-tint: light-dark(#eaf6f0, #10231b);
    --kpi-chip: light-dark(#d6ebe0, #173426);
    /* Dark #008300 reads at only ~2.7:1 on its own chip, so the glyph — an
       identity mark with a label beside it, not a data mark — gets a lighter
       step. The other four clear 3.8-4.9:1 and need no override. */
    --kpi-glyph: light-dark(#0f7a4a, #2f9e63);
}

.kpi-violet {
    --kpi:      light-dark(#5b4bc4, #9085e9);
    --kpi-tint: light-dark(#f0eefb, #191630);
    --kpi-chip: light-dark(#e2ddf7, #241f45);
}

.kpi-amber {
    --kpi:      light-dark(#b06f00, #c98500);
    --kpi-tint: light-dark(#fdf4e6, #241d0f);
    --kpi-chip: light-dark(#f8e8cc, #342a16);
}

.kpi-magenta {
    --kpi:      light-dark(#c04a7d, #d55181);
    --kpi-tint: light-dark(#fceef4, #26161e);
    --kpi-chip: light-dark(#f7dde9, #37202b);
}

/* Five at most, and the grid adapts so four or five each get real width
   rather than five cramped columns on a laptop. */
.kpi-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(212px, 1fr));
    gap: .75rem;
    margin-bottom: 1.25rem;
}

.kpi {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--kpi-tint);
    border: 1px solid transparent;
    border-radius: 14px;
    /* Bottom padding leaves room for the full-bleed sparkline. */
    padding: 1rem 1rem 2.25rem;
    min-width: 0;
    overflow: hidden;
    transition: transform .14s ease, box-shadow .14s ease;
}

.kpi:has(.stretched-link:hover),
.kpi:has(.stretched-link:focus-visible) {
    transform: translateY(-2px);
    box-shadow: 0 6px 18px rgb(15 23 42 / .1);
}

.kpi-top { display: flex; align-items: center; gap: .625rem; min-width: 0; }

/* The icon tile is the card's identity mark — the thing the eye lands on
   before it reads a word. */
.kpi-icon {
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    flex-shrink: 0;
    border-radius: 13px;
    background: var(--kpi-chip);
    /* The glyph is an identity mark with a text label beside it, not a data
       mark, so it answers to plain contrast rather than the categorical
       checks — and it falls back to the validated accent unless a theme has
       to override it for legibility. */
    color: var(--kpi-glyph, var(--kpi));
}

.kpi-icon svg { width: 23px; height: 23px; }

.kpi-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--sc-ink-2);
    line-height: 1.25;
    min-width: 0;
}

/* The number is the point of the card, so it gets the size. Tabular figures
   stop the row from twitching when a value changes width. */
/* Scales with the card so a long currency value shrinks to fit instead of
   breaking across two lines and pushing the row out of alignment. */
.kpi-value {
    font-size: clamp(1.375rem, 2.1vw, 1.75rem);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
    color: var(--sc-ink);
    margin: .625rem 0 0;
    white-space: nowrap;
}

/* Context sentence, not a bare percentage — it says what the number is OF. */
.kpi-delta {
    display: flex;
    align-items: baseline;
    gap: .375rem;
    font-size: 11.5px;
    color: var(--sc-ink-2);
    margin: .25rem 0 0;
    line-height: 1.35;
}

.kpi-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
    transform: translateY(-1px);
}

.kpi-delta-good .kpi-dot { background: var(--sc-good); }
.kpi-delta-warn .kpi-dot { background: var(--sc-warn); }
.kpi-delta-good { color: var(--sc-good); }
.kpi-delta-warn { color: var(--sc-warn); }

/* --- sparkline ---
   Full-bleed along the bottom edge so it reads as the card's own footing
   rather than as a second chart competing with the number. */
.kpi-spark {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 34px;
    pointer-events: none;
}

.kpi-spark-line {
    fill: none;
    stroke: var(--kpi);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    /* The viewBox is stretched to the card width, so without this the stroke
       would thin out on wide cards and thicken on narrow ones. */
    vector-effect: non-scaling-stroke;
    opacity: .85;
}

.kpi-spark-fill { fill: var(--kpi); opacity: .13; stroke: none; }

.kpi-spark-dot {
    fill: var(--kpi);
    stroke: var(--kpi-tint);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
}

@media (max-width: 991.98px) {
    .kpi-row { grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); }
    .kpi-value { font-size: 1.5rem; }
    .kpi-icon { width: 40px; height: 40px; border-radius: 11px; }
    .kpi-icon svg { width: 20px; height: 20px; }
}

@media (max-width: 575.98px) {
    .kpi-row { grid-template-columns: 1fr 1fr; gap: .5rem; }
    .kpi { padding: .8125rem .8125rem 1.875rem; }
    .kpi-top { gap: .5rem; }
    .kpi-value { font-size: 1.25rem; }
    .kpi-icon { width: 34px; height: 34px; border-radius: 10px; }
    .kpi-icon svg { width: 17px; height: 17px; }
    .kpi-spark { height: 26px; }
}

@media (prefers-reduced-motion: reduce) {
    .kpi { transition: none; }
    .kpi:has(.stretched-link:hover) { transform: none; }
}


/* ---------------------------------------------------------- responsive --- */

@media (max-width: 991.98px) {
    .app-sidebar { transform: translateX(-100%); box-shadow: var(--sc-shadow-lg); }
    .app-sidebar.is-open { transform: translateX(0); }
    .app-main { margin-left: 0; }
    .board { grid-auto-columns: 240px; }
    .receipt-grid { grid-template-columns: 1fr; }
    .detail-list { grid-template-columns: 1fr; gap: 0; }
    .detail-list dd { margin-bottom: .5rem; }
}

@media (max-width: 575.98px) {
    .app-content { padding: .875rem; }
    .print-sheet { padding: 1.25rem; }
    .tile-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

/* Wide content scrolls inside its own container; the page body never does.

   .table-responsive alone is not enough: a Bootstrap column is a flex item, and
   a flex item's default min-width:auto is its CONTENT width, so a wide table
   pushes the column — and with it the page — past the viewport before the
   scroll container ever gets a chance to scroll. min-width:0 is what actually
   lets these boxes be narrower than what is inside them. */
.table-responsive { overflow-x: auto; }
.row > [class*="col-"] { min-width: 0; }
.content-card { min-width: 0; }

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}
