/*
 * student-pages.css - the student area's PAGES, as opposed to its chrome.
 *
 * Owns: home (greeting, intro, announcements, the general-info card that moved
 * here), the schedule page, the meeting page, the account page, the login page,
 * and the mascot frames the area uses on empty and success states.
 *
 * Linked after student.css and the two sheets above it, so it may override the
 * shared kit. Anything that belongs to the side menu goes in student-shell.css
 * and anything that belongs to the materials navigation goes in
 * student-materials.css - keep the three disjoint.
 */

/* ── Why every area token below carries a fallback ───────────────────────────
   The design's token block is declared ONCE, on `.stu-shell`, in
   student-shell.css - which is what keeps these tokens off `:root`, where the
   marketing bundle every visitor downloads would inherit them site-wide.
   `.stu-login` has no `.stu-shell` ancestor: the login view is its own root,
   outside StudentShell, because it is the one route the auth guard leaves open
   and there is no rail to draw for somebody who is not signed in yet. So on the
   first screen a student ever sees, a bare `var(--stu-t-xl)` resolves to
   nothing - and an invalid var() does NOT fall back to the property's initial
   value, it makes the whole declaration compute to `inherit`, which is how a
   21px card title silently becomes whatever its parent happened to be.

   Every fallback below is the design specification's own literal for that
   token, so where the token does resolve it wins and the two can never
   disagree. Do not "tidy these up" by deleting them. */

/* ── The mascot frame ───────────────────────────────────────────────────────
   A fixed square box so the artwork never shifts layout while it decodes, and
   so the character keeps its proportions whatever the call site asks for.
   SIZE ALWAYS COMES FROM THE CALL SITE, never from here - see the table in
   src/components/student/StudentMascot.vue for which page shows which pose and
   at what size. The 96px floor in that file is a brand rule, not a preference:
   below it the 3-unit stroke aliases into fuzz. */
.stu-mascot {
    aspect-ratio: 1 / 1;
    flex: none;
    pointer-events: none;
    user-select: none;
}

.stu-mascot svg {
    display: block;
    inline-size: 100%;
    block-size: 100%;
}

/* ── The glass card ─────────────────────────────────────────────────────────
   ONE recipe and one modifier, and every panel this redesign adds uses it.
   `.stu-card` in student.css is left exactly as it is (that file is read-only
   for this work), so the two coexist: a surface opts in by carrying
   `.stu-glass` instead.

   The structure is lifted from `.module-chapter` in public/css/module-view.css,
   which is the house's canonical glass: two radial ellipses over a white ->
   pale-blue linear, plus the same backdrop-filter `.stu-card` already uses.
   Depth, not colour and not a border weight, is what separates the rungs - and
   there are three of them, so nothing here may invent a fourth. */
.stu-glass {
    position: relative;
    isolation: isolate;
    background:
        radial-gradient(ellipse at 15% 10%, rgba(8, 148, 255, 0.10), transparent 65%),
        radial-gradient(ellipse at 90% 95%, rgba(189, 50, 214, 0.07), transparent 65%),
        linear-gradient(180deg,
            var(--stu-glass-top, rgba(255, 255, 255, 0.88)),
            var(--stu-glass-bottom, rgba(239, 246, 255, 0.62)));
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    border: 1px solid var(--stu-glass-line, rgba(98, 98, 234, 0.14));
    border-radius: var(--radius-lg);
    box-shadow: var(--stu-lift-1, 0 2px 12px rgba(0, 60, 130, 0.06));
    padding: var(--space-lg);
    /* The one addition to the recipe as specified, and it is here so the swap is
       a drop-in: `.stu-card` carries `margin-bottom: var(--space-md)`, so a
       surface that trades one class for the other must not silently lose the
       gap between itself and the next card. */
    margin-block-end: var(--space-md);
}

/* The specular edge: one inset hairline of near-white along the block start.
   It is the whole difference between a translucent panel reading as GLASS and
   reading as a tinted rectangle - the same trick `.module-hero-icon` uses. It
   is inset from the corners so it never crosses the border radius. */
.stu-glass::before {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline: var(--stu-s-3, 12px);
    block-size: 1px;
    background: linear-gradient(90deg,
        transparent,
        var(--stu-specular, rgba(255, 255, 255, 0.95)) 22%,
        var(--stu-specular, rgba(255, 255, 255, 0.95)) 78%,
        transparent);
    pointer-events: none;
    z-index: 2;
}

/* Rung two: a card that floats OVER other cards. For the one card on a page
   that is the reason the page exists. */
