/* =============================================================================
   Sep7ro Studio — design system
   Wiki: UI-Redesign-Wireframes, board "00 · Design System".

   Loaded AFTER bootstrap.min.css and app.css, so it is the last word on shared
   surfaces. It restyles the Bootstrap classes the app already uses (card, table,
   btn, badge, form-control, modal, nav-tabs, pagination) rather than asking 34
   pages to adopt new markup — the pages inherit the new look without being
   touched, and a revert is one file.
   ============================================================================= */

:root {
    /* --- Palette (exact tokens from the design-system board) --- */
    --ss-canvas:        #f6f7fb;
    --ss-surface:       #ffffff;
    --ss-rail:          #fbfbfe;
    --ss-panel:         #f1f3f9;
    --ss-border:        #e5e8f0;
    --ss-border-strong: #d4d9e4;
    --ss-ink:           #101828;
    --ss-ink-2:         #475467;
    --ss-muted:         #98a2b3;

    --ss-primary:       #4f46e5;
    --ss-primary-dk:    #4338ca;
    --ss-primary-tint:  #eef2ff;

    --ss-success:       #079455;
    --ss-success-tint:  #e7f6ec;
    --ss-warning:       #d97706;
    --ss-warning-tint:  #fdf1e3;
    --ss-danger:        #d92d20;
    --ss-danger-tint:   #fdecea;
    --ss-info:          #0b7bc4;
    --ss-info-tint:     #e6f2fb;

    /* --- Text-safe variants -------------------------------------------------
       The board's palette is specified for *surfaces*. Several of those colours
       fail WCAG AA as small text on white, which matters because the app puts
       11px labels in them:

         muted   #98a2b3 → 2.58:1   placeholders, help text
         warning #d97706 → 3.19:1
         success #079455 → 3.91:1   the "+6 active" delta on the stat tiles

       AA wants 4.5:1 for text this size. These are the same hues, darkened until
       they pass, and are used only where the colour is carrying words. The
       surface tokens above are unchanged — a border or a pill background has no
       text contrast to fail. */
    --ss-muted-text:    #667085;  /* 4.97:1 */
    --ss-success-text:  #05603a;  /* 7.66:1 */
    --ss-warning-text:  #93370d;  /* 7.52:1 */
    --ss-danger-text:   #912018;  /* 8.66:1 */
    --ss-info-text:     #075985;  /* 7.56:1 */

    /* White on #d97706 is 3.19:1, so the filled warning button needs a darker
       ground for its own label. */
    --ss-warning-solid: #b45309;  /* 5.02:1 against white */

    /* --- Shape & depth --- */
    --ss-radius:    12px;
    --ss-radius-sm: 8px;
    --ss-radius-xs: 6px;
    --ss-pill:      999px;
    --ss-shadow-xs: 0 1px 2px rgba(16, 24, 40, .05);
    --ss-shadow-sm: 0 1px 3px rgba(16, 24, 40, .08), 0 1px 2px rgba(16, 24, 40, .04);
    --ss-shadow-md: 0 4px 12px rgba(16, 24, 40, .08);
    --ss-shadow-lg: 0 12px 32px rgba(16, 24, 40, .12);

    --ss-font: 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;

    /* --- Bridge the legacy names used across app.css and the .razor files, so
           existing markup picks up the new palette without being edited. --- */
    --primary-color:  #4f46e5;
    --primary-dark:   #4338ca;
    --primary-light:  #6366f1;
    --success-color:  #079455;
    --danger-color:   #d92d20;
    --warning-color:  #d97706;
    --info-color:     #0b7bc4;
    --light-bg:       #f6f7fb;
    --border-color:   #e5e8f0;
    --shadow:         var(--ss-shadow-sm);
    --shadow-lg:      var(--ss-shadow-md);

    /* --- Bootstrap 5 variables, so its own utilities follow too.
           The `-rgb` triples are the ones that matter: `.bg-success`, `.text-danger`
           and friends are built from those, not from `--bs-success`. Setting only
           the hex leaves `.bg-success` on Bootstrap's own #198754 — which is how the
           card headers and the WABA stat icons were still a different green. --- */
    --bs-primary:     #4f46e5;
    --bs-primary-rgb: 79, 70, 229;
    --bs-success:     #079455;
    --bs-success-rgb: 7, 148, 85;
    --bs-danger:      #d92d20;
    --bs-danger-rgb:  217, 45, 32;
    --bs-warning:     #d97706;
    --bs-warning-rgb: 217, 119, 6;
    --bs-info:        #0b7bc4;
    --bs-info-rgb:    11, 123, 196;
    --bs-secondary:     #475467;
    --bs-secondary-rgb: 71, 84, 103;
    --bs-body-color:  #101828;
    --bs-body-bg:     #f6f7fb;
    --bs-border-color: #e5e8f0;
    --bs-border-radius: 8px;
    --bs-link-color:  #4f46e5;
    --bs-link-color-rgb: 79, 70, 229;
    --bs-link-hover-color: #4338ca;

    /* Bootstrap's focus and active-state variables, which are a separate family from the
       colour ones above and were all still #0d6efd. They surface on components the design
       system does not restyle directly — the modal close button's halo, an accordion
       header, an active list-group row — so the old blue kept reappearing one control at a
       time. Found by scanning the live stylesheets for Bootstrap's default blue rather
       than by noticing each one. */
    --bs-focus-ring-color: rgba(79, 70, 229, .18);
    --bs-btn-focus-shadow-rgb: 79, 70, 229;
    --bs-btn-close-focus-shadow: 0 0 0 3px rgba(79, 70, 229, .18);
    --bs-accordion-btn-focus-box-shadow: 0 0 0 3px rgba(79, 70, 229, .18);
    --bs-dropdown-link-active-bg: #eef2ff;
    --bs-dropdown-link-active-color: #4338ca;
    --bs-list-group-active-bg: #4f46e5;
    --bs-list-group-active-border-color: #4f46e5;
    --bs-nav-pills-link-active-bg: #4f46e5;
    --bs-pagination-focus-box-shadow: 0 0 0 3px rgba(79, 70, 229, .18);
    --bs-pagination-active-bg: #4f46e5;
    --bs-pagination-active-border-color: #4f46e5;
    --bs-font-sans-serif: 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;
}

