/*
 * student-shell.css - the student area's LAYOUT CHROME.
 *
 * Owns: the area's token block, the page ground, the side menu panel (brand
 * mark, identity block, nav groups, the expanding submenus, the sign-out row
 * pinned to the bottom), the phone/tablet top bar and its drawer, the
 * live-meeting banner, the one focus ring, and the reduced-motion and
 * coarse-pointer blocks.
 *
 * Linked immediately AFTER student.css, so it may override that file's shared
 * kit without inflating specificity. student.css itself is read-only for this
 * area's work: dead rules there are removed in one deliberate cleanup pass,
 * never by a second file racing it.
 *
 * BECAUSE student.css IS READ-ONLY, EVERY RULE OF ITS THAT THIS FILE REPLACES
 * MUST BE REPLACED IN FULL, INCLUDING INSIDE A MEDIA QUERY. A media query adds
 * no specificity, so student.css's `@media (max-width: 1024px) .stu-nav
 * { position: fixed }` and this file's unconditional `.stu-nav { position:
 * sticky }` are the same weight and SOURCE ORDER decides - which means the
 * later file wins at every width, drawer included. The tablet block near the
 * bottom therefore re-states the whole drawer rather than only its deltas.
 *
 * Breakpoints are the house pair, 1024px (tablet) and 767px (phone). RTL is
 * global; use padding-inline / margin-inline rather than left/right wherever
 * the value is directional.
 */

/* ── TOKENS ──────────────────────────────────────────────────────────────────
   The ONE token block for the whole student area, and it is on .stu-shell,
   NEVER on :root. This sheet and its three siblings ship in the PUBLIC bundle
   that every marketing page loads, so a :root token here would leak site-wide
   from a file nobody opens when they edit the landing page. That is why the
   warning trio already sits on this selector in student.css - and it is NOT
   repeated here: tests/studentAccountTabs.spec.ts byte-pins that declaration by
   exact selector text in that file, and a second warm family beside it is one
   family too many. */
