/* ============================================================
   REUSABLE — root variables, reset, shared classes
   Anything used on more than one page lives here, at the top,
   so it is the first thing anyone editing this file sees.
   ============================================================ */

:root {
    /* -- base palette -- */
    --color-bg: #F4F6F9;
    --color-surface: #FFFFFF;
    --color-border: #E2E5EA;
    --color-text: #1F2430;
    --color-text-muted: #6B7280;
    --color-primary: #3FB8AF;
    --color-primary-dark: #339E96;

    /* -- layout tokens -- */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-pill: 999px;
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2.5rem;
    --shadow-card: 0 1px 3px rgba(16, 24, 40, 0.08), 0 1px 2px rgba(16, 24, 40, 0.04);

    /* -- table row helpers -- */
    --row-alt-bg: #F6F7F9;
    --row-hover-bg: #EAF6F5;

    /* -- 4 status colors (light bg / darker text) -- */
    --status-pending-bg: #FFF1E0;
    --status-pending-text: #B45309;
    --status-submitted-bg: #E3F5EA;
    --status-submitted-text: #15803D;
    --status-accepted-bg: #E5F0FF;
    --status-accepted-text: #1D4ED8;
    --status-returned-bg: #FDE8E8;
    --status-returned-text: #B91C1C;

    /* -- 7 day-of-week colors (light bg / darker text) -- */
    --day-mon-bg: #DCEBFB;
    --day-mon-text: #1E3A5F;
    --day-tue-bg: #DCF3EE;
    --day-tue-text: #0F5132;
    --day-wed-bg: #EAE0FB;
    --day-wed-text: #4C2A85;
    --day-thu-bg: #FBF3D2;
    --day-thu-text: #7A5B00;
    --day-fri-bg: #FBE0EC;
    --day-fri-text: #85275B;
    --day-sat-bg: #FCE7D6;
    --day-sat-text: #8A4B12;
    --day-sun-bg: #E7E5FB;
    --day-sun-text: #3730A3;

    /* -- teacher pill (neutral, not status/day related) -- */
    --pill-teacher-bg: #E2E4E8;
    --pill-teacher-text: #374151;

    /* -- login gradient -- */
    --gradient-login: linear-gradient(135deg, #5B7FDE 0%, #4C93C7 55%, #3FB8AF 100%);

    /* -- home dashboard action cards: student (purple) / group (blue) -- */
    --card-student-bg: #ECE5FB;
    --card-student-shadow: rgba(109, 40, 217, 0.28);
    --card-group-bg: #DCEAFD;
    --card-group-shadow: rgba(29, 78, 216, 0.28);
    --alert-number-color: #DC2626;
    --color-red-light: #F87171;

    /* -- "viewing the live/current period" highlight (grade-history
       carousel's period picker + "Текущ период" button) -- */
    --highlight-active-bg: #FEF3C7;
    --highlight-active-border: #F59E0B;
    --highlight-active-text: #92400E;

    /* -- Отсъствия page: a muted/desaturated red for an already-sent
       ("locked") row - reads as "was reported absent" rather than a
       neutral gray, while staying visibly duller than an active,
       still-editable Отсъства row. -- */
    --attendance-locked-bg: #E5DEDE;

    /* -- modern glossy gradient buttons/pills: light-to-dark endpoints
       for the existing primary/danger colors, teal and red. -- */
    --gradient-primary: linear-gradient(180deg, #4FC9C0 0%, var(--color-primary-dark) 100%);
    --gradient-primary-hover: linear-gradient(180deg, var(--color-primary-dark) 0%, #256F68 100%);
    --gradient-danger: linear-gradient(180deg, #F87171 0%, var(--status-returned-text) 100%);
    --gradient-danger-hover: linear-gradient(180deg, var(--status-returned-text) 0%, #8F1D1D 100%);
    --gradient-absent: linear-gradient(180deg, #F87171 0%, #DC2626 100%);

    /* -- tests/exam pages (tests/... URLs): one darker-yellow accent, used
       everywhere those pages need to read as visually distinct from the
       regular grading pages - change the color here and every use below
       (period label, table header, table-wrapper edge, "Изисква внимание"
       heading) follows. -- */
    --test-accent: #B8860B;
    --test-accent-dark: #8C6608;
    --test-accent-tint: #FBF0D9;
    --test-accent-shadow: rgba(184, 134, 11, 0.32);
}

* {
    box-sizing: border-box;
}

body {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    margin: 0;
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.5;
}

a {
    color: inherit;
}

.container {
    max-width: 1180px;
    margin: 0 auto;
    padding: var(--space-5) var(--space-4);
}

/* -- page title with a highlighted, dynamic grading-period value
   (Groups/Students list headings) -- */
.page-title-period {
    font-size: 1.3em;
    font-weight: 800;
    color: var(--color-red-light);
}

/* -- buttons -- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 0.55rem 1.1rem;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn-primary {
    background: var(--gradient-primary);
    color: #FFFFFF;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.12);
}

.btn-primary:hover {
    background: var(--gradient-primary-hover);
}

.btn-secondary {
    background: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
}

.btn-secondary:hover {
    background: var(--row-alt-bg);
}

.btn-danger {
    background: var(--gradient-danger);
    color: #FFFFFF;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.12);
}

.btn-danger:hover {
    background: var(--gradient-danger-hover);
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* -- card -- */
.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    padding: var(--space-5);
}

/* -- pills / badges -- */
.pill {
    display: inline-block;
    border-radius: var(--radius-sm);
    padding: 0.2rem 0.65rem;
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
}

.pill-teacher {
    background: var(--pill-teacher-bg);
    color: var(--pill-teacher-text);
    margin: 0 var(--space-1) var(--space-1) 0;
}

.badge-day {
    border-radius: var(--radius-sm);
}

.badge-status {
    border-radius: var(--radius-pill);
    padding: 0.25rem 0.8rem;
}

.status-PENDING { background: var(--status-pending-bg); color: var(--status-pending-text); }
.status-SUBMITTED { background: var(--status-submitted-bg); color: var(--status-submitted-text); }
.status-ACCEPTED { background: var(--status-accepted-bg); color: var(--status-accepted-text); }
.status-RETURNED { background: var(--status-returned-bg); color: var(--status-returned-text); }

.day-MON { background: var(--day-mon-bg); color: var(--day-mon-text); }
.day-TUE { background: var(--day-tue-bg); color: var(--day-tue-text); }
.day-WED { background: var(--day-wed-bg); color: var(--day-wed-text); }
.day-THU { background: var(--day-thu-bg); color: var(--day-thu-text); }
.day-FRI { background: var(--day-fri-bg); color: var(--day-fri-text); }
.day-SAT { background: var(--day-sat-bg); color: var(--day-sat-text); }
.day-SUN { background: var(--day-sun-bg); color: var(--day-sun-text); }

/* -- form fields -- */
.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.field label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

.field input,
.field select,
.field textarea {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.55rem 0.75rem;
    font-size: 0.95rem;
    font-family: inherit;
    color: var(--color-text);
    background: var(--color-surface);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

.field textarea:read-only {
    background: var(--color-border);
    color: var(--color-text-muted);
    cursor: default;
}

/* -- search + filters bar (shared by Groups and Students pages) -- */
.search-filters-card {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: flex-end;
    margin-bottom: var(--space-5);
}

/* Holds the page's primary action button(s) (+ Нова група / + Нов ученик),
   their help icon, and the "Филтри" accordion trigger all on one line. */
.filters-top-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
    width: 100%;
}

.search-form {
    display: flex;
    gap: var(--space-2);
    flex: 1 1 260px;
}

.search-form input[type="text"] {
    flex: 1;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.55rem 0.75rem;
    font-size: 0.95rem;
    line-height: 1.4;
}

.search-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    border: 1px solid var(--color-primary);
    background: var(--color-primary);
    border-radius: var(--radius-sm);
    color: #FFFFFF;
    cursor: pointer;
}

.search-icon-btn:hover {
    background: var(--color-primary-dark);
}

.filters-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* -- mobile filter drawer (Groups/Students pages): a "Филтри" accordion
   button that only exists below the 720px breakpoint - see the
   @media block for the collapsed/open states and the slide transition.
   Above that width both are inert (button hidden, panel always shown). -- */
.accordion-toggle-btn {
    display: none;
    align-items: center;
    gap: var(--space-1);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.5rem 0.9rem;
    cursor: pointer;
}

.accordion-toggle-icon {
    display: inline-block;
    transition: transform 0.2s ease;
}

.accordion-toggle-btn.open .accordion-toggle-icon {
    transform: rotate(180deg);
}

/* On desktop the wrapper itself shouldn't generate a box - its children
   (.search-form, .filters-row) need to lay out exactly as if they were
   still direct children of .search-filters-card's flex row. Only below
   the mobile breakpoint does it become a real, collapsible box (see the
   @media block, which overrides this back to display: grid). */
.accordion-collapsible {
    display: contents;
}

/* -- header hamburger menu (mobile only - see @media below for the
   collapse mechanic itself, driven by the same accordion_toggle.js as
   the filters drawer above, just a separate box since .site-nav's
   desktop layout is real flex, not a "disappearing" wrapper). -- */
.nav-toggle-btn {
    display: none;
    padding: 0.5rem 0.7rem;
    font-size: 1.3rem;
    line-height: 1;
}

.hamburger-icon {
    display: block;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    background: var(--row-alt-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.3rem 0.9rem;
    font-size: 0.85rem;
}

.chip a {
    text-decoration: none;
    font-weight: 700;
}

/* -- tables (shared by Groups and Students pages) -- */
.table-wrapper {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-card);
    /* A table wider than its wrapper scrolls within this box instead of
       breaking the page's own layout - a no-op whenever the table
       already fits, so it's safe to leave on unconditionally. */
    overflow-x: auto;
}

.table {
    width: 100%;
    border-collapse: collapse;
    min-width: 640px;
}

.table thead th {
    text-align: left;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    padding: var(--space-3) var(--space-2);
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.table tbody td {
    padding: 0;
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}

.table tbody tr:nth-child(odd) {
    background: var(--row-alt-bg);
}

.table tbody tr.row-clickable:hover {
    background: var(--row-hover-bg);
    cursor: pointer;
}

.table td > a.cell-link,
.table td > span.cell-pad {
    display: block;
    padding: 0.7rem var(--space-2);
    color: inherit;
    text-decoration: none;
}

.empty-state {
    padding: var(--space-6) var(--space-4);
    text-align: center;
    color: var(--color-text-muted);
}

/* -- inline table row editing (Groups/Students admin CRUD) -- */
.edit-value {
    display: none;
    width: 100%;
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-sm);
    padding: 0.4rem 0.6rem;
    font-size: 0.9rem;
    font-family: inherit;
    color: var(--color-text);
    background: var(--color-surface);
}

.table tr.editing td > a.cell-link {
    display: none;
}

tr.editing .edit-value {
    display: block;
}

.edit-value.field-invalid {
    border-color: var(--status-returned-text);
}

/* Day-of-week multi-select: checkboxes wrap inside the edit box. */
tr.editing .day-field {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.75rem;
}

.day-checkbox {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.85rem;
    white-space: nowrap;
}

.field-error {
    color: var(--status-returned-text);
    font-size: 0.78rem;
    margin-top: 0.25rem;
}

.table tr.editing td {
    padding: 0.5rem var(--space-2);
}

.table tr.editing td.actions-cell {
    padding: 0;
}

/* Fixed width sized for the edit row's 2 visible buttons (save + discard) -
   the read row only shows 1 (edit), so without this the column would grow
   on entering edit mode and squeeze every other column leftward. */
.actions-col-header,
.actions-cell {
    width: 5.5rem;
    white-space: nowrap;
    text-align: center;
}

.group-readonly-value {
    background: var(--row-alt-bg);
    color: var(--color-text-muted);
}

/* Статус is never editable through the row's quick-edit (it only changes
   via the grading workflow) - shown as a plain, non-boxed readonly value
   instead of the bordered/background look .edit-value gives every actual
   input, so it doesn't read as something you could type into. */
.status-readonly-value {
    background: transparent;
    border: none;
    padding: 0.4rem 0;
}

/* Guardian mini-tables (student detail page + the new-student modal's
   staged rows): the read-mode text for a row with no detail link to go
   to, so it can't reuse a.cell-link - hidden the same way while editing. */
.guardian-view-value {
    display: block;
    padding: 0.7rem var(--space-5);
}

.table tr.editing td > span.guardian-view-value {
    display: none;
}

.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text-muted);
    cursor: pointer;
    padding: 0;
    margin: 0.2rem 0.15rem;
}

.icon-btn[hidden] {
    display: none;
}

.icon-btn:hover {
    background: var(--row-alt-bg);
}

.icon-btn.save-icon-btn,
.icon-btn.guardian-save-btn {
    color: var(--status-submitted-text);
    border-color: var(--status-submitted-text);
}

.icon-btn.save-icon-btn:hover,
.icon-btn.guardian-save-btn:hover {
    background: var(--status-submitted-bg);
}

.icon-btn.discard-icon-btn,
.icon-btn.delete-icon-btn,
.icon-btn.guardian-discard-btn,
.icon-btn.guardian-delete-btn {
    color: var(--status-returned-text);
    border-color: var(--status-returned-text);
}

.icon-btn.discard-icon-btn:hover,
.icon-btn.delete-icon-btn:hover,
.icon-btn.guardian-discard-btn:hover,
.icon-btn.guardian-delete-btn:hover {
    background: var(--status-returned-bg);
}

/* Temporary toggle: features hidden while the add/edit UI is being
   redesigned around a modal-based flow. Not removed - just hidden. */
.hidden-for-now {
    display: none !important;
}

.add-row-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

/* -- teacher multi-select field (text input + dropdown + chips) -- */
.teacher-field {
    position: relative;
    display: none;
    flex-wrap: wrap;
    gap: 0.3rem;
    align-items: center;
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-sm);
    padding: 0.3rem;
    background: var(--color-surface);
}

tr.editing .teacher-field {
    display: flex;
}

.teacher-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: var(--pill-teacher-bg);
    color: var(--pill-teacher-text);
    border-radius: var(--radius-sm);
    padding: 0.15rem 0.5rem;
    font-size: 0.8rem;
    white-space: nowrap;
}

