/* Times Edu Revision AI: UI upgrade layer (docs/UI-UPGRADE.md, task list A).
   Loaded by a <link> right after the app's one <style> block, so on equal specificity these rules win.
   Presentation only: no markup, copy, behaviour or learning content changes. Brand rules kept:
   - the gold CTA (.btn.g) and --gold-solid are never restyled (3.13:1 is a founder decision);
   - no new hues (new tokens point at existing ones or are neutrals needed for contrast);
   - Georgia headings, Inter everywhere else; no external resources.
   Order: tokens, global fixes, components, role-screen layer (.tev), navigation, touch and viewport, dark-only.
   !important is used only where the app writes an inline style that CSS cannot otherwise reach (3 rules, each
   commented). v13's prefers-reduced-motion rule stops every animation and transition added here. */

/* =====================================================================================================
   1. Tokens (A1). Existing v13 tokens are not changed; every value below is new.
   ===================================================================================================== */
:root{
  /* 4.1 spacing: 4-pt scale */
  --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:20px;--sp-6:24px;--sp-7:32px;--sp-8:40px;--sp-9:56px;
  /* 4.2 type */
  --fs-xs:12px;           /* floor for any text, including eyebrows, chips and the bottom nav */
  --fs-sm:13px;           /* labels, small copy, table headers */
  --fs-md:14px;           /* table cells, buttons */
  --fs-body:15px;         /* v13 body */
  --fs-input-touch:16px;  /* inputs below 1024 px (stops iOS focus zoom) */
  --fs-title:17px;        /* card titles (h3 and .ct) */
  --fs-data:24px;         /* KPI values on role screens; 22 below 1024; 20 in .kpis.sm */
  --lh-tight:1.2;--lh-snug:1.3;--lh-body:1.55;--lh-read:1.65;
  --track-eyebrow:.06em;
  --font-data:var(--sans);
  --measure-ui:78ch;
  /* 4.3 radius (v13: --r 12px, --r-lg 16px) */
  --r-xs:6px;--r-sm:8px;--r-md:10px;--r-xl:18px;--r-pill:999px;
  /* 4.4 elevation */
  --e1:var(--sh);                                                   /* card hover, demo window */
  --e2:0 2px 6px rgba(27,36,48,.06),0 12px 32px rgba(27,36,48,.10); /* command palette, toast */
  --e3:0 -12px 40px rgba(20,38,63,.18),0 2px 8px rgba(20,38,63,.08);/* sheet */
  /* 4.5 focus */
  --focus:var(--gold-2);          /* #7F5E2B: 5.9:1 on white, 5.5 on page, 5.1 on beige-2, 4.8 on gold-soft */
  --focus-on-navy:var(--gold);    /* sidebar, upgrade card, passport, footer, CTA band: 3.95:1 on #1D3557 */
  --focus-w:2px;--focus-off:2px;
  --focus-halo:rgba(179,139,77,.45);
  /* 4.6 motion */
  --dur-1:120ms;   /* hover, press */
  --dur-2:200ms;   /* toggles, state changes */
  --dur-3:280ms;   /* sheet and toast entering */
  --ease-out:cubic-bezier(.2,.8,.2,1);
  --ease-in:cubic-bezier(.4,0,1,1);
  /* 4.7 semantic colour additions */
  --ctl-line:#918674;             /* control edges: 3.58 on white, 3.30 on page, 3.04 on beige-2 */
  --track:var(--beige-2);         /* progress-bar and dial track */
  --scrim:rgba(20,38,63,.45);     /* same as v13 in light */
  --skel-hi:#F7F3EC;              /* same as v13 in light */
  --row-hover:var(--white-2);
  --chart-bar:var(--dg1);         /* #1D3557 in light, so the light theme is unchanged */
  --chart-grid:var(--line-2);     /* #EFEAE1 in light, unchanged */
  --chart-dot:var(--white);
  --dial-track:var(--line-2);     /* #EFEAE1 in light, unchanged */
  --dial-ok:#2E7D5B;--dial-mid:var(--dg1);--dial-warn:#B9771A;--dial-bad:#B8453A; /* v13 values in light */
  --eyebrow:var(--muted);
  --touch:44px;
  /* z-index scale (documents v13 values; new layers use these) */
  --z-sticky:1;--z-top:20;--z-bnav:30;--z-sheet:50;--z-toast:60;--z-cmdk:70;
  /* select chevrons, stroked in each theme's --muted (the only data: URIs in this file; CSP allows img-src data:).
     The dark one also serves the navy sidebar, whose select keeps its light text in both themes. */
  --chevron-l:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%235F6875' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --chevron-d:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5' fill='none' stroke='%239AA6B6' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --chevron:var(--chevron-l);
  /* surface behind a scrolling table (sticky first column, edge cover) */
  --tsurf:var(--white);
  /* the public header's glass (92% white) over the page, as a solid colour */
  --phead-solid:var(--white);
}
:root[data-theme="dark"]{
  --focus:var(--gold);            /* #C9A468: 7.1 on card, 7.8 on page, 8.0 on sidebar */
  --focus-on-navy:var(--gold);
  --focus-halo:rgba(201,164,104,.40);
  --e2:0 2px 6px rgba(0,0,0,.35),0 12px 32px rgba(0,0,0,.45);
  --e3:0 -12px 40px rgba(0,0,0,.5);
  --ctl-line:#607086;             /* 3.29 on card, 3.60 on page, 3.21 on beige-2 */
  --track:#2A3649;                /* visible against the #161F2B card; the fill does the 3:1 work */
  --scrim:rgba(0,0,0,.62);
  --skel-hi:var(--dgs);           /* #222C3A: no bright band */
  --chart-grid:var(--line);
  --dial-track:var(--track);
  --dial-ok:var(--dg8);--dial-warn:var(--amber);--dial-bad:var(--dg3); /* --dial-mid is --dg1 = #7FA8DC (6.75:1) */
  --chevron:var(--chevron-d);
  --phead-solid:var(--beige);     /* the dark glass (rgba(15,22,32,.92)) over the page is #0F1620 */
}

