
/* Colours shared by the readability fixes below. Edge/knob grey is 3.8:1 on the light card and 3.7:1
   on the dark one; the darker teal is 4.5:1 light, 3.1:1 dark, with white on it at 4.5:1. Muted text
   is the body colour at an alpha that reaches 4.5:1 on every background it sits on in each theme. */
:root {
    --app-check-edge: #7A8591;
    --app-check-on: #00848D;
    --app-check-edge-hover: #5F6A75;    /* hover moves away from the card: darker here, lighter in dark */
    --app-check-on-hover: #006F77;
    --app-muted-alpha: .65;
}

:root[data-theme=dark] {
    --app-check-edge-hover: #A5ABB3;
    --app-check-on-hover: #00949E;
    --app-muted-alpha: .8;
}

.form-check-input {
    width: 1.4rem !important;
    height: 1.4rem !important;
    margin-top: 0.05rem;
    border: 1px solid var(--app-check-edge);
    background-color: var(--bs-gray-200);
}

/* Switches keep the theme's pill shape; the square size above squashes the knob into a ring. */
.form-switch .form-check-input {
    width: 2.75em !important;
    height: 1.5em !important;
}

/* Checkboxes, radios and switches you can read. The theme draws them at 1.2-2.4:1 against the card
   and fades a disabled one to half opacity, so a locked switch all but disappears. Here every edge,
   knob and fill is 3:1 or better in both themes: teal is on, a grey edge and knob is off, and one that
   can't be changed is grey instead of faded (solid grey when on, dashed edge when off). The theme also
   turns the edge back to its faint grey on focus, hence the :not(:checked) rule covering focus. */
.form-check-input:not(:checked):not(.is-invalid) {
    border-color: var(--app-check-edge);
}

.form-switch .form-check-input:not(:checked) {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%237A8591'/%3e%3c/svg%3e");
}

.form-check-input:checked,
.form-check-input[type=checkbox]:indeterminate,
.form-switch .form-check-input:checked {
    background-color: var(--app-check-on);
    border-color: var(--app-check-on);
}

.form-check-input:disabled {
    opacity: 1;
}

.form-check-input:disabled:checked,
.form-check-input[type=checkbox]:disabled:indeterminate,
.form-switch .form-check-input:disabled:checked {
    background-color: var(--app-check-edge);
    border-color: var(--app-check-edge);
}

.form-check-input:disabled:not(:checked) {
    border-style: dashed;
}

.form-check-input:disabled ~ .form-check-label {
    opacity: 1;
    color: rgba(var(--bs-body-color-rgb), var(--app-muted-alpha));
}

/* the theme turns off pointer events on a disabled control, so the cursor comes from its wrapper */
.form-check:has(> .form-check-input:disabled),
.form-check-input:disabled ~ .form-check-label:hover {
    cursor: not-allowed;
    text-decoration: none;
}

/* Hover, which the theme gives none of: a pointer, the control a shade further from the card, and a
   soft ring in its own colour. The ring is an outline because a focused control's box-shadow is
   switched off below, and a switch stays focused after a click while the pointer is still on it. */
.form-check-input:not(:disabled) {
    cursor: pointer;
}

.form-check-input:not(:disabled):not(:checked):not(.is-invalid):hover {
    border-color: var(--app-check-edge-hover);
    outline: .25rem solid rgba(122, 133, 145, .25);
}

.form-switch .form-check-input:not(:disabled):not(:checked):hover {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%235F6A75'/%3e%3c/svg%3e");
}

:root[data-theme=dark] .form-switch .form-check-input:not(:disabled):not(:checked):hover {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23A5ABB3'/%3e%3c/svg%3e");
}

.form-check-input:not(:disabled):not(.is-invalid):checked:hover,
.form-check-input[type=checkbox]:not(:disabled):not(.is-invalid):indeterminate:hover {
    background-color: var(--app-check-on-hover);
    border-color: var(--app-check-on-hover);
    outline: .25rem solid rgba(0, 132, 141, .25);
}

.form-check-label {
    margin-left: 10px !important;
}

/* Help under a checkbox or switch: on its own line, lined up with the label. The helper puts the
   <small> straight after the label, so it otherwise runs on from it ("BilledFamilies are…"). */
.form-check > .form-text {
    display: block;
    margin-left: 10px;
}

/* Input-group add-ons too, or they keep the theme's lighter border beside the input they belong to. */
.form-control, .form-select, .input-group-text {
    border: 1px solid var(--bs-gray-400);
}