.stu-glass--raised {
    box-shadow: var(--stu-lift-2, 0 10px 32px rgba(0, 60, 130, 0.10));
}

/* The two "this door is closed, here is why" notices keep their own measures,
   padding and centring from student.css and take only the surface from the
   recipe above. Two classes deep so the padding those rules set survives:
   `.stu-glass` and `.stu-frozen` tie on specificity and this sheet is linked
   later, so a single-class rule would quietly shrink both cards by 16px. */
.stu-card.stu-frozen,
.stu-card.stu-locked {
    position: relative;
    isolation: isolate;
    background:
        radial-gradient(ellipse at 15% 10%, rgba(8, 148, 255, 0.10), transparent 65%),
        radial-gradient(ellipse at 90% 95%, rgba(189, 50, 214, 0.07), transparent 65%),
        linear-gradient(180deg,
            var(--stu-glass-top, rgba(255, 255, 255, 0.88)),
            var(--stu-glass-bottom, rgba(239, 246, 255, 0.62)));
    border-color: var(--stu-glass-line, rgba(98, 98, 234, 0.14));
    box-shadow: var(--stu-lift-2, 0 10px 32px rgba(0, 60, 130, 0.10));
}

.stu-card.stu-frozen::before,
.stu-card.stu-locked::before {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline: var(--stu-s-3, 12px);
    block-size: 1px;
    background: linear-gradient(90deg,
        transparent,
        var(--stu-specular, rgba(255, 255, 255, 0.95)) 22%,
        var(--stu-specular, rgba(255, 255, 255, 0.95)) 78%,
        transparent);
    pointer-events: none;
    z-index: 2;
}

/* ── Titles that carry an icon ──────────────────────────────────────────────
   An additive modifier, never a redefinition of `.stu-section-title` itself:
   that class is the shared kit and the materials, prep and reference surfaces
   all render it, so turning it into a flex box here would reach into two other
   workstreams' pages from a sheet they never open.

   THE `.app-icon-svg` RULE HAS TO BE TWO CLASSES DEEP. public/css/app-icon.css
   is linked LAST in index.html (it is the runtime-free FontAwesome shim), and
   its bare `.app-icon-svg { height: 1em }` beats any single-class rule here on
   source order. Fixed block-size with `inline-size: auto`, because the
   FontAwesome viewBoxes are not all square and pinning both axes squashes the
   wide ones. */
.stu-title-icon {
    display: flex;
    align-items: center;
    gap: 10px;
}

.stu-title-icon .app-icon-svg {
    block-size: 17px;
    inline-size: auto;
    flex: none;
    color: var(--text-secondary);
    vertical-align: baseline;
}

/* ── The empty state ────────────────────────────────────────────────────────
   ONE frame for every "there is nothing here yet" on these pages: mascot on
   top, one line of fact, an optional single action.
   Deliberately NOT a bordered card - an empty state that draws a box round the
   absence only makes the absence louder. */
.stu-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-md);
    padding: var(--space-xl) var(--space-lg);
    max-inline-size: 46ch;
    margin-inline: auto;
}

/* 128px and not smaller. Below it the artwork's 3-unit stroke inside a 240
   viewBox falls under a device pixel and the robot reads as a smudge of
   gradient rather than as a character. */
.stu-empty__mascot {
    inline-size: 128px;
    block-size: 128px;
}

.stu-empty__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--stu-t-xl, 21px);
    font-weight: 300;
    letter-spacing: 0;
    color: var(--text-color);
}

.stu-empty__text {
    margin: 0;
    font-size: var(--stu-t-md, 15px);
    line-height: 1.7;
    color: var(--text-secondary);
}

/* ── Home ───────────────────────────────────────────────────────────────────
   The greeting and the mascot are one band: the robot waves at the reading END
   of the line (physical left under RTL), where it closes the head rather than
   pushing the reader's own name off the start of it. */
.stu-page-head--figure {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
}

/* `0 1 auto` AND NOT `1 1 auto`, which is the difference between a band and a
   stray. The greeting block grows to nothing it needs: its h1 is a block whose
   text is right-aligned by the global RTL, so a growing `__main` stretches to
   the full 1040px column, parks the glyphs against the reading edge and leaves
   the robot alone in the far margin - measured at 1440 as 96px of artwork with
   about 700px of empty page between it and the first letter of the student's
   own name. Shrink-to-fit puts the two back within one --space-lg of each
   other at every width; it still shrinks (min-inline-size: 0 below) when a long
   name needs the room, which is the only case `1 1 auto` was protecting. */