/* =====================================================================================================
   2. Global fixes
   ===================================================================================================== */

/* ---- A2 text wrapping (V01, MA-02, BE-01) ----
   .canvas{overflow-wrap:anywhere} lets table columns, chips and buttons shrink to one character. break-word still
   stops overflow but keeps each element's smallest width. Running text (.canvas, .pwrap, .note, .qwrap) keeps
   "anywhere". */
.tbl,.chip,.status,.btn,.seg button,.fb .score,.bnav a{overflow-wrap:break-word}
.tbl th,.tbl .btn,.tbl .chip,.tbl .status,.seg button,.status,.nw,.fb .score{white-space:nowrap}
.chip{flex:none;line-height:1.35}   /* natural width in flex rows; max-width:100% (v13) still caps it. 6.8: a chip
   that does take two lines reads as one pill (owner rule 5 lists chips among the component rules learning views get) */
.fb .score{flex:none}
/* Heatmap tiles (html lang=en). Plain hyphens:auto also split words that fit on their own line, because the
   browser hyphenates whichever word lands at a line end ("Production pos-sibility curves", "Economic sys-tems
   and re-source allocation": 9 to 11 words per width, against 3 or 4 in v13). Only words of 13 letters or more,
   which are wider than a tile at 768 and 1280, may take a hyphen, with 6 letters on each side. Chrome and Safari do
   not hyphenate capitalised words ("Specialisation", "Unemployment", "Macroeconomic"): backend.js (hyphenateHeat)
   gives one that is wider than its tile a soft hyphen, which these rules honour, so it breaks with a visible hyphen. */
.heat a{overflow-wrap:break-word;-webkit-hyphens:auto;hyphens:auto;hyphenate-limit-chars:13 6 6;-webkit-hyphenate-limit-before:6;-webkit-hyphenate-limit-after:6}
.sheet-f .btn,.hd-actions .btn{white-space:nowrap}

/* ---- A3 icons (V02, MA-01, V07, MA-14, V22) ----
   An unsized 24-viewBox icon defaults to 20 px. Zero specificity, so every sized icon keeps its size; learning
   content (notes, figures, question text) is excluded. */
:where(svg[viewBox="0 0 24 24"]:not([width]):not(:is(.note,.fig,.qtext) svg)){width:20px;height:20px;flex:none}
.list li>svg{width:20px;height:20px;flex:none;color:var(--gold-2)}
.cmdk a>svg{width:16px;height:16px;flex:none;color:var(--muted)}
.btn svg{width:18px;height:18px;flex:none}
.btn.sm svg{width:16px;height:16px}
.top .ico svg,.mtop .ico svg{width:20px;height:20px}
.streak svg{width:16px;height:16px;flex:none;color:var(--gold-2)}
.srch svg{width:16px;height:16px;flex:none}
a.avatar{text-decoration:none}

/* ---- A4 charts, dials, bars, skeleton (V03, MA-04, BE-04, V04, V05) ----
   CSS beats an SVG presentation attribute, so colours are re-pointed by attribute value without touching the
   chart code. Every token equals today's colour in light, so the light theme is unchanged. Figures inside notes
   and .fig are content and are left alone. */
.chart:not(:is(.fig,.note) .chart) text{font-variant-numeric:tabular-nums}
.chart:not(:is(.fig,.note) .chart) rect[fill="#1D3557"]{fill:var(--chart-bar)}
.chart:not(:is(.fig,.note) .chart) :is(path,polyline,line,circle)[stroke="#1D3557"]{stroke:var(--chart-bar)}
.chart:not(:is(.fig,.note) .chart) circle[fill="#1D3557"]{fill:var(--chart-bar)}
.chart:not(:is(.fig,.note) .chart) line[stroke="#EFEAE1"]{stroke:var(--chart-grid)}
.chart:not(:is(.fig,.note) .chart) circle[fill="#fff"]{fill:var(--chart-dot)}
.dial path[stroke="#EFEAE1"]{stroke:var(--dial-track)}
.dial path[stroke="#1D3557"]{stroke:var(--dial-mid)}
.dial path[stroke="#2E7D5B"]{stroke:var(--dial-ok)}
.dial path[stroke="#B9771A"]{stroke:var(--dial-warn)}
.dial path[stroke="#B8453A"]{stroke:var(--dial-bad)}
.bar{background:var(--track)}
/* !important: the fill colour is an inline style="background:var(--navy)"; dark --navy is #14263F, invisible on
   the #161F2B card, so dark switches it to --prim (3.23:1). */