/* The theme hard-codes a dark navy here, which is unreadable in dark mode. */
.form-control-plaintext {
    color: var(--bs-body-color);
}

/* Labels under the theme's horizontal .steps circles (it only places them for .steps-vertical).
   The end labels hug the edges because .steps clips anything that sticks out sideways. */
.steps.steps-labelled {
    padding-bottom: 2rem;
}

.steps.steps-labelled .nav-item .nav-text {
    top: calc(100% + .5rem);
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
}

.steps.steps-labelled .nav-item:first-child .nav-text {
    left: 0;
    transform: none;
}

.steps.steps-labelled .nav-item:last-child .nav-text {
    left: auto;
    right: 0;
    transform: none;
}

/* Run progress: completed = green tick, current = primary with a ring, upcoming = hollow grey.
   The theme gives .visited and .active the same primary fill, so the current step looked done. */
.steps.steps-labelled .nav-item .nav-link {
    background-color: var(--bs-body-bg);
    border: 2px solid var(--bs-gray-400);
    color: var(--bs-secondary-color);
}

.steps.steps-labelled .nav-item.visited .nav-link {
    background-color: var(--bs-success);
    border-color: var(--bs-success);
}

.steps.steps-labelled .nav-item.visited::before {
    background-color: var(--bs-success);          /* the connector leaving a completed step */
}

.steps.steps-labelled .nav-item .nav-link.active {
    background-color: var(--bs-primary);
    border-color: var(--bs-primary);
    color: #fff;
    box-shadow: 0 0 0 .25rem rgba(var(--bs-primary-rgb), .25);
}

.steps.steps-labelled .nav-item .nav-text.fw-semibold {
    color: var(--bs-primary);                     /* label under the current step */
}

label.form-check-label:hover {
    text-decoration: underline;
    cursor: pointer;
}

.form-check-input:focus {
    box-shadow: none !important;
}

/* Icing's quick search (element Icing.quick_search). Bootstrap lets an input-group input shrink to
   nothing and its buttons wrap, so beside fixed-width controls in a .col it squeezed to a sliver;
   with a floor and no wrapping inside it, the row wraps instead. */
.mw-500px .input-group {
    flex-wrap: nowrap;
}

.mw-500px .input-group > .form-control[name="search"] {
    min-width: 9rem;
}

/* A single TomSelect (inside .select-one-line) that cuts a long picked label short with "…" instead
   of wrapping it and growing taller. */
.select-one-line .ts-control {
    flex-wrap: nowrap;
}