.teacher-chip .chip-remove {
    border: none;
    background: none;
    cursor: pointer;
    color: inherit;
    font-size: 0.9rem;
    line-height: 1;
    padding: 0;
}

.teacher-search-input {
    border: none;
    outline: none;
    flex: 1;
    min-width: 6rem;
    font-size: 0.85rem;
    padding: 0.2rem;
    background: transparent;
}

.teacher-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-card);
    max-height: 180px;
    overflow-y: auto;
    margin-top: 0.2rem;
}

.teacher-dropdown[hidden] {
    display: none;
}

.teacher-dropdown-option {
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    font-size: 0.88rem;
}

.teacher-dropdown-option:hover {
    background: var(--row-alt-bg);
}

/* -- modal / blurred backdrop (Create ALL confirm, student search picker) -- */
.modal-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.4);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    align-items: center;
    justify-content: center;
    z-index: 100;
    padding: var(--space-4);
}

.modal-backdrop.open {
    display: flex;
}

.modal-dialog {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    max-width: 480px;
    width: 100%;
    padding: var(--space-5);
    max-height: 85vh;
    overflow-y: auto;
}

.modal-dialog.modal-dialog-wide {
    max-width: 720px;
}

.modal-dialog h2 {
    margin-top: 0;
}

.modal-warning-title {
    color: var(--status-returned-text);
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* -- new-student modal: main fields grid + guardian mini-table -- */
.create-student-fields {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

.guardian-section-title {
    margin-bottom: var(--space-2);
}

.guardian-add-btn {
    margin-top: var(--space-3);
}

/* -- "?" help button + its chooser modal -- */
.help-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem;
    height: 2.2rem;
    flex-shrink: 0;
    border-radius: var(--radius-pill);
    border: 1.5px solid var(--color-primary);
    background: var(--color-surface);
    color: var(--color-primary-dark);
    font-weight: 700;
    font-size: 1rem;
    cursor: pointer;
}

.help-btn:hover {
    background: var(--color-primary);
    color: #FFFFFF;
}

.help-chooser-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.help-chooser-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    text-align: left;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    padding: var(--space-3) var(--space-4);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text);
    cursor: pointer;
}

