/* ==========================================================================
   Janki Steno — design system
   Loaded AFTER Bootstrap 5 so these rules win.
   Used by the public site layout and the student area layout.
   ========================================================================== */

:root {
    /* Brand ramp — deep royal navy, reads as "institution" rather than default-Bootstrap blue */
    --js-brand-950: #08152f;
    --js-brand-900: #0f2350;
    --js-brand-800: #17346f;
    --js-brand-700: #1d448f;
    --js-brand-600: #2557b8;
    --js-brand-500: #3272dd;
    --js-brand-100: #dce8fb;
    --js-brand-50: #f0f5fe;

    /* Warm accent — pairs with the ✓ marks and CTA buttons */
    --js-accent-600: #c97a06;
    --js-accent-500: #f0a020;
    --js-accent-100: #fdf1dc;

    --js-success: #15803d;
    --js-danger: #b91c1c;
    --js-warning: #b45309;

    /* Neutrals */
    --js-ink: #101828;
    --js-body: #475467;
    --js-muted: #667085;
    --js-line: #e4e7ec;
    --js-line-soft: #f0f1f4;
    --js-surface: #ffffff;
    --js-canvas: #f6f8fb;

    --js-radius-sm: .5rem;
    --js-radius: .75rem;
    --js-radius-lg: 1rem;

    --js-shadow-xs: 0 1px 2px rgba(16,24,40,.05);
    --js-shadow-sm: 0 1px 3px rgba(16,24,40,.09), 0 1px 2px rgba(16,24,40,.05);
    --js-shadow: 0 4px 10px -2px rgba(16,24,40,.08), 0 2px 6px -2px rgba(16,24,40,.05);
    --js-shadow-lg: 0 12px 28px -6px rgba(16,24,40,.13), 0 4px 10px -4px rgba(16,24,40,.06);

    --js-header-h: 68px;

    --js-font: 'Poppins', 'Segoe UI', system-ui, -apple-system, sans-serif;
    --js-font-hi: 'Hind Siliguri', 'Poppins', 'Nirmala UI', system-ui, sans-serif;

    /* Feed our palette back into Bootstrap's own variables so stock
       components (.btn-primary, .text-primary, .form-control focus…) follow the brand. */
    --bs-primary: var(--js-brand-600);
    --bs-primary-rgb: 37,87,184;
    --bs-link-color: var(--js-brand-600);
    --bs-link-color-rgb: 37,87,184;
    --bs-link-hover-color: var(--js-brand-800);
    --bs-body-color: var(--js-body);
    --bs-body-font-family: var(--js-font);
    --bs-border-color: var(--js-line);
    --bs-border-radius: var(--js-radius);
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

html {
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: var(--js-font);
    color: var(--js-body);
    background: var(--js-canvas);
    font-size: .95rem;
    line-height: 1.65;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Decorative backdrop.
   Two fixed, non-interactive layers behind everything: a soft tint that warms
   the page up, and a pair of waves under the header. Both are inline SVG /
   gradients, so no extra network requests. Kept very low contrast — white
   cards and tables have to stay the thing your eye lands on. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    background:
        radial-gradient(900px 400px at 10% -10%, rgba(37,87,184,.11), transparent 68%),
        radial-gradient(760px 360px at 90% -6%, rgba(240,160,32,.09), transparent 68%),
        linear-gradient(180deg, #e9f0fb 0%, var(--js-canvas) 46%);
}

body::after {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: min(46vh, 420px);
    z-index: -1;
    pointer-events: none;
    background-repeat: no-repeat;
    background-position: top center;
    background-size: 100% 100%;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320' preserveAspectRatio='none'%3E%3Cpath fill='%232557b8' fill-opacity='.055' d='M0,168 C240,232 470,86 726,126 C972,164 1204,262 1440,198 L1440,0 L0,0 Z'/%3E%3Cpath fill='%231d448f' fill-opacity='.045' d='M0,232 C262,148 520,268 782,206 C1044,144 1246,246 1440,186 L1440,0 L0,0 Z'/%3E%3C/svg%3E");
}

/* The waves belong to the app chrome, not to a printed report. */
@media print {
    body::before, body::after {
        display: none;
    }
}

/* Devanagari copy needs a taller line box than Poppins gives it */
:lang(hi), .hi-text {
    font-family: var(--js-font-hi);
    line-height: 1.9;
}

h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
    color: var(--js-ink);
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -.01em;
}

a {
    text-decoration: none;
}

    a:hover {
        text-decoration: none;
    }

:focus-visible {
    outline: 2px solid var(--js-brand-500);
    outline-offset: 2px;
}

/* The page shell: header, then growing content, then footer pinned to the bottom
   on short pages. #root exists in every layout. */
#root {
    display: flex;
    flex-direction: column;
    flex: 1 0 auto;
}

.js-main {
    flex: 1 0 auto;
}

/* --------------------------------------------------------------------------
   Header / navbar
   -------------------------------------------------------------------------- */

.js-header {
    background: linear-gradient(100deg, var(--js-brand-900) 0%, var(--js-brand-700) 55%, var(--js-brand-600) 100%);
    box-shadow: var(--js-shadow);
    position: sticky;
    top: 0;
    z-index: 1030;
    padding: 0;
}

    .js-header .container-fluid,
    .js-header .container {
        min-height: var(--js-header-h);
        gap: .5rem;
        padding-inline: clamp(1rem, 3vw, 2rem);
    }

/* Brand lockup */
.js-brand {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .4rem 0;
    margin-right: .75rem;
    color: #fff;
}

    .js-brand:hover {
        color: #fff;
    }

    .js-brand img {
        width: 42px;
        height: 42px;
        border-radius: 50%;
        background: #fff;
        padding: 2px;
        box-shadow: 0 0 0 1px rgba(255,255,255,.25);
        flex: none;
    }