:root[data-theme="dark"] .bar i[style*="var(--navy)"]{background:var(--prim)!important}
/* Skill profile (analytics, passport): v13's ".rub div{display:grid;grid-template-columns:110px 1fr 46px}" also
   reaches the .bar inside each row, so the fill was a share of a 110 px cell, not of the bar (61% drew as 45% at
   390 px), and the bar overflowed. The bar goes back to a plain block; the row grid is unchanged. */
.rub div.bar{display:block}
.skel{background-image:linear-gradient(90deg,var(--beige-2) 25%,var(--skel-hi) 50%,var(--beige-2) 75%)}

/* ---- A12 shared visual fixes (V19, V27, MA-18) ---- */
.status.published i{background:var(--gold-solid)}   /* D2: a status dot only; the CTA is untouched */
.row>.dial{flex:none}
.dial .l{white-space:nowrap;left:-40px;right:-40px}
@media(max-width:420px){.demo .row.between{flex-wrap:wrap;justify-content:center}}

/* ---- focus ring (MA-10, 6.16) ---- */
:focus-visible{outline:var(--focus-w) solid var(--focus);outline-offset:var(--focus-off)}
:is(.side,.upg,.passport,.pfoot,.cta-band) :focus-visible{outline-color:var(--focus-on-navy)}
/* route landing points, not controls: the h1 that B4 focuses after a page change (app and public pages), or #main
   when a page has no h1 */
#main h1:focus,[data-te-route-focus]:focus,#main[tabindex="-1"]:focus{outline:none}

/* ---- links (V23) ----
   Link colour (--head) and body text (--ink) are nearly the same, so plain links keep a visible 1 px gold rule. */
.canvas a:not([class]){text-decoration-thickness:1px;text-underline-offset:3px;text-decoration-color:var(--gold)}
.canvas a:not([class]):hover{text-decoration-color:currentColor}

/* =====================================================================================================
   3. Components
   ===================================================================================================== */

/* ---- buttons (6.9). .btn.g keeps every colour; only press feedback, timing and focus reach it. ---- */
.btn{transition:background var(--dur-1),border-color var(--dur-1),box-shadow var(--dur-1),transform var(--dur-1)}
.btn:active:not(:disabled){transform:translateY(1px)}

/* ---- clickable cards (6.5): lift with a shadow, nothing moves ---- */
.tcard,.subj,.deck{transition:border-color var(--dur-1),box-shadow var(--dur-1)}
.tcard:hover,.subj:hover,.deck:hover{box-shadow:var(--e1)}
.card .grid>.tbl{align-self:start}
.faq p{max-width:68ch}

/* ---- A5 forms and controls (MA-10, MA-11, MA-09, MA-17, V20, V28) ---- */
.inp,.filters select,.role-bar select{border-color:var(--ctl-line)}   /* D3 */
.inp:hover:not(:focus):not(:disabled):not([aria-invalid="true"]){border-color:var(--muted)}
/* 2 px focus-colour edge (border + 1 px ring) plus a halo; the transparent outline shows in forced-colours mode */
.inp:focus,.filters select:focus-visible,.role-bar select:focus-visible{outline:2px solid transparent;outline-offset:0;border-color:var(--focus);box-shadow:0 0 0 1px var(--focus),0 0 0 4px var(--focus-halo)}
.inp[aria-invalid="true"]{border-color:var(--red);box-shadow:0 0 0 1px var(--red)}
.inp[aria-invalid="true"]:focus{border-color:var(--red);box-shadow:0 0 0 1px var(--red),0 0 0 4px var(--red-soft)}
.field-err{font-size:13px;line-height:1.4;color:var(--red);margin-top:2px}
/* read-only and disabled share one look (6.10); --muted on --beige-2 is 4.8:1 in light and 6.6:1 in dark, so a
   read-only link stays readable, and its Copy button next to it does the work */
.inp:disabled,.inp[readonly]{background-color:var(--beige-2);color:var(--muted)}
.inp:disabled{cursor:not-allowed}
input[type=checkbox],input[type=radio]{accent-color:var(--prim);width:18px;height:18px}
select.inp,.filters select,.role-bar select{-webkit-appearance:none;appearance:none;padding-right:34px;background:var(--white) var(--chevron) no-repeat right 12px center/12px}
select.inp::-ms-expand{display:none}
/* the sidebar's "Preview as" select (admins, 1024 px and wider) gets the same chevron, drawn in the dark-theme
   stroke (#9AA6B6, 5.0:1 on the navy sidebar). !important: its inline style="background:transparent;padding:3px 6px"
   would otherwise clear the image (the inline shorthand also resets repeat, position and size, so the whole
   shorthand is restated) and leave no room for it. */