.help-chooser-item:hover {
    background: var(--row-alt-bg);
    border-color: var(--color-primary);
}

/* -- guided tour: spotlight overlay (4 dim+blurred pieces cut a "hole"
   around the real target, so nothing ever needs to sit above it in
   z-index - the real element is never covered by anything and stays
   fully sharp/clickable no matter what modal it's nested inside) -- */
.tour-dim-piece {
    position: fixed;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: 99998;
    cursor: pointer;
    transition: top 0.25s ease, left 0.25s ease, width 0.25s ease, height 0.25s ease;
}

.tour-ring {
    position: fixed;
    display: none;
    border: 3px solid var(--color-primary);
    border-radius: var(--radius-md);
    box-shadow: 0 0 0 4px rgba(63, 184, 175, 0.28), 0 4px 18px rgba(15, 23, 42, 0.35);
    pointer-events: none;
    z-index: 99999;
    transition: top 0.25s ease, left 0.25s ease, width 0.25s ease, height 0.25s ease;
}

.tour-callout {
    position: fixed;
    z-index: 100000;
    width: min(320px, calc(100vw - 2 * var(--space-4)));
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: 0 10px 30px rgba(15, 23, 42, 0.35);
    padding: var(--space-4);
}

.tour-callout::before {
    content: "";
    position: absolute;
    width: 14px;
    height: 14px;
    background: var(--color-surface);
    transform: rotate(45deg);
    left: var(--tour-arrow-left, calc(50% - 7px));
}

.tour-callout[data-placement="above"]::before {
    bottom: -7px;
    box-shadow: 3px 3px 4px rgba(15, 23, 42, 0.04);
}

.tour-callout[data-placement="below"]::before {
    top: -7px;
    box-shadow: -3px -3px 4px rgba(15, 23, 42, 0.04);
}

.tour-callout[data-placement="center"]::before {
    display: none;
}

.tour-callout-step {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-primary-dark);
    margin-bottom: var(--space-1);
}

.tour-callout-title {
    margin: 0 0 var(--space-2);
    font-size: 1.05rem;
}

.tour-callout-text {
    margin: 0 0 var(--space-4);
    color: var(--color-text);
    font-size: 0.92rem;
    line-height: 1.5;
}

.tour-callout-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.tour-close-btn {
    border: none;
    background: none;
    color: var(--color-text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    padding: 0.2rem;
}

.tour-close-btn:hover {
    color: var(--color-text);
}

.tour-callout-nav {
    display: flex;
    gap: var(--space-2);
}

/* ============================================================
   START NAVIGATION
   ============================================================ */

.site-header {
    position: sticky;
    top: 0;
    z-index: 40;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.site-header .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
}

.site-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-weight: 700;
    font-size: 1.1rem;
    text-decoration: none;
    color: var(--color-text);
}

.site-brand .logo-img {
    width: 40px;
    height: 40px;
    object-fit: contain;
    flex-shrink: 0;
}