.stu-shell {
    /* DEPTH LADDER. Four rungs, and nothing in this area may invent a fifth or
       a shadow of its own. All cool-blue rgba(0, 60, 130, *), never black - the
       shadow family the rest of the site already uses. */
    --stu-lift-1: 0 2px 12px rgba(0, 60, 130, 0.06);                     /* a panel resting on the ground */
    --stu-lift-2: 0 10px 32px rgba(0, 60, 130, 0.10);                    /* a strip floating over the panel */
    --stu-lift-3: 0 24px 64px rgba(0, 60, 130, 0.13),
                  0 2px 6px rgba(0, 60, 130, 0.05);                      /* the object in focus */
    --stu-well:   inset 0 1px 3px rgba(0, 60, 130, 0.08),
                  inset 0 0 0 1px rgba(98, 98, 234, 0.09);               /* a recess CUT INTO a panel */

    /* Glass edges. The 1px lines that make a translucent panel read as glass
       rather than as a tinted rectangle. */
    --stu-glass-line: rgba(98, 98, 234, 0.14);       /* a seam facing content */
    --stu-glass-line-soft: rgba(98, 98, 234, 0.09);  /* a divider inside one surface */
    --stu-specular: rgba(255, 255, 255, 0.95);       /* the inset top highlight */

    /* Glass fills. The three stacked backgrounds are written out per surface;
       these are the two white stops the ladder varies. */
    --stu-glass-top: rgba(255, 255, 255, 0.88);
    --stu-glass-bottom: rgba(239, 246, 255, 0.62);
    --stu-well-tint: rgba(8, 148, 255, 0.055);       /* the recess ground */
    --stu-sheet: rgba(255, 255, 255, 0.86);          /* a raised sheet inside a recess */

    /* TYPE SCALE. Seven steps and no others. No half-pixels anywhere; the two
       documented exceptions are 14px on a level-2 nav row and 11px on a numeral
       sitting in a gutter beside a full-contrast label. */
    --stu-t-xs: 12px;    /* micro labels, meta, counters */
    --stu-t-sm: 13px;    /* level-3 nav rows, index rows, chips */
    --stu-t-md: 15px;    /* level-1 nav, UI body, controls */
    --stu-t-lg: 17px;    /* slide body, reading copy */
    --stu-t-xl: 21px;    /* card and section titles */
    --stu-t-2xl: 28px;   /* slide title */
    --stu-t-3xl: 32px;   /* page title */

    /* SPACE STEPS the global scale does not carry. Everything else uses
       --space-xs/sm/md/lg/xl. */
    --stu-s-3: 12px;
    --stu-s-5: 20px;
    --stu-s-7: 32px;

    /* Layout constants. */
    --stu-rail-w: 288px;
    --stu-drawer-w: min(320px, 88vw);
    --stu-row-1: 44px;       /* level-1 nav row */
    --stu-row-2: 40px;       /* level-2 nav row */
    --stu-row-3: 36px;       /* level-3 meeting row */
    --stu-gutter-num: 22px;  /* the meeting-number column */

    /* Motion. Four durations, one easing, and nothing else. */
    --stu-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
    --stu-dur-1: 0.16s;  /* colour */
    --stu-dur-2: 0.22s;  /* background, opacity */
    --stu-dur-3: 0.28s;  /* transform, indicators */
    --stu-dur-4: 0.32s;  /* the drawer */

    /* The one gradient value, written once so nobody retypes it. Canonical
       3-stop, identical to global.css .brand-hairline. */
    --stu-brand-3: linear-gradient(90deg, #0894FF 0%, #BD32D6 50%, #FFA304 100%);
    /* Turned, for a mark narrower than about 40px: painted at 90deg across a
       box that narrow the three stops crush into two pixels and render as one
       muddy orange line. */
    --stu-brand-3-turned: linear-gradient(180deg, #0894FF 0%, #BD32D6 50%, #FFA304 100%);

    /* The neutraliser for an INACTIVE brand wordmark. grayscale() in the filter
       shorthand works in sRGB, so #0894FF resolves to #7E7E7E and the
       brightness step takes it to about #5A5A5A - which is --text-secondary to
       within a hair, roughly 7:1. Dimming the same mark with opacity puts it
       near 3.4:1 and reads as DISABLED, on a course the student has paid for. */
    --stu-mark-quiet: grayscale(1) brightness(0.72);
}

/* ── PAGE GROUND ─────────────────────────────────────────────────────────────
   Three very soft radials over a near-white base: blue high on the
   reading-start side, violet low on the other, and one almost invisible magenta
   in the middle that stops the two reading as a two-colour wash. Flattened onto
   the shell rather than painted as blurred absolute discs - a 720px
   filter:blur() element behind a long scrolling page is a repaint tax this area
   has no reason to pay. */
.stu-shell {
    min-block-size: 100dvh;
    display: flex;
    background:
        radial-gradient(ellipse 980px 640px at 88% -8%, rgba(8, 148, 255, 0.11), transparent 62%),
        radial-gradient(ellipse 880px 720px at 4% 96%, rgba(105, 53, 216, 0.085), transparent 64%),
        radial-gradient(ellipse 700px 500px at 50% 46%, rgba(189, 50, 214, 0.03), transparent 70%),
        #FAFCFF;
    background-attachment: fixed;
}

/* The content column. */
.stu-main {
    flex: 1 1 auto;
    min-inline-size: 0;
    max-inline-size: 1040px;
    padding: var(--space-xl) clamp(var(--space-lg), 4vw, 56px) 96px;
}

/* ── THE PANEL ───────────────────────────────────────────────────────────────
   Physically right, because it is the first flex child of an RTL row. Sticky,
   full viewport height, its own flex column. THE SCROLLER IS THE NAV, not the
   panel: the brand block above it and the sign-out below it are furniture and
   must never scroll away.

   THE SEAM IS ON THE INLINE END. In RTL inset-inline-start is the physical
   RIGHT, which is the window edge, where a hairline is clipped and invisible.
   The seam that needs definition is the panel against the scrolling content on
   its physical left, which is inset-inline-end. box-shadow has no logical form,
   so the -18px x-offset is written physically and commented; this sheet is
   RTL-only.

   `gap: 0` is not decoration: student.css puts var(--space-md) between every
   child of this panel, which would add 16px above a sign-out row that is
   already pinned by a margin. */
.stu-nav {
    flex: 0 0 var(--stu-rail-w);
    inline-size: var(--stu-rail-w);
    position: sticky;
    inset-block-start: 0;
    block-size: 100dvh;
    display: flex;
    flex-direction: column;
    gap: 0;
    padding: var(--space-lg) 14px var(--space-md);
    background:
        radial-gradient(ellipse at 50% 0%, rgba(8, 148, 255, 0.07), transparent 62%),
        linear-gradient(180deg, var(--stu-glass-top), var(--stu-glass-bottom));
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    border-inline-end: 1px solid var(--stu-glass-line);
    border-inline-start: 0;
    box-shadow: -18px 0 48px rgba(0, 60, 130, 0.06);  /* physical: casts onto the page */
    overflow: clip;                                    /* not hidden: clip creates no scroll container */
}

/* ── Brand block. The mark is the only wide thing in the panel: centred, and
   given room. NO hairline directly under it - the mark IS the brand gradient,
   and a gradient rule beneath a gradient wordmark is one gradient too many on a
   surface that appears on every page of the area. The rule that separates this
   head from the nav is the soft violet one below the identity block. */
.stu-nav__brand {
    flex: 0 0 auto;
    display: flex;
    justify-content: center;
    padding: var(--space-xs) var(--space-sm) var(--stu-s-5);
    text-decoration: none;
}

/* Logo10xCourse renders 0x0 in a shrink-to-fit parent unless a definite size is
   stated: its SVG carries a viewBox and no width/height attributes, so it has a
   ratio but no intrinsic size, and a parent measuring itself from its content
   settles that cycle at zero. State the inline size on the wrapper AND on the
   drawing. See public/css/logo-10x-course.css. */
.stu-nav__brand .logo-10x-course {
    inline-size: 100%;
    max-inline-size: 196px;
}

.stu-nav__brand svg {
    inline-size: 100%;
    block-size: auto;
}

/* ── Identity: the avatar ON TOP of the name and the address, centred.
   Not a card. A centred stack on the panel itself with a soft-edged rule below
   it; a second bordered box this high in a 288px column starts a filing
   cabinet. The border-bottom student.css gives this block is replaced by that
   rule, so it is zeroed rather than left to draw a second line. */
.stu-nav__identity {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 0 var(--space-sm) var(--stu-s-5);
    text-align: center;
    position: relative;
    border-block-end: 0;
}

.stu-nav__identity::after {
    content: '';
    position: absolute;
    inset-block-end: 0;
    inset-inline: 26px;
    block-size: 1px;
    background: linear-gradient(90deg, transparent, rgba(98, 98, 234, 0.22), transparent);
}

.stu-nav__name {
    margin: 0;
    font-size: var(--stu-t-md);
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0;
    color: var(--text-color);
    max-inline-size: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* dir="ltr" in the markup AND `direction` here: an address truncated in an RTL
   context clips its START, the half that identifies the person. text-align
   CENTER, not end - the block is centred now, and `end` under direction:ltr
   computes to LEFT, which is what produced the measured 57px stagger
   student.css documents between an RTL name and an LTR address. */
.stu-nav__email {
    margin: 0;
    direction: ltr;
    text-align: center;
    font-size: var(--stu-t-sm);
    line-height: 1.35;
    color: var(--text-secondary);
    max-inline-size: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The disc keeps student.css's .stu-avatar vocabulary and its measured
   --stu-avatar-ink (#0B5CC4, 5.17:1). Only the size changes here, and the two
   things sized off it: the initials and the camera badge. Two classes deep so
   it outranks .stu-avatar--md. */
.stu-nav__identity .stu-avatar {
    inline-size: 68px;
    block-size: 68px;
    font-size: var(--stu-t-xl);
}

.stu-nav__identity .stu-avatar .app-icon-svg {
    height: 28px;
    width: auto;
}

.stu-nav__identity .stu-avatar-btn__badge {
    inline-size: 22px;
    block-size: 22px;
}

.stu-nav__identity .stu-avatar-btn__badge .app-icon-svg {
    height: 12px;
    width: auto;
}

/* ── The scroller. THE ONLY ONE in the panel.
   The fade is a MASK, not an overlay: a translucent panel has no flat colour an
   overlay could be painted in. 6px and not 14, so a focus ring on the first or
   last row never lands inside a faded band. */
.stu-nav__menu {
    flex: 1 1 auto;
    min-block-size: 0;                    /* WITHOUT THIS the menu cannot shrink and paints over sign-out */
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-block: var(--space-sm);
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 60, 130, 0.16) transparent;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 6px, #000 calc(100% - 6px), transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 6px, #000 calc(100% - 6px), transparent 100%);
}

.stu-nav__menu::-webkit-scrollbar {
    inline-size: 6px;
}

.stu-nav__menu::-webkit-scrollbar-thumb {
    background: rgba(0, 60, 130, 0.16);
    border-radius: 3px;
}

/* Group heading. No tracking, no uppercase: Hebrew is unicameral, so uppercase
   is a no-op waiting for the first Latin token in the string, and tracked caps
   is a Latin small-caps convention with no Hebrew equivalent - at 12px it is
   the least legible type on the page. Size and colour carry the label. */
.stu-nav__group-title {
    margin: var(--space-md) 0 var(--space-xs);
    padding-inline: 14px;
    font-size: var(--stu-t-xs);
    font-weight: 500;
    letter-spacing: 0;
    color: var(--text-secondary);
}

.stu-nav__group-title:first-child {
    margin-block-start: 0;
}

/* ── LEVEL 1 ─────────────────────────────────────────────────────────────────
   `.stu-nav__link` keeps its student.css rules verbatim (44px, icon gutter,
   pill hover, the ::before bar inset 4px). Only these three values change, and
   the third is a guard rather than a look: the nav is a scroller with a mask at
   both ends, so a row that took focus without a scroll margin would be revealed
   INSIDE the faded band and its focus ring with it. */
.stu-nav__link {
    min-block-size: var(--stu-row-1);
    font-size: var(--stu-t-md);
    letter-spacing: 0;
    scroll-margin-block: var(--space-lg);
}

/* THE EXPANDER. A level-1 row that opens a group instead of going anywhere, so
   it deliberately does NOT wear .stu-nav__link - that class means "this
   navigates", and two specs walk every one of them expecting a navigation. The
   structural rules below are student.css's `.stu-nav__link` block restated
   rather than shared, because that file is read-only for this work; keep the
   two in step if either ever moves. */
.stu-nav__expander {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    inline-size: 100%;
    min-block-size: var(--stu-row-1);
    padding: 0 14px;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    font-family: var(--font-body);
    font-size: var(--stu-t-md);
    font-weight: 400;
    letter-spacing: 0;
    color: var(--text-color);
    text-align: start;
    cursor: pointer;
    scroll-margin-block: var(--space-lg);
    transition: background var(--stu-dur-2) ease, color var(--stu-dur-1) ease;
}

.stu-nav__expander::before {
    content: '';
    position: absolute;
    inset-inline-start: 4px;
    inset-block-start: 50%;
    inline-size: 3px;
    block-size: 0;
    border-radius: var(--radius-full);
    background: var(--primary-color);
    transform: translateY(-50%);
    transition: block-size var(--stu-dur-2) ease;
}

.stu-nav__expander:hover {
    background: var(--fsp-hover-bg);
}

.stu-nav__expander:hover .stu-nav__icon {
    color: var(--text-color);
}

/* ANCESTOR vs LEAF. An expanded parent is a TRAIL, not a destination: full ink
   at weight 500, a neutral bar, and no blue at all. Only the LEAF gets the blue
   fill, the blue ink and aria-current="page", so exactly one row on the panel
   is blue and it is always the answer to "where am I". Three simultaneous blue
   rows means decoding three marker shapes to find the page, and the leaf is
   usually the one scrolled out of view. */
.stu-nav__expander.is-trail {
    color: var(--text-color);
    font-weight: 500;
    background: transparent;
}

.stu-nav__expander.is-trail::before {
    block-size: 18px;
    background: var(--border-default);
}

.stu-nav__expander.is-trail .stu-nav__icon {
    color: var(--text-color);
}

/* THE LABEL TAKES THE SLACK, and that is what keeps the row's tail in order.
   student.css's `.stu-nav__lock` claims the free space with
   `margin-inline-start: auto`, which is right on a row whose last element it
   is. Add a chevron with an auto margin of its own and flexbox SPLITS the free
   space between the two, parking the lock two thirds of the way along the row
   with a 60px hole on either side of it. A growing label leaves no free space
   for either margin to claim, so the pair sit together at the row's end. */
.stu-nav__expander-label {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The disclosure chevron. Level 1 and level 2 share it. Kept at the row's end
   by the label above rather than by a margin of its own, for the reason it
   gives. */
.stu-nav__chev {
    flex: 0 0 12px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    transition: transform var(--stu-dur-3) var(--stu-ease);
}

.stu-nav__expander .stu-nav__lock {
    margin-inline-start: 0;
}

.stu-nav__chev .app-icon-svg {
    height: 11px;
    width: auto;
}

[aria-expanded="true"] > .stu-nav__chev {
    transform: rotate(-180deg);
}

/* The lock marker already claims the free space, so a second auto margin on the
   chevron only orders the two. Restated for the expander because student.css
   only knew the marker on a `.stu-nav__link`. */
.stu-nav__expander.is-trail .stu-nav__lock {
    color: var(--text-color);
}

/* ── LEVEL 2: a recess CUT INTO the panel ────────────────────────────────────
   The well's own edge is the indent; no margin is doing that job. Total real
   indentation across BOTH nesting levels is 6px - everything else is depth, row
   height and the numeral gutter, which is what makes twenty meetings legible in
   a 288px column instead of pushed off it. */
.stu-nav__well {
    margin: 6px 6px var(--space-xs);
    padding: 6px;
    border-radius: var(--radius-md);
    background: var(--stu-well-tint);
    box-shadow: var(--stu-well);
}

.stu-nav__sub {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    inline-size: 100%;
    min-block-size: var(--stu-row-2);
    padding-block: 0;                 /* a <button> ships its own, and it is not zero */
    padding-inline: 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font-family: var(--font-body);
    font-size: 14px;                  /* the one value between --stu-t-sm and --stu-t-md */
    font-weight: 400;
    letter-spacing: 0;
    color: var(--text-secondary);
    text-align: start;
    text-decoration: none;
    cursor: pointer;
    scroll-margin-block: var(--space-lg);
    transition: background var(--stu-dur-2) ease, color var(--stu-dur-1) ease;
}

.stu-nav__sub:hover {
    background: rgba(255, 255, 255, 0.72);
    color: var(--text-color);
}

.stu-nav__sub:hover .stu-nav__icon {
    color: var(--text-color);
}

.stu-nav__sub.is-trail {
    color: var(--text-color);
    font-weight: 500;
}

.stu-nav__sub[aria-current="page"] {
    background: rgba(255, 255, 255, 0.9);
    color: var(--primary-color);
    font-weight: 500;
    box-shadow: 0 1px 3px rgba(0, 60, 130, 0.07);
}

.stu-nav__sub[aria-current="page"] .stu-nav__icon {
    color: var(--primary-color);
}

.stu-nav__sub-label {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* tabular-nums in the BODY font, never --font-mono: this label sits beside
   Hebrew, and Hebrew in a mono stack falls to Courier and looks broken. */
.stu-nav__sub-count {
    font-variant-numeric: tabular-nums;
    direction: ltr;
    font-size: 11px;
    color: var(--text-secondary);
}

/* ── LEVEL 3: a raised white SHEET inside the recess, with its own scroller. */
.stu-nav__sheet {
    margin: 5px 2px var(--space-xs);
    padding: var(--space-xs);
    border-radius: var(--radius-sm);
    background: var(--stu-sheet);
    box-shadow: 0 1px 3px rgba(0, 60, 130, 0.07), 0 0 0 1px rgba(255, 255, 255, 0.9) inset;
}

.stu-nav__sheet-empty {
    margin: 0;
    padding: var(--space-sm) 10px;
    font-size: var(--stu-t-sm);
    line-height: 1.5;
    color: var(--text-secondary);
}

/* NO overscroll-behavior: contain here. It is right on .stu-nav__menu and WRONG
   here: two nested contained scrollers in a 288px panel trap the wheel, and the
   rest of the menu becomes unreachable in one gesture. Capped at about six rows
   so the two subjects below the sheet never fall off the panel. */
.stu-nav__sheet-scroll {
    max-block-size: min(300px, 38vh);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 60, 130, 0.14) transparent;
}

.stu-nav__sheet-scroll::-webkit-scrollbar {
    inline-size: 5px;
}

.stu-nav__sheet-scroll::-webkit-scrollbar-thumb {
    background: rgba(0, 60, 130, 0.14);
    border-radius: 3px;
}

/* A meeting row. A numeral GUTTER, not an indent: the numbers form their own
   aligned column and the titles hang off it. That gutter is what recovers the
   width a date column would have cost, and Hebrew has no abbreviation
   conventions - a truncated meeting title identifies no meeting at all. The
   date lives on the row's title attribute, on /schedule, and in the player
   head. */
.stu-nav__meeting {
    display: grid;
    grid-template-columns: var(--stu-gutter-num) 1fr auto;
    align-items: center;
    gap: 7px;
    inline-size: 100%;
    min-block-size: var(--stu-row-3);
    padding-inline: var(--space-sm);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font-family: var(--font-body);
    font-size: var(--stu-t-sm);
    letter-spacing: 0;
    color: var(--text-secondary);
    text-align: start;
    text-decoration: none;
    cursor: pointer;
    scroll-margin-block: var(--space-lg);   /* so a focus or a scrollIntoView never lands under the mask */
    transition: background var(--stu-dur-2) ease, color var(--stu-dur-1) ease;
}

.stu-nav__meeting:hover {
    background: var(--fsp-hover-bg);
    color: var(--text-color);
}

.stu-nav__meeting-label {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* THE STATE MARK IS THE NUMERAL, AND IT SPENDS NO COLOUR.
     bare number  = not yet held
     thin ring    = held
     filled disc  = the meeting you are on
   It replaces an opacity-dimmed past row, which put 13px secondary ink at about
   2.8:1 across eleven of twenty rows and read as "none of this is available"
   rather than "these already happened". */
.stu-nav__meeting-num {
    inline-size: 20px;
    block-size: 20px;
    display: grid;
    place-items: center;
    justify-self: center;
    border: 1px solid transparent;
    border-radius: 50%;
    direction: ltr;
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    color: var(--text-tertiary);
}

.stu-nav__meeting.is-held .stu-nav__meeting-num {
    border-color: var(--border-default);
}

.stu-nav__meeting[aria-current="page"] {
    background: rgba(0, 113, 227, 0.10);
    color: var(--primary-color);
    font-weight: 500;
}

.stu-nav__meeting[aria-current="page"] .stu-nav__meeting-num {
    background: var(--primary-color);
    border-color: transparent;
    color: #fff;
}

/* The next meeting, which is a different question from "where am I". A dot in
   the row's inline-end margin, never a heavier numeral - the numeral column
   belongs to the active state. */
.stu-nav__meeting-next {
    inline-size: 5px;
    block-size: 5px;
    border-radius: 50%;
    background: var(--primary-color);
    box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.14);
}

/* ── THE FOOT: sign-out pinned to the bottom of the PANEL, not the document.
   `margin-block-start: auto` is THE pin. Nothing about it is absolute, so the
   row sits at the foot whatever the nav's height, and the nav above it is the
   only thing that ever scrolls. */
.stu-nav__foot {
    flex: 0 0 auto;
    margin-block-start: auto;
    padding-block-start: var(--stu-s-3);
    position: relative;
}

.stu-nav__foot::before {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline: 10px;
    block-size: 1px;
    background: linear-gradient(90deg, transparent, rgba(98, 98, 234, 0.20), transparent);
}

/* .stu-nav__link--signout keeps its student.css rules verbatim, INCLUDING the
   scaleX(-1) on the glyph: FontAwesome 6.5.1 thin has no RTL twin of
   right-from-bracket, and an exit arrow pointing along the Hebrew reading
   direction reads as ENTERING. The mascot below is never mirrored the same way. */

/* The watermark. Faint, inert, and behind the sign-out row rather than beside
   it: it is the panel's quiet company, not a control. Hidden below 1024px,
   where the drawer has no room to spare. */
.stu-nav__mascot {
    position: absolute;
    inset-block-end: -6px;
    inset-inline-end: -10px;
    inline-size: 104px;
    opacity: 0.13;
    pointer-events: none;
    user-select: none;
    z-index: 0;
}

/* The row has to sit ABOVE the watermark, which means giving it a stacking
   context of its own - a transparent background would otherwise let the artwork
   run through the label. */
.stu-nav__foot .stu-nav__link--signout {
    position: relative;
    z-index: 1;
}

/* ── FOCUS ───────────────────────────────────────────────────────────────────
   ONE rule for the whole area. :focus-visible and not :focus, so a mouse press
   never leaves a ring behind. The box-shadow is the clip-proof companion for a
   control inside an `overflow: clip` parent, where an outline is cut but a
   shadow drawn inside the element's own box is not.

   NO `border-radius` here, deliberately. Both `outline` and `box-shadow` follow
   the element's OWN radius in every browser this area supports, so declaring
   one would only square off the round controls: the 68px avatar disc, and every
   pill button in the area at --radius-full.

   Three structural guards make it actually visible, and all three are elsewhere
   in this file: the menu's mask fade is 6px rather than 14 or 20, every
   scrollable row carries scroll-margin-block, and no scrolling strip in the
   area uses overflow: hidden. */
.stu-shell :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);
}

/* ── TABLET (<=1024px) ───────────────────────────────────────────────────────
   The panel leaves the flow and becomes a right-side drawer. Every property
   student.css sets here has to be re-stated: this sheet's unconditional rules
   are the same specificity and come later, so without these the desktop panel
   would win at every width. */
@media (max-width: 1024px) {
    .stu-shell {
        display: block;
    }

    .stu-nav {
        position: fixed;
        inset-block: 0;
        inset-inline-start: 0;    /* RTL: the physical right, where the drawer belongs */
        inset-inline-end: auto;
        z-index: 1002;
        flex: none;
        inline-size: var(--stu-drawer-w);
        block-size: auto;
        padding: var(--space-lg) 14px var(--space-md);
        /* Opaque, not glass: there is no page behind a drawer for it to be
           glass over, and a translucent one over a scrim reads as a smear. */
        background: #fff;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        border-inline-end: 1px solid var(--stu-glass-line);
        border-inline-start: 0;
        box-shadow: var(--stu-lift-3);
        /* `transform` is PHYSICAL and does not flip with direction, so 100%
           pushes the drawer off the physical right - correct for RTL exactly as
           written. */
        transform: translateX(100%);
        transition: transform var(--stu-dur-4) ease;
    }

    /* After the rule above, never before it: same specificity, and the open
       state has to be the later declaration or the drawer never opens. */
    .stu-nav--open {
        transform: translateX(0);
    }

    /* Capped against the DRAWER rather than at a fixed pixel value, so the
       level-1 items below the sheet are never what scrolls away. */
    .stu-nav__sheet-scroll {
        max-block-size: min(240px, 30vh);
    }

    .stu-nav__mascot {
        display: none;
    }

    .stu-main {
        max-inline-size: none;
        padding: var(--space-lg) var(--stu-s-5) 80px;
    }
}

/* ── PHONE (<=767px) ─────────────────────────────────────────────────────── */
@media (max-width: 767px) {
    /* iOS composites a fixed background on every scroll frame. The gradient is
       soft enough that scrolling with it costs nothing visually. */
    .stu-shell {
        background-attachment: scroll;
    }

    /* The identity block must not consume 330px before the first nav item. */
    .stu-nav__identity {
        padding-block-end: var(--space-md);
    }

    .stu-nav__identity .stu-avatar {
        inline-size: 48px;
        block-size: 48px;
        font-size: var(--stu-t-md);
    }

    .stu-nav__identity .stu-avatar .app-icon-svg {
        height: 20px;
    }

    .stu-nav__brand {
        padding-block-end: var(--space-md);
    }

    .stu-main {
        padding: var(--stu-s-5) var(--space-md) 72px;
    }
}

/* ── MOTION AND POINTER ──────────────────────────────────────────────────────
   Nothing in this area animates for longer than --stu-dur-4, and nothing
   animates layout. Reduced motion turns off every transform and transition,
   KEEPS every colour change (a state that exists only as motion is a state a
   reduced-motion reader never sees), and kills smooth scrolling. */
@media (prefers-reduced-motion: reduce) {
    .stu-shell *,
    .stu-shell *::before,
    .stu-shell *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .stu-nav__chev {
        transition: none;
    }
}

/* Coarse pointers pay the space; a mouse keeps the tight desktop rhythm. No
   target in this area may be under 44px on a touch screen, and there is ONE
   block that says so - which is why it names rows this sheet does not otherwise
   own. A second copy of this rule in another sheet is a second place to forget
   a row. */
@media (pointer: coarse) {
    .stu-nav__sub,
    .stu-nav__meeting,
    .stu-deck__index-row,
    .stu-deck__step,
    .stu-tab,
    .stu-coursetab {
        min-block-size: 44px;
    }

    .stu-nav__sub,
    .stu-nav__meeting,
    .stu-deck__index-row {
        padding-inline: var(--stu-s-3);
    }

    .stu-deck__dots i {
        inline-size: 8px;
        block-size: 8px;
    }

    .stu-deck__dots button {
        min-inline-size: 44px;
        min-block-size: 44px;
    }
}

/* ── The panel has to fit its own destinations ───────────────────────────────
 *
 * MEASURED DEFECT, 2026-09-04. With חומרי לימוד expanded AND the meetings sheet
 * open - which is the state a reader is in whenever they are reading a meeting,
 * so it is the COMMON state and not an edge case - the menu overflowed and the
 * rows below the sheet were simply not on screen:
 *
 *     1440x900  44px over, החשבון שלי cut
 *     1440x800  144px over, חומרי עזר and the whole account group gone
 *     1280x720  224px over, הכנה לקורס as well
 *     1024x768  176px over, same four, IN THE DRAWER
 *      390x844   73px over, the account group gone
 *
 * The panel scrolls, so nothing was unreachable in principle. In practice the
 * fade was 6px and macOS/iOS paint no scrollbar until a wheel gesture, so a
 * reader looking for their account saw a menu that ended after the meetings and
 * concluded the page did not exist.
 *
 * Two changes, and BOTH are needed. Making the furniture shorter alone still
 * overflows on a 720px laptop with twenty meetings; making the cue louder alone
 * leaves the common case needing a scroll it should never have needed.
 */

/* 1. THE SHEET YIELDS FIRST, AND BY EXACTLY THE RIGHT AMOUNT.
 *
 * The meetings list is the one unbounded part of the panel - twenty rows on a
 * full intake - so it is the part that must give way, never the account group
 * below it. The previous cap was `min(300px, 38vh)`: a guess measured against
 * the VIEWPORT, which knows nothing about the 213px of brand and identity above
 * the menu or about how many rows sit below the sheet. Every constant of that
 * shape is wrong at some window size, and it was wrong at five of the five I
 * measured.
 *
 * So the sheet is not capped by a number at all any more. The whole chain from
 * the scroller down to the sheet is a flex column, and the sheet is the ONLY
 * member of it allowed to grow or shrink. It therefore absorbs exactly the space
 * the fixed rows do not use, at any window height, with any number of meetings.
 * `min-block-size: 0` on every link in the chain is what lets it shrink at all:
 * a flex item's default `min-size: auto` refuses to go below its content, which
 * is precisely how the account group got pushed off the bottom.
 *
 * The floor keeps about three rows visible so the sheet never degenerates into a
 * scroll-only stub on a very short window. */
.stu-nav__menu {
    display: flex;
    flex-direction: column;
}

.stu-nav__menu > .stu-nav__group {
    min-block-size: 0;
}

/* The group holding חומרי לימוד is the one that carries the sheet, so it is the
   one that flexes; the account group keeps its natural height and therefore
   keeps its place. */
.stu-nav__menu > .stu-nav__group:has(.stu-nav__well) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.stu-nav__well {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-block-size: 0;
}

.stu-nav__sheet {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-block-size: 0;
}

.stu-nav__sheet-scroll {
    /* BASIS ZERO, not auto. `auto` makes the flex algorithm start from this
       list's full content height - twenty meetings - and shrink from there,
       so every pixel freed anywhere above it was immediately eaten by the sheet
       and the account row stayed exactly as far under the edge as before.
       Measured: trimming 8px of the scroller's padding moved the overflow the
       WRONG WAY, from 6px to 9px. With a basis of zero the sheet asks for
       nothing and receives only what the fixed rows leave. */
    flex: 1 1 0;
    /* NO FLOOR, deliberately, and this is the line the whole fix turns on.
       Any floor here is a promise the panel cannot keep: when the window is
       shorter than brand + identity + every fixed row + that floor, something
       has to be pushed out of view, and the flex chain pushes whatever comes
       LAST - which is the account group and the reader's way to their own
       details. Measured at 116px and again at 92px: both still bound on a
       1280x720 laptop and both still cut `החשבון שלי`. A short sheet that
       scrolls is a mild inconvenience; a destination that is not on screen and
       gives no sign it exists is the defect being fixed. The cap above still
       stops it eating the panel on a tall window. */
    min-block-size: 0;
    max-block-size: 300px;
}

/* 2. THE FURNITURE ABOVE IT GETS SHORTER as the viewport does, rather than only
      at the phone breakpoint. A 720px laptop is not a phone but has no more
      vertical room than one. */
@media (max-height: 860px) {
    .stu-nav__brand {
        padding-block: 2px var(--space-sm);
    }

    .stu-nav__brand .logo-10x-course {
        max-inline-size: 168px;
    }

    .stu-nav__identity {
        gap: var(--space-xs);
        padding-block-end: var(--space-sm);
    }

    .stu-nav__identity .stu-avatar {
        inline-size: 52px;
        block-size: 52px;
    }
}

/* 3. AND THE OVERFLOW SAYS SO. The mask stays 6px - a focus ring on the first
      or last row must never land inside a faded band - but the scrollbar is now
      drawn rather than left to an overlay engine that shows nothing until the
      reader already guessed. `scrollbar-gutter` keeps the rows from shifting
      sideways when it appears. */
.stu-nav__menu {
    scrollbar-color: rgba(0, 60, 130, 0.28) transparent;
    scrollbar-gutter: stable;
}

.stu-nav__menu::-webkit-scrollbar-thumb {
    background: rgba(0, 60, 130, 0.28);
    border-radius: 3px;
}

.stu-nav__menu::-webkit-scrollbar-track {
    background: transparent;
}
