/* ============================================================
   ATTENDANCE TRACKER — the student-facing page

   Now speaks the same language as the admin pages (see
   students-page.css) and the QR Generator: sky/cyan accent
   (#0ea5e9 → #06b6d4), dark surfaces (var(--surface)), a hero with a rule
   on top, and round chips. A student now sees one product, from
   generating a QR through to checking their record.

   The old look had its own vocabulary: Times New Roman across the
   whole body (while every other page used the native stack), a
   violet-indigo gradient (#667eea / #764ba2 / #1a0b2e), and a neon
   cyan (#00f0ff) rule under the header found nowhere else in the
   app. The subject boxes carried `border: 1px solid var(--ink-2)` — a
   near-white edge on a dark card, left over from a design meant
   for a white page.

   THE RESERVED COLORS — never use as decoration:
     green  #10b981 → recorded / present
     amber  #f59e0b → warning
     red    #ef4444 → absent, not on the list, wrong thing searched for
   Sky is only the page's identity; it carries no status meaning,
   so it does not compete with the three above.
   ============================================================ */

.trk-page {
    --trk: #0ea5e9;
    --trk-deep: #06b6d4;
    --trk-soft: rgba(14, 165, 233, .14);
    --trk-line: rgba(14, 165, 233, .3);
    --trk-ink: #7dd3fc;

    --surface-2: var(--bg);
    --border: rgba(var(--tint), .07);

    --text: var(--ink-2);
    --text-dim: rgba(var(--tint), .55);
    --text-faint: rgba(var(--tint), .38);

    --ok: #10b981;
    --ok-ink: #34d399;
    --warn: #f59e0b;
    --warn-ink: #fcd34d;
    --bad: #ef4444;
    --bad-ink: #f87171;

    --radius: 16px;
    --radius-sm: 10px;
}

/* One typeface for the whole page. Native stack — no webfont to
   wait on from a CDN, so no flash of unstyled text on a slow
   connection. */
.trk-page,
.trk-page input,
.trk-page button,
.trk-page select {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
}

html {
    box-sizing: border-box;
}

.trk-page *,
.trk-page *::before,
.trk-page *::after {
    box-sizing: border-box;
}

body.trk-page {
    margin: 0;
    min-height: 100vh;
    padding: clamp(12px, 3vw, 32px);
    background: var(--bg);
    color: var(--text);
    font-size: 16px;
    line-height: 1.5;
    overflow-x: hidden;
}

/* The particles are decoration only — behind everything, matching
   the body color. The box used to be var(--surface-2) while the body was
   violet: the seam was obvious at the edge of the screen whenever
   the page ran longer than the viewport. */
#particles-js {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    background-color: var(--bg);
    z-index: 0;
    pointer-events: none;
}

/* ─── Card ────────────────────────────────────────────────── */

.trk-shell {
    position: relative;
    z-index: 10;
    width: 100%;
    max-width: 860px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    padding: clamp(1rem, 2.5vw, 1.6rem);
    border-radius: 20px;
    border: 1px solid var(--border);
    background: var(--surface);
    box-shadow: 0 24px 60px rgba(0, 0, 0, .55);
    opacity: 0;
    transform: translateY(24px);
    animation: trk-rise .6s cubic-bezier(.2, .7, .3, 1) forwards;
}

@keyframes trk-rise {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ─── Hero ────────────────────────────────────────────────── */

.trk-hero {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1.15rem 1.4rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background:
        radial-gradient(circle at 0% 0%, rgba(14, 165, 233, .16), transparent 55%),
        linear-gradient(135deg, rgba(var(--tint), .04), rgba(var(--tint), .015));
    overflow: hidden;
}

.trk-hero::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: linear-gradient(90deg, var(--trk), var(--trk-deep));
    box-shadow: 0 0 12px rgba(14, 165, 233, .6);
}

.trk-hero-icon {
    flex-shrink: 0;
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: grid;
    place-items: center;
    background: linear-gradient(135deg, var(--trk), var(--trk-deep));
    box-shadow: 0 8px 20px rgba(14, 165, 233, .35);
    overflow: hidden;
}