/* =============================================================================
   1 · Base
   ============================================================================= */

html, body {
    /* app.css paints a purple gradient here. The new canvas is a flat off-white. */
    background: var(--ss-canvas) !important;
    background-attachment: initial !important;
    font-family: var(--ss-font);
    color: var(--ss-ink);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    font-size: 13px;
    line-height: 1.55;
    letter-spacing: -0.005em;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--ss-ink);
    font-weight: 700;
    letter-spacing: -0.018em;
    margin-bottom: .5rem;
}

/* The type scale from the board: 22/700 page title, 15/700 section, 13/400 body. */
h1, .h1 { font-size: 1.375rem; line-height: 1.3; margin-bottom: 1rem; }
h2, .h2 { font-size: 1.125rem; line-height: 1.35; }
h3, .h3 { font-size: 1rem; }
h4, .h4 { font-size: .9375rem; }
h5, .h5 { font-size: .875rem; }
h6, .h6 { font-size: .8125rem; }

a { color: var(--ss-primary); text-decoration: none; }
a:hover { color: var(--ss-primary-dk); text-decoration: underline; }

.text-muted { color: var(--ss-ink-2) !important; }
small, .small { font-size: .75rem; }
code, kbd, pre, samp { font-family: 'JetBrains Mono', 'Cascadia Mono', Consolas, monospace; }

hr { border-color: var(--ss-border); opacity: 1; }

/* Focus ring — one indigo halo everywhere instead of Bootstrap's blue. */
:focus-visible,
.form-control:focus, .form-select:focus, .form-check-input:focus,
.btn:focus-visible, .btn:focus {
    outline: none;
    border-color: var(--ss-primary) !important;
    box-shadow: 0 0 0 3px rgba(79, 70, 229, .18) !important;
}

/* =============================================================================
   2 · Buttons
   ============================================================================= */

.btn {
    --bs-btn-border-radius: var(--ss-radius-sm);
    border-radius: var(--ss-radius-sm);
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    padding: .5rem .875rem;
    /* `border-style` matters as much as the width here: app.css sets `.btn { border: none }`,
       and that shorthand leaves style at `none`, so a width alone computes to 0. Every
       outline and secondary button in the app was borderless — visible only as coloured
       text — except `.btn-outline-primary`, which app.css happens to give its own
       `2px solid`. That one exception is why it looked deliberate. */
    border-style: solid;
    border-width: 1px;
    box-shadow: none;
    transition: background-color .15s ease, border-color .15s ease, color .15s ease, box-shadow .15s ease;
}

.btn:hover { transform: none; box-shadow: none; }
.btn-sm  { font-size: .75rem;   padding: .3125rem .625rem; border-radius: var(--ss-radius-xs); }
.btn-lg  { font-size: .875rem;  padding: .625rem 1.125rem; }

.btn-primary {
    background: var(--ss-primary); border-color: var(--ss-primary); color: #fff;
    box-shadow: var(--ss-shadow-xs);
}
.btn-primary:hover, .btn-primary:active, .btn-primary:focus {
    background: var(--ss-primary-dk) !important; border-color: var(--ss-primary-dk) !important; color: #fff !important;
}