.stu-page-head--figure .stu-page-head__main {
    flex: 0 1 auto;
    min-inline-size: 0;
}

.stu-page-head__title {
    letter-spacing: -0.02em;
}

/* 96px is the brand floor for the character and it is held at every width: the
   head has room for it even on a 390px screen, and a mascot shrunk to fit is a
   mascot that should not have been placed. */
.stu-home-head__mascot {
    inline-size: 96px;
    block-size: 96px;
}

/* The one brand hairline this page is allowed. The gradient budget for the home
   page is the rail's programme mark plus this rule and nothing else, so it is
   spent on the single transition worth marking: the greeting block giving way
   to the page's actual content. `.brand-hairline`'s own margin is `56px auto`,
   far too tall for a seam inside a content column. */
.stu-home__rule {
    margin-block: var(--space-lg) var(--space-xl);
}

.stu-home-section {
    margin-block-end: var(--space-xl);
}

.stu-home-section:last-child {
    margin-block-end: 0;
}

.stu-home-section__title {
    margin: 0 0 var(--space-md);
    font-family: var(--font-display);
    font-size: var(--stu-t-xl, 21px);
    font-weight: 500;
    letter-spacing: 0;
    color: var(--text-color);
}

/* The staff-written welcome. Reading copy, so it takes the reading size and a
   measure: a 1040px column of 17px text runs to about 120 characters a line,
   roughly twice what anybody reads comfortably. */
.stu-home-intro__text {
    max-inline-size: 72ch;
    font-size: var(--stu-t-lg, 17px);
    line-height: 1.75;
    color: var(--text-color);
}

.stu-announcement {
    margin-block-end: var(--space-md);
}

.stu-announcement:last-child {
    margin-block-end: 0;
}

.stu-announcement__body {
    max-inline-size: 72ch;
    font-size: var(--stu-t-md, 15px);
    line-height: 1.7;
    color: var(--text-secondary);
}

/* Tabular figures in the BODY face - never the mono stack, which would drop the
   Hebrew beside them into Courier.
   And deliberately NO `dir="ltr"` here, unlike every other numeral run in this
   sheet: `formatHebrewDateLong` returns the month as a Hebrew word ("1
   בספטמבר 2026"), so the string is Hebrew with figures in it and belongs at the
   paragraph's own level. Isolating it LTR would move the year to the wrong
   side of the month. */
.stu-announcement__date {
    font-variant-numeric: tabular-nums;
    font-size: var(--stu-t-xs, 12px);
}

/* The general information card: staff prose with the teach pose beside it. The
   robot sits at the reading start so the eye meets it before the text, and the
   text keeps its own measure rather than wrapping round the figure. */
.stu-home-info {
    display: flex;
    align-items: flex-start;
    gap: var(--space-lg);
}

.stu-home-info__mascot {
    inline-size: 96px;
    block-size: 96px;
}

.stu-home-info__text {
    flex: 1 1 auto;
    min-inline-size: 0;
    max-inline-size: 72ch;
    font-size: var(--stu-t-lg, 17px);
    line-height: 1.75;
    color: var(--text-color);
}

/* ── Schedule: one meeting row ──────────────────────────────────────────────
   The row keeps its shape from student.css. What changes is the two places it
   spent a mono face on numerals sitting beside Hebrew, and the way a meeting
   that has already been held is marked. */
.stu-session-item {
    border-color: var(--stu-glass-line, rgba(98, 98, 234, 0.14));
}

/* THE STATE MARK IS THE NUMERAL, AND IT SPENDS NOTHING ON THE PAST.
   A held meeting used to be the whole row at `opacity: 0.65`, which put 13px
   secondary ink near 2.8:1 across every row of a course that has started, and
   read as "none of this is available to you" rather than as "these already
   happened". The numeral carries the state instead: a filled blue disc is a
   meeting still ahead, a thin ring is one already held, and the row's own ink
   stays at full contrast either way. */
.stu-session-item--past {
    opacity: 1;
}

.stu-session-item__index {
    font-family: var(--font-body);
    font-variant-numeric: tabular-nums;
    font-size: var(--stu-t-sm, 13px);
}

.stu-session-item--past .stu-session-item__index {
    background: transparent;
    border: 1px solid var(--border-default);
    color: var(--text-tertiary);
}

.stu-session-item__time {
    font-family: var(--font-body);
    font-variant-numeric: tabular-nums;
    font-size: var(--stu-t-xs, 12px);
}

.stu-session-item__when .app-icon-svg {
    block-size: 13px;
    inline-size: auto;
}