.trk-hero-icon img {
    width: 34px;
    height: 34px;
    object-fit: contain;
    border-radius: 8px;
}

.trk-hero-text {
    flex: 1 1 240px;
    min-width: 0;
}

.trk-hero-text h1 {
    margin: 0 0 3px;
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--ink);
}

.trk-hero-text p {
    margin: 0;
    font-size: .85rem;
    color: var(--text-faint);
}

.trk-chips {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
    margin-left: auto;
}

.trk-chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .42rem .85rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    color: var(--trk-ink);
    background: var(--trk-soft);
    border: 1px solid var(--trk-line);
    white-space: nowrap;
}

/* ─── Panel ───────────────────────────────────────────────── */

.trk-panel {
    padding: 1.15rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface);
}

.panel-title {
    display: flex;
    align-items: center;
    gap: .55rem;
    margin: 0 0 1rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--trk-ink);
}

.panel-title i {
    font-size: .95rem;
}

/* ─── Paghahanap ──────────────────────────────────────────── */

.field-label {
    display: block;
    margin-bottom: .4rem;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .3px;
    color: var(--ink-3);
}

.field-hint {
    display: block;
    margin-top: .45rem;
    font-size: .74rem;
    color: var(--text-faint);
}

.search-wrapper {
    position: relative;
}

/* The only field you type into on this page, so it is larger than
   a normal input — the page asks exactly one question. */
.search-input {
    display: block;
    width: 100%;
    min-height: 54px;
    padding: .6rem 6.5rem .6rem 2.6rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--surface-3);
    background: var(--surface-2);
    color: var(--ink-2);
    font-size: 1.1rem;
    font-weight: 600;
    letter-spacing: .06em;
    outline: none;
    transition: border-color .18s ease, box-shadow .18s ease;
}

.search-input::placeholder {
    font-weight: 400;
    letter-spacing: normal;
    color: rgba(var(--tint), .25);
}

.search-input:focus {
    border-color: var(--trk);
    box-shadow: 0 0 0 3px rgba(14, 165, 233, .18);
}

.search-icon {
    position: absolute;
    left: .85rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 1rem;
    line-height: 1;
    color: var(--text-faint);
    pointer-events: none;
}

.search-input:focus~.search-icon {
    color: var(--trk-ink);
}

.search-status {
    position: absolute;
    right: .85rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: .76rem;
    pointer-events: none;
}

.status-idle {
    color: var(--text-faint);
    font-weight: 500;
}

/* Showing and hiding is held by a class on the wrapper, not by
   `style.display` from the JS — an inline style could not be won
   back by the media query below that hides "Type to search" on a
   narrow phone. */
.status-checking {
    display: none;
    align-items: center;
    gap: .4rem;
    color: var(--trk-ink);
    font-weight: 600;
}

.search-wrapper.is-checking .status-idle {
    display: none;
}

.search-wrapper.is-checking .status-checking {
    display: inline-flex;
}

.spinner {
    flex-shrink: 0;
    width: 14px;
    height: 14px;
    animation: spin 1s linear infinite;
}