.side #roleSel{-webkit-appearance:none;appearance:none;background:transparent var(--chevron-d) no-repeat right 7px center/10px!important;padding-right:24px!important}
.side #roleSel option{color:var(--ink);background:var(--white)}
.filters select{min-height:38px;padding:7px 34px 7px 12px;border-radius:var(--r-md)}
.role-bar select{padding-top:5px;padding-bottom:5px}
.tog i{box-shadow:inset 0 0 0 1.5px var(--ctl-line);transition:background var(--dur-2)}
.tog i::after{transition:left var(--dur-2) var(--ease-out)}
.tog.on i{box-shadow:none}
.task .cb{border-color:var(--ctl-line);position:relative}
.ledger i:not([data-b]),.ledger i[data-b="0"],.legend i[style*="var(--m0)"]{box-shadow:inset 0 0 0 1px var(--ctl-line)}
@media(max-width:1023px){
  .inp,.filters select,.role-bar select,td select.inp{font-size:var(--fs-input-touch)}   /* no iOS focus zoom */
}
/* a one-field search row (CMS list): the button takes the field's height instead of sitting 13 px short beside it */
form.row[role=search]>.btn{align-self:stretch}
/* admin-users filter row (V20, V28): buttons sit on the input baseline */
.filt{display:grid;column-gap:12px;row-gap:12px;align-items:end}
form[role=search] .filt{grid-template-columns:minmax(0,1.6fr) repeat(3,minmax(0,1fr)) auto}
.filt>.field{margin-bottom:0}   /* fields and buttons share one bottom edge; the card padding closes the form */
.filt .fact{align-self:end;display:flex;gap:8px;margin-bottom:0}
.filt .fact .btn{min-height:calc(var(--fs-body)*1.55 + 22px)}   /* the computed height of .inp: line box + padding + border */
@media(max-width:1023px){.filt .fact .btn{min-height:calc(var(--fs-input-touch)*1.55 + 22px)}}
@media(max-width:1023px){
  form[role=search] .filt{grid-template-columns:repeat(3,minmax(0,1fr))}
  form[role=search] .filt>:first-child,.filt .fact{grid-column:1/-1}
}
@media(max-width:599px){
  form[role=search] .filt{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .filt .fact>.btn{flex:1 1 0}
}

/* ---- A6 tables (BE-03, MA-12, V15, V14, BE-02d) ---- */
td.n,th.n{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.tbl .meta{display:block;font-size:12px;line-height:1.4;color:var(--muted);margin-top:2px;font-weight:400}
@media(hover:hover){.tbl tbody tr:hover>td{background:var(--row-hover)}}
.mbar{display:flex;align-items:center;gap:8px;white-space:nowrap}
.mbar .bar{width:80px;flex:none}
.mbar span{font-size:12px;min-width:4ch;text-align:right;font-variant-numeric:tabular-nums}
/* keyboard-scrollable regions (B6 adds tabindex="0"). position:relative keeps absolutely positioned children
   (a visually hidden "Actions" header, the stacked thead) inside the scroller instead of widening the page. */
.tscroll{position:relative}
.tscroll:focus-visible{outline-offset:-2px}
/* tables that scroll inside a card: sticky first column, and a soft edge shadow on the side with more content
   (the "local" cover scrolls with the table and hides the "scroll" shadow at each end) */
.card .tscroll,.tscroll:has(>.cmp){
  background:
    linear-gradient(to right,var(--tsurf) 40%,transparent) left center/28px 100% no-repeat local,
    linear-gradient(to left,var(--tsurf) 40%,transparent) right center/28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,rgba(20,38,63,.16),transparent) left center/12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%,rgba(20,38,63,.16),transparent) right center/12px 100% no-repeat scroll;
}
:root[data-theme="dark"] :is(.card .tscroll,.tscroll:has(>.cmp)){
  background:
    linear-gradient(to right,var(--tsurf) 40%,transparent) left center/28px 100% no-repeat local,
    linear-gradient(to left,var(--tsurf) 40%,transparent) right center/28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,rgba(0,0,0,.55),transparent) left center/12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%,rgba(0,0,0,.55),transparent) right center/12px 100% no-repeat scroll;
}
.card .tscroll .tbl :is(th,td):first-child,.tscroll .cmp :is(th,td):first-child{position:sticky;left:0;z-index:var(--z-sticky);background:var(--tsurf)}
@media(hover:hover){.card .tscroll .tbl tbody tr:hover>td:first-child{background:var(--row-hover)}}
.psec.alt{--tsurf:var(--beige)}
.swipe-note{margin-bottom:0}
@media(min-width:1024px){.swipe-note{display:none}}
/* stacked rows below 768 (BE-03). Tables live in cards, so rows use dividers, like v13's .pitem list. */
@media(max-width:767px){
  table.tbl.stack{min-width:0!important}   /* !important: beats a leftover inline style="min-width:520px" */
  table.tbl.stack thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  table.tbl.stack,table.tbl.stack tbody,table.tbl.stack tr,table.tbl.stack td{display:block;width:100%}
  table.tbl.stack tr{padding:12px 0;border-top:1px solid var(--line-2)}
  table.tbl.stack tr:first-child{border-top:0;padding-top:4px}
  table.tbl.stack tr:last-child{padding-bottom:0}
  table.tbl.stack td{border:0;padding:3px 0;display:flex;justify-content:space-between;align-items:center;gap:12px;text-align:right;min-height:28px}
  table.tbl.stack td[data-l]::before{content:attr(data-l);flex:none;font:500 12.5px/1.3 var(--sans);letter-spacing:0;color:var(--muted);text-align:left}
  table.tbl.stack td:first-child{display:block;text-align:left;padding-bottom:6px;font-weight:600;color:var(--head)}
  table.tbl.stack td:first-child .meta{font-weight:400}
  table.tbl.stack td.act{justify-content:flex-end;flex-wrap:wrap;padding-top:8px}
  table.tbl.stack td:empty{display:none}
  table.tbl.stack td.n{white-space:normal}
  .card .tscroll table.tbl.stack :is(th,td):first-child{position:static;background:none}
  @media(hover:hover){table.tbl.stack tbody tr:hover>td{background:none}}
  .tscroll:has(>.tbl.stack){overflow:visible;background:none}
  .tscroll:has(>.tbl.stack)+.swipe-note{display:none}
}