.site-nav {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.site-nav a {
    text-decoration: none;
    padding: 0.5rem 0.9rem;
    border-radius: var(--radius-sm);
    font-weight: 600;
    color: var(--color-text-muted);
}

.site-nav a:hover,
.site-nav a.active {
    background: var(--row-alt-bg);
    color: var(--color-text);
}

/* Тестове: yellow instead of the generic gray active state, matching the
   tests/... pages' own accent, so the nav itself hints which flow you're
   in - wins over the generic rule above on specificity (3 classes vs 2). */
.site-nav a.nav-tests-link.active {
    background: var(--test-accent-tint);
    color: var(--test-accent-dark);
}

.site-nav .btn {
    margin-left: var(--space-2);
}

/* ============================================================
   END NAVIGATION
   ============================================================ */

/* ============================================================
   START LOGIN PAGE
   ============================================================ */

.login-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

.login-card {
    width: 100%;
    max-width: 380px;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.login-card-header {
    background: var(--gradient-login);
    color: #FFFFFF;
    padding: var(--space-6) var(--space-5) var(--space-5);
    text-align: center;
}

.login-card-header h1 {
    margin: 0 0 var(--space-1);
    font-size: 1.4rem;
}

.login-card-header p {
    margin: 0;
    opacity: 0.9;
    font-size: 0.9rem;
}

.login-card-body {
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.login-card-body .field input {
    padding: 0.7rem 0.85rem;
}

.login-errors {
    background: var(--status-returned-bg);
    color: var(--status-returned-text);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    font-size: 0.88rem;
}

.login-actions {
    display: flex;
    justify-content: flex-end;
}

.login-actions .btn-primary {
    background: #3FB8AF;
}

.login-actions .btn-primary:hover {
    background: var(--color-primary-dark);
}

/* ============================================================
   END LOGIN PAGE
   ============================================================ */

/* ============================================================
   START HOME PAGE
   ============================================================ */

.home-heading {
    margin-bottom: var(--space-4);
}

.home-heading h1 {
    margin: 0 0 var(--space-1);
    font-size: 1.5rem;
}

.home-heading p {
    margin: 0;
    color: var(--color-text-muted);
}

.action-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--space-4);
}

.action-card {
    display: block;
    text-decoration: none;
    color: inherit;
    padding: var(--space-4);
    border: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.action-card .card-title {
    font-weight: 700;
    font-size: 1.05rem;
    margin-bottom: var(--space-1);
}

.action-card .card-subtitle {
    color: var(--color-text-muted);
    font-size: 0.88rem;
    margin-bottom: var(--space-3);
}

.action-card .card-line {
    font-size: 0.9rem;
    margin-bottom: var(--space-1);
}

.card-counts {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: var(--space-3);
    margin-top: var(--space-2);
}

.card-counts .count-group {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    white-space: nowrap;
}

.card-counts .count-number {
    font-size: 1.2rem;
    font-weight: 700;
    color: var(--alert-number-color);
}

.card-counts .count-number-positive {
    color: var(--status-submitted-text);
}

.card-teachers,
.card-pill-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin: var(--space-1) 0 var(--space-2);
}

/* -- 'Отсъстващи' admin review cards (home page): reuses the exact
   action-card-group/action-card-student colors, just with an absence
   count / "Не се яви" flag instead of a grading status pill. -- */
.pill-absent-flag {
    background: var(--status-returned-bg);
    color: var(--status-returned-text);
}

.action-card-student {
    background: var(--card-student-bg);
}

.action-card-student:hover {
    transform: translateY(-5px);
    box-shadow: 0 16px 30px var(--card-student-shadow);
}

.action-card-group {
    background: var(--card-group-bg);
}

.action-card-group:hover {
    transform: translateY(-5px);
    box-shadow: 0 16px 30px var(--card-group-shadow);
}

.new-period-highlight {
    display: block;
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: 0.03em;
    color: var(--color-primary-dark);
    margin: var(--space-2) 0 var(--space-3);
}

/* ============================================================
   END HOME PAGE
   ============================================================ */

/* ============================================================
   START GROUPS PAGE
   ============================================================ */

.groups-table .teachers-cell {
    display: flex;
    flex-wrap: wrap;
}

/* ============================================================
   END GROUPS PAGE
   ============================================================ */

/* ============================================================
   START STUDENTS PAGE
   ============================================================ */

/* Fixed layout with per-column widths pinned on the header row - auto
   layout would otherwise resize the "Група" column when its read-mode
   text is swapped for a <select> in edit mode (a <select>'s intrinsic
   width follows its widest *option*, not the CSS width:100% it's given),
   which pushed every other column sideways for the row being edited. */
.students-table {
    table-layout: fixed;
}

/* Same scroll-on-desktop bug the tests/ table copied this table's
   markup from originally: the shared 640px floor (.table's min-width)
   forces a horizontal scrollbar on desktop windows narrower than that,
   even though table-layout: fixed already keeps every column readable
   at 100% of whatever width the wrapper actually has. */
.students-page .table-wrapper {
    overflow-x: visible;
}

.students-page .students-table {
    min-width: 0;
}

/* Widths are keyed by class, not nth-child position - the teacher's
   table inserts the Отсъстващи column first (see below), which would
   shift every position-based rule onto the wrong column for that role.
   Име/Фамилия are left with no explicit width on purpose: table-layout:
   fixed hands them whatever's left over after every other column below
   claims its share, so they end up the widest columns by construction. */
.students-table .col-group {
    width: 24%;
}

.students-table .col-schoolclass {
    width: 7%;
}

.students-table .col-school {
    width: 16%;
}

.students-table .col-status {
    width: 8%;
}

.students-page-title {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}

/* Students page: fixed-width search box + status field filling the rest
   of the row, so a handful of status chips has room to stay on one line
   instead of wrapping. Scoped to .students-search-filters rather than the
   shared .search-form/.filters-row classes, which the Groups page also
   uses with different fields. */
.students-search-filters .search-form {
    flex: 0 0 300px;
    max-width: 300px;
}

.students-search-filters .filters-row {
    flex: 1 1 0;
    min-width: 0;
}

.status-filter-field {
    flex: 1 1 auto;
    max-width: none;
    width: 100%;
}

/* -- status multi-select field (chips + click-only dropdown, no typing) -- */
.status-select {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.4rem 0.5rem;
    background: var(--color-surface);
    min-height: 2.4rem;
    cursor: pointer;
}

.status-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    flex: 1;
}

.status-chips:empty::before {
    content: attr(data-placeholder);
    color: var(--color-text-muted);
    font-size: 0.9rem;
    padding: 0.15rem 0.2rem;
}

.status-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    border-radius: var(--radius-sm);
    padding: 0.15rem 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
    background: var(--row-alt-bg);
    color: var(--color-text);
}

.status-chip-PENDING { background: var(--status-pending-bg); color: var(--status-pending-text); }
.status-chip-SUBMITTED { background: var(--status-submitted-bg); color: var(--status-submitted-text); }
.status-chip-RETURNED { background: var(--status-returned-bg); color: var(--status-returned-text); }
.status-chip-ACCEPTED { background: var(--status-accepted-bg); color: var(--status-accepted-text); }

.status-chip .chip-remove {
    border: none;
    background: none;
    cursor: pointer;
    color: inherit;
    font-size: 0.9rem;
    line-height: 1;
    padding: 0;
}

.status-select-trigger {
    margin-left: auto;
    color: var(--color-text-muted);
    font-size: 0.75rem;
}

.status-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-card);
    max-height: 220px;
    overflow-y: auto;
    margin-top: 0.2rem;
}

.status-dropdown[hidden] {
    display: none;
}

.status-dropdown-option {
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    font-size: 0.88rem;
}

.status-dropdown-option:hover {
    background: var(--row-alt-bg);
}

/* ============================================================
   END STUDENTS PAGE
   ============================================================ */

/* ============================================================
   START ABSENCES PAGE
   ============================================================ */

.absences-page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.absences-title {
    margin: 0;
}

.absences-header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* -- group picker: pick any group (any teacher can browse every group
   on this page), not just today's - sits to the left of the help/send
   buttons on desktop, its own full-width row above them on mobile (see
   @media). Uses the same grid-template-rows 0fr/1fr slide trick as the
   nav/filter drawers, but is wired up by its own group_picker.js
   instead of the shared accordion_toggle.js, since that script only
   opens/closes things below the mobile breakpoint and this picker has
   to work at every width. -- */
.group-picker {
    position: relative;
}

.group-picker-toggle {
    display: inline-flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    min-width: 13rem;
    padding: 0.85rem 1.15rem;
    background: rgba(63, 184, 175, 0.08);
    border: 1.5px solid var(--color-primary);
    border-radius: var(--radius-md);
    color: var(--color-primary-dark);
    font-size: 0.95rem;
    box-shadow: var(--shadow-card);
    transition: background 0.15s ease, box-shadow 0.15s ease;
}

.group-picker-toggle:hover {
    background: rgba(63, 184, 175, 0.16);
}

.group-picker-toggle.open {
    box-shadow: 0 0 0 3px rgba(63, 184, 175, 0.18), var(--shadow-card);
}

.group-picker-toggle.open .accordion-toggle-icon {
    transform: rotate(180deg);
}