.spinner-circle {
    stroke-dasharray: 50;
    stroke-dashoffset: 25;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

/* ─── Status message ──────────────────────────────────────── */
/* This sits below the input now, not above it. Previously the
   message box appearing pushed the field itself down while you
   were typing — the target moved under your finger. That is also
   why 60px of space is reserved there even with no message. */

.message-container:empty {
    display: none;
}

.message-box {
    display: flex;
    align-items: center;
    gap: .55rem;
    margin-top: .75rem;
    padding: .65rem .85rem;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    font-size: .84rem;
    font-weight: 500;
    line-height: 1.45;
    animation: trk-fade .25s ease;
}

@keyframes trk-fade {
    from {
        opacity: 0;
        transform: translateY(-3px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.message-box svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.message-checking,
.message-info {
    background: var(--trk-soft);
    border-color: var(--trk-line);
    color: var(--trk-ink);
}

.message-success {
    background: rgba(16, 185, 129, .12);
    border-color: rgba(16, 185, 129, .25);
    color: var(--ok-ink);
}

.message-error {
    background: rgba(239, 68, 68, .12);
    border-color: rgba(239, 68, 68, .25);
    color: var(--bad-ink);
}

@keyframes checkmarkDraw {
    0% {
        stroke-dasharray: 0, 100;
    }

    100% {
        stroke-dasharray: 100, 0;
    }
}

.checkmark-icon {
    animation: checkmarkDraw .5s ease-out;
}

/* ─── Naghihintay na estado ───────────────────────────────── */
/* The bottom of the page used to be blank before you searched —
   it looked half-loaded when you arrived. */

.trk-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: 2.5rem 1.5rem;
    border-radius: var(--radius);
    border: 1px dashed rgba(var(--tint), .13);
    background: rgba(var(--tint), .015);
    text-align: center;
}

.trk-placeholder i {
    font-size: 2rem;
    line-height: 1;
    color: rgba(125, 211, 252, .35);
}

.trk-placeholder h2 {
    margin: .35rem 0 0;
    font-size: .95rem;
    font-weight: 700;
    color: var(--ink-2);
}

.trk-placeholder p {
    margin: 0;
    max-width: 34ch;
    font-size: .82rem;
    color: var(--text-faint);
}

/* ─── Resulta ─────────────────────────────────────────────── */

.results-container {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    animation: trk-rise .45s cubic-bezier(.2, .7, .3, 1) backwards;
}

/* Who the student is. This used to be four "Label: Value" rows —
   the name and the section carried equal weight. The name is what
   the eye looks for to confirm the right person was found. */
.trk-identity {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1.15rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background:
        radial-gradient(circle at 0% 0%, rgba(14, 165, 233, .1), transparent 55%),
        var(--surface);
}

.trk-avatar {
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: grid;
    place-items: center;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--on-accent);
    background: linear-gradient(135deg, var(--trk), var(--trk-deep));
    box-shadow: 0 8px 20px rgba(14, 165, 233, .3);
}

/* The student's photo, when there is one. It COVERS the initials
   rather than replacing them: att_display.php gives the <img> an
   `onerror` that removes it, so a row in student_photos whose file
   is gone falls back to the letters instead of showing a broken
   image. Same arrangement as .dash-act-avatar on the dashboard.

   The 1px inset ring keeps a pale photo from bleeding into a pale
   card edge — the tile is the first thing you check to confirm the
   search found the right person. */
.trk-avatar img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
    box-shadow: inset 0 0 0 1px rgba(var(--tint), .12);
}

.trk-identity-text {
    flex: 1 1 200px;
    min-width: 0;
}

.trk-identity-text h2 {
    margin: 0 0 .35rem;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--ink);
    overflow-wrap: anywhere;
}

.trk-meta {
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
}

.trk-meta span {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .3rem .7rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 600;
    color: var(--ink-3);
    background: rgba(var(--tint), .05);
    border: 1px solid rgba(var(--tint), .1);
}

.trk-meta span i {
    color: var(--trk-ink);
}

/* ── Stats ──
   This used to be one 72px number pulsing continuously. Motion is
   the first thing the eye catches, and it came back every two
   seconds while you were reading the list below. */
.trk-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .75rem;
}

/* The value is pinned to the bottom: on a narrow screen "Last
   attended" wraps to two lines while "Subjects" stays on one — in
   normal flow the two numbers beside each other would sit at
   different heights. */
.trk-stat {
    display: flex;
    flex-direction: column;
    padding: 1rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface);
}

.trk-stat-label {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-faint);
}

.trk-stat-value {
    margin-top: auto;
    padding-top: .35rem;
    font-size: 1.8rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--ink);
}

/* The date is text, not a number — it should not be as tall as the
   figures beside it, or it overruns its box. */
