/* Arimo, served from this origin: the tablet app's own typeface.

   The panel was set in Nunito until 23 September 2026, and the app in Arimo -
   one programme in two faces. Nunito's rounded letters were also the softest
   thing in a panel whose design idea is "Rizal's Classroom": civic, heritage,
   navy. Now the panel, its login and the tablet share one face.

   Declared here rather than in a separate fonts.css behind an @import: this
   file's URL carries a content hash (tools/stamp_assets.py) and an imported
   one's did not, so a change to it could sit behind the CDN's seven-day cache.

   Arimo is the metric twin of Arial, SIL Open Font License 1.1 (licence:
   era_admin/fonts/ARIMO-OFL.txt). One variable file covers weights 400-700 -
   the same .ttf the app bundles. A subset .woff2 would be about a tenth of the
   size and needs fontTools to make. font-src stays 'self'. */
@font-face {
    font-family: 'Arimo';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url(../fonts/arimo-variable.ttf) format('truetype');
}

/* ---------------------------------------------------------------------------
   ARAL admin panel
   The page background stays white everywhere, so separation between surfaces
   comes from borders and soft shadows rather than grey fills.
   --------------------------------------------------------------------------- */

:root {
    --aral-blue: #0F2B5B;
    --aral-blue-soft: #1E4D8C;
    --aral-orange: #FF9800;
    --aral-green: #16A34A;
    --aral-red: #DC2626;

    --line: #E7EAF0;
    --line-strong: #D3D9E4;
    --ink: #1E1E1E;
    --ink-muted: #667085;

    /* Ink for a coloured fill or tint. Measured, not guessed: white on
       Tailwind blue-500 is 3.68:1 and fails AA, and the stat icons were worse -
       green-500 on green-50 is 2.18:1 against a 3:1 floor for non-text. These
       are the values that pass. The app learned the same lesson; see
       AppColors.OnAccent and AccentContrastTest. */
    --aral-orange-ink: #A85400;
    --aral-green-ink: #16A34A;
    --aral-red-ink: #DC2626;
    --aral-blue-ink: #2563EB;

    --radius: 14px;
    --shadow-card: 0 1px 2px rgba(16, 24, 40, .04), 0 6px 16px -8px rgba(16, 24, 40, .10);
    --shadow-card-hover: 0 1px 2px rgba(16, 24, 40, .05), 0 12px 24px -10px rgba(16, 24, 40, .16);
}

body {
    font-family: 'Arimo', Arial, sans-serif;
    background: #FFFFFF;
    color: var(--ink);
    -webkit-font-smoothing: antialiased;
}

/* Every panel surface. Border first, shadow second - on white, a shadow alone
   reads as a smudge. */
.aral-card {
    background: #FFFFFF;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    transition: box-shadow .18s ease, border-color .18s ease, transform .18s ease;
}

/* Only where there is a real pointer. A touch screen fires :hover on tap and
   then leaves it applied, so on a tablet the card lifted and stayed lifted. */
@media (hover: hover) and (pointer: fine) {
    .aral-card-interactive:hover {
        box-shadow: var(--shadow-card-hover);
        border-color: var(--line-strong);
        transform: translateY(-1px);
    }
}

/* Section heading above a card or table. */
.aral-section-title {
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--aral-blue);
}

/* ------------------------------ Tables ---------------------------------- */

.aral-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}

/* The header row sits above every body cell, and its first cell above the
   rest of the header.

   This was z-index 1, and it outranks the z-20 and z-10 utilities on the
   cells themselves (a class and two elements against one class). So every
   header cell was level, and the learner table's pinned "Learner" heading
   slid under its neighbours the moment the table moved sideways: the names
   stayed put under a heading reading "Parent education". The pinned name
   cells (z-10) also rode over the header when the table moved down. */
.aral-table thead th {
    position: sticky;
    top: 0;
    z-index: 20;
    background: #FFFFFF;
    text-align: left;
    font-size: .72rem;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-muted);
    padding: .85rem 1rem;
    border-bottom: 1px solid var(--line-strong);
}

.aral-table thead th.left-0 {
    z-index: 30;
}

.aral-table tbody td {
    padding: .9rem 1rem;
    border-bottom: 1px solid var(--line);
    font-size: .9rem;
    vertical-align: middle;
}

.aral-table tbody tr {
    transition: background-color .12s ease;
}

/* A tint on hover only - the resting background stays white. */
.aral-table tbody tr:hover {
    background: #F7F9FC;
}

.aral-table tbody tr:last-child td {
    border-bottom: none;
}

/* ------------------------- Profile pictures ------------------------------ */
/* A photo, or the drawing that stands in for one: round, never squashed. */
.aral-avatar {
    border-radius: 9999px;
    object-fit: cover;
    flex: none;
    background: #ffffff;
}

/* The photo box on a form. Its own rule: tailwind.css is built ahead of time
   and has no w-20. */
.aral-avatar-lg {
    width: 5rem;
    height: 5rem;
}

/* ------------------------------ Buttons --------------------------------- */

.aral-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    font-weight: 700;
    border-radius: 12px;
    padding: .65rem 1.15rem;
    font-size: .875rem;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform .12s ease, box-shadow .18s ease, background-color .18s ease;
}

.aral-btn:active {
    transform: scale(.97);
}

.aral-btn-primary {
    background: var(--aral-blue);
    color: #FFFFFF;
}

.aral-btn-primary:hover {
    background: var(--aral-blue-soft);
    box-shadow: 0 8px 18px -8px rgba(15, 43, 91, .55);
}

.aral-btn-accent {
    background: var(--aral-orange);
    color: #FFFFFF;
}

.aral-btn-accent:hover {
    box-shadow: 0 8px 18px -8px rgba(255, 152, 0, .6);
}

/* ---------------------------------------------------------------------------
   One blue.

   Every filled button was Tailwind's blue-600 (#2563EB) while the navigation,
   the headings and the brand itself are navy - two blues, both saying "this
   is the main thing". Primary actions and the current selection now share the
   navy that .nav-item-active already used: 13.8:1 for white text, 8.9:1 on
   hover, where blue-600 managed 5.17:1.

   .aral-btn-primary above existed for exactly this and was never applied.
   --------------------------------------------------------------------------- */
.aral-btn-primary:disabled,
.aral-btn-primary:disabled:hover {
    background: var(--aral-blue);
    box-shadow: none;
}

/* A progress bar or a count in the same voice. */
.aral-fill-primary { background: var(--aral-blue); }
.aral-ink-primary  { color: var(--aral-blue); }

/* The CSV picker's "Choose file" button, which a class on the input cannot
   reach without Tailwind's file: variant - and that only offered blue-600. */
.aral-file-input::file-selector-button {
    margin-right: 1rem;
    padding: .625rem 1rem;
    border: 0;
    border-radius: .75rem;
    background: var(--aral-blue);
    color: #FFFFFF;
    font-size: .875rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color .15s ease;
}
.aral-file-input::file-selector-button:hover { background: var(--aral-blue-soft); }