/* ── Account ────────────────────────────────────────────────────────────────
   The page is long and mostly money. Its three section titles used to carry a
   brand hairline each; the gradient budget allows this page ONE instance beside
   the rail's programme mark, and it is spent on the seam above the password
   card - the one place on the page where the reader changes task rather than
   scrolls on. The other two seams keep a hairline, just not the brand's: the
   same neutral violet fade the side menu uses between its own blocks. */
.stu-account-section__rule--quiet {
    inline-size: min(220px, 100%);
    block-size: 1px;
    margin: 0 0 var(--space-lg);
    /* `margin-inline-start: 0` pins the rule to the reading start, which under
       RTL is the physical right, directly under where the title begins. */
    margin-inline-start: 0;
    border: 0;
    border-radius: 0;
    /* 270deg and not 90: a gradient angle is PHYSICAL and does not flip with
       direction, so 90deg would put the solid end at the physical left - the
       far end from the title - and fade the rule out exactly where it should
       be strongest. 270 points the gradient line leftwards, so the first stop
       lands on the right. */
    background: linear-gradient(270deg, rgba(98, 98, 234, 0.28), rgba(98, 98, 234, 0.04));
    opacity: 1;
}

.stu-account-section__title {
    letter-spacing: 0;
}

/* The one brand hairline on the account page, above the password card. Centred
   in the column, unlike the section rules above: it separates two cards rather
   than introducing a title. */
.stu-account__rule {
    margin-block: var(--space-lg);
}

/* The account section's head, and the LAST mascot on this page: money is a
   mascot exclusion zone, so nothing from the payments section down carries
   one. */
.stu-account-head {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-block-end: var(--space-md);
}

/* Shrink-to-fit for the same reason the home greeting is, and here the effect
   was worse: this h2 is ALSO a flex box (it carries `.stu-title-icon`), so
   growing it stretched the icon-and-label group to the full column width, held
   it against the reading edge and stranded the robot 693px away at 1440 and
   749px at 1024 - a lone 96px figure in an otherwise empty margin. */
.stu-account-head .stu-account-section__title {
    flex: 0 1 auto;
    min-inline-size: 0;
    margin-block-end: 0;
}

.stu-account-head__mascot {
    inline-size: 96px;
    block-size: 96px;
}

.stu-account__email {
    font-size: var(--stu-t-md, 15px);
}

/* The signed-in address, and the only place on the page it appears. The LTR
   isolation is on the markup; this only keeps a long address from being clipped
   at its START, which is the half that identifies the person. */
.stu-account__email-value {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Enrollment cards ───────────────────────────────────────────────────────
   Dates and cohort numbers are figures inside Hebrew labels, so they take
   tabular figures in the body face and are isolated with `dir="ltr"` in the
   markup. Their ink stays solid: a numeral is never the place for the brand
   gradient, whatever its weight. */
.stu-facts__item dd {
    font-variant-numeric: tabular-nums;
}

.stu-enrollment__title {
    font-size: var(--stu-t-xl, 21px);
    letter-spacing: 0;
}

.stu-certificate {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
}

.stu-certificate .app-icon-svg {
    block-size: 15px;
    inline-size: auto;
}

/* ── Login ──────────────────────────────────────────────────────────────────
   The first screen a student ever sees, and the only one in the area with no
   rail, no top bar and no `.stu-shell` ancestor - which is the reason every
   token in this sheet carries its literal as a fallback.

   The programme mark is this page's single brand-gradient instance. The
   hairline that used to sit under it is gone: a gradient rule directly beneath
   a gradient wordmark is one gradient too many, and the budget for the login
   page is the mark alone. */
.stu-login__header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-sm);
    /* A DEFINITE inline size, and it is load-bearing rather than cosmetic.
       `.stu-login` is a centred flex column, so this header is a flex item that
       would otherwise shrink to fit - and `.stu-login__logo svg` in student.css
       is `width: 100%; height: auto`, which inside a shrink-to-fit ancestor
       resolves `max-width: 100%` against a width still being measured and
       settles at ZERO. Logo10xCourse has a viewBox and no intrinsic size, so
       there is nothing to fall back to and the mark simply disappears.
       public/css/logo-10x-course.css documents the same trap at length. */
    inline-size: 100%;
    max-inline-size: 420px;
    margin-block-end: var(--space-xl);
    text-align: center;
}

/* The other half of the same guarantee: a definite width for the svg's
   `width: 100%` to resolve against. 190px is where student.css caps the mark;
   this only gives that cap something to be a percentage of. */