.select-one-line .ts-control > .item {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Readable text on the theme's tinted colours. The theme writes each soft tint's text in the same
   colour as its tint (yellow on pale yellow is 1.5:1) and puts white text on its yellow (1.6:1).
   These keep the theme's backgrounds and darken only the text, to at least 5.9:1. :root matches the
   theme's own [data-theme=dark] rules, which would otherwise win. */
:root .text-bg-primary-soft { color: #00666e !important; }
:root .text-bg-secondary-soft { color: #4f5a65 !important; }
:root .text-bg-success-soft { color: #13663d !important; }
:root .text-bg-info-soft { color: #135d72 !important; }
:root .text-bg-warning-soft { color: #6b5300 !important; }
:root .text-bg-danger-soft { color: #a3173f !important; }

:root .text-bg-primary-soft .alert-link,
:root .text-bg-secondary-soft .alert-link,
:root .text-bg-success-soft .alert-link,
:root .text-bg-info-soft .alert-link,
:root .text-bg-warning-soft .alert-link,
:root .text-bg-danger-soft .alert-link {
    color: inherit;
}

:root .text-bg-warning { color: #3d3000 !important; }

/* Muted text you can read. The theme writes muted text, help text, captions and table headings as
   the body colour at 35%, which is 2.2:1; --app-muted-alpha (top of this file) lifts it to 4.5:1+. */
:root .text-muted { color: rgba(var(--bs-body-color-rgb), var(--app-muted-alpha)) !important; }

:root .form-text,
:root caption,
:root .table > thead th {
    color: rgba(var(--bs-body-color-rgb), var(--app-muted-alpha));
}

/* Except the idle arrows on a sortable column heading (Icing's PaginatorHelper marks them text-muted):
   they stay at the theme's faint 35% on purpose, so the active arrow is the one that stands out. */
:root .list-sort .text-muted { color: rgba(var(--bs-body-color-rgb), .3525) !important; }

/* Those arrows sit in a Font Awesome stack, which is 2em tall, so a sortable heading's line was taller
   than a plain one's and, in a header row with both (Note, Actions), the plain headings sat lower.
   A 1em stack keeps every heading on the same line height, the arrows sized like any inline icon. */
.list-sort .fa-stack {
    height: 1em;
    line-height: 1em;
    vertical-align: -.125em;
}

:root .alert-warning {
    --bs-alert-color: #3d3000;
    --bs-alert-link-color: #3d3000;
}

/* A filter button strip that spans the row on phones, with tighter buttons, instead of running off
   the side of the page (the theme's buttons carry wide side padding). */
@media (max-width: 575.98px) {
    .btn-group-fill-xs {
        display: flex;
    }

    .btn-group-fill-xs > .btn {
        flex: 1 1 auto;
        --bs-btn-padding-x: .25rem;
    }
}

/* The selection bar under a table with row checkboxes (element bulk_bar). Hidden until a row is ticked,
   then it sticks to the bottom of the window while the table is on screen, so its actions stay in
   reach while ticking rows further down, and settles under the last row at the end of the list. Its
   side padding matches the table's, so the count lines up with the checkbox column. */
.bulk-bar {
    position: sticky;
    bottom: 0;
    z-index: 3;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1rem;
    padding: .75rem 1.25rem;
    background-color: var(--bs-white);
    border-top: 1px solid var(--bs-border-color);
    box-shadow: 0 -.25rem .75rem rgba(14, 34, 56, .08);
}

/* A dropdown button in an input group (the Fee Report's quick date ranges) shows the same thin chevron
   as the selects beside it, instead of the theme's large solid triangle, and flips while its menu is
   open. It keeps .dropdown-toggle, which Bootstrap needs to round the group's corners. */
.input-group > .dropdown-chevron:hover,
.input-group > .dropdown-chevron[aria-expanded="true"] {
    background-color: rgba(var(--bs-body-color-rgb), .05);
}

.input-group > .dropdown-chevron::after {
    width: 16px;
    height: 12px;
    margin: 0;
    padding: 0;
    border: 0;
    vertical-align: middle;
    background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e") no-repeat center / 16px 12px;
    transition: transform .15s ease-in-out;
}

:root[data-theme=dark] .input-group > .dropdown-chevron::after {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23bcc0c6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
}

.input-group > .dropdown-chevron[aria-expanded="true"]::after {
    transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .input-group > .dropdown-chevron::after {
        transition: none;
    }
}

/* Outline buttons have a card-coloured face instead of a clear one. In a card nothing changes, but one
   sitting straight on the page's grey ground was only a coloured ring and didn't read as a button.
   --bs-white is the card colour in both themes (#2d2d2d in dark). Hover (and keyboard focus, which
   Bootstrap draws with the hover colours) is a light tint of the button's own colour over that face,
   keeping its text and edge: the theme's full fill on hover looked the same as the chosen button in a
   group (Pending / Approved / Declined). Pressed and chosen keep the full fill. White and light
   outlines are left alone, as they're meant for dark grounds. */
:root [class*="btn-outline-"]:not(.btn-outline-white):not(.btn-outline-light) {
    --bs-btn-bg: var(--bs-white);
    --bs-btn-disabled-bg: var(--bs-white);
    --bs-btn-hover-bg: color-mix(in srgb, rgb(var(--bs-btn-focus-shadow-rgb)) 15%, var(--bs-white));
    --bs-btn-hover-color: var(--bs-btn-color);
    --bs-btn-hover-border-color: var(--bs-btn-border-color);
}

/* The theme's secondary grey (#9EA9B4) is 2.4:1 on white, so the grey outline buttons (Prev / Today /
   Next, Clear, the "—" toggle), grey badges and the solid grey Cancel button's white text all read
   faintly. Bootstrap's own #6C757D is 4.7:1 either way round. Light theme only: on the dark card the
   theme's grey is already 6.5:1. The outline hover tint (below) follows it through the rgb value. */
:root:not([data-theme=dark]) {
    --bs-secondary: #6C757D;
    --bs-secondary-rgb: 108, 117, 125;
}

:root:not([data-theme=dark]) .btn-secondary {
    --bs-btn-bg: #6C757D;
    --bs-btn-border-color: #6C757D;
    --bs-btn-hover-bg: #5C636A;
    --bs-btn-hover-border-color: #565E64;
    --bs-btn-active-bg: #565E64;
    --bs-btn-active-border-color: #51585E;
    --bs-btn-disabled-bg: #6C757D;
    --bs-btn-disabled-border-color: #6C757D;
    --bs-btn-focus-shadow-rgb: 108, 117, 125;
}

/* the grey badge spells the old grey out rather than using the variable, and its white text is
   2.4:1 in both themes, so it takes the new grey in both */
:root .text-bg-secondary {
    background-color: RGBA(108, 117, 125, var(--bs-bg-opacity, 1)) !important;
}

:root:not([data-theme=dark]) .btn-outline-secondary {
    --bs-btn-color: #6C757D;
    --bs-btn-border-color: #6C757D;
    --bs-btn-active-bg: #6C757D;
    --bs-btn-active-border-color: #6C757D;
    --bs-btn-disabled-color: #6C757D;
    --bs-btn-disabled-border-color: #6C757D;
    --bs-btn-focus-shadow-rgb: 108, 117, 125;
}

/* The theme's light button turns its text white on hover and press, over a pale grey (1.5:1), so
   "Month grid", Print, View and the rest went blank under the pointer. In the light theme they keep
   their dark text and only the face darkens a shade; the dark theme's light button is fine as is. */
:root:not([data-theme=dark]) .btn-light {
    --bs-btn-hover-color: var(--bs-btn-color);
    --bs-btn-active-color: var(--bs-btn-color);
}

/* Toggle buttons (a .btn-check input with its .btn label: Present / Absent on the attendance sheet,
   the report choices) hover like any other button. Bootstrap switches their hover off, since its full
   fill would look like "chosen"; with the outline hover above a tint, they can share it. */
.btn-check:not(:checked):not(:disabled) + .btn:hover {
    color: var(--bs-btn-hover-color);
    background-color: var(--bs-btn-hover-bg);
    border-color: var(--bs-btn-hover-border-color);
}

/* A wide table of figures (the invoice run's family table, 12 columns): tighter gaps between columns,
   the theme's full side padding kept at the card's edges, so it fits a 1440px screen without
   scrolling sideways. */
.table-figures > :not(caption) > * > * {
    padding-left: .375rem;
    padding-right: .375rem;
}

.table-figures > :not(caption) > * > :first-child {
    padding-left: 1.25rem;
}

.table-figures > :not(caption) > * > :last-child {
    padding-right: 1.25rem;
}

/* The attendance month grid: children down the side, school days across, framed by its card. The table
   draws no outer edge and its header has no fill, so the card is the only frame. Every cell draws its
   own top and left edge in one grid colour. Bootstrap's bordered table gave the tinted cells
   (table-light / -secondary / -primary) darker edges of their own, and the collapsed borders showed them
   on one side of a tinted cell but not the other. A firmer rule marks the structure: under the header,
   above each classroom and the totals row, after the names, where each week starts and before the
   totals columns. Fills are the body colour (or teal) at a low alpha, so they suit both themes; the
   Bootstrap ones are fixed light colours that glare on the dark card. As on the printed report grid,
   grey means closed and only closed; a day out of the classroom is hatched. The legend's keys are
   boxes filled like the cells they explain. */
.table-month,
.month-legend {
    --app-grid-line: rgba(var(--bs-body-color-rgb), .1);
    --app-grid-rule: rgba(var(--bs-body-color-rgb), .25);
    --app-fill-closed: rgba(var(--bs-body-color-rgb), .14);
    --app-fill-vacation: rgba(var(--bs-primary-rgb), .18);
    --app-hatch-off: repeating-linear-gradient(135deg, rgba(var(--bs-body-color-rgb), .14) 0 1px, transparent 1px 6px);
}

.table.table-month > :not(caption) > * > * {
    padding: .375rem;
    border-width: 1px 0 0 1px;
    border-color: var(--app-grid-line);
}

.table.table-month > :not(thead) > * > * {
    vertical-align: middle;
}

.table.table-month > thead > tr > * {
    border-top-width: 0;
}

.table.table-month > :not(caption) > tr > :first-child {
    border-left-width: 0;
    padding-left: 1.25rem;
}

.table.table-month > :not(caption) > tr > :last-child {
    padding-right: 1.25rem;
}

.table.table-month > tbody > tr:first-child > *,
.table.table-month > tfoot > tr:first-child > * {
    border-top-color: var(--app-grid-rule);
}

.table.table-month .dates-start,
.table.table-month .week-start,
.table.table-month .sum-start {
    border-left-color: var(--app-grid-rule);
}

.table.table-month > tbody > .section-head > th {
    padding-top: .75rem;
    font-size: var(--bs-body-font-size);
}

.table-month .is-closed, .month-legend .is-closed { background-color: var(--app-fill-closed); }
.table-month .is-vacation, .month-legend .is-vacation { background-color: var(--app-fill-vacation); }
.table-month .is-off, .month-legend .is-off { background-image: var(--app-hatch-off); }

/* a closed day: one cell down the classroom, the closure's name written up it, cut short with "…"
   when the classroom has too few children for it (the cell's title has it whole) */
.table-month .closure-band {
    position: relative;
}

.table-month .closure-band > span {
    position: absolute;
    top: .375rem;
    bottom: .375rem;
    left: 50%;
    transform: translateX(-50%) rotate(180deg);
    writing-mode: vertical-rl;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: 600;
}

/* today's date: full-strength text over the muted headings, with a teal bar under it */
.table.table-month > thead .is-today {
    color: var(--bs-body-color);
    box-shadow: inset 0 -3px 0 var(--app-check-on);
}

.month-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1.25rem;
}

.month-legend .legend-key {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.5rem;
    margin-right: .375rem;
    vertical-align: middle;
    border: 1px solid var(--app-grid-rule);
    color: var(--bs-body-color);
}

.month-legend .legend-key .care-marks {
    margin-left: 0;
}
/* Student billing tab sub-nav */
/* The Billing tab on the student page (Decision 7): a vertical pill list on the left with a teal
   left border on the current section, one pane at a time on the right. Below lg the list turns
   into one horizontally scrollable row of pills above the panes. Count badges sit at the far end
   of each pill. */
.billing-subnav {
    flex-direction: column;
    gap: .125rem;
    position: sticky;
    top: 1rem;
}

.billing-subnav .nav-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    width: 100%;
    padding: .5rem .75rem;
    border-left: 3px solid transparent;
    border-radius: 0 .5rem .5rem 0;
    color: var(--bs-body-color);
    text-align: left;
    white-space: nowrap;
}

.billing-subnav .nav-link:hover,
.billing-subnav .nav-link:focus-visible {
    background-color: rgba(var(--bs-body-color-rgb), .05);
}

.billing-subnav .nav-link.active {
    background-color: rgba(0, 132, 141, .12);
    border-left-color: var(--app-check-on);
    color: var(--app-check-on-hover);
    font-weight: 700;
}

:root[data-theme=dark] .billing-subnav .nav-link.active {
    color: var(--app-check-on-hover);
}

.billing-subnav-count {
    margin-left: auto;
    padding: .15em .5em;
    border: 1px solid var(--bs-border-color);
    background-color: var(--bs-body-bg);
    color: rgba(var(--bs-body-color-rgb), var(--app-muted-alpha));
    font-size: .7rem;
    font-weight: 600;
    line-height: 1.2;
}

.billing-subnav .nav-link.active .billing-subnav-count {
    border-color: var(--app-check-on);
    color: var(--app-check-on-hover);
}

@media (max-width: 991.98px) {
    .billing-subnav {
        flex-direction: row;
        flex-wrap: nowrap;
        gap: .375rem;
        position: static;
        margin-left: -16px;
        margin-right: -16px;
        padding: 0 16px .25rem;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }

    .billing-subnav::-webkit-scrollbar {
        display: none;
    }

    .billing-subnav .nav-link {
        flex: 0 0 auto;
        width: auto;
        padding: .4rem .75rem;
        border-left: 0;
        border-bottom: 3px solid transparent;
        border-radius: .5rem .5rem 0 0;
    }

    .billing-subnav .nav-link.active {
        border-bottom-color: var(--app-check-on);
    }
}

/* Overview stat cards: label / big number / one-line note */
.billing-stat .card-body {
    padding: .875rem 1rem;
}

.billing-stat-label {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: rgba(var(--bs-body-color-rgb), var(--app-muted-alpha));
}

.billing-stat-value {
    margin-top: .125rem;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.01em;
    line-height: 1.2;
}

.billing-stat-sub {
    margin-top: .125rem;
    font-size: .8rem;
    color: rgba(var(--bs-body-color-rgb), var(--app-muted-alpha));
}