.js-brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.js-brand-name {
    font-size: 1.12rem;
    font-weight: 700;
    letter-spacing: -.015em;
    color: #fff;
}

.js-brand-tag {
    font-size: .68rem;
    font-weight: 500;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: rgba(255,255,255,.62);
}

/* Nav links */
.js-header .navbar-nav {
    gap: .15rem;
    align-items: center;
}

.js-nav-link {
    display: flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem .8rem;
    border-radius: var(--js-radius-sm);
    color: rgba(255,255,255,.8);
    font-size: .9rem;
    font-weight: 500;
    white-space: nowrap;
    transition: background-color .15s ease, color .15s ease;
}

    .js-nav-link svg, .js-nav-link i {
        opacity: .85;
        flex: none;
    }

    .js-nav-link:hover, .js-nav-link:focus-visible {
        background: rgba(255,255,255,.12);
        color: #fff;
    }

    .js-nav-link.is-active {
        background: rgba(255,255,255,.16);
        color: #fff;
        font-weight: 600;
    }

        .js-nav-link.is-active svg, .js-nav-link.is-active i {
            opacity: 1;
        }

.navbar-toggler {
    border-color: rgba(255,255,255,.3);
    padding: .35rem .55rem;
}

    .navbar-toggler:focus {
        box-shadow: 0 0 0 3px rgba(255,255,255,.18);
    }

/* Profile dropdown in the header */
.js-user {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .35rem .7rem .35rem .45rem;
    border-radius: 999px;
    background: rgba(255,255,255,.1);
    border: 1px solid rgba(255,255,255,.16);
    color: #fff;
    transition: background-color .15s ease;
}

    .js-user:hover, .js-user:focus-visible, .js-user[aria-expanded="true"] {
        background: rgba(255,255,255,.19);
        color: #fff;
    }

    .js-user::after {
        display: none;
    }

.js-user-avatar {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: rgba(255,255,255,.9);
    color: var(--js-brand-800);
    font-weight: 700;
    font-size: .85rem;
    flex: none;
    text-transform: uppercase;
}

.js-user-meta {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    text-align: left;
    min-width: 0;
}

.js-user-hello {
    font-size: .66rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: rgba(255,255,255,.6);
}

.js-user-name {
    font-size: .84rem;
    font-weight: 600;
    color: #fff;
    max-width: 15ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dropdown-menu {
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius);
    box-shadow: var(--js-shadow-lg);
    padding: .4rem;
    font-size: .9rem;
}

.dropdown-item {
    border-radius: var(--js-radius-sm);
    padding: .5rem .7rem;
    display: flex;
    align-items: center;
    gap: .6rem;
    color: var(--js-body);
    font-weight: 500;
}

    .dropdown-item:hover, .dropdown-item:focus {
        background: var(--js-brand-50);
        color: var(--js-brand-800);
    }

    .dropdown-item.text-danger:hover {
        background: #fef2f2;
        color: var(--js-danger);
    }

.dropdown-header {
    padding: .5rem .7rem .35rem;
    font-size: .7rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--js-muted);
    font-weight: 600;
}

@media (max-width: 991.98px) {
    .js-header .navbar-collapse {
        padding: .75rem 0 1rem;
    }

    .js-header .navbar-nav {
        gap: .15rem;
        align-items: stretch;
        margin-bottom: .75rem;
    }

    .js-nav-link {
        padding: .6rem .75rem;
    }

    .js-user {
        width: 100%;
        justify-content: flex-start;
        border-radius: var(--js-radius);
    }

    .js-user-name {
        max-width: none;
    }
}

/* --------------------------------------------------------------------------
   Page header strip (title + breadcrumb + actions)
   -------------------------------------------------------------------------- */

.js-page-head {
    background: var(--js-surface);
    border-bottom: 1px solid var(--js-line);
    padding: 1.4rem 0;
    margin-bottom: 1.75rem;
}

.js-page-title {
    font-size: 1.4rem;
    font-weight: 650;
    margin: 0;
}

.js-page-sub {
    color: var(--js-muted);
    font-size: .9rem;
    margin: .15rem 0 0;
}

/* --------------------------------------------------------------------------
   Surfaces
   -------------------------------------------------------------------------- */

.card {
    background: var(--js-surface);
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-lg);
    box-shadow: var(--js-shadow-xs);
}

.card-header {
    background: transparent;
    border-bottom: 1px solid var(--js-line);
    padding: 1rem 1.25rem;
    font-weight: 600;
    color: var(--js-ink);
}

.card-body {
    padding: 1.25rem;
}

.card-footer {
    background: transparent;
    border-top: 1px solid var(--js-line);
    padding: .9rem 1.25rem;
}

/* Lift only where the card is genuinely clickable */
.js-card-link {
    display: block;
    color: inherit;
    transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}

    .js-card-link:hover {
        transform: translateY(-2px);
        box-shadow: var(--js-shadow);
        border-color: var(--js-brand-100);
        color: inherit;
    }

.js-panel {
    background: var(--js-surface);
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-lg);
    box-shadow: var(--js-shadow-xs);
    padding: 1.25rem;
}

/* Stat tile */
.js-stat {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
}

.js-stat-icon {
    width: 46px;
    height: 46px;
    border-radius: var(--js-radius);
    display: grid;
    place-items: center;
    background: var(--js-brand-50);
    color: var(--js-brand-600);
    font-size: 1.15rem;
    flex: none;
}

.js-stat-value {
    font-size: 1.55rem;
    font-weight: 700;
    color: var(--js-ink);
    line-height: 1.15;
}