.aral-btn-quiet {
    background: #FFFFFF;
    color: var(--ink);
    border-color: var(--line-strong);
}

.aral-btn-quiet:hover {
    border-color: var(--aral-blue);
    color: var(--aral-blue);
}

/* --------------------------- Accessibility ------------------------------- */

/* Visible keyboard focus. The default Tailwind reset removes it in places. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid rgba(30, 77, 140, .35);
    outline-offset: 2px;
    border-radius: 8px;
}

/* ------------------------- Loading and empty ----------------------------- */

.aral-skeleton {
    position: relative;
    overflow: hidden;
    background: #EFF2F7;
    border-radius: 8px;
}

.aral-skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .75), transparent);
    animation: aral-shimmer 1.4s infinite;
}

@keyframes aral-shimmer {
    100% { transform: translateX(100%); }
}

.aral-empty {
    text-align: center;
    padding: 3rem 1rem;
    color: var(--ink-muted);
}

.aral-empty i {
    font-size: 2rem;
    color: var(--line-strong);
    margin-bottom: .75rem;
    display: block;
}

/* ---------------------------- Status pills ------------------------------- */

.aral-pill {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .72rem;
    font-weight: 800;
    padding: .25rem .6rem;
    border-radius: 999px;
    border: 1px solid transparent;
}