/* ---- A8 empty, error and loading states (V12, V13, V04) ---- */
.empty.sm,.empty.err{display:flex;gap:12px;align-items:flex-start;text-align:left;border-radius:var(--r-md)}
.empty.sm{border:0;background:var(--beige-2);padding:16px}
.empty.err{border:1px solid var(--line);border-left:3px solid var(--red);background:var(--white);padding:16px 18px}
.empty .ei{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;flex:none;background:var(--white);color:var(--muted)}
.empty.err .ei{background:var(--red-soft);color:var(--red)}
.empty .ei svg{width:16px;height:16px}
.empty .eb{min-width:0;flex:1}
.empty .eb>b{display:block;color:var(--head);font-weight:600}
.empty.sm p,.empty.err p{margin:2px 0 0;max-width:60ch;font-size:13.5px;color:var(--ink-2)}
.empty.err h3{font-size:16px;margin:0}
.empty .eb .btn{margin-top:10px}
.empty .eb .row .btn{margin-top:0}
.empty .eb>.row{margin-top:10px}
.skel:is(.sk-l,.sk-v,.sk-t,.sk-b,.sk-row){min-height:0}
.skel.sk-l{height:12px;width:60%}
.skel.sk-v{height:24px;width:40%;margin-top:10px}
.skel.sk-t{height:16px;width:35%}
.skel.sk-b{height:180px;margin-top:14px}
.skel.sk-row{height:40px;margin-top:10px}

/* ---- A9 sheet, command palette, toast (V21, MA-15) ---- */
.sheet-bg,.cmdk{background:var(--scrim)}
.sheet{box-shadow:var(--e3);max-height:88vh;max-height:88dvh}
.sheet-bg.on{animation:te-fade var(--dur-2) var(--ease-out)}
.sheet-bg.on .sheet{animation:te-sheet-in var(--dur-3) var(--ease-out)}
.sheet-f{padding-bottom:calc(12px + env(safe-area-inset-bottom))}
.sheet-h .btn{min-width:44px;min-height:44px}
body:has(.sheet-bg.on),body:has(.cmdk.on){overflow:hidden}
.cmdk.on{animation:te-fade var(--dur-2) var(--ease-out)}
.cmdk.on .box{animation:te-pop var(--dur-2) var(--ease-out)}
.cmdk .box{box-shadow:var(--e2)}
.cmdk input{background:var(--white);color:var(--ink)}
.cmdk input::placeholder{color:var(--muted)}
.toast{border-radius:var(--r-md);box-shadow:var(--e2);transition:opacity var(--dur-3) var(--ease-out),transform var(--dur-3) var(--ease-out)}
@media(max-width:1023px){.toast{bottom:calc(var(--bnav) + 16px + env(safe-area-inset-bottom))}}
@keyframes te-fade{from{opacity:0}to{opacity:1}}
@keyframes te-sheet-in{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}
@keyframes te-pop{from{opacity:0;transform:translateY(-6px) scale(.98)}to{opacity:1;transform:none}}
@media(min-width:1024px){
  @keyframes te-sheet-in{from{opacity:0;transform:scale(.98)}to{opacity:1;transform:none}}
}

/* =====================================================================================================
   4. Role-screen layer: screens rendered by backend-views.js and Settings carry .canvas.tev (student learning
      screens never do). Spacing and hierarchy only.
   ===================================================================================================== */

/* ---- page header and eyebrow (6.3, V10) ---- */
.tev .hd{margin-bottom:20px}
.tev .hd .sub{max-width:68ch}
.hd-actions{gap:8px}
/* the title block gives way first, so header actions stay on the title row while the subtitle wraps */
.tev .hd>div:first-child{flex:1 1 320px;min-width:0}
.tev .hd>.hd-actions{flex:0 1 auto}
.eyebrow,.role-bar.self{font-size:12px;line-height:1.2;font-weight:600;letter-spacing:var(--track-eyebrow);text-transform:uppercase;color:var(--eyebrow)}
.eyebrow.mb-s,.eyebrow+.kpis{margin-top:0}
.eyebrow.mb-s{margin-bottom:8px}
.kpis+.eyebrow,.kpis.mb+.eyebrow{margin-top:4px}
@media(max-width:599px){
  .hd:has(>.hd-actions)>div:first-child,.hd-actions{width:100%}
  .hd-actions>.btn{flex:1 1 calc(50% - 4px)}
  .hd-actions>.btn.p{order:-1;flex-basis:100%}
  .hd-actions>:not(.btn){flex-basis:100%}
  .hd-actions>:not(.btn) :is(select,.inp){width:100%}
}