.stu-login__logo {
    inline-size: 220px;
    max-inline-size: 100%;
}

.stu-login__mascot {
    inline-size: 96px;
    block-size: 96px;
    margin-block-end: var(--space-xs);
}

.stu-login__title {
    margin: 0;
    letter-spacing: 0;
}

/* The instruction under the title. It used to be a second `h2.stu-login__title`,
   which put two headings of identical rank and identical size on a page with
   one subject; it is a sentence, so it is typed as one. */
.stu-login__lead {
    margin: 0;
    max-inline-size: 42ch;
    font-size: var(--stu-t-md, 15px);
    line-height: 1.6;
    color: var(--text-secondary);
}

/* Same glass as every card behind the login, and the same specular edge. The
   card keeps its `max-inline-size` and the roomier `--space-xl` padding from
   student.css: it is the one card on the site whose padding was measured
   against the fixed-pixel Google pill it holds. */
.stu-login__card {
    position: relative;
    isolation: isolate;
    background:
        radial-gradient(ellipse at 15% 10%, rgba(8, 148, 255, 0.10), transparent 65%),
        radial-gradient(ellipse at 90% 95%, rgba(189, 50, 214, 0.07), transparent 65%),
        linear-gradient(180deg,
            var(--stu-glass-top, rgba(255, 255, 255, 0.88)),
            var(--stu-glass-bottom, rgba(239, 246, 255, 0.62)));
    border-color: var(--stu-glass-line, rgba(98, 98, 234, 0.14));
    box-shadow: var(--stu-lift-2, 0 10px 32px rgba(0, 60, 130, 0.10));
}

.stu-login__card::before {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline: var(--stu-s-3, 12px);
    block-size: 1px;
    background: linear-gradient(90deg,
        transparent,
        var(--stu-specular, rgba(255, 255, 255, 0.95)) 22%,
        var(--stu-specular, rgba(255, 255, 255, 0.95)) 78%,
        transparent);
    pointer-events: none;
    z-index: 2;
}

/* ── The focus ring ─────────────────────────────────────────────────────────
   The area-wide rule lives in student-shell.css, on `.stu-shell :is(...)`, and
   is NOT repeated here: home, schedule and account all sit inside the shell and
   are covered by it. What follows is the two places that rule cannot reach.

   FIRST, the login page, which has no `.stu-shell` ancestor at all - the login
   view is its own root, being the one route the auth guard leaves open, so the
   very first screen a student meets would otherwise be the only unringed one in
   the area. `:focus-visible` and not `:focus`, so a mouse press never leaves a
   ring standing behind it; the box-shadow is the clip-proof companion to the
   outline, which is cut at a clipping ancestor where a shadow drawn inside the
   element's own box is not. */
.stu-login :is(a, button, summary, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
    box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.22);
    border-radius: var(--radius-sm);
}

/* SECOND, the meeting row, which the area rule reaches but mis-shapes: it sets
   `border-radius: var(--radius-sm)` so a ring never overruns a small control,
   and this row is a full-width `--radius-lg` card whose corners would visibly
   snap in on focus. Same specificity as the area rule and a later sheet, so
   this wins on source order. */
.stu-session-item:focus-visible {
    border-radius: var(--radius-lg);
}

/* ── Tablet ─────────────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
    .stu-home__rule {
        margin-block: var(--space-md) var(--space-lg);
    }
}

/* ── Phone ──────────────────────────────────────────────────────────────── */
@media (max-width: 767px) {
    /* The greeting keeps the mascot beside it rather than stacking: 96px is the
       brand floor and a 390px head still leaves about 240px for the name, which
       is more than the greeting has ever needed. What moves is the gap. */
    .stu-page-head--figure {
        gap: var(--space-md);
    }

    /* The general-information card stacks: 96px of robot plus a 72ch measure
       does not fit side by side on a phone, and the text is the point. */
    .stu-home-info {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--space-md);
    }

    .stu-account-head {
        gap: var(--space-sm);
    }

    .stu-login__header {
        margin-block-end: var(--space-lg);
    }
}

/* ── Reduced motion ─────────────────────────────────────────────────────────
   student-shell.css carries the area-wide block; this is the copy for the one
   page that sits outside `.stu-shell`. Colour changes are kept and only motion
   is dropped: a state that exists ONLY as movement is a state a reduced-motion
   reader never sees at all. */
@media (prefers-reduced-motion: reduce) {
    .stu-login *,
    .stu-login *::before,
    .stu-login *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