.js-stat-label {
    font-size: .8rem;
    color: var(--js-muted);
    text-transform: uppercase;
    letter-spacing: .05em;
    font-weight: 500;
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
    --bs-btn-border-radius: var(--js-radius-sm);
    font-weight: 550;
    font-size: .9rem;
    padding: .5rem 1.05rem;
    border-radius: var(--js-radius-sm);
    transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease, transform .12s ease;
}

    .btn:active {
        transform: translateY(1px);
    }

.btn-lg {
    padding: .7rem 1.5rem;
    font-size: 1rem;
}

.btn-sm {
    padding: .35rem .75rem;
    font-size: .82rem;
}

.btn-primary {
    --bs-btn-bg: var(--js-brand-600);
    --bs-btn-border-color: var(--js-brand-600);
    --bs-btn-hover-bg: var(--js-brand-700);
    --bs-btn-hover-border-color: var(--js-brand-700);
    --bs-btn-active-bg: var(--js-brand-800);
    --bs-btn-active-border-color: var(--js-brand-800);
    --bs-btn-disabled-bg: var(--js-brand-500);
    --bs-btn-disabled-border-color: var(--js-brand-500);
    box-shadow: var(--js-shadow-xs);
}

.btn-outline-primary {
    --bs-btn-color: var(--js-brand-700);
    --bs-btn-border-color: var(--js-brand-600);
    --bs-btn-hover-bg: var(--js-brand-600);
    --bs-btn-hover-border-color: var(--js-brand-600);
    --bs-btn-active-bg: var(--js-brand-700);
    --bs-btn-active-border-color: var(--js-brand-700);
}

.btn-accent {
    --bs-btn-color: #3d2600;
    --bs-btn-bg: var(--js-accent-500);
    --bs-btn-border-color: var(--js-accent-500);
    --bs-btn-hover-color: #3d2600;
    --bs-btn-hover-bg: #e39316;
    --bs-btn-hover-border-color: #e39316;
    --bs-btn-active-color: #3d2600;
    --bs-btn-active-bg: var(--js-accent-600);
    --bs-btn-active-border-color: var(--js-accent-600);
    color: #3d2600;
    background: var(--js-accent-500);
    border: 1px solid var(--js-accent-500);
    box-shadow: var(--js-shadow-xs);
}

/* Header CTA on the dark bar */
.js-header .btn-login {
    color: #fff;
    background: rgba(255,255,255,.12);
    border: 1px solid rgba(255,255,255,.35);
    font-weight: 600;
}

    .js-header .btn-login:hover {
        background: #fff;
        border-color: #fff;
        color: var(--js-brand-800);
    }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.form-label {
    font-size: .85rem;
    font-weight: 600;
    color: var(--js-ink);
    margin-bottom: .35rem;
}

.form-control, .form-select {
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-sm);
    padding: .55rem .8rem;
    font-size: .92rem;
    color: var(--js-ink);
    background-color: var(--js-surface);
    box-shadow: var(--js-shadow-xs);
    transition: border-color .15s ease, box-shadow .15s ease;
}

    .form-control:focus, .form-select:focus {
        border-color: var(--js-brand-500);
        box-shadow: 0 0 0 3.5px rgba(50,114,221,.15);
    }

    .form-control::placeholder {
        color: #98a2b3;
    }

.form-check-input:checked {
    background-color: var(--js-brand-600);
    border-color: var(--js-brand-600);
}

.form-check-input:focus {
    border-color: var(--js-brand-500);
    box-shadow: 0 0 0 3.5px rgba(50,114,221,.15);
}

.input-group-text {
    background: var(--js-brand-50);
    border-color: var(--js-line);
    color: var(--js-brand-700);
    border-radius: var(--js-radius-sm);
}

/* --------------------------------------------------------------------------
   Tables
   -------------------------------------------------------------------------- */

.js-table-wrap {
    background: var(--js-surface);
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-lg);
    box-shadow: var(--js-shadow-xs);
    overflow: hidden;
}

    .js-table-wrap .table-responsive {
        overflow-x: auto;
    }

.table {
    --bs-table-border-color: var(--js-line-soft);
    margin-bottom: 0;
    font-size: .89rem;
    color: var(--js-body);
    vertical-align: middle;
}

    .table > thead th {
        background: var(--js-brand-50);
        color: var(--js-brand-900);
        font-weight: 600;
        font-size: .74rem;
        letter-spacing: .07em;
        text-transform: uppercase;
        border-bottom: 1px solid var(--js-line);
        padding: .8rem 1rem;
        white-space: nowrap;
    }

    .table > tbody td {
        padding: .8rem 1rem;
        border-bottom: 1px solid var(--js-line-soft);
    }

    .table > tbody tr:last-child td {
        border-bottom: 0;
    }

.table-hover > tbody > tr:hover > * {
    background: var(--js-brand-50);
    --bs-table-accent-bg: var(--js-brand-50);
}

/* --------------------------------------------------------------------------
   Badges, alerts, modals, misc
   -------------------------------------------------------------------------- */

.badge {
    font-weight: 600;
    font-size: .72rem;
    letter-spacing: .03em;
    padding: .35em .65em;
    border-radius: 999px;
}

.js-badge-soft-success {
    background: #ecfdf3;
    color: var(--js-success);
}

.js-badge-soft-danger {
    background: #fef3f2;
    color: var(--js-danger);
}

.js-badge-soft-warning {
    background: var(--js-accent-100);
    color: var(--js-warning);
}

.js-badge-soft-brand {
    background: var(--js-brand-50);
    color: var(--js-brand-700);
}