/* ---- role bar (6.4, V08, V09, BE-05) ---- */
.role-bar.self{display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:none;border:0;border-radius:0;padding:0;margin:0 0 6px}
.role-bar.self .rb-switch{margin-left:auto;text-transform:none;letter-spacing:0;font-weight:500;font-size:13px;color:var(--muted)}
.role-bar .rb-switch{display:inline-flex;align-items:center;gap:8px}
.role-bar .rb-switch select{color:var(--ink);border-radius:var(--r-sm)}   /* font size: 13 px (v13), 16 px below 1024 (no iOS zoom) */
.role-bar.preview{border-left:3px solid var(--gold);border-radius:var(--r-sm);padding:8px 12px 8px 14px;color:var(--ink);font-weight:500}
.role-bar.preview .rb-switch{margin-left:auto;font-size:13px;color:var(--ink-2)}
@media(min-width:1024px){.rb-switch,.role-bar .rb-switch{display:none}}   /* the sidebar foot has the same select */
@media(max-width:1023px){.role-bar select{min-height:36px}}

/* ---- cards (6.5, V11, V24, MA-23) ---- */
.tev .card{padding:20px}
@media(max-width:599px){.tev .card{padding:16px}}
h2.ct{font-size:17px;line-height:1.3;margin:0 0 4px}
.tev .card>:is(h3,.ct),.tev .card>.row>:is(h3,.ct){margin-bottom:10px}
.tev .card>.row:has(>:is(h3,.ct)){margin-bottom:10px}
.tev .card>.row>:is(h3,.ct){margin-bottom:0}
.tev .card>:is(h3,.ct,.row:has(>:is(h3,.ct)))+:is(.small.muted,.sub,.tiny.muted){margin:-6px 0 12px}
/* a table right under a title: the title's 10 px is the gap (its own .mt-s would make it 18) */
.tev .card>:is(h3,.ct,.row:has(>:is(h3,.ct)))+.tscroll>.tbl.mt-s:first-child{margin-top:0}
.tev .card .ct.mt{margin-top:22px}
/* the first divided row under a card title has no rule of its own (v13 drops it only for :first-child) */
.tev .card>:is(h3,.ct)+:is(.ach,.insight,.task,.qrow),.tev .card>:is(h3,.ct)+:is(.small,.tiny,.sub)+:is(.ach,.insight,.task,.qrow){border-top:0;padding-top:0}
.tev .card>p{max-width:var(--measure-ui)}
.tev .card ul:not([class]){padding-left:20px;margin:0 0 4px}
.tev .card ul:not([class])>li{margin-bottom:6px;line-height:1.6}
.tev .card>.row.mt-s:last-child{margin-top:12px}

/* ---- KPI (6.6, V06, V26, MA-21). D1: Inter lining figures on role screens only; student KPIs keep Georgia. ---- */
.tev .kpi .v{font-family:var(--font-data);font-weight:600;font-size:var(--fs-data);letter-spacing:-.015em;font-variant-numeric:tabular-nums lining-nums}
.tev .kpi .v small{font-weight:400;letter-spacing:0}
.tev .num{font-family:var(--font-data);font-weight:600;font-variant-numeric:tabular-nums lining-nums}
.tev .kpi .d a{font-weight:500}
.kpis.sm .kpi{padding:12px 14px}
.tev .kpis.sm .kpi .v{font-size:20px}
@media(max-width:1023px){.tev .kpi .v{font-size:22px}}
@media(min-width:720px) and (max-width:1023px){
  .tev .kpis{grid-template-columns:repeat(4,minmax(0,1fr))}
  .tev .kpis.k5{grid-template-columns:repeat(5,minmax(0,1fr))}
}
/* CMS status tiles: when one status label takes two lines, every count in the row still sits on one line */
.tev .kpis.k5>.kpi{display:flex;flex-direction:column}
.tev .kpis.k5>.kpi>.l{flex:1 0 auto}
/* a label that wraps (3 tiles a row at 390) keeps its dot on the first line instead of between the two lines */
.kpis.k5 .status{align-items:flex-start}
.kpis.k5 .status i{flex:none;margin-top:calc((1.55em - 8px)/2)}
@media(max-width:599px){
  .tev .kpis.k5{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
  .tev .kpis.k5 .kpi{padding:10px 12px}
  .tev .kpis.k5 .kpi .v{font-size:20px}
}

/* ---- share rows: share of a whole with 5 or fewer parts (admin plan mix) ---- */
.share{display:grid;grid-template-columns:minmax(90px,120px) minmax(0,1fr) auto;gap:10px;align-items:center;padding:6px 0;font-size:13.5px}
.share .sl{color:var(--ink);font-weight:500;overflow-wrap:break-word}
.share .bar{height:8px}
.share .sv{white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--ink-2);min-width:9ch;text-align:right}   /* each row is its own grid: a common value width keeps the bars the same length ("0 · 0%" beside "4 · 80%") */
.share+.share{border-top:1px solid var(--line-2)}

/* ---- table rhythm on role screens (6.7) ---- */
.tev .tbl th{padding:10px 12px;font-size:12.5px;line-height:1.3;vertical-align:bottom}
.tev .tbl td{padding:10px 12px}
.tev .tbl td .btn.sm+.btn.sm{margin-left:6px}
/* segmented filters on phones: at 14 px side padding the tutor homework filter was 50 px wider than its card at
   390, so "All (2)" sat out of sight in the scroller; 7 px lets all four fit */