/* max-height here is only a fallback for the instant before JS runs (or
   if JS fails to load) - group_picker.js overwrites it inline with the
   real distance from the toggle's bottom edge to the viewport bottom
   every time the panel opens, since a flat vh value has no way to know
   how far down the (possibly sticky) toggle button actually sits on
   screen, which is what was making the panel run off the bottom of the
   screen before. */
.group-picker-list {
    position: absolute;
    top: calc(100% + var(--space-2));
    left: 0;
    z-index: 30;
    min-width: 100%;
    max-width: 22rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    max-height: min(60vh, 26rem);
    overflow-y: auto;
    display: grid;
    grid-template-rows: 0fr;
    opacity: 0;
    pointer-events: none;
    transition: grid-template-rows 0.28s ease, opacity 0.28s ease;
}

.group-picker-list > * {
    min-height: 0;
    overflow: hidden;
}

.group-picker-list.open {
    grid-template-rows: 1fr;
    opacity: 1;
    pointer-events: auto;
}

.group-picker-list.open > * {
    overflow: visible;
}

.group-picker-items {
    list-style: none;
    margin: 0;
    padding: var(--space-2);
}

.group-picker-items li + li {
    border-top: 1px solid var(--color-border);
}

.group-picker-items a {
    display: block;
    padding: 0.9rem var(--space-4);
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--color-text);
    font-weight: 600;
    font-size: 1rem;
}

.group-picker-items a:hover {
    background: var(--row-hover-bg);
}

/* A group this user actually teaches, shown ahead of every other group
   and tinted so it's obviously different at a glance - .active (the
   group currently on screen) is defined after this so it still wins on
   background/text color when a "mine" group is also the current one,
   while the teal left border still shows through as a secondary cue. */
.group-picker-items a.group-picker-mine {
    background: rgba(63, 184, 175, 0.12);
    border-left: 3px solid var(--color-primary);
    padding-left: calc(var(--space-4) - 3px);
}

.group-picker-items a.active {
    background: var(--highlight-active-bg);
    color: var(--highlight-active-text);
}

.group-picker-section-label {
    padding: 0.6rem var(--space-4) 0.3rem;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

.group-picker-empty {
    padding: 0.9rem var(--space-4);
    color: var(--color-text-muted);
}

/* -- 'Присъствие' column: a 2-color status pill (see .attendance-pill
   below), sized like a normal status column - reuses the students
   table's compact/col-hide-mobile machinery for everything else. -- */
.attendance-col-header,
.attendance-cell {
    width: 8rem;
    text-align: center;
}

/* This is a single daily task, not a dense scan-many-rows list, so it
   can afford noticeably more room per row than the students list. */
.absences-page .table td > span.cell-pad,
.absences-page .table td > a.cell-link {
    padding: 0.9rem var(--space-3);
}

.absences-page .col-status,
.absences-page .attendance-cell {
    padding: 0.9rem var(--space-2);
}

/* Always the same red "Отсъства" button - there's no separate "present"
   color/label to switch to any more (a student who isn't clicked simply
   isn't reported absent), so the pill itself never changes; only the
   row's own .attendance-marked state (below) shows whether it's
   currently selected. */
.attendance-pill {
    background: var(--gradient-absent);
    color: #FFFFFF;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-weight: 700;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.15);
}

/* -- attendance row: the whole row is the control - clicking it toggles
   whether this student is currently selected (see attendance.js),
   styled to look "pressed" (a neutral gray shadow, not a color/label
   change - the button stays red/"Отсъства" either way) once marked so
   the two states are obviously different at a glance. A row already
   reported today (attendance-row-locked) never gets a click listener at
   all, and looks disabled (muted red, not gray - it's still "reported
   absent", just no longer editable) to match.
   Specificity note: the base .table striping rule (.table tbody
   tr:nth-child(odd)) carries 2 elements + 2 classes/pseudo-classes, which
   otherwise beats a plain .attendance-row.attendance-marked (2 classes,
   0 elements) once the row stops being :hover'd - every rule below is
   written with the same tbody/tr prefix so it wins regardless of
   odd/even position. */
.table tbody tr.attendance-row {
    cursor: pointer;
    transition: background-color 0.15s ease, box-shadow 0.15s ease;
}

.table tbody tr.attendance-row:hover {
    background: var(--row-hover-bg);
}

.table tbody tr.attendance-row.attendance-marked,
.table tbody tr.attendance-row.attendance-marked:hover {
    background: #D1D5DB;
    box-shadow: inset 0 2px 6px rgba(15, 23, 42, 0.35);
}

.table tbody tr.attendance-row.attendance-row-locked,
.table tbody tr.attendance-row.attendance-row-locked:hover {
    background: var(--attendance-locked-bg);
    color: var(--color-text-muted);
    cursor: not-allowed;
}

.attendance-row-locked .attendance-pill {
    opacity: 0.8;
}

/* ============================================================
   END ABSENCES PAGE
   ============================================================ */

/* ============================================================
   START STUDENT DETAIL PAGE
   ============================================================ */

.detail-stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.info-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-2) var(--space-4);
    margin: 0;
}

.info-list dt {
    color: var(--color-text-muted);
    font-weight: 600;
}

.info-list dd {
    margin: 0;
}

/* -- absence history (student detail): "Юни 2026" -> a row of date pills,
   one such pair per period that has any -- */
.absence-history-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-2) var(--space-4);
    align-items: start;
    margin: 0 0 var(--space-4);
}

.absence-history-list dt {
    color: var(--color-text-muted);
    font-weight: 600;
    white-space: nowrap;
}