/* "Secondary" on the board is a white button with a grey border, not a grey slab. */
.btn-secondary, .btn-outline-secondary, .btn-light, .btn-outline-dark {
    background: var(--ss-surface); border-color: var(--ss-border-strong); color: var(--ss-ink-2);
    box-shadow: var(--ss-shadow-xs);
}
.btn-secondary:hover, .btn-outline-secondary:hover, .btn-light:hover, .btn-outline-dark:hover {
    background: var(--ss-panel) !important; border-color: var(--ss-border-strong) !important; color: var(--ss-ink) !important;
}

.btn-outline-primary { border-color: var(--ss-primary); color: var(--ss-primary); background: transparent; }
.btn-outline-primary:hover { background: var(--ss-primary) !important; border-color: var(--ss-primary) !important; color: #fff !important; }

.btn-success { background: var(--ss-success); border-color: var(--ss-success); }
.btn-success:hover { background: #05763f !important; border-color: #05763f !important; }
.btn-danger  { background: var(--ss-danger);  border-color: var(--ss-danger); }
.btn-danger:hover { background: #b42318 !important; border-color: #b42318 !important; }
.btn-warning { background: var(--ss-warning-solid); border-color: var(--ss-warning-solid); color: #fff; }
.btn-warning:hover { background: #b45309 !important; border-color: #b45309 !important; color: #fff !important; }
.btn-info    { background: var(--ss-info);    border-color: var(--ss-info); color: #fff; }
.btn-info:hover { background: #0a6aa8 !important; border-color: #0a6aa8 !important; color: #fff !important; }

.btn-outline-danger  { border-color: var(--ss-danger);  color: var(--ss-danger); }
.btn-outline-danger:hover  { background: var(--ss-danger) !important;  border-color: var(--ss-danger) !important;  color: #fff !important; }
.btn-outline-success { border-color: var(--ss-success); color: var(--ss-success); }
.btn-outline-success:hover { background: var(--ss-success) !important; border-color: var(--ss-success) !important; color: #fff !important; }

/* Ghost — the board's third button: no border until hovered. */
.btn-link, .btn-ghost {
    background: transparent; border-color: transparent; color: var(--ss-ink-2);
    text-decoration: none; box-shadow: none;
}
.btn-link:hover, .btn-ghost:hover { background: var(--ss-panel) !important; color: var(--ss-ink) !important; text-decoration: none; }

/* Tinted — indigo text on an indigo wash. */
.btn-tinted { background: var(--ss-primary-tint); border-color: transparent; color: var(--ss-primary-dk); font-weight: 600; }
.btn-tinted:hover { background: #e0e7ff !important; color: var(--ss-primary-dk) !important; }

.btn:disabled, .btn.disabled { opacity: .5; box-shadow: none; }

/* Button groups. Giving every `.btn` a radius broke these: Bootstrap squares the inner
   corners itself, and once every button is rounded the -1px overlap slides a rounded edge
   over its neighbour's border and hides it. The User Management row actions looked like
   three bare icons next to one outlined button, when all four are outline buttons. */
.btn-group > .btn { border-radius: 0; }
.btn-group > .btn:first-child { border-top-left-radius: var(--ss-radius-sm); border-bottom-left-radius: var(--ss-radius-sm); }
.btn-group > .btn:last-child  { border-top-right-radius: var(--ss-radius-sm); border-bottom-right-radius: var(--ss-radius-sm); }
.btn-group > .btn:only-child  { border-radius: var(--ss-radius-sm); }
.btn-group-sm > .btn:first-child { border-top-left-radius: var(--ss-radius-xs); border-bottom-left-radius: var(--ss-radius-xs); }
.btn-group-sm > .btn:last-child  { border-top-right-radius: var(--ss-radius-xs); border-bottom-right-radius: var(--ss-radius-xs); }
.btn-group > .btn:not(:first-child) { margin-left: -1px; }
/* The hovered or active button has to sit above its neighbours or its own border is
   the one that gets covered. */
.btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn.active { z-index: 1; }

/* `btn-check` toggle groups (the template status filter) follow the same rules. */
.btn-group > .btn-check:checked + .btn { z-index: 1; }

/* Outline variants the design system had not defined, so they were still Bootstrap's. */
.btn-outline-warning { border-color: var(--ss-warning-solid); color: var(--ss-warning-text); background: transparent; }
.btn-outline-warning:hover { background: var(--ss-warning-solid) !important; border-color: var(--ss-warning-solid) !important; color: #fff !important; }
.btn-outline-info { border-color: var(--ss-info); color: var(--ss-info-text); background: transparent; }
.btn-outline-info:hover { background: var(--ss-info) !important; border-color: var(--ss-info) !important; color: #fff !important; }

/* =============================================================================
   3 · Cards & surfaces
   ============================================================================= */

.card {
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    box-shadow: var(--ss-shadow-xs);
    transition: box-shadow .18s ease;
}

/* app.css lifts cards 4px on hover. On a dense operational page that is noise. */
.card:hover { transform: none; box-shadow: var(--ss-shadow-sm); }

.card-header {
    background: var(--ss-surface);
    border-bottom: 1px solid var(--ss-border);
    padding: .875rem 1.125rem;
    font-weight: 700;
    font-size: .9375rem;
    color: var(--ss-ink);
    border-radius: var(--ss-radius) var(--ss-radius) 0 0 !important;
}
.card-header.bg-primary, .card-header.bg-dark,
.card-header.bg-success, .card-header.bg-danger,
.card-header.bg-info, .card-header.bg-warning,
.card-header.bg-secondary { color: #fff; border-bottom-color: transparent; }

.card-body   { padding: 1.125rem; }
.card-footer { background: var(--ss-panel); border-top: 1px solid var(--ss-border); padding: .75rem 1.125rem; border-radius: 0 0 var(--ss-radius) var(--ss-radius) !important; }
.card-title  { color: var(--ss-ink); font-size: .9375rem; font-weight: 700; }

/* 31 pages wrap themselves in `.content-wrapper`, which painted a white panel
   around the whole page. Every board draws cards floating on the canvas instead —
   a panel holding panels reads as one box too many and costs 2.5rem of width on a
   laptop. So the wrapper becomes a plain page container.

   The two pages that had no card of their own (ClassCreate, ClassEdit) got one, so
   nothing is left sitting bare on the canvas. */
.content-wrapper {
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
}

/* …except when it is deliberately a standalone panel, e.g. the 404 and
   access-denied views in Routes.razor, which centre a single block of text. */
.content-wrapper.ss-panel {
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    box-shadow: var(--ss-shadow-xs);
    padding: 1.25rem;
}

.page-header {
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0 0 1rem 0;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--ss-border);
}
.page-header h1 { color: var(--ss-ink); text-shadow: none; }

/* Stat / KPI tile. Dashboard, Messaging and WABA Messaging each defined `.stat-card`
   and `.stat-icon` in their own <style> block, at 40px / 52px / 60px icons and three
   different shadows. They never collided — each block only exists on its own page —
   but the same tile looked different depending where you were standing. One
   definition; the Dashboard keeps only what makes its variant different. */
.stat-card {
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    padding: 1.125rem;
    box-shadow: var(--ss-shadow-xs);
    display: flex;
    align-items: center;
    gap: .875rem;
    text-decoration: none;
    color: inherit;
}
.stat-card:hover { text-decoration: none; color: inherit; }

.stat-icon {
    width: 40px; height: 40px; min-width: 40px;
    border-radius: var(--ss-radius-sm);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.125rem; color: #fff;
}

.stat-details { display: flex; flex-direction: column; min-width: 0; }
.stat-details h3 { font-size: 1.75rem; font-weight: 700; margin: 0; color: var(--ss-ink); letter-spacing: -0.03em; line-height: 1.1; }
.stat-details p  { margin: 0; color: var(--ss-ink-2); font-size: .75rem; font-weight: 500; }

/* Stat / KPI tile — big number, label under it, delta chip. */
.ss-stat {
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    padding: 1rem 1.125rem;
    box-shadow: var(--ss-shadow-xs);
}
.ss-stat-value { font-size: 1.75rem; font-weight: 700; line-height: 1.1; color: var(--ss-ink); letter-spacing: -0.03em; }
.ss-stat-label { font-size: .75rem; color: var(--ss-ink-2); margin-top: .125rem; }
.ss-stat-delta { font-size: .6875rem; font-weight: 600; color: var(--ss-success-text); }
.ss-stat-delta.down { color: var(--ss-danger-text); }
.ss-stat-icon {
    width: 34px; height: 34px; border-radius: var(--ss-radius-sm);
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--ss-primary-tint); color: var(--ss-primary); font-size: 1rem;
}

/* =============================================================================
   4 · Tables
   ============================================================================= */

.table {
    --bs-table-bg: transparent;
    font-size: .8125rem;
    color: var(--ss-ink);
    margin-bottom: 0;
    border-color: var(--ss-border);
}

.table thead { background: transparent; }

.table thead th {
    background: var(--ss-panel);
    color: var(--ss-ink-2);
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: .625rem .875rem;
    border-bottom: 1px solid var(--ss-border);
    border-top: none;
    white-space: nowrap;
}

.table tbody td {
    padding: .6875rem .875rem;
    border-top: none;
    border-bottom: 1px solid var(--ss-border);
    vertical-align: middle;
    color: var(--ss-ink);
}

.table tbody tr { transition: background-color .12s ease; }
.table tbody tr:hover { background: var(--ss-panel); transform: none; }
.table tbody tr:last-child td { border-bottom: none; }
.table-striped > tbody > tr:nth-of-type(odd) > * { background: #fbfbfe; --bs-table-accent-bg: transparent; }

.table-responsive {
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    box-shadow: var(--ss-shadow-xs);
    overflow: auto;
}
/* A table already inside a card must not draw a second frame. */
.card .table-responsive, .card-body > .table-responsive {
    border: none; border-radius: 0; box-shadow: none; background: transparent;
}

/* Avatar chip — initials in a tinted circle, used in every list. */
.ss-avatar {
    width: 30px; height: 30px; border-radius: var(--ss-pill);
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--ss-primary-tint); color: var(--ss-primary-dk);
    font-size: .6875rem; font-weight: 700; letter-spacing: .01em;
    flex: 0 0 auto; overflow: hidden; object-fit: cover;
}
.ss-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.ss-avatar-lg { width: 44px; height: 44px; font-size: .9375rem; }

/* `.avatar` / `.avatar-img` are the names the Students, Guardians and Teachers
   lists already use. They carried three byte-identical copies of the same rule,
   each painting a 40px indigo gradient; this is the single definition. */
.avatar {
    width: 32px; height: 32px; border-radius: var(--ss-pill);
    display: flex; align-items: center; justify-content: center;
    background: var(--ss-primary-tint); color: var(--ss-primary-dk);
    font-size: .6875rem; font-weight: 700; flex: 0 0 auto;
}
.avatar-img {
    width: 32px; height: 32px; border-radius: var(--ss-pill);
    object-fit: cover; display: inline-block; flex: 0 0 auto;
}

/* =============================================================================
   5 · Badges & pills
   ============================================================================= */

.badge {
    border-radius: var(--ss-pill);
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: 0;
    padding: .25rem .5625rem;
    line-height: 1.4;
    text-transform: none;
}

/* Solid Bootstrap badges become quiet tinted pills — colour still carries the
   meaning, but a table of 80 rows is no longer a wall of saturated blocks. */
.badge.bg-primary   { background: var(--ss-primary-tint) !important; color: var(--ss-primary-dk) !important; }
.badge.bg-success   { background: var(--ss-success-tint) !important; color: #05603a !important; }
.badge.bg-danger    { background: var(--ss-danger-tint)  !important; color: #912018 !important; }
.badge.bg-warning   { background: var(--ss-warning-tint) !important; color: #93370d !important; }
.badge.bg-info      { background: var(--ss-info-tint)    !important; color: #075985 !important; }
.badge.bg-secondary { background: var(--ss-panel)        !important; color: var(--ss-ink-2) !important; }
.badge.bg-light     { background: var(--ss-panel)        !important; color: var(--ss-ink-2) !important; }
.badge.bg-dark      { background: #eef0f5                !important; color: var(--ss-ink) !important; }

/* Language badges. Two pages disagreed about what these look like: Students painted a
   solid red "RO" and a solid green "EN"; Guardians painted the Romanian tricolour and a
   Union-Jack gradient, with white text and a shadow to hold it together. On the yellow
   third of that tricolour, white text is about 1.2:1 — the shadow was doing all the work.

   One definition: a neutral pill with the flag as a small swatch in front of the label.
   The flag still carries at a glance, and the word is ink on panel. */
.lang-badge {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    padding: .1875rem .5rem .1875rem .375rem;
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-pill);
    background: var(--ss-panel);
    color: var(--ss-ink) !important;
    font-size: .6875rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0;
    text-shadow: none !important;
    min-width: 0;
}

.lang-badge::before {
    content: '';
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: 0 0 auto;
    border: 1px solid rgba(16, 24, 40, .12);
    background: var(--ss-muted);
}

/* Romanian tricolour and the Union Jack's blue/red, as the swatch rather than the ground. */
.lang-badge.lang-ro::before { background: linear-gradient(90deg, #002B7F 0 33%, #FCD116 33% 66%, #CE1126 66% 100%); }
.lang-badge.lang-en::before { background: linear-gradient(135deg, #012169 0 50%, #C8102E 50% 100%); }
.lang-badge.lang-other::before { background: var(--ss-muted); }

/* A dot before the label reads faster than colour alone (and survives print). */
.ss-pill-dot::before {
    content: ''; display: inline-block; width: 6px; height: 6px;
    border-radius: 50%; background: currentColor; margin-right: .375rem; vertical-align: middle;
}

/* Belt levels keep their real colours — they are the domain, not decoration. A tinted
   "Advanced" pill would say the same thing as a tinted "Active" pill, and they mean
   different kinds of thing.
     Newbie → white · Beginner → yellow · Intermediate → orange
     Advanced → green · Expert → blue
   app.css set these to the CSS keywords (`yellow` is #ffff00, `blue` is #0000ff), which
   its own comment calls a placeholder "until the client's exact belt hex" arrives. Those
   have not arrived, so these are the same five belts at a quality that sits next to the
   rest of the palette — unmistakably the named colour, just not a raw primary.
   Every pairing below is AA: 10.8, 8.3, 5.1 and 4.6 to 1. */
.badge.bg-belt-white, .badge.bg-belt-yellow, .badge.bg-belt-orange,
.badge.bg-belt-green, .badge.bg-belt-blue, .badge.bg-belt-brown,
.badge.bg-belt-black { border-radius: var(--ss-pill); }

.badge.bg-belt-white  { background-color: var(--ss-surface) !important; color: var(--ss-ink) !important; border: 1px solid var(--ss-border-strong); }
.badge.bg-belt-yellow { background-color: #f4c430 !important; color: var(--ss-ink) !important; }
.badge.bg-belt-orange { background-color: #f59e0b !important; color: var(--ss-ink) !important; }
.badge.bg-belt-green  { background-color: #1a7f37 !important; color: #fff !important; }
.badge.bg-belt-blue   { background-color: #1f6feb !important; color: #fff !important; }

/* =============================================================================
   6 · Forms
   ============================================================================= */

.form-control, .form-select {
    border: 1px solid var(--ss-border-strong);
    border-radius: var(--ss-radius-sm);
    font-size: .8125rem;
    padding: .5rem .75rem;
    color: var(--ss-ink);
    background-color: var(--ss-surface);
    box-shadow: var(--ss-shadow-xs);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.form-control::placeholder { color: var(--ss-muted-text); }
.form-control:disabled, .form-select:disabled, .form-control[readonly] {
    background: var(--ss-panel); color: var(--ss-ink-2); box-shadow: none;
}
.form-control-sm, .form-select-sm { font-size: .75rem; padding: .375rem .625rem; border-radius: var(--ss-radius-xs); }

.form-label { font-size: .75rem; font-weight: 600; color: var(--ss-ink-2); margin-bottom: .3125rem; }
.form-text  { font-size: .6875rem; color: var(--ss-muted-text); }
.col-form-label { font-size: .75rem; font-weight: 600; color: var(--ss-ink-2); }

.form-check-input { border-color: var(--ss-border-strong); border-radius: 4px; }
.form-check-input:checked { background-color: var(--ss-primary); border-color: var(--ss-primary); }
.form-check-input[type=checkbox] { width: 1rem; height: 1rem; margin-top: .2rem; }
.form-check-label { font-size: .8125rem; color: var(--ss-ink); }
.form-switch .form-check-input { width: 2rem; height: 1.125rem; border-radius: var(--ss-pill); }

.input-group-text {
    background: var(--ss-panel); border-color: var(--ss-border-strong);
    color: var(--ss-ink-2); font-size: .8125rem; border-radius: var(--ss-radius-sm);
}

/* Sticky save/cancel footer — board 04. The student form is 1,200 lines of markup;
   reaching Save meant scrolling past every section you had just filled in. */
.form-actions {
    position: sticky;
    bottom: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-top: 1.25rem;
    padding: .875rem 1rem;
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    box-shadow: 0 -2px 10px rgba(16, 24, 40, .07);
}

/* A short form does not need to pin anything; below that height the bar just sits
   at the end of the page as before. */
@media (max-height: 34rem) {
    .form-actions { position: static; box-shadow: none; }
}

.invalid-feedback, .validation-message { font-size: .6875rem; color: var(--ss-danger); }
.form-control.invalid, .invalid { border-color: var(--ss-danger) !important; }
.form-control.modified.valid { border-color: var(--ss-success); }

/* =============================================================================
   7 · Alerts
   ============================================================================= */

.alert {
    border-radius: var(--ss-radius);
    border: 1px solid transparent;
    border-left-width: 3px;
    font-size: .8125rem;
    padding: .75rem 1rem;
    box-shadow: none;
}
.alert-info    { background: var(--ss-info-tint);    border-color: #bfdcf2; border-left-color: var(--ss-info);    color: #075985; }
.alert-success { background: var(--ss-success-tint); border-color: #bbe7cd; border-left-color: var(--ss-success); color: #05603a; }
.alert-danger  { background: var(--ss-danger-tint);  border-color: #f8c9c4; border-left-color: var(--ss-danger);  color: #912018; }
.alert-warning { background: var(--ss-warning-tint); border-color: #f5d9ad; border-left-color: var(--ss-warning); color: #93370d; }
.alert-secondary, .alert-light { background: var(--ss-panel); border-color: var(--ss-border); border-left-color: var(--ss-muted); color: var(--ss-ink-2); }
.alert-heading { font-size: .875rem; font-weight: 700; }

/* =============================================================================
   8 · Tabs, pagination, dropdowns, modals
   ============================================================================= */

.nav-tabs {
    border-bottom: 1px solid var(--ss-border);
    gap: .125rem;
}
.nav-tabs .nav-link {
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    color: var(--ss-ink-2);
    font-size: .8125rem;
    font-weight: 600;
    padding: .5625rem .875rem;
    background: transparent;
}
.nav-tabs .nav-link:hover { color: var(--ss-ink); background: var(--ss-panel); border-bottom-color: var(--ss-border-strong); }
.nav-tabs .nav-link.active { color: var(--ss-primary); background: transparent; border-bottom-color: var(--ss-primary); }

.nav-pills .nav-link { border-radius: var(--ss-pill); font-size: .8125rem; font-weight: 600; color: var(--ss-ink-2); padding: .375rem .875rem; }
.nav-pills .nav-link.active { background: var(--ss-primary); color: #fff; }

.pagination { --bs-pagination-border-radius: var(--ss-radius-xs); gap: .1875rem; margin-bottom: 0; }
.page-link {
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius-xs) !important;
    color: var(--ss-ink-2);
    font-size: .75rem;
    font-weight: 600;
    padding: .3125rem .625rem;
    background: var(--ss-surface);
}
.page-link:hover { background: var(--ss-panel); color: var(--ss-ink); border-color: var(--ss-border-strong); }
.page-item.active .page-link { background: var(--ss-primary); border-color: var(--ss-primary); color: #fff; }
.page-item.disabled .page-link { background: var(--ss-surface); color: var(--ss-muted-text); border-color: var(--ss-border); }

.dropdown-menu {
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius-sm);
    box-shadow: var(--ss-shadow-lg);
    padding: .3125rem;
    font-size: .8125rem;
}
.dropdown-item { border-radius: var(--ss-radius-xs); padding: .4375rem .625rem; color: var(--ss-ink); }
.dropdown-item:hover, .dropdown-item:focus { background: var(--ss-panel); color: var(--ss-ink); }
.dropdown-item.active { background: var(--ss-primary-tint); color: var(--ss-primary-dk); }
.dropdown-divider { border-color: var(--ss-border); }

.modal-content { border: 1px solid var(--ss-border); border-radius: var(--ss-radius); box-shadow: var(--ss-shadow-lg); }
/* `color` is not decoration here: app.css sets `.modal-header { color: white }`, which was
   right when the header had a coloured ground. On the white one it makes any text that is
   not inside `.modal-title` invisible. */
.modal-header  { background: var(--ss-surface); color: var(--ss-ink); border-bottom: 1px solid var(--ss-border); padding: 1rem 1.25rem; border-radius: var(--ss-radius) var(--ss-radius) 0 0; }
.modal-header .modal-title { color: var(--ss-ink); font-size: 1rem; font-weight: 700; }
.modal-body    { padding: 1.25rem; font-size: .8125rem; }
.modal-footer  { background: var(--ss-panel); border-top: 1px solid var(--ss-border); padding: .875rem 1.25rem; border-radius: 0 0 var(--ss-radius) var(--ss-radius); }

/* Breadcrumbs — the detail pages' way back up (board 03). */
.breadcrumb { font-size: .75rem; margin-bottom: .375rem; }
.breadcrumb-item + .breadcrumb-item::before { color: var(--ss-muted); }
.breadcrumb-item a { color: var(--ss-ink-2); }
.breadcrumb-item a:hover { color: var(--ss-primary); }
.breadcrumb-item.active { color: var(--ss-muted-text); }

.list-group-item { border-color: var(--ss-border); font-size: .8125rem; padding: .6875rem .875rem; color: var(--ss-ink); }
.list-group-item:first-child { border-top-left-radius: var(--ss-radius); border-top-right-radius: var(--ss-radius); }
.list-group-item:last-child  { border-bottom-left-radius: var(--ss-radius); border-bottom-right-radius: var(--ss-radius); }

.progress { background: var(--ss-panel); border-radius: var(--ss-pill); height: 6px; }
.progress-bar { background: var(--ss-primary); }

.spinner-border { color: var(--ss-primary); border-width: .15em; }

/* app.css sets `.spinner-border { width: 3rem; height: 3rem; display: block; margin: 2rem auto }`,
   which is right for the page-level "Loading students…" spinner and wrong for every other one:
   it also hits `.spinner-border-sm`, so the spinner inside a "Saving…" button rendered at
   **48×48px as a block with 32px of vertical margin**. Bootstrap's own `-sm` sizing is
   variable-driven and loses to app.css's direct values. Restored for the small variant only. */
.spinner-border-sm {
    width: 1rem;
    height: 1rem;
    display: inline-block;
    margin: 0;
    border-width: .15em;
    vertical-align: -0.125em;
}

.toast { border-radius: var(--ss-radius); border: 1px solid var(--ss-border); box-shadow: var(--ss-shadow-lg); font-size: .8125rem; }

.accordion-button { font-size: .875rem; font-weight: 600; color: var(--ss-ink); background: var(--ss-surface); }
.accordion-button:not(.collapsed) { background: var(--ss-primary-tint); color: var(--ss-primary-dk); box-shadow: none; }
.accordion-item { border-color: var(--ss-border); }

/* =============================================================================
   9 · Authentication shell — board 13
   Five pages (Login, 2FA, Register, Forgot, Reset) share these classes. They sat
   on a purple #667eea→#764ba2 gradient that belonged to the old palette; against
   indigo it reads as a different product.
   ============================================================================= */

.auth-container {
    background: var(--ss-canvas);
    /* A very quiet indigo wash off the top-left, so the card has something to sit
       on without the page shouting before anyone has logged in. */
    background-image:
        radial-gradient(60rem 40rem at 15% -10%, #eef2ff 0%, rgba(238, 242, 255, 0) 60%),
        radial-gradient(50rem 35rem at 100% 100%, #f1f3f9 0%, rgba(241, 243, 249, 0) 55%);
    padding: 2rem 1rem;
}

.auth-card {
    background: var(--ss-surface);
    border: 1px solid var(--ss-border);
    border-radius: var(--ss-radius);
    box-shadow: var(--ss-shadow-lg);
    padding: 2.25rem;
    max-width: 25rem;
}

.auth-header { margin-bottom: 1.5rem; }
.auth-header h1 { font-size: 1.375rem; color: var(--ss-ink); margin-bottom: .25rem; }
.auth-header p  { font-size: .8125rem; color: var(--ss-ink-2); }

/* The logo floated up and down on a 3s infinite loop. On the page people stare at
   while typing a password, that is motion with nothing to say. */
.chess-icon {
    font-size: 2.5rem;
    margin-bottom: .875rem;
    color: var(--ss-primary);
    animation: none;
}

.auth-logo { height: 44px; width: auto; }

.auth-footer {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--ss-border);
    font-size: .8125rem;
    color: var(--ss-ink-2);
}

.auth-link { color: var(--ss-primary); font-weight: 600; }
.auth-link:hover { color: var(--ss-primary-dk); }

/* Floating labels are used on these forms; keep them on the new input metrics. app.css
   gives these a 2px border at 10px radius, so the login fields were visibly heavier and
   rounder than every other input in the application. */
.form-floating > .form-control {
    height: auto;
    padding: 1.125rem .75rem .375rem;
    border: 1px solid var(--ss-border-strong);
    border-radius: var(--ss-radius-sm);
}
.form-floating > label { font-size: .8125rem; color: var(--ss-muted-text); padding: .625rem .75rem; }

/* =============================================================================
   10 · Workflow editor — board 18
   The panels were already close (12px radii, quiet borders); this just puts them
   on the same greys as everything else. The WhatsApp preview keeps WhatsApp's own
   colours — #efe7dd wallpaper, #128c7e teal — because it is imitating WhatsApp,
   not following us.
   ============================================================================= */

.workflow-config-card    { border-color: var(--ss-border); box-shadow: var(--ss-shadow-xs); }
.workflow-config-divider { border-left-color: var(--ss-border); }
.workflow-compact-panel  { border-color: var(--ss-border); background: var(--ss-rail); border-radius: var(--ss-radius-sm); }
.workflow-summary-tile   { border-color: var(--ss-border); border-radius: var(--ss-radius-sm); }
.workflow-language-selector label { border-color: var(--ss-border-strong); color: var(--ss-ink-2); font-size: .75rem; }

/* =============================================================================
   11 · Empty state — the board's shared "nothing here yet" panel
   ============================================================================= */

.ss-empty {
    text-align: center;
    padding: 2.5rem 1.25rem;
    color: var(--ss-ink-2);
}
.ss-empty-icon {
    width: 44px; height: 44px; border-radius: var(--ss-radius);
    background: var(--ss-panel); color: var(--ss-muted);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 1.25rem; margin-bottom: .75rem;
}
.ss-empty-title { font-size: .9375rem; font-weight: 700; color: var(--ss-ink); margin-bottom: .25rem; }
.ss-empty-text  { font-size: .8125rem; color: var(--ss-ink-2); max-width: 26rem; margin: 0 auto; }