.trk-stat-value.is-text {
    font-size: 1.05rem;
    font-weight: 600;
}

/* Only the primary figure carries color: it is the page's answer to
   "how many times did I attend?" */
.trk-stat.is-primary {
    background:
        radial-gradient(circle at 100% 0%, rgba(14, 165, 233, .14), transparent 60%),
        var(--surface);
    border-color: var(--trk-line);
}

.trk-stat.is-primary .trk-stat-label {
    color: var(--trk-ink);
}

/* Absences are a status — red is the page's "absent" — so the tile
   takes it only while there is one; at zero it is a plain figure. */
.trk-stat.is-absent {
    background:
        radial-gradient(circle at 100% 0%, rgba(239, 68, 68, .12), transparent 60%),
        var(--surface);
    border-color: rgba(239, 68, 68, .3);
}

.trk-stat.is-absent .trk-stat-label {
    color: var(--bad-ink);
}

/* How an absence is counted, under the figures it explains. */
.trk-note {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    margin: 0;
    font-size: .78rem;
    line-height: 1.45;
    color: var(--text-dim);
}

.trk-note i {
    margin-top: .1rem;
    color: var(--trk-ink);
}

/* ── Subjects ── */

.subjects-container {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.subject-card {
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface);
    overflow: hidden;
}

.subject-header {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    padding: .9rem 1.05rem;
    border-bottom: 1px solid var(--border);
    background: rgba(var(--tint), .02);
}

.subject-header h3 {
    margin: 0;
    font-size: .95rem;
    font-weight: 700;
    color: var(--ink-2);
    overflow-wrap: anywhere;
}

.instructor-name {
    margin: .15rem 0 0;
    font-size: .76rem;
    color: var(--text-faint);
}

.subject-heading {
    flex: 1 1 180px;
    min-width: 0;
}

/* This count is green because it means attended — that is a status,
   not decoration. The old violet (#47468e) said nothing. */
.subject-count {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .32rem .75rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 700;
    white-space: nowrap;
    color: var(--ok-ink);
    background: rgba(16, 185, 129, .12);
    border: 1px solid rgba(16, 185, 129, .25);
}

/* Beside the green count, never instead of it: both are true. */
.subject-absent {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .32rem .75rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 700;
    white-space: nowrap;
    color: var(--bad-ink);
    background: rgba(239, 68, 68, .12);
    border: 1px solid rgba(239, 68, 68, .28);
}

.class-count {
    margin: .2rem 0 0;
    font-size: .76rem;
    color: var(--text-dim);
}

/* An enrolled subject whose class has not been scanned yet. */
.subject-empty {
    margin: 0;
    padding: .85rem 1.05rem;
    font-size: .82rem;
    color: var(--text-faint);
}

/* ── Table ──
   In its own box with `overflow-x` — on a 320px screen the three
   columns used to overflow and drag the whole page sideways. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.attendance-table {
    width: 100%;
    border-collapse: collapse;
}

.attendance-table th {
    padding: .6rem 1.05rem;
    text-align: left;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--trk-ink);
    background: rgba(14, 165, 233, .08);
    border-bottom: 1px solid var(--trk-line);
}

.attendance-table td {
    padding: .65rem 1.05rem;
    font-size: .85rem;
    color: var(--ink-3);
    border-bottom: 1px solid rgba(var(--tint), .05);
}

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

.attendance-table tbody tr:hover td {
    background: rgba(14, 165, 233, .07);
}

.attendance-table .col-num {
    width: 3.5rem;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
}

.attendance-table .cell-date {
    color: var(--ink-2);
    font-weight: 600;
    white-space: nowrap;
}

.attendance-table .cell-day {
    display: block;
    font-size: .72rem;
    font-weight: 400;
    color: var(--text-faint);
}

/* With only three columns the browser splits the leftover width and
   leaves the time floating in the middle of a large gap. Anchoring
   it right gives every row two clean edges. */
.attendance-table .col-time {
    text-align: right;
}