.alert {
    border: 1px solid transparent;
    border-radius: var(--js-radius);
    font-size: .9rem;
    padding: .8rem 1rem;
}

.alert-success {
    background: #ecfdf3;
    border-color: #abefc6;
    color: #05603a;
}

.alert-danger {
    background: #fef3f2;
    border-color: #fecdca;
    color: #912018;
}

.alert-info {
    background: var(--js-brand-50);
    border-color: var(--js-brand-100);
    color: var(--js-brand-800);
}

.modal-content {
    border: 0;
    border-radius: var(--js-radius-lg);
    box-shadow: var(--js-shadow-lg);
}

.modal-header, .modal-footer {
    border-color: var(--js-line);
    padding: 1rem 1.25rem;
}

.modal-body {
    padding: 1.25rem;
}

.nav-tabs {
    border-bottom: 1px solid var(--js-line);
    gap: .25rem;
}

    .nav-tabs .nav-link {
        border: 0;
        border-bottom: 2px solid transparent;
        border-radius: 0;
        color: var(--js-muted);
        font-weight: 550;
        padding: .6rem .9rem;
    }

        .nav-tabs .nav-link:hover {
            color: var(--js-brand-700);
            border-bottom-color: var(--js-brand-100);
        }

        .nav-tabs .nav-link.active {
            color: var(--js-brand-700);
            background: transparent;
            border-bottom-color: var(--js-brand-600);
        }

.js-empty {
    text-align: center;
    padding: 3rem 1rem;
    color: var(--js-muted);
}

    .js-empty svg, .js-empty i {
        color: var(--js-line);
        margin-bottom: .75rem;
    }

/* --------------------------------------------------------------------------
   Public site footer
   -------------------------------------------------------------------------- */

.js-footer {
    flex: none;
    background: var(--js-brand-950);
    color: rgba(255,255,255,.68);
    font-size: .89rem;
    margin-top: auto;
}

.js-footer-top {
    padding: 3rem 0 2.25rem;
}

.js-footer-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1.4fr;
    gap: 2.5rem;
}

@media (max-width: 860px) {
    .js-footer-grid {
        grid-template-columns: 1fr;
        gap: 2rem;
    }
}

.js-footer h5 {
    color: #fff;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    margin-bottom: 1.1rem;
}

.js-footer p {
    margin-bottom: .6rem;
}

.js-footer a {
    color: rgba(255,255,255,.68);
    transition: color .15s ease;
}

    .js-footer a:hover {
        color: #fff;
    }

.js-footer-brand {
    display: flex;
    align-items: center;
    gap: .7rem;
    margin-bottom: 1rem;
}

    .js-footer-brand img {
        width: 44px;
        height: 44px;
        border-radius: 50%;
        background: #fff;
        padding: 2px;
    }

    .js-footer-brand span {
        color: #fff;
        font-weight: 700;
        font-size: 1.05rem;
    }

.js-footer-links {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: .55rem;
}

.js-contact-row {
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    margin-bottom: .8rem;
}

    .js-contact-row svg {
        flex: none;
        margin-top: .2rem;
        color: var(--js-accent-500);
    }

.js-footer-bottom {
    border-top: 1px solid rgba(255,255,255,.1);
    padding: 1.1rem 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .6rem;
    font-size: .82rem;
    color: rgba(255,255,255,.5);
}

.js-footer-legal {
    display: flex;
    flex-wrap: wrap;
    gap: 1.1rem;
}

/* Compact footer used inside the student app shell */
.js-appfooter {
    flex: none;
    margin-top: auto;
    background: var(--js-surface);
    border-top: 1px solid var(--js-line);
    padding: 1rem 0;
    font-size: .83rem;
    color: var(--js-muted);
}

    .js-appfooter .js-appfooter-inner {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: .6rem;
        padding-inline: clamp(1rem, 3vw, 2rem);
    }

    .js-appfooter a {
        color: var(--js-brand-700);
        font-weight: 550;
    }

        .js-appfooter a:hover {
            color: var(--js-brand-900);
        }

/* --------------------------------------------------------------------------
   Floating WhatsApp button
   -------------------------------------------------------------------------- */

/* Collapsed to a disc; widens into a labelled pill on hover/focus. */
.js-whatsapp {
    position: fixed;
    right: 1.5rem;
    bottom: 1.5rem;
    z-index: 1040;
    height: 52px;
    padding: 0 7px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    gap: .6rem;
    max-width: 52px;
    overflow: hidden;
    background: #1faa54;
    color: #fff;
    box-shadow: 0 4px 14px rgba(16,24,40,.18), 0 1px 3px rgba(16,24,40,.1);
    transition: max-width .28s cubic-bezier(.4,0,.2,1), background-color .18s ease, box-shadow .18s ease;
}

    .js-whatsapp:hover, .js-whatsapp:focus-visible {
        color: #fff;
        max-width: 240px;
        background: #199247;
        box-shadow: 0 8px 22px rgba(16,24,40,.22), 0 2px 6px rgba(16,24,40,.12);
    }

.js-whatsapp-icon {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: rgba(255,255,255,.16);
    flex: none;
}

    .js-whatsapp-icon svg {
        width: 22px;
        height: 22px;
    }

.js-whatsapp-label {
    font-size: .88rem;
    font-weight: 600;
    white-space: nowrap;
    padding-right: .85rem;
    opacity: 0;
    transition: opacity .2s ease .06s;
}

.js-whatsapp:hover .js-whatsapp-label,
.js-whatsapp:focus-visible .js-whatsapp-label {
    opacity: 1;
}

/* Touch devices have no hover — keep it a clean disc rather than a stuck-open pill. */
@media (hover: none) {
    .js-whatsapp {
        max-width: 52px;
    }

    .js-whatsapp-label {
        display: none;
    }
}