.absence-history-list dd {
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

/* Sheet info card: Група/Статус on the left, Подадена на/Прегледана на on
   the right, aligned row-for-row (Група<->Подадена на, Статус<->Прегледана
   на) rather than stacked - explicit grid-area placement (not
   grid-auto-flow) so the layout stays correct even when the date fields
   are conditionally absent (sheet not yet submitted/reviewed). */
.sheet-info-grid {
    grid-template-columns: auto 1fr auto 1fr;
}

.info-cell-r1c1 { grid-area: 1 / 1; }
.info-cell-r1c2 { grid-area: 1 / 2; }
.info-cell-r1c3 { grid-area: 1 / 3; }
.info-cell-r1c4 { grid-area: 1 / 4; }
.info-cell-r2c1 { grid-area: 2 / 1; }
.info-cell-r2c2 { grid-area: 2 / 2; }
.info-cell-r2c3 { grid-area: 2 / 3; }
.info-cell-r2c4 { grid-area: 2 / 4; }

.grading-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.grading-card-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.grading-card-header h2 {
    margin: 0;
}

.grading-period-heading {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* -- grade-history carousel: prev/next arrows + period picker + "jump to
   current" (student-detail grading card). The card itself is the
   positioning context for the two arrows, which sit pinned to its
   vertical center regardless of how tall the card grows. -- */
.grading-card {
    position: relative;
    padding-left: 3.2rem;
    padding-right: 3.2rem;
}

.grading-nav {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}

.grading-period-select {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.55rem 0.75rem;
    font-size: 0.95rem;
    font-family: inherit;
    color: var(--color-text);
    background: var(--color-surface);
}

.grading-period-select:focus {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* Highlights "Текущ период" in yellow while it's actually useful to
   press - i.e. while viewing a *past* period, so pressing it jumps back
   to "now". On the live/current slide itself it's inert, so it just gets
   the ordinary disabled look (grey, per .btn:disabled) instead. */
#grading-nav-latest.active {
    background: var(--highlight-active-bg);
    border-color: var(--highlight-active-border);
    color: var(--highlight-active-text);
}

/* Solid filled triangles (not a glyph) pinned to the card's vertical
   center via clip-path - visually distinct from the site's other
   (rectangular/pill) buttons on purpose, since these are the one control
   meant to read as a slide-deck's prev/next, not a form action. */
.grading-nav-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 1.9rem;
    height: 2.8rem;
    padding: 0;
    border: none;
    background: var(--color-primary);
    cursor: pointer;
    z-index: 2;
    transition: background-color 0.15s ease, transform 0.1s ease;
}

.grading-nav-arrow:hover:not(:disabled) {
    background: var(--color-primary-dark);
}

.grading-nav-arrow:active:not(:disabled) {
    transform: translateY(-50%) scale(0.9);
}

.grading-nav-arrow:disabled {
    background: var(--color-border);
    cursor: not-allowed;
}

.grading-nav-prev {
    left: 0.3rem;
    clip-path: polygon(100% 0, 100% 100%, 0 50%);
}

.grading-nav-next {
    right: 0.3rem;
    clip-path: polygon(0 0, 0 100%, 100% 50%);
}

/* -- grade-history carousel: the sliding "page" of categories/notes that
   swaps content (not DOM nodes) as the active period changes, so the
   change reads as one slide animating out and the next animating in
   rather than a hard content jump. -- */
.grading-slide-viewport {
    overflow: hidden;
}

.grading-slide-viewport .criteria-category:first-child {
    margin-top: 0;
}

/* A little daylight between the last slider and the notes textarea below
   it - .criterion-row's own border-bottom otherwise sat right up against
   the field's margin-top, reading as part of the same block. */
.grading-slide-viewport .criteria-category:last-child {
    margin-bottom: var(--space-3);
}

.grading-slide-viewport {
    transition: transform 0.18s ease, opacity 0.18s ease;
}

.grading-slide-viewport.slide-out-left {
    transform: translateX(-28px);
    opacity: 0;
}

.grading-slide-viewport.slide-out-right {
    transform: translateX(28px);
    opacity: 0;
}

.grading-slide-viewport.slide-in-prep-left {
    transform: translateX(-28px);
    opacity: 0;
    transition: none;
}

.grading-slide-viewport.slide-in-prep-right {
    transform: translateX(28px);
    opacity: 0;
    transition: none;
}

.criteria-category h3 {
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    margin: var(--space-4) 0 var(--space-2);
}

.criterion-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-border);
}

.criterion-row .criterion-label {
    flex: 0 0 auto;
    width: 9rem;
}

/* Holds the 0/100/current-value label row above the bar itself, both
   full-width so the bubble's left/right % offsets line up with the same
   x-position in the bar below it (see .progress-value-bubble). */