.attendance-table .cell-time {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Before the time, not after it: the column is right-aligned, so
   the times keep one clean edge whether or not a row is late. */
.attendance-table .late-tag {
    display: inline-block;
    margin-right: .35rem;
    padding: .05rem .45rem;
    border-radius: 999px;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .03em;
    color: var(--warn-ink);
    background: rgba(245, 158, 11, .12);
    border: 1px solid rgba(245, 158, 11, .3);
}

/* A day the class met without the student: where the time would be. */
.attendance-table .absent-tag {
    display: inline-block;
    padding: .05rem .45rem;
    border-radius: 999px;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .03em;
    color: var(--bad-ink);
    background: rgba(239, 68, 68, .12);
    border: 1px solid rgba(239, 68, 68, .3);
}

.attendance-table tr.is-absent .cell-date {
    color: var(--text-dim);
}

/* ─── Empty / nothing found ───────────────────────────────── */

.no-results {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    padding: 2.5rem 1.5rem;
    border-radius: var(--radius);
    border: 1px dashed rgba(var(--tint), .13);
    background: rgba(var(--tint), .015);
    text-align: center;
}

.no-results svg {
    width: 44px;
    height: 44px;
    color: rgba(var(--tint), .22);
}

.no-results h3 {
    margin: .25rem 0 0;
    font-size: .95rem;
    font-weight: 700;
    color: var(--ink-2);
}

.no-results p {
    margin: 0;
    max-width: 38ch;
    font-size: .82rem;
    color: var(--text-faint);
}

.hidden {
    display: none;
}

/* ─── Footer ──────────────────────────────────────────────── */
/* The colors are already written as inline styles in
   components/footer.php — all that is added here is a divider rule.
   The old `footer { background: var(--surface-slate) }` never beat those inline
   styles: it was a dead rule. */
.trk-page footer {
    border-top: 1px solid var(--border);
}

/* ─── Responsive ──────────────────────────────────────────── */

@media (max-width: 640px) {
    /* The hero becomes a real column when narrow rather than relying
       on flex wrapping — that way the logo is guaranteed its own row
       instead of breaking wherever the title length happens to put
       it. Matches the QR generator, which does the same at its own
       breakpoint (860px, where its two-column shell collapses). */
    .trk-hero {
        padding: 1rem;
        flex-direction: column;
        align-items: stretch;
        gap: .85rem;
    }

    /* The whole hero centers: logo, title, subtitle and chips. With
       only the chips wrapping and everything else left aligned it
       reads as an accident — they should all follow one axis. */
    .trk-hero-icon {
        width: 44px;
        height: 44px;
        border-radius: 12px;
        align-self: center;
    }

    .trk-hero-icon img {
        width: 28px;
        height: 28px;
    }

    .trk-hero-text {
        flex-basis: auto;
        text-align: center;
    }

    .trk-hero-text h1 {
        font-size: 1.15rem;
    }

    .trk-chips {
        margin-left: 0;
        width: 100%;
        justify-content: center;
    }

    /* In a narrow field "Type to search" competes with the
       placeholder saying the same thing. The spinner stays — it is
       the only part that carries information. */
    .status-idle {
        display: none;
    }

    .search-input {
        padding-left: 2.4rem;
        padding-right: 2.8rem;
        font-size: 1rem;
    }

    .search-wrapper.is-checking .status-checking span {
        display: none;
    }

    /* Two columns: the large figures stay readable, unlike three
       squeezed into 320px. */
    .trk-stats {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .trk-stat.is-primary {
        grid-column: 1 / -1;
    }

    .attendance-table th,
    .attendance-table td {
        padding-left: .75rem;
        padding-right: .75rem;
    }

    .subject-header {
        padding: .8rem .75rem;
    }
}

/* Respects the system setting — the same thing shape.js does for
   the particles. */
@media (prefers-reduced-motion: reduce) {

    .trk-shell,
    .results-container,
    .message-box,
    .checkmark-icon {
        animation: none;
        opacity: 1;
        transform: none;
    }
}