.aral-pill-good   { color: var(--aral-green); border-color: rgba(22, 163, 74, .3); }
.aral-pill-warn   { color: #B45309;          border-color: rgba(180, 83, 9, .3); }
.aral-pill-danger { color: var(--aral-red);  border-color: rgba(220, 38, 38, .3); }
.aral-pill-info   { color: var(--aral-blue-soft); border-color: rgba(30, 77, 140, .3); }

/* ------------------------------ Scrollbar -------------------------------- */

* {
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
}

*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--line-strong);
    border-radius: 999px;
    border: 3px solid #FFFFFF;
}
*::-webkit-scrollbar-thumb:hover { background: #B9C1D1; }

/* --------------------------- Page entrance ------------------------------- */

.aral-fade-in {
    animation: aral-fade-in .28s ease both;
}

@keyframes aral-fade-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------------
   Motion, and the parts of the page the browser draws.

   Checked on 21 September 2026 against Emil Kowalski's design-engineering
   rules and impeccable's craft floor, and kept to what a panel used every
   school day can afford: short, ease-out, transform and opacity only, and
   nothing on the things people do dozens of times an hour.
   --------------------------------------------------------------------------- */
:root {
    /* The built-in `ease-out` is too weak to read as a response. */
    --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

/* Every button answers a press. .aral-btn always did; the Tailwind-styled
   buttons - most of them - did not, so pressing Save looked exactly like not
   pressing it until the network replied. `scale` rather than `transform`,
   because several buttons are positioned with a translate and a transform
   here would replace it and make them jump. */
button {
    transition: scale .12s var(--ease-out);
}
button.transition {
    /* Tailwind's list plus scale, so these keep their colour transitions. */
    transition-property: color, background-color, border-color, text-decoration-color,
        fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, scale;
}
/* .aral-btn already scales with transform; both would compound to .94. */
button:not(:disabled):not(.aral-btn):active {
    scale: .97;
}

/* Dialogs arrive instead of appearing. Eleven of them used to switch on in a
   single frame. Centred, so they grow from the middle - a dialog belongs to
   the page, not to the button that opened it. Closing stays instant: leaving
   should always be faster than arriving. */
.aral-dialog:not(.hidden) {
    animation: aral-fade .16s ease-out both;
}
.aral-dialog:not(.hidden) > * {
    animation: aral-dialog-in .2s var(--ease-out) both;
}
/* What only the programme operator uses (the Schools link and page, the
   "Viewing" school picker), hidden for a school admin from the first paint.
   guard.js sets .aral-school-admin on <html> before the page is drawn;
   script.js used to hide these once the school list had loaded, so they
   showed for a moment on every page. */
.aral-school-admin .aral-superadmin-only { display: none; }

/* Never taller than the window (4 October 2026). The Add School and Add
   Teacher cards had no limit, so on a short laptop window - 1280x585, a
   laptop at 150% with the bookmarks bar showing - "Save School" sat below the
   screen with no way to scroll to it. Every dialog's card now scrolls inside
   itself, as the learner and account dialogs already did. */
.aral-dialog > * {
    max-height: 100%;
    overflow-y: auto;
}
@keyframes aral-fade {
    from { opacity: 0; }
}
@keyframes aral-dialog-in {
    from { opacity: 0; scale: .97; }
}

/* Placeholders were Tailwind's default grey, 2.54:1 on white. Several carry
   the only hint of what a field wants ("Search by name, school, or email"),
   so they get the panel's muted ink: 4.83:1. */
input::placeholder,
textarea::placeholder {
    color: #6B7280;
    opacity: 1;
}

/* The browser's own blue selection and black caret belonged to no design. */
::selection {
    background: rgba(30, 77, 140, .18);
}
input,
textarea {
    caret-color: var(--aral-blue-soft);
}

/* Numbers that sit in columns or change in place keep one width per digit,
   so "17" and "11" line up and a count does not twitch as it loads. */
.aral-table td,
.aral-stat {
    font-variant-numeric: tabular-nums;
}

/* Reduced motion means less movement, not no feedback.

   This used to cut every animation and transition to nothing, which also
   removed the fades and colour changes that say something happened - a hover,
   a dialog arriving, a row being selected. Movement goes; those stay. */
@media (prefers-reduced-motion: reduce) {
    .aral-skeleton::after { animation: none; }
    .aral-fade-in { animation-name: aral-fade; }
    .aral-dialog:not(.hidden) > * { animation-name: aral-fade; }
    .aral-card-interactive:hover,
    .aral-btn:active { transform: none; }
    button:not(:disabled):not(.aral-btn):active { scale: none; }
    * { scroll-behavior: auto !important; }
}

/* ---------------------------------------------------------------------------
   The active navigation item.

   Was `bg-blue-500 text-white` inline on four pages - a colour outside the
   brand tokens, repeated, at 3.68:1 against a 4.5:1 requirement. Brand navy
   is 13.84:1 and is already the panel's primary colour.
   --------------------------------------------------------------------------- */
.nav-item-active {
    background: var(--aral-blue);
    color: #FFFFFF;
}
.nav-item-active:hover { background: var(--aral-blue-soft); }

/* ---------------------------------------------------------------------------
   The Privacy Notice and the Terms of Use, where people can see them.

   They were 12px grey words between bullets at the far end of the footer -
   technically present, practically invisible. They are now proper links with
   an icon, a border and a 32px target, in the panel's own blue (#1E4D8C on
   #EFF5FF is well past 4.5:1). Still in the footer, where people expect them,
   and still plainly secondary to anything on the page itself. (They were 40px
   until the footer got smaller, below.)
   --------------------------------------------------------------------------- */

/* The footer, smaller (the owner, 4 October 2026: "smaller but still readable
   so the tables have some space"). Two lines of text beside 32px logos and
   40px links took about 66px off every screen; one row of 24px logos, the name
   at 13px and the department at 12px takes about 44. Below about 1140px the
   row would wrap, so the department line steps out - the DepEd logo beside
   it says the same - and the footer stays one row. */
.aral-footer {
    position: relative;
    z-index: 20;
    flex-shrink: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .35rem 1.5rem;
    padding: .35rem 1.5rem;
    background: #fff;
    border-top: 1px solid #e5e7eb;
    color: #6b7280;
    font-size: .75rem;
    line-height: 1.35;
}
.aral-footer-brand { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.aral-footer-brand img { height: 1.5rem; width: auto; flex: none; }
.aral-footer-brand p { margin: 0 0 0 .4rem; min-width: 0; }
.aral-footer-brand strong { color: #374151; font-size: .8125rem; font-weight: 700; margin-right: .4rem; }
@media (max-width: 1140px) { .aral-footer-brand span { display: none; } }
.legal-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: .5rem;
}
.legal-link {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    min-height: 32px;
    padding: .3rem .8rem;
    border: 1px solid #BFD3F2;
    border-radius: 999px;
    background: #EFF5FF;
    color: var(--aral-blue-soft);
    font-size: .8125rem;
    font-weight: 700;
    text-decoration: none;
    transition: background-color .15s ease, border-color .15s ease;
}
.legal-link:hover {
    background: #E0ECFF;
    border-color: var(--aral-blue-soft);
}
.legal-link:focus-visible,
.legal-consent a:focus-visible {
    outline: 2px solid var(--aral-blue-ink);
    outline-offset: 2px;
}
.legal-link .aral-icon { font-size: .9rem; }
.legal-ext {
    padding: .3rem .45rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--ink-muted);
}
.legal-ext:hover { color: var(--ink); text-decoration: underline; }

/* The sign-in column centres its card when there is room, and scrolls from
   the top when there is not (5 October 2026). items-center centred it either
   way, so on a window shorter than the card its top - "Back to site" - sat
   above the scroll area where nothing could reach it: at 1366x768 once the
   Google button made the card taller, and on shorter windows before that.
   Auto margins centre into free space only. */
.aral-login-pane { align-items: flex-start; }
.aral-login-pane > * { margin-top: auto; margin-bottom: auto; }

/* Sign in with Google (5 October 2026), in Google's own button style: white,
   a grey edge, its four-colour "G" at 18px, "Sign in with Google". Full width
   like the Login button above it, and the same 48px height. */
.aral-or {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin: 1.25rem 0;
    color: var(--ink-muted);
    font-size: .75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
}
.aral-or::before,
.aral-or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--line-strong);
}
.aral-google-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .75rem;
    width: 100%;
    min-height: 48px;
    padding: .65rem 1rem;
    border: 1px solid #747775;
    border-radius: .75rem;
    background: #FFFFFF;
    color: #1F1F1F;
    font-size: .9rem;
    font-weight: 600;
    text-decoration: none;
    transition: background-color .15s ease, box-shadow .15s ease;
}
.aral-google-btn:focus-visible {
    outline: 2px solid var(--aral-blue-ink);
    outline-offset: 2px;
}
@media (hover: hover) and (pointer: fine) {
    .aral-google-btn:hover { background: #F7F8F8; box-shadow: 0 1px 2px rgba(60, 64, 67, .3), 0 1px 3px 1px rgba(60, 64, 67, .15); }
}
.aral-google-g { width: 18px; height: 18px; flex: none; }

/* The password meter under a new-password box (5 October 2026,
   password-strength.js). Three bars and a word, so the level is never told by
   colour alone; the sentence after the word is what the server would say. The
   strong green is green-700: the green-ink token is 3.3:1 on white, short of
   the 4.5:1 the word needs at this size. */
.aral-strength { margin-top: .5rem; }
.aral-strength-bar {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}
.aral-strength-bar span {
    height: 4px;
    border-radius: 2px;
    background: var(--line-strong);
    transition: background-color .15s ease;
}
.aral-strength-text {
    margin-top: .375rem;
    font-size: .75rem;
    line-height: 1.45;
    color: var(--ink-muted);
}
.aral-strength[data-level="weak"] .aral-strength-bar span:nth-child(1) { background: var(--aral-red-ink); }
.aral-strength[data-level="fair"] .aral-strength-bar span:nth-child(-n+2) { background: var(--aral-orange-ink); }
.aral-strength[data-level="strong"] .aral-strength-bar span { background: #15803D; }
.aral-strength[data-level="weak"] [data-part="label"] { color: var(--aral-red-ink); }
.aral-strength[data-level="fair"] [data-part="label"] { color: var(--aral-orange-ink); }
.aral-strength[data-level="strong"] [data-part="label"] { color: #15803D; }
@media (prefers-reduced-motion: reduce) {
    .aral-strength-bar span { transition: none; }
}

/* The sign-in page had no link to either document at all. */
.legal-consent {
    margin-top: 1.25rem;
    font-size: .875rem;
    line-height: 1.55;
    color: #475467;
}
.legal-consent a {
    color: var(--aral-blue-soft);
    font-weight: 700;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ---------------------------------------------------------------------------
 * The school filter must not be able to widen the page.
 *
 * A <select> sizes itself to its longest <option>, and "Los Baños Central
 * Elementary School" is wider than a phone - so the filter alone gave every
 * page carrying it a horizontal scrollbar. The option text is still readable
 * in the open list, which is where it is actually read.
 *
 * Hand-written rather than a Tailwind utility: tailwind.css is generated from
 * the markup and max-w-full is not in the built sheet, so the class would have
 * looked right in the HTML and done nothing. tools/check_admin_css.py is what
 * caught that.
 * ------------------------------------------------------------------------- */
#schoolFilter {
    max-width: 100%;
}

/* ---------------------------------------------------------------------------
   Rizal's Classroom, at a desk (23 September 2026)

   The same programme as the tablet: one navy for "this is the main thing",
   words that say what they do, and nothing that only decorates.
   --------------------------------------------------------------------------- */

/* Page titles. They were Tailwind's blue-900 (#1E3A8A) - a second navy, a
   shade off the brand's. Arimo sets loose at display sizes, so the tracking
   comes in, as it does on the tablet. */
.aral-page-title {
    color: var(--aral-blue);
    letter-spacing: -0.02em;
}

/* A link that reads as one, in the panel's one blue. */
.aral-text-link {
    color: var(--aral-blue);
    font-weight: 700;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    text-decoration-color: rgba(15, 43, 91, .35);
    transition: text-decoration-color .15s ease;
}
@media (hover: hover) and (pointer: fine) {
    .aral-text-link:hover { text-decoration-color: currentColor; }
}

/* Needs attention: one line per unfinished thing, with the way to finish it. */
.aral-attention {
    list-style: none;
    margin: 0;
    padding: 0;
}
.aral-attention-item {
    padding: .45rem 0;
    border-top: 1px solid var(--line);
}
.aral-attention-item:first-child { border-top: none; padding-top: 0; }
.aral-attention-line {
    font-size: .9rem;
    line-height: 1.3;
    color: var(--ink);
}
.aral-attention-line strong { color: var(--aral-blue); font-weight: 700; }
/* Whose it is, and the way to it, on one line under it. */
.aral-attention-foot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-top: .1rem;
    line-height: 1.3;
}
.aral-attention-names {
    min-width: 0;
    font-size: .8rem;
    color: var(--ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.aral-attention-action {
    flex: none;
    font-size: .8rem;
}

/* A fact about a learner, not a verdict. "Internet at home: No" used to be a
   red pill - the colour this panel keeps for errors - on a third of the rows.
   Facts are neutral; red is for something that went wrong. */
.aral-fact {
    display: inline-flex;
    align-items: center;
    font-size: .72rem;
    font-weight: 700;
    padding: .2rem .55rem;
    border-radius: 999px;
    color: #475467;
    background: #F2F4F7;
}

/* ---------------------------------------------------------------------------
   One blue, everywhere (23 September 2026)

   The markup still carries Tailwind's own blues - blue-500 to blue-800 for
   links, hovers, focus rings and the logo - 120-odd places that each said
   "this is the main thing" in a blue that is not ARAL's. tailwind.css is
   built ahead of time and cannot gain classes without a rebuild, so the
   remap lives here instead: this file loads after it, the selectors match
   its own, and so these win. Monument Navy for emphasis, Lake Blue (8.9:1 on
   white) for links and quieter ink, navy-tinted washes for the pale fills.
   --------------------------------------------------------------------------- */
.text-blue-800,
.hover\:text-blue-800:hover,
.hover\:text-blue-600:hover { color: var(--aral-blue); }

.text-blue-700,
.text-blue-600,
.text-blue-500 { color: var(--aral-blue-soft); }

.bg-blue-50,
.group:hover .group-hover\:bg-blue-50 { background-color: #EEF2F8; }
.hover\:bg-blue-50\/50:hover { background-color: rgba(15, 43, 91, .04); }
.bg-blue-100 { background-color: #E1E8F2; }
.bg-blue-600 { background-color: var(--aral-blue); }
.hover\:border-blue-200:hover { border-color: #C9D5E8; }
.accent-blue-600 { accent-color: var(--aral-blue); }

.focus\:ring-blue-500:focus,
.focus-visible\:ring-blue-600:focus-visible { --tw-ring-color: rgba(30, 77, 140, .45); }

/* Row actions say what they do. They were bare 30x38 icons - a pencil, a key,
   a box - so finding "archive" meant hovering over each one for its title. */
.aral-row-actions {
    display: flex;
    justify-content: flex-end;
    gap: .4rem;
}
.aral-row-action {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-height: 2.25rem;
    padding: .35rem .7rem;
    border: 1px solid var(--line-strong);
    border-radius: 10px;
    background: #FFFFFF;
    color: var(--aral-blue);
    font-size: .78rem;
    font-weight: 700;
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease, scale .12s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
    .aral-row-action:hover { border-color: var(--aral-blue); background: #F5F8FC; }
    .aral-row-action-quiet:hover { color: var(--ink); border-color: var(--ink-muted); background: #FFFFFF; }
}
.aral-row-action:active { scale: .97; }
.aral-row-action-quiet { color: var(--ink-muted); }

/* The learner table's household columns, hidden until asked for. */
.aral-details-hidden .aral-detail { display: none; }

/* The learner table is nowrap so names and IDs never break; school names and
   the two "last year" headings are the exceptions, or six columns scroll
   sideways on a laptop for the sake of one long school name. */
.aral-table .aral-wrap { white-space: normal; min-width: 11rem; }
.aral-table .aral-th-narrow { min-width: 6.5rem; max-width: 8rem; line-height: 1.25; }

/* ---------------------------------------------------------------------------
   PCs and laptops only (24 September 2026)

   The owner's decision: the admin panel is used on a computer, never on a
   phone or tablet. A touch screen with no mouse - (hover: none) and
   (pointer: coarse), the same test script.js makes - gets the one message in
   .aral-desktop-only and nothing else, including on the sign-in page. It goes
   by the input, not the width, so a laptop in a narrow window still works,
   a touchscreen laptop still works (its trackpad is its primary pointer), and
   a phone's "Request desktop site" does not get past it.

   A phone layout was built the same morning and taken out again for this.
   --------------------------------------------------------------------------- */
.aral-desktop-only { display: none; }

@media (hover: none) and (pointer: coarse) {
    body > :not(.aral-desktop-only) { display: none !important; }
    body.h-screen { height: auto; overflow: visible; }
    .aral-desktop-only {
        display: flex;
        min-height: 100vh;
        min-height: 100dvh;
        align-items: center;
        justify-content: center;
        padding: 2rem 1.5rem;
        background: #FFFFFF;
    }
}
.aral-desktop-only-body {
    max-width: 26rem;
    color: var(--ink-muted);
    font-size: 1rem;
    line-height: 1.6;
}
.aral-desktop-only-body p + p { margin-top: .75rem; }
.aral-desktop-only-body strong { color: var(--ink); font-weight: 700; overflow-wrap: anywhere; }
.aral-desktop-only-mark {
    font-size: 2rem;
    font-weight: 900;
    letter-spacing: -0.02em;
    line-height: 1;
    margin-bottom: 1.5rem;
}
.aral-desktop-only-title {
    color: var(--aral-blue);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.25;
    margin-bottom: .75rem;
}
.aral-desktop-only-note {
    font-size: .875rem;
    padding-top: .75rem;
    border-top: 1px solid var(--line);
}

/* Show-password eyes. The sign-in one was a 22x32 target and the teacher
   form's 21x31, both under WCAG 2.2's 24px minimum. 44px now, on every
   password field, and the field leaves room for it. */
.aral-password-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
    min-height: 2.75rem;
    right: .25rem;
    border-radius: 10px;
}
.aral-password-input { padding-right: 3.25rem; }

/* ---------------------------------------------------------------------------
   Pre/post results (results.html, 28 September 2026)

   A statistics table read by people checking numbers, so the numbers line up:
   right-aligned in tabular figures, the spread and the interval quieter than
   the value they qualify, and each measure's name a row header so a screen
   reader says which measure a p-value belongs to.
   --------------------------------------------------------------------------- */
.aral-results .aral-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.aral-results thead th.aral-num { text-align: right; }
.aral-results .aral-th-sub { font-weight: 600; text-transform: none; letter-spacing: 0; }
.aral-results tbody th.aral-result-measure {
    text-align: left;
    font-weight: 700;
    font-size: .9rem;
    color: var(--ink);
    padding: .9rem 1rem;
    border-bottom: 1px solid var(--line);
    min-width: 11rem;
}
.aral-results .aral-result-unit,
.aral-results .aral-result-detail {
    display: block;
    font-size: .75rem;
    font-weight: 500;
    color: var(--ink-muted);
    white-space: nowrap;
}
.aral-results .aral-result-sd { color: var(--ink-muted); }
.aral-results .aral-result-test { display: block; font-weight: 700; white-space: nowrap; }
.aral-results .aral-result-size {
    display: block;
    margin-top: .3rem;
    font-size: .75rem;
    color: var(--ink-muted);
    white-space: nowrap;
}
/* The domain headings break the table into Reading, Writing and the rest. */
.aral-results tbody tr.aral-results-group th {
    text-align: left;
    font-size: .72rem;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--aral-blue);
    background: #F7F9FC;
    padding: .55rem 1rem;
    border-bottom: 1px solid var(--line);
}
.aral-results tbody tr.aral-results-group:hover { background: transparent; }
.aral-results tbody tr:last-child th { border-bottom: none; }
.aral-results .aral-pill { white-space: nowrap; }
.aral-results tbody tr.aral-results-empty td { font-size: .8rem; color: var(--ink-muted); }
.aral-results tbody tr.aral-results-empty:hover { background: transparent; }

.aral-method ol { list-style: decimal; padding-left: 1.25rem; }
.aral-method li { font-size: .875rem; color: var(--ink); line-height: 1.6; margin-bottom: .5rem; max-width: 75ch; }

/* ---------------------------------------------------------------------------
   Dropdowns (30 September 2026)

   Every list in the panel was the browser's own: a grey box that snapped open
   and shut, and in the forms - which carry Tailwind's appearance-none - a box
   with no arrow at all, so nothing said it opened.

   Two layers. Every browser gets the arrow, the pointer and a border that
   answers the mouse. A browser that can style the list itself
   (appearance: base-select) also gets a list that arrives: 180ms, ease-out,
   growing from the control it belongs to, opacity and transform only. It is
   still a real <select> - the keyboard, the screen reader and the form all
   work as before - and a browser that cannot do this shows its own list.
   --------------------------------------------------------------------------- */
select:not([multiple]):not([size]) {
    appearance: none;
    cursor: pointer;
    padding-right: 2.4rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 7.5 5 5 5-5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .7rem center;
    background-size: 1.05rem;
    transition: border-color .15s ease, box-shadow .15s ease;
}
@media (hover: hover) and (pointer: fine) {
    select:not([multiple]):not([size]):hover:not(:disabled) { border-color: #B9C1D1; }
}
select:disabled { cursor: not-allowed; opacity: .6; }

@supports (appearance: base-select) {
    select:not([multiple]):not([size]),
    select:not([multiple]):not([size])::picker(select) {
        appearance: base-select;
    }

    /* The control. The arrow is the list's own icon now, so it can turn. */
    select:not([multiple]):not([size]) {
        background-image: none;
        padding-right: .75rem;
        align-items: center;
        gap: .6rem;
    }
    select::picker-icon {
        content: "";
        flex: none;
        width: 1.05rem;
        height: 1.05rem;
        margin-left: auto;
        background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 7.5 5 5 5-5'/%3E%3C/svg%3E") center / contain no-repeat;
        transition: rotate .2s var(--ease-out);
    }
    select:open::picker-icon { rotate: 180deg; }
    select:open { border-color: var(--aral-blue-soft); }

    /* A styled control is as wide as what is chosen, not as its longest
       option, so the school filter would change width with every choice and
       push the buttons beside it along. It keeps room for a school's name. */
    #schoolFilter { min-width: 15rem; }

    /* The list. */
    select::picker(select) {
        margin-top: .4rem;
        padding: .35rem;
        border: 1px solid var(--line-strong);
        border-radius: 12px;
        background: #FFFFFF;
        box-shadow: 0 2px 6px rgba(16, 24, 40, .06), 0 16px 32px -12px rgba(16, 24, 40, .28);
        max-height: min(22rem, 60vh);
        overflow-y: auto;

        opacity: 0;
        translate: 0 -6px;
        scale: .98;
        transform-origin: top center;
        transition:
            opacity .14s ease-out,
            translate .18s var(--ease-out),
            scale .18s var(--ease-out),
            overlay .18s allow-discrete,
            display .18s allow-discrete;
    }
    select:open::picker(select) {
        opacity: 1;
        translate: 0 0;
        scale: 1;
    }
    @starting-style {
        select:open::picker(select) {
            opacity: 0;
            translate: 0 -6px;
            scale: .98;
        }
    }

    select option {
        display: flex;
        align-items: center;
        gap: .5rem;
        padding: .5rem .7rem;
        border-radius: 8px;
        font-size: .875rem;
        font-weight: 500;
        color: var(--ink);
        cursor: pointer;
        transition: background-color .1s ease;
    }
    select option::checkmark {
        order: 2;
        margin-left: auto;
        color: var(--aral-blue);
        font-weight: 700;
    }
    select option:checked {
        background: rgba(15, 43, 91, .07);
        color: var(--aral-blue);
        font-weight: 700;
    }
    select option:disabled { color: var(--ink-muted); cursor: default; }
    select option:focus-visible {
        outline: 2px solid rgba(30, 77, 140, .45);
        outline-offset: -2px;
    }
    @media (hover: hover) and (pointer: fine) {
        select option:not(:disabled):hover { background: #F1F5FB; }
        select option:checked:hover { background: rgba(15, 43, 91, .11); }
    }

    /* Reduced motion: the list still fades in, it just does not travel. */
    @media (prefers-reduced-motion: reduce) {
        select::picker(select),
        select:open::picker(select) { translate: none; scale: none; }
        select::picker-icon { transition: none; }
    }
}

/* The learner form's buttons: Archive on the left when editing, and the
   Cancel/Save pair pushed right whether or not it is there. (ml-auto is not
   in the built tailwind.css.) */
.aral-form-actions-end { margin-left: auto; }

/* The line under a wide table that says how to reach the rest of it. */
.aral-scroll-hint { font-size: .78rem; color: var(--ink-muted); }
.aral-scroll-hint kbd {
    font: inherit;
    font-weight: 700;
    color: var(--ink);
    padding: .05rem .35rem;
    border: 1px solid var(--line-strong);
    border-radius: 6px;
    background: #F7F9FC;
}

/* ==========================================================================
   Restoring, and the expanded learner table (1 October 2026)
   ========================================================================== */

/* "Restore this learner?" asks in the panel's blue, not archiving's amber. */
#confirmOk.aral-ok-restore { background: var(--aral-blue); }
@media (hover: hover) and (pointer: fine) {
    #confirmOk.aral-ok-restore:hover { background: var(--aral-blue-soft); }
}
.aral-dialog .aral-confirm-icon-restore { background: #E8EFF8; }

/*
 * Expand: the learner table's card fills the window, in the page. The
 * dialogs are z-50, so Edit, PIN and Archive still open above it - the
 * browser's full screen showed only the table and hid them.
 */
body.aral-table-expanded { overflow: hidden; }
body.aral-table-expanded::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 44;
    background: rgb(15 23 42 / .5);
}
.aral-card.aral-card-expanded {
    position: fixed;
    inset: 1rem;
    z-index: 45;
    box-shadow: 0 24px 64px -16px rgb(15 23 42 / .45);
    animation: aral-card-expand .18s var(--ease-out) both;
}
@keyframes aral-card-expand {
    from { opacity: 0; scale: .98; }
}
@keyframes aral-card-expand-still {
    from { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .aral-card.aral-card-expanded { animation-name: aral-card-expand-still; }
}

/* The logo (4 October 2026): the RCOF sun over an open book, as on the
   public site and the browser tab. */
.aral-logo-mark {
    width: 2.6rem;
    height: 2.6rem;
    flex: none;
    border-radius: 0.6rem;
    box-shadow: 0 1px 0 rgba(15, 43, 91, .25), 0 8px 16px -10px rgba(15, 43, 91, .7);
}
.aral-logo-mark-lg { width: 3.5rem; height: 3.5rem; border-radius: 0.8rem; margin-bottom: 1rem; display: block; }

/* The dashboard on one screen (4 October 2026, the owner's group: "it should
   have all the things ready to see"; the owner again on 11 October, after
   build 20's charts had made the page scroll). On a laptop - 1260 by 580 and
   larger, so a 1366x768 screen with the browser's own bars, and a 14-inch
   1920x1080 one at Windows' 150% (about 1280 by 590 in the browser) - the
   page itself does not scroll. One grid fills the window: what needs doing down the left
   (Needs attention, then Recent activity) and the four charts two by two
   beside it. The charts are drawn to the height their card has; a list
   longer than its card scrolls inside it, as a last resort. Smaller or
   shorter windows keep the normal page, which scrolls: under 1260 wide a
   chart card is too narrow for a ring beside its legend. */
.aral-dash {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas: "todo todo" "chapters progress" "retention tests";
    gap: 1.25rem;
}
.aral-dash-todo { grid-area: todo; display: flex; flex-direction: column; gap: 1.25rem; min-height: 0; }
.aral-dash-chapters { grid-area: chapters; }
.aral-dash-progress { grid-area: progress; }
.aral-dash-retention { grid-area: retention; }
.aral-dash-tests { grid-area: tests; }
.aral-dash-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    padding: 1.1rem 1.25rem;
    /* The charts read the card's width to fit their legends (below). */
    container-type: inline-size;
}
.aral-dash-card-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; margin-bottom: .75rem; flex: none; }
.aral-dash-card-head h2 { line-height: 1.25; }
.aral-dash-card-aside { font-size: .75rem; font-weight: 700; color: var(--ink-muted); white-space: nowrap; }
.aral-dash-card-body { flex: 1 1 auto; min-height: 0; }
/* A card's "nothing yet" or "could not load" note, without the big icon the
   full pages give it: a dashboard card has a few lines of room. */
.aral-dash-card-body > .text-center { padding-block: .25rem; }
.aral-dash-card-body > .text-center > .aral-icon { display: none; }
.aral-dash-count { margin-left: .4rem; vertical-align: .1em; padding: .1rem .5rem; }

@media (min-width: 1260px) and (min-height: 580px) {
    .aral-dash-main {
        display: flex;
        flex-direction: column;
        overflow: hidden;
        padding: 1rem 2rem;
    }
    .aral-dash-main > header { margin-bottom: .75rem; padding-bottom: .6rem; align-items: center; }
    /* The title and the counts on one line: the cards need the height. */
    .aral-dash-heading { display: flex; align-items: baseline; gap: .9rem; flex-wrap: wrap; }
    .aral-dash-heading > h1 { font-size: 1.35rem; line-height: 1.2; margin: 0; }
    .aral-dash {
        flex: 1;
        min-height: 0;
        grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr);
        grid-template-rows: repeat(2, minmax(0, 1fr));
        grid-template-areas: "todo chapters progress" "todo retention tests";
        gap: 1rem;
    }
    .aral-dash-todo { gap: 1rem; }
    .aral-dash-card { overflow: hidden; padding: .9rem 1.1rem; }
    .aral-dash-card-head { margin-bottom: .5rem; }
    /* Needs attention takes the height its list needs; Recent activity the
       rest, never under about four lines. */
    .aral-dash-attention { flex: 0 1 auto; }
    .aral-dash-recent { flex: 1 0 8rem; }
    .aral-dash-card-body { overflow: auto; }
    .aral-dash-card-body.aral-chart-body { flex: 1 1 0; height: auto; overflow: hidden; }
}
/* A short window (under 700 tall): the legends and lists close up a little
   so five retention statuses still stand beside their ring. */
@media (min-width: 1260px) and (min-height: 580px) and (max-height: 700px) {
    .aral-dash .aral-chart-legend { font-size: .78rem; gap: .12rem; }
    .aral-attention-line { font-size: .85rem; }
    .aral-dash-recent { flex-basis: 7rem; }
    .aral-meters { gap: .55rem; }
    .aral-meter { row-gap: .25rem; }
}

/* The charts (build 20, 11 October 2026) ------------------------------------
   Drawn by js/charts.js: the Dashboard's four, and the Results page's
   up/same/down bars. Text stays in the text colours; the marks carry the
   colour, and every number is printed beside its mark. */
.aral-chart-body { height: 9.5rem; }
.aral-chart-donut { height: 100%; display: flex; align-items: center; gap: 1rem; }
/* The legend keeps its whole width; the ring is square, as tall as the card
   allows, and gives way sideways when the legend needs the room (the drawing
   shrinks to fit its box). */
.aral-chart-ring { height: 100%; max-height: 9.5rem; width: auto; aspect-ratio: 1; flex: 0 1 auto; min-width: 0; }
.aral-bars { display: flex; align-items: stretch; gap: .6rem; height: 100%; }
.aral-bar { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; }
.aral-bar-value { font-size: .85rem; font-weight: 700; color: #1f2937; }
.aral-bar-track { flex: 1; width: 100%; display: flex; align-items: flex-end; border-bottom: 1px solid #767676; }
.aral-bar-fill { display: block; width: 100%; min-height: 2px; border-radius: 4px 4px 0 0; }
.aral-bar-label { margin-top: .3rem; font-size: .72rem; color: #4b5563; white-space: nowrap; }
.aral-chart-centre { font-size: 26px; font-weight: 800; fill: #1f2937; }
.aral-chart-caption { font-size: 11px; fill: #4b5563; }
.aral-chart-legend { list-style: none; margin: 0; padding: 0; display: grid; gap: .3rem; font-size: .85rem; color: #1f2937; flex: none; }
.aral-chart-legend li { display: flex; align-items: center; gap: .45rem; white-space: nowrap; }
.aral-chart-legend strong { margin-left: auto; padding-left: .5rem; font-variant-numeric: tabular-nums; }
.aral-chart-legend-row { display: flex; flex-wrap: wrap; gap: .4rem 1.25rem; margin-bottom: .75rem; }
.aral-chart-legend-row strong { margin-left: 0; }
.aral-chart-key { width: .7rem; height: .7rem; border-radius: 50%; flex: none; }
.aral-chart-empty { margin: .25rem 0; font-size: .9rem; color: #4b5563; }
.aral-chart-foot { margin-top: .6rem; font-size: .75rem; color: var(--ink-muted); }
/* Tests recorded: a label and its count over a bar, one scale for both. */
.aral-meters { display: grid; gap: .7rem; }
.aral-meter { display: grid; grid-template-columns: minmax(0, 1fr) auto; row-gap: .35rem; align-items: baseline; }
.aral-meter-label { font-size: .85rem; font-weight: 700; color: #1f2937; }
.aral-meter-count { font-size: .8rem; color: #4b5563; font-variant-numeric: tabular-nums; }
.aral-meter-count strong { color: #1f2937; font-size: .95rem; }
.aral-meter-track { grid-column: 1 / -1; height: .7rem; border-radius: 999px; background: #EEF1F5; overflow: hidden; }
.aral-meter-fill { display: block; height: 100%; min-width: 2px; border-radius: 999px; }
.aral-share-row { display: grid; grid-template-columns: 13rem minmax(0, 1fr) 11rem; align-items: center; gap: 1rem; padding: .3rem 0; font-size: .85rem; color: #1f2937; }
.aral-share-bar { display: flex; gap: 2px; height: .9rem; border-radius: 4px; overflow: hidden; background: #f3f4f6; }
.aral-share-part { display: block; min-width: 2px; }
.aral-share-counts { color: #4b5563; white-space: nowrap; font-variant-numeric: tabular-nums; }
.aral-share-none { grid-column: 2 / 4; color: #6b7280; font-style: italic; }
@media (hover: hover) and (pointer: fine) {
    .aral-chart-ring circle:hover, .aral-bar-fill:hover, .aral-share-part:hover { opacity: .8; }
}
/* A narrow card: smaller words beside a smaller ring. */
@container (max-width: 300px) {
    .aral-chart-donut { gap: .6rem; }
    .aral-chart-ring { max-height: 7.5rem; }
    .aral-dash .aral-chart-legend { font-size: .72rem; gap: .15rem; }
    .aral-chart-key { width: .55rem; height: .55rem; }
    .aral-bars { gap: .35rem; }
    .aral-bar-label { font-size: .65rem; }
}

/* Attendance (4 October 2026) ----------------------------------------------
   The sidebar's calendar icon, drawn for ARAL in the shape of the Iconsax set
   (icons.css is generated, so it is not added there). */
.icon-calendar-check { --aral-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Cpath%20d%3D%27M7.25%202a.75.75%200%200%201%20.75.75V4h8V2.75a.75.75%200%200%201%201.5%200V4h.25A3.25%203.25%200%200%201%2021%207.25v10.5A3.25%203.25%200%200%201%2017.75%2021H6.25A3.25%203.25%200%200%201%203%2017.75V7.25A3.25%203.25%200%200%201%206.25%204h.25V2.75A.75.75%200%200%201%207.25%202ZM4.5%209.5v8.25c0%20.97.78%201.75%201.75%201.75h11.5c.97%200%201.75-.78%201.75-1.75V9.5h-15Zm10.78%203.22a.75.75%200%200%201%200%201.06l-3.75%203.75a.75.75%200%200%201-1.06%200l-1.75-1.75a.75.75%200%201%201%201.06-1.06L11%2015.94l3.22-3.22a.75.75%200%200%201%201.06%200Z%27%2F%3E%3C%2Fsvg%3E"); }

/* The month's sheet, laid out like DepEd's School Form 2: the learner's name
   stays in view while the days scroll past; a day that was not taken is
   greyed in the head, and its cells say so. */
.aral-att-scroll { max-height: 70vh; }

/* On a laptop the sheet is the only thing that scrolls (the owner, 4 October
   2026): the title, the filters and the sheet's heading stay put and the
   learners scroll under the sheet's sticky head, which now has the room the
   "In short" card had. Shorter or narrower windows keep the normal page,
   which scrolls, with the sheet capped at 70% of the window as above. */
@media (min-width: 1024px) and (min-height: 560px) {
    .aral-att-main {
        display: flex;
        flex-direction: column;
        overflow: hidden;
        padding: 1.25rem 2rem;
    }
    .aral-att-main > header { margin-bottom: 1rem; padding-bottom: .75rem; }
    .aral-att-main > header h1 { font-size: 1.35rem; line-height: 1.2; }
    .aral-att-card {
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: column;
        padding: 1.1rem 1.4rem;
    }
    .aral-att-card > .aral-att-scroll { flex: 1; min-height: 0; max-height: none; }
}
.aral-att-sheet { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; }
.aral-att-sheet th, .aral-att-sheet td { padding: .45rem .5rem; border-bottom: 1px solid var(--line); text-align: center; white-space: nowrap; }
.aral-att-sheet thead th { position: sticky; top: 0; background: #fff; z-index: 2; font-size: .72rem; font-weight: 700; color: #374151; padding: .55rem .5rem; text-align: center; }
/* The sheet's rows at the height it was drawn for. .aral-table's
   "tbody td" (one class, two elements) outranked the one-element rule above,
   so every row got the learner list's roomy 0.9rem padding: 53px a row, and
   four learners in view on a laptop. Matched here, later in the file. */
.aral-att-sheet tbody td { padding: .45rem .5rem; }
.aral-att-sheet .aral-att-name { position: sticky; left: 0; background: #fff; z-index: 1; text-align: left; font-weight: 600; color: #111827; min-width: 12rem; padding-left: 1rem; border-right: 1px solid var(--line); }
.aral-att-sheet thead .aral-att-name { z-index: 3; }
.aral-att-sheet .aral-att-section { text-align: left; color: #4b5563; font-size: .8rem; }
.aral-att-day, .aral-att-cell { min-width: 2.1rem; line-height: 1.15; }
.aral-att-day span { display: block; font-weight: 600; font-size: .62rem; color: #6b7280; text-transform: uppercase; letter-spacing: .04em; }
.aral-att-day-off { color: #9ca3af !important; background: #f9fafb !important; }
.aral-att-total { font-variant-numeric: tabular-nums; font-weight: 700; color: #111827; min-width: 3.5rem; }
.aral-att-total.aral-att-often { color: var(--aral-red-ink); }
.aral-att-mark { display: inline-flex; align-items: center; justify-content: center; width: 1.45rem; height: 1.45rem; border-radius: .4rem; font-size: .75rem; font-weight: 800; }
.aral-att-present { background: #dcfce7; color: #166534; }
.aral-att-absent { background: #fee2e2; color: #991b1b; }
.aral-att-none { color: #9ca3af; }
.aral-att-legend { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.aral-att-legend .aral-att-mark { margin-left: .5rem; }
/* Build 20: a day with a tablet problem carries a small warning beside its
   mark (the note on hover), and two totals close each row. */
.aral-att-problem { display: inline-flex; vertical-align: middle; margin-left: .2rem; color: #b45309; font-size: .95rem; }
.aral-att-sheet .aral-att-extra { color: #374151; font-weight: 600; }

/* The Learners page's Scores box (build 20): ten measures, a Pre-test and a
   Post-test box each. It scrolls inside itself on a short laptop window. */
.aral-scores-card { max-height: calc(100vh - 2rem); display: flex; flex-direction: column; }
.aral-scores-scroll { flex: 1; min-height: 0; overflow-y: auto; border: 1px solid var(--line); border-radius: .75rem; }
.aral-scores-table { width: 100%; border-collapse: separate; border-spacing: 0; }
.aral-scores-table thead th { position: sticky; top: 0; z-index: 1; background: #fff; font-size: .72rem; font-weight: 700; color: #374151; text-align: center; padding: .6rem .75rem; border-bottom: 1px solid var(--line-strong); }
.aral-scores-table td { padding: .3rem .75rem; text-align: center; border-bottom: 1px solid var(--line); }
.aral-scores-table .aral-scores-label { text-align: left; font-size: .85rem; font-weight: 600; color: var(--ink); padding: .3rem .75rem; border-bottom: 1px solid var(--line); }
.aral-scores-table .aral-scores-domain { text-align: left; font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-muted); background: #F8FAFC; padding: .45rem .75rem; border-bottom: 1px solid var(--line); }
.aral-scores-input { width: 4.5rem; padding: .35rem .5rem; text-align: center; font-variant-numeric: tabular-nums; border: 1px solid var(--line-strong); border-radius: .5rem; }
.aral-scores-input:focus { outline: 2px solid var(--aral-blue); outline-offset: 1px; }
.aral-scores-input[aria-invalid="true"] { border-color: var(--aral-red-ink); background: #FEF2F2; }
.aral-scores-table .aral-scores-wait { padding: 2rem .75rem; font-size: .875rem; color: var(--ink-muted); }

/* ---------------------------------------------------------------------------
 * The sign-in card on a laptop (6 October 2026).
 *
 * The card - Back to site down to the copyright - is about 770px tall. A
 * laptop's browser window is usually 590 to 730px (1366x768, or 1920x1080 at
 * 125-150% scaling), so on the owner's laptop it scrolled while on a big
 * monitor it did not. On a short window the spacing tightens and the logo
 * sits beside the name instead of above it; on a very short one the line
 * under the heading goes too. The card then fits from a 600px window down.
 * Nothing is hidden that says what to do: the fields, the buttons, the
 * Terms/Privacy line and the copyright all stay.
 * ------------------------------------------------------------------------- */
@media (max-height: 820px) {
    .aral-login-shell { padding: 1rem; gap: 1.5rem; }
    .aral-login-back { margin-bottom: .75rem; padding-top: .25rem; padding-bottom: .25rem; }
    .aral-login-head {
        display: grid;
        grid-template-columns: auto 1fr;
        column-gap: .875rem;
        align-items: center;
        margin-bottom: 1.25rem;
    }
    .aral-login-head .aral-logo-mark-lg { grid-row: 1 / span 2; width: 2.75rem; height: 2.75rem; margin-bottom: 0; }
    .aral-login-head .aral-login-word { font-size: 1.875rem; line-height: 2.125rem; margin-bottom: 0; }
    .aral-login-head .aral-login-sub { margin-bottom: 0; }
    .aral-login-head h1,
    .aral-login-head .aral-login-hint { grid-column: 1 / -1; }
    .aral-login-head h1 { margin-top: .75rem; }
    #adminLoginForm > :not([hidden]) ~ :not([hidden]) { margin-top: 1rem; }
    #adminLoginForm label { margin-bottom: .25rem; }
    .aral-or { margin: .75rem 0; }
    .legal-consent { margin-top: .75rem; }
    .aral-login-foot { margin-top: .75rem; }
}
@media (max-height: 680px) {
    .aral-login-head .aral-login-hint { display: none; }
    .aral-or { margin: .5rem 0; }
    .legal-consent { margin-top: .5rem; }
    .aral-login-foot { margin-top: .5rem; }
}

/* Tables on a laptop (6 October 2026). At 1280px wide - a 1920x1080 laptop
   at 150% - the Schools table hid 109px and the Learners table 79px of their
   Actions column behind a sideways scroll, so Edit and Archive were off the
   edge. Below 1366px the cells keep 12px a side instead of 16px, and the
   Actions column is pinned to the right edge the way the learner's name is
   pinned to the left: whatever else a long name or address pushes off the
   side, the buttons for that row stay in view. White like the pinned name
   column, with a soft edge so it reads as lying over the row.
   At every width since build 20 (12 October 2026): the Learners table's
   Scores button made its row 105px too wide at 1366px too, which put
   Archive off the edge there. */
@media (max-width: 1365px) {
    .aral-table thead th,
    .aral-table tbody td { padding-left: .75rem; padding-right: .75rem; }
}
.aral-table tbody td:has(> .aral-row-actions),
.aral-table:has(.aral-row-actions) thead th:last-child {
    position: sticky;
    right: 0;
    background: #FFFFFF;
    box-shadow: -6px 0 8px -6px rgba(15, 43, 91, .18);
}
.aral-table tbody td:has(> .aral-row-actions) { z-index: 5; }

/* Lists on a short window (6 October 2026). Schools, Learners, Teachers and
   the Activity log fill the window with one card and give the table whatever
   height is left. On a laptop that was very little: at a 600px-tall window
   the Learners table had 58px - not one row - under its filters, and 1.7
   rows at 730px. On a window under 820px tall the table keeps at least
   20rem (six or seven rows) and the page beside the sidebar scrolls to it
   instead; the sidebar and the top bar stay where they are. */
@media (max-height: 820px) {
    main.overflow-hidden:has(> .aral-card.flex-1) { overflow-y: auto; }
    main > .aral-card.flex-1 { flex: 1 0 auto; }
    main > .aral-card.flex-1 > .flex-1.overflow-auto { flex: 1 0 20rem; min-height: 20rem; }
}

/* =========================================
   MODULES PAGE (8 October 2026, js/modules.js)
   Tailwind is built ahead of time, so the few looks this page needs that no
   other page uses are written out here.
========================================= */
.aral-mod-card {
    border: 1px solid #E5E7EB;
    border-radius: 1rem;
    padding: 1.25rem;
    margin-bottom: 1rem;
    background: #FFFFFF;
}
.aral-mod-form { border-color: var(--aral-blue-soft); }
.aral-mod-note {
    font-size: 0.875rem;
    color: #374151;
    background: #EFF6FF;
    border-radius: 0.75rem;
    padding: 0.625rem 0.875rem;
}
.aral-mod-badge {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 700;
    border-radius: 9999px;
    padding: 0.25rem 0.625rem;
    white-space: nowrap;
}
.aral-mod-badge-builtin { background: #EFF6FF; color: var(--aral-blue-soft); }
.aral-mod-badge-draft   { background: #FFF7ED; color: var(--aral-orange-ink); }
.aral-mod-badge-hidden  { background: #F3F4F6; color: #4B5563; }
.aral-mod-badge-live    { background: #F0FDF4; color: #15803D; }
.aral-mod-inline {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: #4B5563;
    margin-right: 0.25rem;
}
.aral-mod-progress {
    font-size: 0.875rem;
    color: var(--aral-blue-soft);
    font-weight: 600;
    margin-bottom: 0.75rem;
}