/* ==========================================================================
   Page header — title band used by pages that are not a plain report table
   ========================================================================== */

/* Deliberately compact: this band only identifies the page, so it should cost
   as little vertical space as possible above the actual content. */
.js-pagehead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: .6rem 1.25rem;
    background: var(--js-surface);
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius);
    box-shadow: var(--js-shadow-xs);
    padding: .7rem 1.05rem;
    margin-bottom: 1rem;
}

.js-pagehead-main {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-width: 0;
}

.js-pagehead-icon {
    width: 36px;
    height: 36px;
    border-radius: .55rem;
    display: grid;
    place-items: center;
    background: linear-gradient(140deg, var(--js-brand-600), var(--js-brand-800));
    color: #fff;
    flex: none;
    box-shadow: 0 3px 8px -2px rgba(37,87,184,.4);
}

    .js-pagehead-icon svg {
        width: 18px;
        height: 18px;
    }

.js-pagehead-title {
    font-size: 1.12rem;
    font-weight: 650;
    margin: 0;
    line-height: 1.2;
}

.js-pagehead-sub {
    margin: .1rem 0 0;
    font-size: .8rem;
    line-height: 1.4;
    color: var(--js-muted);
}

    .js-pagehead-sub b {
        color: var(--js-brand-700);
        font-weight: 600;
    }

.js-pagehead-actions {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
}

@media (max-width: 620px) {
    .js-pagehead-actions {
        width: 100%;
    }
}

/* ==========================================================================
   Package / pricing cards
   ========================================================================== */

/* Cards stay compact — a package holds a handful of facts, so the card should
   be only as tall as those facts. max-width stops a single package from
   stretching into a billboard on a wide screen. */
.js-pkg-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
    gap: 1.15rem;
    align-items: start;
}

    .js-pkg-grid > .js-pkg {
        max-width: 340px;
    }

.js-pkg {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--js-surface);
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-lg);
    box-shadow: var(--js-shadow-sm);
    overflow: hidden;
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}

    .js-pkg:hover {
        transform: translateY(-3px);
        box-shadow: var(--js-shadow-lg);
        border-color: var(--js-brand-100);
    }

    /* Accent strip along the top edge */
    .js-pkg::before {
        content: "";
        position: absolute;
        inset: 0 0 auto;
        height: 3px;
        background: linear-gradient(90deg, var(--js-brand-600), var(--js-brand-500));
    }