@media(max-width:420px){.tev .seg button{padding-left:7px;padding-right:7px}}
/* v13's 680 px floor for .wide tables is 2 px wider than the card body at 768 and at 1024 (both 678 px), which made
   tables that fit scroll by 2 px. The floor now stops at the card width; a table whose columns need more (the tutor
   tables below about 1190 px) still scrolls inside its region, with the sticky first column and edge shadows. */
.tev .tbl.wide{min-width:min(680px,100%)}
@media(max-width:1023px){
  .tev .tbl :is(th,td){padding-left:10px;padding-right:10px}   /* tablet: more columns fit 768 */
}
/* Column priorities (tutor students and homework tables). From 768 to 1199 px the low-priority columns (.t-lo:
   mastery bar, last active, estimated time, required marks) step out, and the same figures show as a line inside the
   row (.t-alt), so the table fits its card instead of scrolling sideways. Stacked rows on phones and 1200 px and
   wider keep the columns and hide the extra lines, so nothing is read twice. */
.tbl .t-alt{display:none}
.tbl .acts{display:inline-flex;flex-wrap:wrap;justify-content:flex-end;gap:6px}
.tev .tbl .acts .btn.sm+.btn.sm{margin-left:0}   /* the gap spaces them */
@media(min-width:768px) and (max-width:1199px){
  .tbl :is(th,td).t-lo{display:none}
  .tbl .t-alt{display:block}
  .tut-hw .acts{flex-direction:column;align-items:stretch}   /* "Mark done" over "Cancel": one narrow column */
}

/* ---- sticky editor actions (MA-19) ---- */
.sticky-actions{gap:8px}
@media(max-width:1023px){
  .sticky-actions{position:sticky;bottom:calc(var(--bnav) + 8px + env(safe-area-inset-bottom));background:var(--beige);padding:8px 0;z-index:var(--z-sticky);box-shadow:0 -8px 12px -10px rgba(20,38,63,.25)}
  .card .sticky-actions{background:var(--white);margin-inline:-20px;padding-inline:20px}   /* spans the card edge to edge */
}
/* 1024 and wider: the markup moved Save and the workflow buttons from the header to the end of the Resource card,
   under a 320 px text area, which puts them below the fold at 1280x800. The row now sticks to the bottom of the
   window while the card is in view, and at rest it closes the card like a footer. */
@media(min-width:1024px){
  .tev .card .sticky-actions{position:sticky;bottom:0;z-index:var(--z-sticky);background:var(--white);margin:0 -20px -20px;padding:12px 20px 20px;border-top:1px solid var(--line-2);border-radius:0 0 calc(var(--r) - 1px) calc(var(--r) - 1px)}
  html:has(.tev .card .sticky-actions){scroll-padding-bottom:88px}   /* a focused field is never left under the row */
}
@media(max-width:599px){
  .card .sticky-actions{margin-inline:-16px;padding-inline:16px}
  .sticky-actions>.btn{flex:1 1 auto;padding-inline:10px}   /* one row at 390 when the labels fit; equal rows when not */
}

/* =====================================================================================================
   5. Navigation (A10: V08, V21, V25, MA-03, MA-20, MA-05, MA-21, BE-05)
   ===================================================================================================== */