.progress-bar-stack {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.progress-scale-row {
    position: relative;
    height: 1.1rem;
}

.progress-scale-endpoint {
    position: absolute;
    top: 0;
    font-size: 0.75rem;
    font-weight: 700;
}

.progress-scale-min {
    left: 0;
    color: var(--status-returned-text);
}

.progress-scale-max {
    right: 0;
    color: #059669;
}

/* Tracks the thumb's x-position (see grading.js's applyValue) and shares
   the drag/click value's own color, so it reads as "the number this fill
   color represents" rather than a separate UI element. Hidden until a
   value actually exists (matches .progress-thumb, which only shows once
   .editable, but this also has to appear for read-only history slides -
   see grade_history.js - so it isn't gated on .editable itself). */
.progress-value-bubble {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    font-size: 0.8rem;
    font-weight: 700;
    white-space: nowrap;
}

.progress-bar {
    position: relative;
    height: 14px;
    background: var(--row-alt-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}

.progress-bar.editable {
    cursor: pointer;
    border: 2px dashed var(--color-primary);
    background: rgba(63, 184, 175, 0.08);
    box-shadow: 0 0 0 3px rgba(63, 184, 175, 0.12);
}

.progress-fill {
    height: 100%;
    width: 0%;
    background: var(--color-border);
    border-radius: var(--radius-pill);
    transition: width 0.08s ease, background-color 0.08s ease;
}

.progress-thumb {
    display: none;
    position: absolute;
    top: 50%;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #FFFFFF;
    border: 3px solid var(--color-primary);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
    transform: translate(-50%, -50%);
    pointer-events: none;
}

/* Instantly sets a criterion to 100 - starts dim/inert and only becomes
   clickable once .editable (same gating as the drag bar itself, kept in
   sync in grading.js/grade_history.js), so it can't be used to bypass
   entering edit mode first. */
.criterion-max-btn {
    flex: 0 0 auto;
    padding: 0.45rem 0.8rem;
    border-radius: var(--radius-sm);
    border: 1.5px solid #059669;
    background: rgba(5, 150, 105, 0.08);
    color: #059669;
    font-weight: 700;
    font-size: 0.78rem;
    letter-spacing: 0.02em;
    cursor: pointer;
    opacity: 0.4;
    pointer-events: none;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.criterion-max-btn.editable {
    opacity: 1;
    pointer-events: auto;
}

.criterion-max-btn.editable:hover {
    background: rgba(5, 150, 105, 0.18);
}

.progress-bar.editable .progress-thumb {
    display: block;
}

.revision-note {
    background: var(--status-returned-bg);
    color: var(--status-returned-text);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    margin-bottom: var(--space-4);
}

.review-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

.btn-edit-toggle {
    background: var(--status-pending-bg);
    color: var(--status-pending-text);
    border: 1px solid var(--status-pending-text);
}

.btn-edit-toggle:hover {
    background: #FCE4C4;
}

.btn-edit-toggle.active {
    background: var(--status-submitted-text);
    color: #FFFFFF;
    border-color: var(--status-submitted-text);
}

.btn-edit-toggle.active:hover {
    background: #106B30;
}

.notes-char-count {
    display: block;
    margin-top: var(--space-1);
    font-size: 0.82rem;
    color: var(--color-text-muted);
}

.notes-char-count.notes-char-count-invalid {
    color: var(--status-returned-text);
    font-weight: 600;
}

.notes-char-count[hidden] {
    display: none;
}

/* display: block above would otherwise beat the hidden attribute's own
   UA-stylesheet display: none (author CSS always wins over the UA
   stylesheet for the same property, regardless of specificity) - same
   fix already used elsewhere in this file for .icon-btn/.teacher-dropdown
   /.status-dropdown. Without this, the error text (baked into the
   template up front, unlike notes-length-error which starts empty) would
   render on page load for every criterion, before any submit was ever
   attempted. */
.criterion-grade-error {
    display: block;
    margin-top: var(--space-1);
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--status-returned-text);
}

.criterion-grade-error[hidden] {
    display: none;
}

/* ============================================================
   END STUDENT DETAIL PAGE
   ============================================================ */

/* ============================================================
   START TEST PAGES (tests/... - shared across tests_home,
   test_students_list, test_student_detail)
   ============================================================ */

/* -- yellow accent: marks every tests/... page as visually distinct from
   the regular monthly-grading pages it mirrors. Every rule below reads
   from the --test-accent* tokens in :root, so a future color change is
   one edit there instead of hunting through the rules that use it. -- */
.tests-page .page-title-period {
    color: var(--test-accent);
}

/* "За преглед"/"Изисква внимание" heading text on tests_home - for every
   role (admin included). The tint itself now lives on the whole card
   (.tests-home-page .card below), not just around this text. */
.tests-page .heading-attention {
    color: var(--test-accent-dark);
}

.tests-page .search-filters-card {
    background: var(--test-accent-tint);
}

/* tests_home's own cards - all 3 for an admin (За преглед/Изисква
   внимание, Активни, Завършени), just the 1 a teacher gets - same tint
   as the table header/filter card, applied to the whole card instead of
   only around its heading. :not(.action-card) excludes the blue/purple
   group-vs-student mini-cards nested inside - those carry the "card"
   class too, and without the exclusion this rule's extra .tests-home-page
   class would out-specificity (2 classes vs 1) their own
   .action-card-group/.action-card-student background and paint them
   yellow as well. */
.tests-home-page .card:not(.action-card) {
    background: var(--test-accent-tint);
}

.tests-page .table thead th {
    background: var(--test-accent-tint);
    color: var(--test-accent-dark);
}

.tests-page .table-wrapper {
    border-bottom: 3px solid var(--test-accent);
    box-shadow: var(--shadow-card), 0 6px 14px -6px var(--test-accent-shadow);
    /* Only 4 narrow columns on this table (unlike the 7-column regular
       Ученици table) - no need for the shared 640px floor that forces a
       horizontal scrollbar on narrower desktop widths. */
    overflow-x: visible;
}

.tests-page .students-table {
    min-width: 0;
}

/* Every row's bottom edge in the same yellow as the table-wrapper's
   outer bottom edge above, not just the last row. */
.tests-page .table tbody td {
    border-bottom-color: var(--test-accent);
}

/* Take 10% each from Име/Фамилия (left with no explicit width, so
   table-layout: fixed hands them whatever's left over) and give the
   resulting 20% to Тестови статус, which needed more room than the
   regular Ученици table's plain "Статус" column. Desktop only - this
   selector's extra .tests-page class would otherwise out-specificity (3
   classes vs 2) the mobile compact-column rule in RESPONSIVE ADJUSTMENTS
   and leak this width into the narrow mobile layout too. */
@media (min-width: 721px) {
    .tests-page .students-table .col-status {
        width: 28%;
    }
}

/* -- average-score gauge (test-detail page): read-only for now (the
   average is always derived from Тест 1 / Тест 2, never entered
   directly) but built to look and feel like the draggable progress bars
   above it - same red-to-green fill color by value (see
   window.GradingBars.colorForValue, shared with grading.js so the color
   for a given number never drifts out of sync between the two), just
   taller and pill-shaped so the number reads clearly at a glance. -- */
.score-gauge {
    position: relative;
    width: 100%;
    height: 3rem;
    margin-top: 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--row-alt-bg);
    border: 1px solid var(--color-border);
    overflow: hidden;
}

.score-gauge-fill {
    position: absolute;
    inset: 0;
    width: 0%;
    background: var(--color-border);
    border-radius: inherit;
    transition: width 0.3s ease, background-color 0.3s ease;
}

.score-gauge-value {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-size: 1.4rem;
    font-weight: 800;
    color: #000000;
    font-variant-numeric: tabular-nums;
}

/* ============================================================
   END TEST PAGES
   ============================================================ */

/* ============================================================
   RESPONSIVE ADJUSTMENTS
   ============================================================ */

@media (max-width: 720px) {
    .container {
        padding: var(--space-1) var(--space-2);
    }

    /* -- header: brand + hamburger stay on one row (the container is
       already flex-wrap: wrap), the nav wraps onto its own full-width
       row below and collapses/slides via the same grid-rows trick as
       the filters drawer -- */
    .nav-toggle-btn {
        display: inline-flex;
    }

    .site-nav.nav-collapsible {
        width: 100%;
        display: grid;
        grid-template-rows: 0fr;
        grid-auto-rows: 0fr;
        row-gap: 0;
        opacity: 0;
        transition: grid-template-rows 0.28s ease, grid-auto-rows 0.28s ease, opacity 0.28s ease, row-gap 0.28s ease;
    }

    .site-nav.nav-collapsible > * {
        min-height: 0;
        overflow: hidden;
    }

    .site-nav.nav-collapsible.open > * {
        overflow: visible;
    }

    .site-nav.nav-collapsible.open {
        grid-template-rows: 1fr;
        grid-auto-rows: 1fr;
        row-gap: var(--space-2);
        opacity: 1;
        margin-top: var(--space-3);
    }

    /* -- filter bar: every field goes edge-to-edge, and the whole thing
       collapses behind a "Филтри" accordion button pinned to the top
       right, sliding open/closed instead of always taking up space -- */
    .search-filters-card {
        flex-direction: column;
        align-items: stretch;
        position: relative;
        padding: var(--space-2);
    }

    .accordion-toggle-btn {
        display: inline-flex;
        align-self: flex-end;
    }

    .accordion-collapsible {
        display: grid;
        grid-template-rows: 0fr;
        grid-auto-rows: 0fr;
        row-gap: 0;
        opacity: 0;
        transition: grid-template-rows 0.28s ease, grid-auto-rows 0.28s ease, opacity 0.28s ease, row-gap 0.28s ease;
    }

    /* overflow only hides while collapsed, to squash content into the 0fr
       row - once .open, it reverts to visible so things like the status
       multi-select's dropdown popup can still escape their row and show
       on top of the page instead of being clipped by it. */
    .accordion-collapsible > * {
        min-height: 0;
        overflow: hidden;
    }

    .accordion-collapsible.open > * {
        overflow: visible;
    }

    .accordion-collapsible.open {
        grid-template-rows: 1fr;
        grid-auto-rows: 1fr;
        row-gap: var(--space-4);
        opacity: 1;
        margin-top: var(--space-3);
    }

    .search-form,
    .students-search-filters .search-form {
        flex: 1 1 auto;
        max-width: none;
    }

    .filters-row {
        flex-direction: column;
    }

    .filters-row .field,
    .status-filter-field {
        max-width: 100%;
        width: 100%;
    }

    .filter-hide-mobile {
        display: none;
    }

    /* Tables shrink to fit the viewport instead of forcing horizontal
       scroll (the desktop min-width still applies above this breakpoint);
       .table-wrapper's overflow-x: auto is only a fallback from here on. */
    .table {
        min-width: 0;
    }

    /* -- Groups table: Име + Преподаватели only, each free to wrap onto
       2+ lines so both stay fully visible without a scrollbar -- */
    .groups-table th:nth-child(2),
    .groups-table td:nth-child(2),
    .groups-table th:nth-child(3),
    .groups-table td:nth-child(3),
    .groups-table th:nth-child(4),
    .groups-table td:nth-child(4) {
        display: none;
    }

    .groups-table td:nth-child(1) a.cell-link,
    .groups-table td:nth-child(5) a.cell-link {
        white-space: normal;
        word-break: break-word;
    }

    /* -- Students table: Име, Фамилия, Статус (+ Отсъстващи for teachers)
       only, for every role - Група/Клас/Училище hidden. A real class
       rather than nth-child, since the absence column's position shifts
       (first for teachers, absent entirely for admins). -- */
    .col-hide-mobile {
        display: none;
    }

    /* Teachers' table still gets an ellipsis-truncate + tighter padding
       treatment on its remaining columns, so 4 columns comfortably fit
       without a scrollbar even on a narrow phone. */
    .students-table-compact td > a.cell-link,
    .students-table-compact td > span.cell-pad,
    .students-table-compact th {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .students-table-compact td > a.cell-link,
    .students-table-compact td > span.cell-pad {
        padding: 0.5rem 0.35rem;
    }

    /* -- Статус: sized to fit exactly one status pill's text - not more.
       A future, longer status label truncates with an ellipsis instead
       of stealing width from Име/Фамилия, which (table-layout: fixed)
       split whatever's left over between them, ~35% each. -- */
    .students-table th.col-status,
    .students-table td.col-status {
        width: 2rem;
        overflow: hidden;
    }

    .students-table td.col-status .pill {
        display: inline-block;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        vertical-align: middle;
    }

    /* -- Actions column (Groups + Students admin tables, and any
       edit/add-row cell reusing these same classes): much narrower. Icon
       buttons become centered blocks rather than a flex row - a lone
       button (read state) still centers itself via auto margins, and 2 of
       them (edit mode's save+discard) simply stack since block elements
       flow vertically - no display: flex on the <td> itself, which table
       cells handle unreliably for alignment. -- */
    .actions-col-header,
    .actions-cell {
        width: 0.5rem;
        padding: 0.3rem 0.15rem;
    }

    .students-table th:nth-child(1), .students-table th:nth-child(2),
    .students-table td:nth-child(1), .students-table td:nth-child(2) {
        width: 30%;
    }

    /* groups page mobile table fixes */
    .groups-page .actions-col-header,
    .groups-page .actions-cell {
        width: 3rem;
    }
        .groups-page .groups-table th:nth-child(1),
    .groups-page .groups-table td:nth-child(1) {
        width: 35%;
    }

    .icon-btn {
        display: block;
        margin: 0.15rem auto;
    }

    .sheet-info-grid {
        grid-template-columns: auto 1fr;
    }

    .sheet-info-grid .info-cell-r1c1,
    .sheet-info-grid .info-cell-r1c2,
    .sheet-info-grid .info-cell-r1c3,
    .sheet-info-grid .info-cell-r1c4,
    .sheet-info-grid .info-cell-r2c1,
    .sheet-info-grid .info-cell-r2c2,
    .sheet-info-grid .info-cell-r2c3,
    .sheet-info-grid .info-cell-r2c4 {
        grid-area: auto;
    }

    /* -- grading card: stack instead of cramming into one row, and make
       every interactive control at least finger-sized (~44px) -- */
    .grading-card-header {
        flex-wrap: wrap;
    }

    .grading-card-actions {
        flex: 1 1 auto;
        justify-content: flex-end;
    }

    #grading-edit-toggle {
        flex: 1 1 auto;
    }

    .grading-nav {
        flex-direction: column;
        align-items: stretch;
    }

    .criterion-row {
        flex-wrap: wrap;
        row-gap: var(--space-2);
    }

    .criterion-row .criterion-label {
        width: 100%;
    }

    .progress-bar {
        height: 26px;
    }

    .progress-thumb {
        width: 24px;
        height: 24px;
    }

    .progress-scale-row {
        height: 1.3rem;
    }

    .progress-scale-endpoint,
    .progress-value-bubble {
        font-size: 0.9rem;
    }

    .btn,
    .help-btn,
    .grading-nav-arrow,
    .grading-period-select,
    .status-select,
    .criterion-max-btn {
        min-height: 44px;
    }

    .review-actions {
        flex-direction: column;
        align-items: stretch;
    }

    .review-actions .btn {
        width: 100%;
    }

    /* -- Отсъствия page: title/button row stays pinned right below the
       site header (attendance.js sets the exact "top" offset, since the
       header's own height varies), and only the table body scrolls -
       everything above it (nav, title, send button) stays put. -- */
    .absences-page-header {
        position: sticky;
        z-index: 20;
        background: var(--color-bg);
        padding-bottom: var(--space-3);
        margin-bottom: 0;
    }

    .absences-scroll-area {
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* Title gets its own row; the group picker gets the row below it,
       full width and edge-to-edge, above the help/send row (which then
       wraps onto its own line since the picker already claims 100%);
       the send button stretches to fill the rest of that row, from
       right after the help icon all the way to the edge. */
    .absences-title {
        width: 100%;
    }

    .absences-header-actions {
        width: 100%;
        flex-wrap: wrap;
    }

    .group-picker,
    .group-picker-toggle {
        width: 100%;
    }

    .group-picker-list {
        left: 0;
        right: 0;
        min-width: 0;
        max-width: none;
        max-height: 70vh; /* fallback only - group_picker.js sets the real value */
    }

    .absences-header-actions .btn-primary {
        flex: 1;
    }

    .attendance-col-header,
    .attendance-cell {
        width: 5.5rem;
    }

    /* Bigger text and more room per row than the students list gets on
       mobile - this page is read/tapped once a day, not scanned dense. */
    .absences-page .table {
        font-size: 1.05rem;
    }

    .absences-page .table td > span.cell-pad,
    .absences-page .table td > a.cell-link,
    .absences-page .col-status,
    .absences-page .attendance-cell {
        padding: 0.8rem var(--space-2);
    }

    .absences-page .attendance-pill {
        font-size: 0.95rem;
        padding: 0.3rem 0.85rem;
    }

    /* -- modals: use nearly the full screen width, one field per row -- */
    .modal-backdrop {
        padding: var(--space-2);
    }

    .modal-dialog,
    .modal-dialog.modal-dialog-wide {
        max-width: 100%;
    }

    .create-student-fields {
        grid-template-columns: 1fr;
    }

    .login-card {
        max-width: 100%;
    }
}

/* Назад (test-detail page) and Изход (header logout): full width below
   500px, half the row - pinned to the right edge - from 500px up to
   720px, then back to their plain unstyled desktop width from 720px on
   (no rule needed for that last band - absence of a rule is the "same
   as now in desktop" state). */
@media (max-width: 499.98px) {
    .test-back-btn,
    .nav-exit-btn {
        width: 100%;
    }

    /* .site-nav .btn's margin-left pushes a 100%-wide button off-center
       (it's added on top of the full width, not inside it) - drop it at
       this width so Изход sits flush instead of looking shifted. 3
       classes so it reliably beats .site-nav .btn's own 2. */
    .site-nav .btn.nav-exit-btn {
        margin-left: 0;
    }
}

@media (min-width: 500px) and (max-width: 719.98px) {
    .test-back-row,
    .nav-exit-form {
        text-align: right;
    }

    .test-back-btn,
    .nav-exit-btn {
        width: 50%;
    }
}