.js-pkg--owned {
    border-color: #abefc6;
}

    .js-pkg--owned::before {
        background: linear-gradient(90deg, #12b76a, #32d583);
    }

.js-pkg-ribbon {
    position: absolute;
    top: 1rem;
    right: 1rem;
    z-index: 1;
    background: #ecfdf3;
    color: #05603a;
    border: 1px solid #abefc6;
    border-radius: 999px;
    padding: .22rem .6rem;
    font-size: .69rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
}

.js-pkg-head {
    padding: 1.05rem 1.1rem .2rem;
}

.js-pkg-title {
    font-size: 1rem;
    font-weight: 650;
    line-height: 1.35;
    margin: 0 0 .2rem;
    /* Two lines max, so cards in a row keep the same rhythm */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.js-pkg-desc {
    font-size: .82rem;
    color: var(--js-muted);
    margin: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.js-pkg-price {
    display: flex;
    align-items: baseline;
    gap: .3rem;
    padding: .7rem 1.1rem .75rem;
}

.js-pkg-amount {
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: -.025em;
    color: var(--js-brand-800);
    line-height: 1;
}

.js-pkg-period {
    font-size: .82rem;
    color: var(--js-muted);
    font-weight: 500;
}

.js-pkg-meta {
    list-style: none;
    margin: 0;
    padding: 0 1.1rem .95rem;
    display: grid;
    gap: .45rem;
}

    .js-pkg-meta li {
        display: flex;
        align-items: center;
        gap: .55rem;
        font-size: .84rem;
        color: var(--js-body);
    }

.js-pkg-ico {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--js-brand-50);
    color: var(--js-brand-600);
    flex: none;
}

.js-pkg--owned .js-pkg-ico {
    background: #ecfdf3;
    color: #12b76a;
}

.js-pkg-foot {
    margin-top: auto;
    padding: .8rem 1.1rem .9rem;
    border-top: 1px solid var(--js-line-soft);
    background: linear-gradient(180deg, rgba(246,248,251,.5), rgba(246,248,251,1));
    display: grid;
    gap: .45rem;
}

    .js-pkg-foot .btn {
        width: 100%;
    }

.js-pkg-expiry {
    text-align: center;
    font-size: .75rem;
    color: var(--js-muted);
    margin: .1rem 0 0;
}

.js-pkg-ribbon {
    top: .75rem;
    right: .75rem;
}

/* Sign-up nudge under the public package grid */
.js-pkg-note {
    margin: 1.5rem 0 0;
    text-align: center;
    font-size: .9rem;
    color: var(--js-muted);
}

    .js-pkg-note a {
        color: var(--js-brand-700);
        font-weight: 600;
    }

        .js-pkg-note a:hover {
            color: var(--js-brand-900);
        }

/* --------------------------------------------------------------------------
   Page shell — the breathing room around a report page's content.
   Keeps content off the window edges and stops very wide monitors from
   stretching a table across 2000px.
   -------------------------------------------------------------------------- */

.js-page {
    width: 100%;
    max-width: 1560px;
    margin-inline: auto;
    /* Less padding at the top — the header band sits right under the navbar. */
    padding: clamp(1rem, 1.6vw, 1.5rem) clamp(1.15rem, 3vw, 2.75rem) clamp(1.75rem, 3vw, 2.75rem);
}

/* ==========================================================================
   JsTable — shared report/list table (see wwwroot/js/js-table.js)
   ========================================================================== */

.js-dt {
    margin-bottom: 1rem;
}

/* Toolbar above the table. Pages carry their own .js-pagehead band, so this
   row is just the record count plus the search/filter controls. */
.js-dt-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem 1rem;
    margin-bottom: .85rem;
}

.js-dt-title {
    font-size: 1.35rem;
    font-weight: 650;
    margin: 0;
}

.js-dt-count {
    margin: .2rem 0 0;
    font-size: .82rem;
    color: var(--js-muted);
    min-height: 1.2em;
}

.js-dt-tools {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
}

.js-dt-slot {
    display: flex;
    align-items: center;
    gap: .5rem;
}

    .js-dt-slot:empty {
        display: none;
    }

/* Filter chips that pages drop into the slot */
.js-chip {
    border: 1px solid var(--js-line);
    background: var(--js-surface);
    color: var(--js-body);
    border-radius: 999px;
    padding: .38rem .95rem;
    font-size: .84rem;
    font-weight: 550;
    box-shadow: var(--js-shadow-xs);
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

    .js-chip:hover {
        border-color: var(--js-brand-100);
        background: var(--js-brand-50);
        color: var(--js-brand-700);
    }

    .js-chip.is-active {
        background: var(--js-brand-600);
        border-color: var(--js-brand-600);
        color: #fff;
    }

/* Dropdown filter: caption + select in one pill. Turns brand-coloured while
   a filter is actually applied, so an active filter is never invisible. */
.js-dt-filter {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin: 0;
    padding: .28rem .5rem .28rem .7rem;
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-sm);
    background: var(--js-surface);
    box-shadow: var(--js-shadow-xs);
    font-size: .78rem;
    color: var(--js-muted);
    transition: border-color .15s ease, background-color .15s ease;
}

    .js-dt-filter > span {
        font-weight: 600;
        letter-spacing: .04em;
        text-transform: uppercase;
        font-size: .68rem;
        white-space: nowrap;
    }

    .js-dt-filter select {
        border: 0;
        background: transparent;
        font-size: .85rem;
        font-weight: 550;
        color: var(--js-ink);
        padding: .1rem 1.35rem .1rem .1rem;
        cursor: pointer;
        appearance: none;
        background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23667085'%3E%3Cpath d='M1.6 4.5 8 10.9l6.4-6.4-1.1-1.1L8 8.7 2.7 3.4z'/%3E%3C/svg%3E");
        background-repeat: no-repeat;
        background-position: right .25rem center;
        background-size: 10px;
        max-width: 170px;
    }

        .js-dt-filter select:focus {
            outline: none;
        }

    .js-dt-filter.is-on {
        border-color: var(--js-brand-500);
        background: var(--js-brand-50);
        color: var(--js-brand-700);
    }

        .js-dt-filter.is-on select {
            color: var(--js-brand-800);
        }

.js-dt-search {
    position: relative;
    display: flex;
    align-items: center;
}

    .js-dt-search svg {
        position: absolute;
        left: .7rem;
        color: var(--js-muted);
        pointer-events: none;
    }

    .js-dt-search input {
        border: 1px solid var(--js-line);
        border-radius: var(--js-radius-sm);
        background: var(--js-surface);
        padding: .48rem .8rem .48rem 2.1rem;
        font-size: .88rem;
        color: var(--js-ink);
        width: 220px;
        box-shadow: var(--js-shadow-xs);
        transition: border-color .15s ease, box-shadow .15s ease, width .18s ease;
    }

        .js-dt-search input:focus {
            outline: none;
            border-color: var(--js-brand-500);
            box-shadow: 0 0 0 3.5px rgba(50,114,221,.15);
            width: 260px;
        }

/* Table surface */
.js-dt-surface {
    background: var(--js-surface);
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-lg);
    box-shadow: var(--js-shadow-xs);
    overflow: hidden;
}

.js-dt-scroll {
    overflow-x: auto;
}

/* table-layout: fixed is what makes text-overflow: ellipsis actually work in a
   cell — with the default `auto` algorithm the column just grows to fit the
   longest value instead of clipping it. Columns keep the widths declared in the
   JsTable config; the rest share what is left. min-width means narrow screens
   scroll sideways rather than crushing every column. */