/* student-only chrome: hidden only when the script has said which view is showing (fail-safe) */
:root[data-te-view]:not([data-te-view="student"]) :is(.top .streak,#planPill){display:none}

@media(max-width:1023px){
  .bnav{height:calc(var(--bnav) + env(safe-area-inset-bottom))}
  /* icons sit on one line across the five tabs, 8 px from the top (as in a native tab bar), and the label hangs
     below, so a two-line label grows downwards (ending 2 px above the edge) instead of pushing its icon up */
  .bnav a{position:relative;min-width:0;padding:8px 2px 0;justify-content:flex-start;font-size:12px;line-height:1.15;transition:color var(--dur-1)}
  /* one line when it fits (every student and staff label). The spec's nowrap + ellipsis would cut the two parent
     labels, "Weekly report" (99 px) and "Tutor feedback" (107 px), which are wider than a 78 px tab at 390 and,
     with the other three, wider than the whole bar; they are v13 copy that CSS cannot shorten, so they take a
     balanced second line instead of being cut off. Words are never split. */
  .bnav a span{max-width:100%;text-align:center;overflow-wrap:normal;text-wrap:balance;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
  .bnav a.on span{font-weight:600}
  .bnav a.on::before{content:"";position:absolute;top:0;left:28%;right:28%;height:3px;border-radius:0 0 3px 3px;background:var(--gold)}

  /* public header: the nav becomes a second row that scrolls sideways instead of disappearing (MA-05) */
  .phead .in{flex-wrap:wrap;height:auto;min-height:56px;row-gap:0}
  .phead .in>.brand{min-height:48px}
  .phead nav{display:flex;order:9;flex:1 0 100%;gap:2px;margin:0 -14px;padding:0 3px 4px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .phead nav::-webkit-scrollbar{display:none}
  .phead nav a{white-space:nowrap;min-height:40px;display:inline-flex;align-items:center;flex:none}
  html:has(#pubMain .phead){scroll-padding-top:100px}
}
@media(min-width:600px) and (max-width:1023px){
  .bnav{padding-inline:max(0px,calc((100vw - 600px)/2))}   /* the five tabs stay together on a tablet */
}
/* parent tabs: "Weekly report" (77 px) and "Tutor feedback" (83 px) are wider than a fifth of a 390 px bar, but
   all five labels together need about 325 px. Each tab gets at least its one-line label width and the other tabs
   share what is left equally, so every label stays on one line at 12 px (from 340 px up; below that they wrap as
   before). Keyed on the view attribute that the script sets, so other roles keep five equal tabs. */
@media(min-width:340px) and (max-width:1023px){
  :root[data-te-view="parent"] .bnav{grid-template-columns:repeat(5,minmax(max-content,1fr))}
}
.phead nav .nav-login{display:none}
/* at 420 and below "Log in" (the header hides its own button there) stays pinned at the right end of the scrolling
   row, so it is always in view; the other links slide under it. Its fade ends in the header's own colour. */
@media(max-width:420px){.phead nav .nav-login{display:inline-flex;font-weight:600;color:var(--head);position:sticky;right:0;margin-left:auto;padding-left:30px;border-radius:0;background:linear-gradient(to right,transparent,var(--phead-solid) 26px)}}

/* =====================================================================================================
   6. Touch, viewport and keyboard (A11: MA-06, MA-07, MA-08, MA-19, MA-21, MA-24)
   ===================================================================================================== */
@media(max-width:1023px){
  html{scroll-padding-top:70px;scroll-padding-bottom:calc(var(--bnav) + 16px + env(safe-area-inset-bottom))}
  .canvas{padding-bottom:calc(var(--bnav) + 24px + env(safe-area-inset-bottom))}
  .composer{bottom:calc(var(--bnav) + 8px + env(safe-area-inset-bottom))}
}
@media(min-width:600px) and (max-width:1023px){
  .canvas{padding:22px 24px calc(var(--bnav) + 28px + env(safe-area-inset-bottom))}
  .mtop{padding:0 20px}
}
/* touch devices only, so desktop density stays */
@media(pointer:coarse){
  .btn{min-height:var(--touch)}
  .btn.sm,.fsz .btn{min-height:40px}
  .fsz .btn{min-width:40px}
  .ico{width:var(--touch);height:var(--touch)}
  .phead .btn,.phead nav a{min-height:var(--touch)}
  .nav a{min-height:var(--touch)}
  select.inp,.filters select,.role-bar select,.inp{min-height:var(--touch)}
  .tog{min-height:var(--touch)}
  :is(a,button).chip,.fchip,.modes button,.side-panel .tabs button,.seg button,.msg .fu button,.msg .src a{min-height:40px}
  .fchip,.modes button,.side-panel .tabs button,.msg .fu button{display:inline-flex;align-items:center}
  .mtoc a{display:inline-flex;align-items:center;min-height:40px}
  .qnav button{width:40px;height:40px}
  .crumb a{position:relative}
  .crumb a::after{content:"";position:absolute;inset:-12px -4px}
  .faq summary{min-height:48px}
  .pfoot a{padding:12px 0;margin-bottom:0}
  .task .cb::after{content:"";position:absolute;inset:-11px}   /* 44 px hit area around the 22 px circle */
  /* small links keep their look; an invisible ::after extends the hit area to 44 px without moving anything */
  .mtop .brand{min-height:var(--touch)}
  .avatar,.task a.t,.qrow a.t,.insight a,a.small,a.tiny,.list li>a:not([class]){position:relative}
  .avatar::after{content:"";position:absolute;inset:-5px}
  .task a.t::after,.qrow a.t::after,.insight a::after,a.small::after,a.tiny::after,.list li>a:not([class])::after{content:"";position:absolute;inset:-14px 0}
  .sheet-h .btn{min-width:var(--touch);min-height:var(--touch)}
}
/* the on-screen keyboard: the bottom nav steps aside while a text field has focus */
@media(max-width:1023px) and (pointer:coarse){
  body:has(:is(input:not([type=checkbox]):not([type=radio]):not([type=range]),textarea):focus) .bnav{display:none}
  body:has(.composer :focus) .composer{bottom:8px}
  body:has(:is(input:not([type=checkbox]):not([type=radio]):not([type=range]),textarea):focus) .sticky-actions{bottom:8px}
}

/* =====================================================================================================
   7. Dark-only rules
   ===================================================================================================== */
:root[data-theme="dark"] .side{border-right:1px solid var(--line-2)}
:root[data-theme="dark"] .task:not(.done) .cb{border-color:var(--gold-2)}
:root[data-theme="dark"] .role-bar.preview{background:rgba(201,164,104,.10)}
:root[data-theme="dark"] .sheet{border:1px solid var(--line)}
:root[data-theme="dark"] .cmdk .box{border:1px solid var(--line)}
:root[data-theme="dark"] .toast{border:1px solid var(--line)}
@media(max-width:1023px){:root[data-theme="dark"] .sheet{border-bottom:0}}
:root[data-theme="dark"] .empty.err{background:var(--white)}
:root[data-theme="dark"] .empty.sm{background:var(--beige)}   /* recessed below the card, as beige-2 is in light */