.js-dt-table {
    width: 100%;
    min-width: 940px;
    table-layout: fixed;
    border-collapse: separate;
    border-spacing: 0;
    font-size: .89rem;
    color: var(--js-body);
}

    .js-dt-table thead th {
        background: var(--js-brand-100);
        color: var(--js-brand-900);
        font-weight: 600;
        font-size: .73rem;
        /* Tight tracking: wide letter-spacing was clipping short labels like
           "Incorrect" in their own column. */
        letter-spacing: .035em;
        text-transform: uppercase;
        text-align: left;
        padding: .85rem .85rem;
        white-space: nowrap;
        border-bottom: 2px solid var(--js-brand-600);
        border-right: 1px solid rgba(37,87,184,.14);
        position: sticky;
        top: 0;
        z-index: 1;
    }

        .js-dt-table thead th:last-child {
            border-right: 0;
        }

    /* Single line everywhere; anything longer is clipped with an ellipsis and
       gets a title attribute from JsTable._markTruncated() so hovering shows
       the full value. */
    .js-dt-table tbody td {
        padding: .8rem 1rem;
        border-bottom: 1px solid var(--js-line);
        border-right: 1px solid var(--js-line-soft);
        vertical-align: middle;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

        .js-dt-table tbody td:last-child {
            border-right: 0;
        }

        /* Action / badge cells opt out via truncate:false so buttons aren't clipped. */
        .js-dt-table tbody td.js-dt-full {
            overflow: visible;
            text-overflow: clip;
        }

        .js-dt-table tbody td.is-clipped {
            cursor: help;
        }

    .js-dt-table thead th {
        overflow: hidden;
        text-overflow: ellipsis;
    }

        /* A clipped header still needs its sort arrow visible, so reserve room
           for it and let the label take whatever is left. */
        .js-dt-table thead th.is-clipped {
            cursor: help;
        }

        .js-dt-table thead th.js-dt-sortable.is-clipped {
            cursor: pointer;
        }

    .js-dt-table tbody tr:last-child td {
        border-bottom: 0;
    }

    /* Zebra striping — the tint has to stay light enough that the row
       hover state still reads as a change. */
    .js-dt-table tbody tr:nth-child(odd) {
        background: var(--js-surface);
    }

    .js-dt-table tbody tr:nth-child(even) {
        background: #f7f9fc;
    }

    .js-dt-table tbody tr {
        transition: background-color .12s ease, box-shadow .12s ease;
    }

        .js-dt-table tbody tr:hover {
            background: var(--js-brand-50);
            box-shadow: inset 3px 0 0 var(--js-brand-600);
        }

/* Striping is meaningless behind the shimmer placeholders */
.js-dt.is-loading .js-dt-table tbody tr:nth-child(even) {
    background: var(--js-surface);
}

.js-dt-end {
    text-align: right;
}

.js-dt-center {
    text-align: center;
}

/* Sortable headers */
.js-dt-sortable {
    cursor: pointer;
    user-select: none;
}

    .js-dt-sortable:hover {
        color: var(--js-brand-600);
    }

.js-dt-arrow {
    display: inline-block;
    width: 0;
    height: 0;
    margin-left: .4rem;
    vertical-align: middle;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-bottom: 5px solid currentColor;
    opacity: .22;
}

.js-dt-sorted-asc .js-dt-arrow {
    opacity: 1;
}

.js-dt-sorted-desc .js-dt-arrow {
    opacity: 1;
    transform: rotate(180deg);
}

/* Skeleton loader */
.js-dt-skel {
    display: block;
    height: 11px;
    border-radius: 5px;
    background: linear-gradient(90deg, #eef0f4 25%, #f7f8fa 37%, #eef0f4 63%);
    background-size: 400% 100%;
    animation: js-dt-shimmer 1.3s ease-in-out infinite;
}

@keyframes js-dt-shimmer {
    0% {
        background-position: 100% 50%;
    }

    100% {
        background-position: 0 50%;
    }
}

.js-dt-skel-row td {
    padding-block: 1.05rem;
}

.js-dt.is-loading .js-dt-table tbody tr:hover {
    background: transparent;
}

/* Empty / error states */
.js-dt-state {
    padding: 3.25rem 1.5rem;
    text-align: center;
}

.js-dt-state-icon {
    color: var(--js-line);
    margin-bottom: .6rem;
}

.js-dt-state--error .js-dt-state-icon {
    color: #fda29b;
}

.js-dt-state-title {
    font-weight: 600;
    color: var(--js-ink);
    margin: 0 0 .25rem;
}

.js-dt-state-msg {
    color: var(--js-muted);
    font-size: .87rem;
    margin: 0 0 1rem;
}

/* Footer: page size + pager */
.js-dt-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-top: 1rem;
}

.js-dt-size {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .82rem;
    color: var(--js-muted);
    margin: 0;
}

    .js-dt-size select {
        border: 1px solid var(--js-line);
        border-radius: var(--js-radius-sm);
        background: var(--js-surface);
        padding: .3rem 1.7rem .3rem .6rem;
        font-size: .84rem;
        color: var(--js-ink);
        cursor: pointer;
        appearance: none;
        background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23667085'%3E%3Cpath d='M1.6 4.5 8 10.9l6.4-6.4-1.1-1.1L8 8.7 2.7 3.4z'/%3E%3C/svg%3E");
        background-repeat: no-repeat;
        background-position: right .5rem center;
        background-size: 11px;
    }

.js-dt-pager {
    display: flex;
    align-items: center;
    gap: .25rem;
    flex-wrap: wrap;
}

.js-dt-pg {
    min-width: 34px;
    height: 34px;
    padding: 0 .5rem;
    display: inline-grid;
    place-items: center;
    border: 1px solid var(--js-line);
    border-radius: var(--js-radius-sm);
    background: var(--js-surface);
    color: var(--js-body);
    font-size: .84rem;
    font-weight: 550;
    transition: background-color .13s ease, border-color .13s ease, color .13s ease;
}

    .js-dt-pg:hover:not(:disabled):not(.is-current) {
        background: var(--js-brand-50);
        border-color: var(--js-brand-100);
        color: var(--js-brand-700);
    }

    .js-dt-pg.is-current {
        background: var(--js-brand-600);
        border-color: var(--js-brand-600);
        color: #fff;
    }

    .js-dt-pg:disabled {
        opacity: .4;
        cursor: not-allowed;
    }

.js-dt-gap {
    padding: 0 .2rem;
    color: var(--js-muted);
}

/* Cell helpers */
.js-dt-strong {
    font-weight: 600;
    color: var(--js-ink);
}

.js-dt-sub {
    display: block;
    font-size: .78rem;
    color: var(--js-muted);
}

.js-dt-actions {
    display: flex;
    gap: .45rem;
    white-space: nowrap;
}

/* Stack into cards on narrow screens instead of scrolling sideways forever */
@media (max-width: 720px) {
    /* Card mode: rows stack, so the fixed layout and the single-line clipping
       both stop applying — a value gets its own line and wraps instead. */
    .js-dt-table {
        min-width: 0;
        table-layout: auto;
        display: block;
    }

    .js-dt-table thead {
        display: none;
    }

    .js-dt-table tbody tr {
        display: block;
        border-bottom: 1px solid var(--js-line);
        padding: .5rem 0;
    }

        .js-dt-table tbody tr:last-child {
            border-bottom: 0;
        }

    .js-dt-table tbody td {
        display: flex;
        justify-content: space-between;
        gap: 1rem;
        border: 0;
        padding: .38rem 1rem;
        text-align: right;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
        word-break: break-word;
    }

        .js-dt-table tbody td::before {
            content: attr(data-label);
            font-size: .72rem;
            letter-spacing: .06em;
            text-transform: uppercase;
            color: var(--js-muted);
            font-weight: 600;
            text-align: left;
            flex: none;
        }

    .js-dt-actions {
        justify-content: flex-end;
    }

    .js-dt-search input, .js-dt-search input:focus {
        width: 100%;
    }

    .js-dt-tools {
        width: 100%;
    }

    .js-dt-search {
        flex: 1;
    }
}

/* --------------------------------------------------------------------------
   Auth pages (login / register / admin login) — these views set Layout = null
   and link theme.css directly.
   -------------------------------------------------------------------------- */

.js-auth {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: clamp(1rem, 4vw, 3rem) 1rem;
    background: linear-gradient(135deg, var(--js-brand-950) 0%, var(--js-brand-800) 100%);
}

.js-auth-card {
    width: min(1020px, 100%);
    display: grid;
    grid-template-columns: 0.85fr 1fr;
    background: var(--js-surface);
    border-radius: var(--js-radius-lg);
    box-shadow: 0 24px 60px -12px rgba(8,21,47,.45);
    overflow: hidden;
}

.js-auth-card--narrow {
    grid-template-columns: 1fr;
    max-width: 430px;
}

/* Left brand panel */
.js-auth-aside {
    background: linear-gradient(160deg, var(--js-brand-800) 0%, var(--js-brand-950) 100%);
    color: #fff;
    padding: clamp(2rem, 4vw, 2.75rem);
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: center;
}

    /* contain, not cover — the logo has text in it and must never be clipped */
    .js-auth-aside img {
        width: 116px;
        height: 116px;
        border-radius: 50%;
        object-fit: contain;
        margin: 0 auto 1.4rem;
        background: #fff;
        padding: 6px;
        box-shadow: 0 0 0 6px rgba(255,255,255,.09);
    }

    .js-auth-aside h2 {
        color: #fff;
        font-size: 1.22rem;
        font-weight: 650;
        margin-bottom: .6rem;
    }

    .js-auth-aside p {
        color: rgba(255,255,255,.7);
        font-size: .88rem;
        margin: 0;
    }

.js-auth-social {
    display: flex;
    justify-content: center;
    gap: .7rem;
    margin-top: 1.8rem;
}

    .js-auth-social img {
        width: 42px;
        height: 42px;
        object-fit: contain;
        background: #fff;
        margin: 0;
        padding: 0;
        box-shadow: none;
        border-radius: 50%;
        border: 2px solid rgba(255,255,255,.25);
        transition: transform .15s ease, border-color .15s ease;
    }

        .js-auth-social img:hover {
            transform: translateY(-2px);
            border-color: var(--js-accent-500);
        }

/* Right form panel */
.js-auth-form {
    padding: clamp(1.75rem, 4vw, 2.75rem);
    display: flex;
    flex-direction: column;
    justify-content: center;
}

    .js-auth-form h1 {
        font-size: 1.45rem;
        font-weight: 650;
        margin-bottom: .3rem;
    }

.js-auth-lead {
    color: var(--js-muted);
    font-size: .9rem;
    margin-bottom: 1.5rem;
}

.js-auth-form .form-control {
    padding: .65rem .85rem;
}

.js-auth-form .btn-submit {
    width: 100%;
    padding: .68rem 1rem;
    font-size: .95rem;
    font-weight: 600;
}

.js-auth-hint {
    font-size: .78rem;
    color: var(--js-muted);
    margin-top: .4rem;
}

.js-auth-divider {
    border: 0;
    border-top: 1px solid var(--js-line);
    margin: 1.5rem 0 1.15rem;
}

.js-auth-foot {
    text-align: center;
    font-size: .89rem;
    color: var(--js-muted);
}

    .js-auth-foot a {
        color: var(--js-brand-700);
        font-weight: 600;
    }

        .js-auth-foot a:hover {
            color: var(--js-brand-900);
        }

.js-auth-msg {
    border-radius: var(--js-radius-sm);
    padding: .65rem .85rem;
    font-size: .87rem;
    font-weight: 500;
    margin-bottom: 1rem;
}

.js-auth-msg--ok {
    background: #ecfdf3;
    border: 1px solid #abefc6;
    color: #05603a;
}

.js-auth-msg--err {
    background: #fef3f2;
    border: 1px solid #fecdca;
    color: #912018;
}

.js-auth-back {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    margin-top: 1.25rem;
    color: rgba(255,255,255,.7);
    font-size: .85rem;
}

    .js-auth-back:hover {
        color: #fff;
    }

@media (max-width: 820px) {
    .js-auth-card {
        grid-template-columns: 1fr;
    }

    .js-auth-aside {
        padding: 2rem 1.5rem;
    }

        .js-auth-aside img {
            width: 84px;
            height: 84px;
            margin-bottom: 1rem;
        }
}

@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: .001ms !important;
        transition-duration: .001ms !important;
    }
}
