/* LEGIBILITY PASS (2026-08-28, Marc: "font is also too small. let's make
   sure everything is legible. We don't want to fatigue eyes when we have so
   much space to work with").

   Every font-size below 15px was raised on one converging scale rather than
   by hand, so the type keeps its relative order — a mono label is still
   smaller than the body text beside it — and the whole thing is one table to
   tune or revert:

     10 -> 12    11.5 -> 13.5    13   -> 15
     10.5 -> 12.5  12 -> 14      13.5 -> 15.5
     11 -> 13    12.5 -> 14.5    14   -> 15.5
                                 14.5 -> 16

   The lift is largest at the bottom (+2px) and smallest at the top (+1.5px),
   which compresses a nine-step scale that had grown too fine to read as
   hierarchy anyway. Sizes at 15px and above were already comfortable and are
   untouched. */
:root{
  /* The palette is /styles/tokens.css now (2026-08-03) — the same values the
     home page and What I do use. This block used to carry its OWN darker
     scheme (--board:#1D3E36, --card:#264C42, --ink:#F3F9F7), which is why
     the in-app screens still looked like the old site after every .html page
     had been brought onto the new one: the palette pass covered the pages
     and missed this file, and this is what every app screen actually reads.
     accent is still overwritten per-subject at runtime by app.js. */
  --accent:#3FE0CB; --accent-soft:rgba(63,224,203,.16); --accent-ink:#8FE3D6;
  --board:#1D3E36; --card:#264C42; --card2:#2E5A4E; --edge:#40766A; --edge2:#35635A;
  /* #40766A (--edge) is 2.9:1 against these backgrounds — under WCAG's 3:1
     floor for UI-component boundaries (1.4.11). Fine for decorative
     dividers, which have no contrast requirement, but every actually-
     clickable bordered control (.opt, .notesbtn, .gradebtn, calendar nav,
     help/bail buttons) was using it too, making the button read as barely
     more than plain text — exactly the "hard to read" mobile report.
     #5C9389 is 4.3:1, already proven correct since the marketing nav uses
     the identical value for its own interactive-control borders. */
  --edge-control:#5C9389;
  --ink:#F3F9F7; --muted:#A9CBC1; --faint:#7FA79C;
  --good:#4FAE95; --good-bg:rgba(79,174,149,.14); --good-line:rgba(79,174,149,.4);
  --bad:#EA8280; --bad-bg:rgba(234,130,128,.14); --bad-line:rgba(234,130,128,.4);
  --warn:#E8A94A; --warn-bg:rgba(232,169,74,.14); --warn-line:rgba(232,169,74,.4);
  --paper2:#16302A;
  --display:"Newsreader",serif;
  --body:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,Menlo,monospace;}
*{box-sizing:border-box;}
html,body{margin:0; overscroll-behavior-y:none;}
/* No general anchor rule existed anywhere in this file — any plain <a> tag
   without its own class (e.g. "Forgot password?", "Register") was falling
   back to the browser's default blue/purple link colors instead of the
   app's own theme. One rule fixes it everywhere this pattern occurs, not
   just the one page it was first noticed on. */
/* SCOPED TO UNCLASSED LINKS (2026-09-02, Marc: "free account button is too
   hard to read and doesn't match the site palette").

   `a:visited` has specificity (0,1,1) and BEAT every single-class button rule
   in the app — .fs-cta, .btn, .notesbtn are all (0,1,0). So any <a> styled as
   a button turned accent-teal the moment the student had been to the page it
   points at: teal text on the gold Free Account pill, which is 1.5:1 and
   unreadable. It looked intermittent because it depended on browsing history,
   which is exactly the kind of bug that never reproduces on demand.

   The rule was written for "Forgot password?" and "Register" — plain links
   with no class of their own — and :not([class]) says that, so a link that
   carries its own styling keeps it. */
a:not([class]){color:var(--accent);}
a:not([class]):visited{color:var(--accent);}
body{font-family:var(--body); color:var(--ink); line-height:1.55;
  background:
    radial-gradient(1200px 600px at 80% -10%, rgba(79,174,149,.10), transparent 60%),
    radial-gradient(900px 500px at -10% 110%, rgba(196,132,46,.05), transparent 55%),
    var(--board);
  -webkit-text-size-adjust:100%; -webkit-tap-highlight-color:transparent;
  padding:calc(18px + var(--safe-top)) 0 calc(74px + var(--safe-bot));}
/* 1400, matching the marketing pages (2026-08-04). This was 1120 while the
   nav above it was 1200, so the dashboard always looked narrower than its
   own header — a separate value in a separate file, which is why the earlier
   width change missed it. */
.wrap{max-width:1400px; margin:0 auto; padding:0 28px;}

::selection{background:var(--accent-soft);}
button{font:inherit;}

/* ---------- subject tabs (top nav) ---------- */
/* touch-action:pan-x is the actual fix here, not overscroll-behavior — this
   element only claims horizontal pan gestures, so a vertical scroll
   attempt while the cursor happens to be over this sticky bar passes
   straight through to the page instead of getting captured by this strip.
   Course/subject pages are the only place in the app with a horizontal
   scroller like this, which is exactly why the trackpad-scroll issue was
   isolated to them specifically. */
.subtabs{position:sticky; top:var(--navh, 58px); z-index:55; background:var(--board); display:flex; gap:2px; overflow-x:auto; border-bottom:1px solid var(--edge); margin:4px 0 20px; scrollbar-width:none; touch-action:pan-x;}
.subtabs::-webkit-scrollbar{display:none;}
/* The sticky tab bar OVERLAPS what follows it (2026-08-11, Marc). It has
   z-index 55 and no margin, so the first row of buttons sat underneath it and
   read as cut off — the content was there, just covered. Margin rather than
   padding on the bar itself, so the bar keeps its own height when stuck. */
.subtabs + *{ margin-top:14px; }
.subtab{flex:0 0 auto; font-family:var(--mono); font-size:15.5px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--muted); background:none; border:none; cursor:pointer; padding:11px 14px;
  border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; transition:color .15s;}
.subtab:hover{color:var(--ink);}
.subtab.on{color:var(--sub); border-bottom-color:var(--sub);}
.subtab.showall{color:var(--accent); opacity:.85;}
.subtab.showall:hover{opacity:1;}

/* ---------- shared bits ---------- */
.eyebrow{font-family:var(--mono); font-size:15px; letter-spacing:.2em; text-transform:uppercase; color:var(--accent); font-weight:600;}
h1{font-family:var(--display); font-weight:600; text-transform:uppercase; letter-spacing:.005em;
   font-size:clamp(36px,10vw,54px); line-height:.94; margin:.1em 0 .12em;}
h1 .u{position:relative; display:inline-block;}
h1 .u::after{content:""; position:absolute; left:-2px; right:-2px; bottom:.07em; height:.13em; background:var(--accent-soft); border-radius:2px;}
.lede{color:var(--muted); font-size:17.5px; max-width:none; margin:.4em 0 0;}

/* Same reason as .btn above — app.js renders one anchor with this class. */
.notesbtn{display:inline-flex; align-items:center; gap:6px; margin-top:12px; text-decoration:none; background:var(--card2);
  border:1px solid var(--edge-control); border-radius:7px; padding:9px 12px; font-family:var(--mono); font-size:15.5px;
  color:var(--muted); cursor:pointer;}
.notesbtn:hover{color:var(--ink); border-color:var(--accent-soft);}
/* Reference-style actions (notes, how-do-i) shouldn't visually compete
   with the actual things-to-do below them — same shape, lighter weight,
   so the row reads as one clear set of actions with two quiet footnotes
   rather than seven equally-loud buttons. */
.notesbtn.subtle{background:transparent; border-color:transparent; color:var(--faint); padding:8px 10px; font-size:15.5px;}
/* The chosen one of a Yes/No pair (2026-08-30, the blanks declaration). Border
   AND background, not colour alone — a green-on-green tint at this size is not
   a reliable signal that a choice registered, and this gate holds the mark
   back until every row has an answer. */
.notesbtn.on{background:var(--accent); border-color:var(--accent); color:#04231c; font-weight:650;}
.notesbtn.on:hover{color:#04231c;}
.notesbtn.subtle:hover{color:var(--muted); border-color:var(--edge);}

.subject-actions-primary{display:grid; grid-template-columns:1fr 1fr 1fr; gap:16px; margin-top:18px;}
/* Buttons FILL their cell (2026-08-11, Marc). They were pinned to 190px and
   left-aligned inside a third of the page, so a three-column grid rendered
   as three narrow buttons with a wide dead gap after each — the grid was
   right, the buttons just were not using it. */
.subject-actions-primary .notesbtn{justify-self:stretch; width:100%; max-width:260px; justify-content:center; margin-top:0; padding:11px 14px; font-size:15.5px;}
.subject-actions-primary .notesbtn[disabled]{opacity:.4; cursor:not-allowed;}
.subject-actions-primary .notesbtn[disabled]:hover{border-color:var(--edge); color:var(--muted);}
/* Had no mobile rule at all — three 190px-wide columns has no room on a
   phone screen and was overflowing/cramming (2026-08-03). */
@media(max-width:700px){
  .subject-actions-primary{grid-template-columns:1fr 1fr;}
}
/* TWO ACROSS ON A PHONE (2026-08-11, Marc: "mobile needs work"). One column
   made every tile a full-width banner for a two-word label — ten of them ran
   past two screens, so the assignment lists underneath were never seen. Two
   columns halves the height and the labels still fit. */
@media(max-width:480px){
  .subject-actions-primary{grid-template-columns:1fr 1fr; gap:10px;}
  .subject-actions-primary .notesbtn{font-size:14.5px; padding:12px 8px; max-width:none;}
  .subject-actions-primary .notesbtn{width:100%; justify-self:stretch;}
}
/* Larger, roomier — the dashboard's own action row, now that it carries
   the weight the course list used to (that section became a calendar, or
   Function access while a parent is previewing). Bigger targets for what
   is now the primary way to actually do something from here. */
/* THREE ACROSS (2026-08-11, Marc). Seven tiles in two columns left a single
   orphan on the last row, and each button ran nearly half the screen wide for
   two words of label — the row read as a stack of banners rather than a set
   of choices. Three columns fits nine evenly and brings the width down to
   something a label actually fills. Two on tablet, one on a phone. */
.hub-actions-lg{display:grid; grid-template-columns:repeat(3,1fr); gap:14px; margin-top:18px; margin-bottom:24px;}
@media (max-width:900px){ .hub-actions-lg{grid-template-columns:1fr 1fr;} }
@media (max-width:560px){ .hub-actions-lg{grid-template-columns:1fr;} }
.hub-actions-lg .notesbtn{width:100%; justify-content:center; margin-top:0; padding:18px 22px; font-size:16px;
  border-radius:12px; gap:9px;}
/* THE EXPIRED-TRIAL STATE (2026-08-25, Marc: "greyed out with a requires
   tokens message"). Greyed enough to read as unavailable, not so faint it
   reads as broken — a student has to be able to see WHICH thing needs
   tokens, which is the whole point of leaving it on screen instead of
   removing it. */
.notesbtn.paid-locked{opacity:.45; cursor:not-allowed;}
.notesbtn.paid-locked:hover{border-color:var(--edge); color:var(--muted);}
/* Its own line inside the tile — flex-basis 100% breaks the row so the note
   sits under the label instead of squeezing it. */
.paidnote{flex:0 0 100%; font-family:var(--mono); font-size:12.5px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--faint); margin-top:3px;}
.hub-actions-lg .notesbtn[disabled]{opacity:.4; cursor:not-allowed;}
.hub-actions-lg .notesbtn[disabled]:hover{border-color:var(--edge); color:var(--muted);}
@media(max-width:600px){
  .hub-actions-lg{grid-template-columns:1fr;}
}

.hubactions{display:flex; flex-wrap:wrap; gap:8px; margin-top:16px;}
.hubactions .notesbtn{margin-top:0;}
.howto-answer{margin-top:16px; padding:16px 18px; background:var(--card); border:1px solid var(--edge);
  border-radius:11px; font-size:17px; line-height:1.5;}
.howto-answer:empty{display:none;}
.howto-answer p{margin:0 0 10px;}
.howto-answer p:last-child{margin-bottom:0;}
.howto-answer h4, .howto-answer h5, .howto-answer h6{
  font-family:var(--display); font-weight:600; letter-spacing:.01em; margin:16px 0 6px; line-height:1.25;}
.howto-answer h4{font-size:18px;} .howto-answer h5{font-size:16px;} .howto-answer h6{font-size:15px;}
.howto-answer > *:first-child{margin-top:0;}
.howto-answer ol, .howto-answer ul{margin:0 0 10px; padding-left:1.3em;}
.howto-answer li{margin-bottom:4px;}
.howto-answer li:last-child{margin-bottom:0;}
.howto-answer hr{border:none; border-top:1px solid var(--edge); margin:12px 0;}
.howto-answer strong{color:var(--accent-ink);}

/* FORMULA SHEET (2026-08-19). Each group is a .cband heading (same rule
   used everywhere else for "Reference"/"Current assignments") followed
   by a stack of cards — one per formula, name/expression/optional note. */
.formula-list{display:flex; flex-direction:column; gap:8px; margin-bottom:4px;}
.formula-row{background:var(--card2); border:1px solid var(--edge); border-radius:10px; padding:12px 16px;}
.formula-name{font-family:var(--mono); font-size:13px; letter-spacing:.07em; text-transform:uppercase; color:var(--muted); margin-bottom:6px;}
.formula-expr{font-size:16.5px; line-height:1.5; color:var(--ink);}
.formula-expr sub{font-size:.72em;}
.formula-expr sup{font-size:.72em;}
.formula-note{margin-top:6px; font-size:15px; line-height:1.4; color:var(--muted);}

.fboverlay{position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:80;
  display:flex; align-items:flex-end; justify-content:center; padding:0;}
@media(min-width:640px){.fboverlay{align-items:center; padding:20px;}}
.fbcard{width:100%; max-width:520px; border-radius:16px 16px 0 0; margin:0;}
@media(min-width:640px){.fbcard{border-radius:14px;}}
.fbcard h3{font-family:var(--display); font-size:20.5px; margin-bottom:12px;}

.checklist{margin-top:26px;}
.clist{list-style:none; margin-top:14px; display:flex; flex-direction:column; gap:8px;}
.citem{background:var(--card); border:1px solid var(--edge); border-left:3px solid var(--accent);
  border-radius:0 9px 9px 0; padding:11px 14px;}
.citem.term{border-left-color:var(--warn);}
.clab{display:block; font-weight:600; font-size:16.5px; margin-bottom:3px;}
.cdet{display:block; font-size:15px; color:var(--muted); line-height:1.5;}

.notepad-wrap{margin-top:30px;}
.notepad-area{width:100%; background:var(--card); border:1px solid var(--edge-control); border-radius:11px;
  padding:16px; font-family:var(--body); font-size:17.5px; line-height:1.6; color:var(--ink);
  resize:vertical; margin-top:12px;}   /* height: /styles/forms.css */
.notesaved{display:block; font-family:var(--mono); font-size:15px; color:var(--good); margin-top:8px; height:1.2em;}
.isub.ok{color:var(--good);}

.newterms{background:var(--warn-bg); border:1px solid var(--warn-line); border-radius:10px;
  padding:13px 15px; font-size:16px; line-height:1.55; color:var(--ink); margin-top:16px;}
.newterms b{color:var(--warn);}
.fwarn{background:var(--warn-bg); border:1px solid var(--warn-line); border-radius:10px;
  padding:12px 14px; font-size:15.5px; line-height:1.5; color:var(--ink); margin-top:14px;}

.searchbox{width:100%; background:var(--card); border:1px solid var(--edge-control); border-radius:11px;
  padding:14px 16px; font-family:var(--body); font-size:18px; color:var(--ink); margin-top:8px;
  -webkit-appearance:none;}
.searchbox:focus{outline:none; border-color:var(--accent);}
.searchresults{display:flex; flex-direction:column; gap:9px; margin-top:16px;}
.sresult{display:block; width:100%; text-align:left; background:var(--card); border:1px solid var(--edge-control);
  border-left:3px solid var(--sub, var(--accent)); border-radius:0 10px 10px 0; padding:12px 15px; cursor:pointer;}
.sresult:hover{border-color:var(--sub, var(--accent));}
.sr-top{display:flex; justify-content:space-between; gap:10px; margin-bottom:4px;}
.srkind{font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase; color:var(--sub, var(--accent));}
.srsub{font-family:var(--mono); font-size:14px; color:var(--faint);}
.srlabel{font-weight:600; font-size:17px; margin-bottom:3px;}
.srsnip{font-size:15.5px; color:var(--muted); line-height:1.5;}

.dym{margin-top:10px; font-size:16.5px; color:var(--muted);}
.dymlabel{font-family:var(--mono); font-size:15.5px; color:var(--faint); margin-right:2px;}

/* DARK INK ON THE ACCENT FILL, NOT WHITE (2026-08-19).

   White on #3FE0CB measures 1.65:1 — WCAG AA wants 4.5:1 for text, so the
   label on the app's PRIMARY button was the least readable text on the
   screen. Caught by the designer's note on mockup 4f, and the arithmetic
   confirms it. --paper2 on the same fill is 8.55:1.

   Same class of bug as the --edge one documented at the top of this file:
   a colour that looks right in a palette and fails the moment text sits on
   it. Every accent-filled control below is corrected the same way. */
/* text-decoration:none because SEVEN of these are anchors, not buttons
   (2026-09-01, caught on the tour closer: "Start the assessment" rendered as
   underlined link text inside a solid pill). .btn never said anything about
   decoration, so the browser's default underline for <a> came straight
   through — the color was fine, which is why it survived this long. Applies
   to every a.btn in app.js and exam-ui.js, not just the new one. */
.btn{font-family:var(--mono); font-weight:600; font-size:15.5px; letter-spacing:.04em; text-transform:uppercase;
  border-radius:10px; padding:14px 20px; cursor:pointer; border:1px solid var(--accent); width:100%;
  text-decoration:none; background:var(--accent); color:var(--paper2);}
.btn:active{transform:translateY(1px);}
.btn:disabled{opacity:.3; cursor:default;}
.btn.ghost{background:transparent; color:var(--accent);}
.btn+.btn{margin-top:9px;}
/* Used everywhere for button pairs (Cancel/Confirm, Try again, etc.), some
   with genuinely long labels ("Yes, permanently delete everything",
   "Run another assessment") — without wrap, two such buttons side by side
   can force horizontal overflow on a narrow phone. */
.actions{margin-top:15px; display:flex; gap:10px; flex-wrap:wrap;}
/* SAME SIZE, BOTH OF THEM (2026-08-28, Marc, on the tour: "make all the
   buttons the same size").

   They were the same WIDTH and 9px different in height, which is the giveaway
   that it was never a sizing rule: .btn+.btn adds margin-top:9px for buttons
   STACKED down a card, and inside a flex row that margin pushes the second
   button down and shortens it against a stretched first one. The row's own
   gap already spaces them on both axes, including when they wrap onto two
   lines on a phone, so the margin has nothing left to do here. */
.actions .btn{width:auto; flex:1;}
.actions .btn+.btn{margin-top:0;}
/* For a row of several small peer actions (child management, admin rows) —
   distinct from .actions above, which is for 2-3 equal-width paired buttons
   (Cancel/Confirm). Content-sized and left-aligned instead of stretched,
   so 5-7 buttons of different label lengths read as a compact toolbar
   instead of a stack of oversized blocks. */
.btn-group{display:flex; gap:8px; flex-wrap:wrap;}
.btn-group .btn{width:auto; flex:0 0 auto; padding:9px 15px; font-size:14.5px; margin-top:0;}
.badge.review{background:var(--faint);}

/* ---------- hub ---------- */
.subjects{display:grid; gap:11px; margin-top:22px;}
/* The top-of-dashboard strip — 4 courses, compact, horizontal. Distinct
   from .subjects (the old full vertical list) rather than a variant of it,
   since this is a quick-glance row, not the primary content anymore. */
/* AUTO-FILL, NOT FOUR (2026-08-17). The strip was capped at four courses in
   JS to match this four-column grid; options now make five or six normal, and
   a fixed column count would either overflow or force the cap back. */
/* FLEX, NOT GRID (2026-08-30, Marc: "Push courses all the way to the
   right"). The auto-fill grid spread every chip across the row; with the
   profile and Check-ins boxes on the left, the courses now right-align and
   the spare space lives in the middle (the .strip-spacer the dashboard
   inserts between the two groups). Chips keep the 220px footprint the grid
   tracks gave them and wrap on narrow screens exactly as before. */
/* THEY SHRINK BEFORE THEY WRAP (2026-09-01, Marc: "boxes are too big causing
   the fourth course to be pushed to the second row").

   At a fixed 220px, the profile box + Check-ins + four courses need 1320px
   of chips before gaps — more than the 1400px page has once padding and the
   spacer are paid for, so the fourth course dropped onto a row of its own
   and the row read as five courses and a stray.

   Two changes, and the second is the one that matters: the chips are 200px
   rather than 220, and they may SHRINK. Flexbox wraps on the flex-basis
   before it ever shrinks anything, so allowing shrink alone would have
   changed nothing — the basis itself had to come down. At 200 the six boxes
   need 1272px of the 1360 available and the spacer keeps the rest, so the
   courses still sit right where Marc put them. min-width holds the floor at
   150 so a seventh chip crushes only so far before it wraps, which is the
   right outcome at that point. */
.course-strip{display:flex; flex-wrap:wrap; gap:12px; margin-top:18px; margin-bottom:26px;}
.course-strip .course-chip{flex:0 1 200px; min-width:150px;}
.course-strip .strip-spacer{flex:1 1 0; min-width:0;}
/* A GAP BETWEEN THE PROFILE AND THE COURSES (2026-08-28, Marc: "Add a little
   space between academic profile and the courses"). It is first in the same
   grid, so at gap:12px it read as a fourth course.

   margin-right on the item rather than a wider column-gap: gap is uniform
   across a grid and widening it would space the courses from each other too,
   which is not what was asked. The box gives up 16px of its own track and
   the courses keep theirs.

   width:auto is not optional here. .course-chip sets width:100%, which makes
   the box the full width of its track no matter what its margin says — the
   margin then pushed OUT of the track instead of shrinking the box, and the
   measured gap stayed at 12px. In a grid cell, width:auto fills the track
   minus the margins, which is the behaviour this rule assumed it had.

   Dropped at the breakpoint below, where the strip becomes two columns and
   the profile no longer leads a row. */
/* The 48px gap moved onto the spacer when the strip went flex — the
   profile no longer needs to give up its own track. */
/* Same shrink-before-wrap rule as the course chips beside it — see above. */
.course-strip .profile-chip{flex:0 1 200px; min-width:150px; width:200px;}
.credits-badge{display:inline-block; font-family:var(--mono); font-size:15.5px; color:var(--muted);
  border:1px solid var(--edge); background:var(--card); padding:6px 14px; border-radius:99px; margin-top:16px;}
.course-chip{display:block; width:100%; text-align:left; background:var(--card); border:1px solid var(--edge-control);
  border-top:4px solid var(--sub); border-radius:10px; padding:12px 13px; cursor:pointer; color:var(--ink);}
.course-chip:hover{border-color:var(--faint); border-top-color:var(--sub);}

/* THE COURSE-CARD CHECKBOX IS GONE (2026-08-28). It lived for one morning:
   a tick in the corner of each big course card, which was the first answer to
   "let a student filter the calendar". Marc's second answer is better and is
   what shipped — the courses are chips in the same row as the types, mounted
   above the calendar. The checkbox wrapper it needed is removed here.

   .course-chip above stays: homework-ui.js still builds one for its course
   picker. .course-strip has no builder left in any module — kept rather than
   deleted only because it is the grid .course-chip sits in and removing a
   layout rule that a live class depends on is a bigger change than this;
   flagged so the next person can retire the pair together.

   The chip row's own slot. renderCalFilter owns what is inside it. */
.cal-filter-slot{margin-bottom:22px;}
.cal-filter-slot .cal-filter{margin:0;}

/* THE GOAL REMINDER (2026-08-28, Marc: "should be really visible" + "add
   Current Average Beside it"). Full width, its own accent edge, and the two
   numbers side by side at a size worth reading — the target and where they
   are now. Wraps to a stack on a phone rather than shrinking the numbers,
   because the numbers are the whole point of the band. */
.goalband{background:var(--card); border:1px solid var(--edge); border-left:3px solid var(--accent);
  border-radius:14px; padding:20px 24px; margin:0 0 22px;
  display:flex; gap:28px; align-items:center; flex-wrap:wrap;}
.goalband .gtext{flex:1 1 300px; min-width:250px;}
.goalband .glab{font-family:var(--mono); font-size:13px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--faint); margin:0 0 6px;}
.goalband h2{font-family:var(--display,Newsreader),serif; font-size:27px; line-height:1.15;
  margin:0 0 6px; color:var(--ink);}
.goalband .gtext p:last-child{margin:0; color:var(--muted); font-size:16px; line-height:1.5;}
.goalband .gnums{display:flex; gap:26px; flex:0 0 auto;}
.goalband .gnum{text-align:center; padding:0 2px;}
.goalband .gnum b{display:block; font-family:var(--display,Newsreader),serif; font-size:44px;
  line-height:1; color:var(--accent);}
.goalband .gnum.muted b{color:var(--ink);}
.goalband .gnum span{display:block; font-family:var(--mono); font-size:12.5px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--faint); margin-top:7px; white-space:nowrap;}
.goalband .gact{flex:0 0 auto;}
.goalband .gact .btn{width:auto;}
@media (max-width:620px){
  .goalband{padding:16px 18px; gap:18px;}
  .goalband h2{font-size:22px;}
  .goalband .gnum b{font-size:36px;}
}

/* THE FULL BREAKDOWN (2026-08-28, Marc: "See the full breakdown should open
   up a summary of his targets and current mark for each course"). One row per
   course, four columns, and the whole row is the button that opens its marks
   — a separate chevron would be a 24px target on a phone for something the
   row already implies.

   Sizes deliberately above the old table numbers (Marc, same day: "font is
   also too small. let's make sure everything is legible"). */
.gbreak{margin:0 0 26px;}
.gbreak-head h3{font-family:var(--display,Newsreader),serif; font-size:24px; margin:0 0 4px;}
.gbreak-head .isub{margin:0 0 14px; font-size:16px;}
.gbtable{display:flex; flex-direction:column;}
.gbrow{display:grid; grid-template-columns:1fr 92px 92px 82px; align-items:center; gap:12px;
  width:100%; text-align:left; background:var(--card); border:1px solid var(--edge);
  border-radius:12px; padding:14px 18px; margin-bottom:8px; cursor:pointer; font:inherit; color:var(--ink);}
.gbrow:hover{border-color:var(--accent);}
.gbrow-h{background:none; border:none; padding:0 18px 6px; margin:0; cursor:default;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--faint);}
.gbrow-h span:not(:first-child){text-align:center;}
.gb-name b{display:block; font-size:18px; line-height:1.25;}
.gb-name .gb-note{display:block; font-style:normal; font-size:14.5px; color:var(--faint); margin-top:3px;}
.gb-num{text-align:center; font-family:var(--mono); font-size:21px; color:var(--ink);}
.gb-gap{font-size:18px;}
.gb-gap.up{color:var(--good);}
.gb-gap.down{color:var(--muted);}
.gb-panel{padding:2px 18px 14px;}
.gb-panel .markslist{margin-top:0;}
@media (max-width:620px){
  .gbrow{grid-template-columns:1fr 62px 62px 58px; gap:8px; padding:12px 14px;}
  .gbrow-h{padding:0 14px 6px;}
  .gb-num{font-size:18px;}
  .gb-name b{font-size:17px;}
}
.cc-name{display:block; font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:15px; letter-spacing:.02em;}
.cc-stat{display:block; font-size:14.5px; color:var(--muted); margin-top:4px;}
.cc-meter{display:block; height:3px; background:var(--edge); border-radius:99px; overflow:hidden; margin-top:8px;}
.cc-meter>i{display:block; height:100%; background:var(--sub); border-radius:99px;}

/* Homework upload/analyze — there's no real byte-level progress from a
   single request/response call, so this is a staged, honest-feeling bar:
   it advances through fixed checkpoints tied to the stage text, not a
   smooth fake fill to 100% that lies about being almost done. */
.hw-progress{margin-top:14px;}
.hw-progress-label{font-size:15.5px; color:var(--muted); margin-bottom:6px;}
.hw-progress-track{height:6px; background:var(--edge); border-radius:99px; overflow:hidden;}
.hw-progress-fill{display:block; height:100%; width:6%; background:var(--sub); border-radius:99px;
  transition:width .6s ease;}
@media(max-width:700px){
  .course-strip .course-chip, .course-strip .profile-chip{width:calc(50% - 6px);}
  .course-strip .strip-spacer{display:none;}
  /* Two columns: the profile sits above the courses rather than beside them,
     so a right margin would just make one box narrower than its neighbour. */
  .course-strip .profile-chip{margin-right:0;}
}
.subject{display:block; width:100%; text-align:left; background:var(--card); border:1px solid var(--edge-control);
  border-left:5px solid var(--sub); border-radius:12px; padding:16px 16px; cursor:pointer; color:var(--ink);
  transition:border-color .15s, transform .1s;}
.subject:hover{border-color:var(--faint); border-left-color:var(--sub);}
.subject:active{transform:translateY(1px);}
.subject:focus-visible{outline:2px solid var(--sub); outline-offset:2px;}
.subject .row{display:flex; align-items:baseline; gap:10px;}
.subject h2{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:21.5px; margin:0; letter-spacing:.02em;}
.subject .n{font-family:var(--mono); font-size:15px; color:var(--faint); margin-left:auto;}
.subject .stat{font-size:15.5px; color:var(--muted); margin-top:5px;}
.subject .stat b{color:var(--sub); font-weight:600;}
.subject .meter{height:4px; background:var(--edge); border-radius:99px; overflow:hidden; margin-top:9px;}
.subject .meter>i{display:block; height:100%; background:var(--sub); border-radius:99px;}

.hubfoot{margin-top:24px; border-top:1px solid var(--edge2); padding-top:16px;}
/* .hubtriple is retired (2026-08-28, Marc: "This section is no longer
   needed"). The row it styled held the term goal and the best-practices card;
   the goal band above carries both numbers now, and best practices is a
   button in the Reference band. Rules removed rather than left dead — nothing
   builds the class any more. */
.access-list{margin-top:14px; border-top:1px solid var(--edge2); padding-top:12px;}
.access-list h4{font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted); margin:0 0 4px;}
.access-note{font-size:15px; color:var(--faint); margin:0 0 10px;}
.access-row{display:flex; align-items:center; justify-content:space-between; gap:10px; padding:8px 0;
  border-top:1px solid var(--edge2);}
.access-row:first-of-type{border-top:none;}
.access-label{font-size:15px; color:var(--ink);}
.access-toggle{font-family:var(--mono); font-size:14.5px; font-weight:600; border-radius:99px; padding:6px 13px;
  cursor:pointer; white-space:nowrap; border:1px solid transparent;}
.access-toggle.approved{background:var(--good-bg); border-color:var(--good-line); color:var(--good);}
.access-toggle.approval-required{background:var(--warn-bg); border-color:var(--warn-line); color:var(--warn);}
.access-toggle.restricted{background:var(--bad-bg); border-color:var(--bad-line); color:var(--bad);}
/* THE PINNED LIST, IN THE ROW THE STAT BOXES HELD (2026-08-28, Marc: "I'd
   like the pinned list there. those three boxes are taking up way too much
   room anyway"). One line per item, the date right-aligned so a column of
   them scans down the edge. .metrics-row / .metric-card below are kept —
   nothing builds them today, but they are the shape the Sessions / Avg
   session / Total hours boxes go back into if that route is ever built. */
/* THE WEEK CARD: FOUR BOXES LEFT, PINNED LIST RIGHT (2026-08-28, Marc: "Put
   the list on the right vertically lined up with a date beside. Create 4
   boxes on the left with the content from the three current boxes and the
   last login. Make Carter's week a much larger font").

   Two columns that become one on a tablet, so the boxes never squeeze to a
   width their numbers cannot sit in. The dates are right-aligned in a
   fixed-width mono column, which is what makes them line up as a column
   rather than trailing each title at a different place. */
.wr-toprow{display:grid; grid-template-columns:minmax(300px,1fr) minmax(280px,1fr);
  gap:22px; align-items:start; margin:16px 0 4px;}
.wr-metrics{display:grid; grid-template-columns:1fr 1fr; gap:12px;}
.wr-pinned{margin:0;}
.wr-pinned-lab{font-family:var(--mono); font-size:13px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--faint); margin-bottom:10px;}
.wr-pin{display:flex; align-items:baseline; gap:12px; padding:9px 0;
  border-top:1px solid var(--edge2);}
.wr-pin:first-of-type{border-top:0; padding-top:0;}
.wr-pin-t{font-weight:600; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.wr-pin-w{margin-left:auto; font-family:var(--mono); font-size:14.5px; color:var(--muted);
  white-space:nowrap; text-align:right;}
.wr-pin-empty{margin:0; font-size:15.5px;}
@media(max-width:900px){ .wr-toprow{grid-template-columns:1fr;} }
@media(max-width:520px){ .wr-metrics{grid-template-columns:1fr;} }

/* "Much larger font" — the card's own heading, not the section bands. */
.weekly-report .wr-title{font-family:var(--display,Newsreader),serif; font-size:26px; line-height:1.15;
  margin:0 0 4px; color:var(--ink);}

.metrics-row{display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin:18px 0;}
@media(max-width:420px){
  .metrics-row{grid-template-columns:1fr;}
}
.metric-card{background:var(--card); border:1px solid var(--edge); border-radius:12px; padding:14px 16px;}
.metric-label{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.04em; text-transform:uppercase; color:var(--faint);}
.metric-value{display:block; font-family:var(--display); font-weight:700; font-size:22px; margin-top:4px;}
.course-breakdown{margin-top:8px;}
.course-row{display:flex; justify-content:space-between; padding:8px 0; border-top:1px solid var(--edge2); font-size:16px;}
.course-row:first-child{border-top:none;}
.func-list{margin-top:8px;}
.func-row{display:flex; justify-content:space-between; padding:8px 0; border-top:1px solid var(--edge2); font-size:16px;}
.func-row:first-child{border-top:none;}
.func-label{color:var(--muted);}
.func-value{font-family:var(--mono); color:var(--ink);}
.weekly-report{background:var(--card); border:1px solid var(--edge); border-radius:14px; padding:18px 17px 16px; margin-top:16px;}
.wr-title{font-family:var(--display); font-weight:600; font-size:18px; margin:0;}
/* MOBILE (2026-08-10, Marc). The weekly panel is rendered inside pages that
   were built at desktop width, and on a phone it sat wider than the viewport
   — the page scrolled sideways and the text either side was cut off. The
   metric tiles already collapse to one column; what was missing is a floor
   on the panel itself, so nothing inside it can force the card wider than
   the screen it is on. */
@media (max-width:760px){
  .weekly-report{ max-width:100%; box-sizing:border-box; overflow-x:hidden; }
  .weekly-report .metric-card{ min-width:0; }
  .wr-title{ font-size:17px; word-break:break-word; }
}
.wr-facts{margin-top:8px;}
.weekly-report .metrics-row{margin:14px 0;}
.wr-section{margin-top:14px; border-top:1px solid var(--edge2); padding-top:12px;}
.wr-section h4{font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); margin:0 0 4px;}
.hubfoot h3{font-family:var(--mono); font-size:15.5px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); margin:0 0 9px;}
.chips{display:flex; flex-wrap:wrap; gap:6px;}
.chip{font-family:var(--mono); font-size:15px; background:var(--bad-bg); border:1px solid var(--bad-line); color:var(--bad);
  border-radius:6px; padding:4px 9px;}
.chip.none{background:var(--good-bg); border-color:var(--good-line); color:var(--good);}

/* ---------- subject view ---------- */
/* Was 13.5px muted mono with no border and no padding — small, low-contrast
   and easy to miss on a page of full-width buttons. It is the control people
   reach for most, so it gets a real target and readable text. */
.back{font-family:var(--mono); font-size:15px; letter-spacing:.06em; text-transform:uppercase; color:var(--ink);
  background:var(--card2); border:1px solid var(--edge); border-radius:9px;
  padding:10px 16px; margin-bottom:6px; cursor:pointer; display:inline-flex; align-items:center; gap:8px;}
.back:hover{color:var(--accent); border-color:var(--accent);}
.shead{margin-bottom:18px;}
.shead .back{margin-bottom:6px;}
.shead h2{font-family:var(--display); font-weight:700; font-size:23.5px; margin:0;}

.quizhead{display:flex; align-items:baseline; justify-content:space-between; margin:24px 2px 9px;}
.quizhead h2{font-family:var(--display); text-transform:uppercase; font-weight:600; letter-spacing:.03em; font-size:23.5px; margin:0;}
.quizhead h2.topiclist{text-transform:none; font-size:15px; font-weight:500; letter-spacing:.01em; color:var(--muted); line-height:1.35;}
.score{font-family:var(--mono); font-size:15px; color:var(--muted); border:1px solid var(--edge); background:var(--card); padding:3px 10px; border-radius:99px;}
.bar{height:5px; background:var(--edge); border-radius:99px; overflow:hidden; margin:0 2px 16px;}
.bar>i{display:block; height:100%; width:0; background:var(--accent); transition:width .35s ease;}

/* ---------- question card ---------- */
.card{background:var(--card); border:1px solid var(--edge); border-radius:14px; padding:18px 17px 16px;}
.diag-row{display:flex; justify-content:space-between; align-items:center; padding:9px 0; border-top:1px dashed var(--edge); font-size:15.5px; color:var(--muted);}
.diag-row:first-of-type{border-top:none;}
.diag-row b{color:var(--ink); font-family:var(--mono); font-weight:700;}
.qnum{font-family:var(--mono); font-size:15px; letter-spacing:.08em; color:var(--faint); text-transform:uppercase;}
.badge{font-family:var(--mono); font-size:13.5px; letter-spacing:.08em; text-transform:uppercase; color:#fff;
  background:var(--accent); border-radius:4px; padding:2px 6px; margin-left:8px;}
/* Mockup 5e (2026-08-19): the question named above its stem, and the
   steps-done recap that keeps the command word + what it acts on in view
   while the first move is chosen. */
.q-eyebrow{font-family:var(--mono); font-size:13px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent-ink); margin:2px 0 0;}
.qrecap{border:1px solid var(--edge-control); border-radius:10px; background:var(--paper2);
  padding:12px 15px; margin:14px 0 4px;}
.qrecap-h{display:flex; align-items:center; gap:8px; font-family:var(--mono); font-size:13px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--accent-ink);}
.qrecap-chip{display:inline-flex; align-items:center; justify-content:center; width:18px; height:18px;
  border-radius:50%; background:var(--accent); color:var(--paper2); font-style:normal; font-size:13px;}
.qrecap p{margin:8px 0 0; font-size:16px; color:var(--muted);}
.qrecap p b{color:var(--ink);}
.askstep{color:var(--warn);}

.stem{font-size:19.5px; line-height:1.45; margin:12px 0 2px; font-weight:500;}
.stem mark{background-color:transparent; color:inherit;
  background-image:linear-gradient(var(--accent-soft),var(--accent-soft)); background-repeat:no-repeat;
  background-size:0% 44%; background-position:0 86%; padding:0 2px;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
  animation:swipe .5s cubic-bezier(.4,.9,.3,1) forwards;}
@keyframes swipe{to{background-size:100% 44%;}}
.ask{font-family:var(--mono); font-size:16px; letter-spacing:.06em; text-transform:uppercase; margin:15px 0 10px; color:var(--accent);}

.opts{display:grid; gap:9px;}
.opt{display:flex; gap:11px; align-items:center; width:100%; text-align:left; cursor:pointer; background:var(--card);
  border:1px solid var(--edge-control); border-radius:10px; padding:13px; font-size:17px; color:var(--ink);
  transition:border-color .15s, background .15s;}
.opt:hover{border-color:var(--faint);}
.opt:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* Text input inside a setup card — the school typeahead and the add-a-club
   field (renderSchoolStep / renderClubStep in app.js). There was no
   class-based text-input rule in this file at all before these two screens
   needed one: every other input here is a checkbox, a range, or the
   join-code field with its own bespoke rule. Deliberately matched to .opt
   above rather than invented, so a field and the options under it read as
   one control stack. */
.ifield{display:block; width:100%; background:var(--card); color:var(--ink);
  border:1px solid var(--edge-control); border-radius:10px; padding:13px;
  font-family:var(--body); font-size:17px; margin-bottom:10px;}
.ifield::placeholder{color:var(--muted); opacity:1;}
.ifield:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
/* The add-your-own club row: field and its button side by side. Its own
   class rather than reusing .opts, which is a single-column grid — a grid
   item does not flex, so the two would have stacked. */
.clubown{display:flex; gap:9px; align-items:stretch;}
.clubown .ifield{margin-bottom:0; flex:1 1 auto; min-width:0;}
/* Real checkbox rows for multi-select intake questions — a label wrapping
   an actual <input type=checkbox>, not a button that just changes color,
   since a genuine checkbox is a clearer "pick more than one" affordance. */
.opt.checkopt{cursor:pointer;}
.opt.checkopt input[type=checkbox]{width:20px; height:20px; accent-color:var(--accent); cursor:pointer; flex:0 0 auto;}
/* Neutral selection state for assessment mode — deliberately NOT using
   --good/--warn here, since the whole point of this mode is that nothing
   reveals right or wrong until the student actually submits. This only
   ever means "this is what you picked," same visual weight regardless of
   whether it turns out to be correct. */
.opt.picked{background:var(--accent-soft); border-color:var(--accent);}
.opt.picked .key{background:var(--accent); color:var(--paper2);}
.opt .key{flex:0 0 auto; width:24px; height:24px; border-radius:5px; background:var(--edge); color:var(--muted);
  font-family:var(--mono); font-weight:600; font-size:15.5px; display:grid; place-items:center;}
.opt .mk{flex:0 0 auto; width:18px; text-align:center; font-family:var(--mono); font-weight:600; opacity:0;}
.opt.correct{background:var(--good-bg); border-color:var(--good-line);}
.opt.correct .key{background:var(--good); color:#fff;}
.opt.correct .mk{opacity:1; color:var(--good);}
/* Softened from --bad (alarm red) to --warn (the same warm amber already
   used for the word-check quiz's "unsure" wrong state) — a wrong answer
   during learning isn't a system error, and reads a lot less demoralizing
   as "worth a second look" amber than as stop-sign red. Actual system
   errors (failed login, a form that didn't submit) stay on --bad
   elsewhere — this change is scoped to in-quiz wrong-answer feedback only. */
/* .opt.right was MISSING (2026-08-04). The scaffold adds "right" to a
   correctly chosen option and "wrong" to an incorrect one, but only .wrong
   was ever styled — so picking the RIGHT answer painted nothing and the
   choice looked like it had not registered at all. The disabled state also
   had no visual, so the whole group looked untouched after answering. */
.opt.right{background:var(--good-bg); border-color:var(--good-line);}
.opt.right .key{background:var(--good); color:#06201C;}
.opt.right .mk{opacity:1; color:var(--good);}
.opt.wrong{background:var(--warn-bg); border-color:var(--warn-line);}
.opt.wrong .key{background:var(--warn); color:#16302A;}
.opt.wrong .mk{opacity:1; color:var(--warn);}
.opt.dim{opacity:.45;}
/* Answered: the options that were NOT chosen fade back, so the one that was
   chosen reads as the choice rather than as one of five equal buttons. */
.opt[disabled]{cursor:default; opacity:.5;}
.opt[disabled].right, .opt[disabled].wrong{opacity:1;}

.why{margin-top:13px; padding:13px 14px; border-radius:10px; background:var(--card2); border:1px solid var(--edge); font-size:16.5px; display:none;}
.why.show{display:block; animation:fade .25s ease;}
.why .lab{font-family:var(--mono); font-weight:600; font-size:15.5px; letter-spacing:.06em; text-transform:uppercase; display:block; margin-bottom:5px;}
.why.ok .lab{color:var(--good);}
.why.no .lab{color:var(--warn);}
.why.half .lab{color:var(--warn);}
.why .topic{display:inline-block; font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--accent-ink); background:var(--accent-soft); padding:2px 7px; border-radius:4px; margin-top:9px;}
@keyframes fade{from{opacity:0; transform:translateY(4px);}to{opacity:1; transform:none;}}

/* ---------- summary ---------- */
.done h2{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:27px; margin:0; text-align:center;}
.big{font-family:var(--display); font-size:56px; font-weight:600; line-height:1; color:var(--accent); text-align:center; margin:8px 0 0;}
.big small{font-size:23.5px; color:var(--faint);}
.msg{color:var(--muted); font-size:17px; margin:10px auto 0; max-width:none; text-align:center;}
.rev{margin-top:20px; border-top:1px solid var(--edge2); padding-top:16px;}
.rev h3{font-family:var(--mono); font-size:15.5px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); margin:0 0 9px;}
.rev ul{list-style:none; margin:0; padding:0; display:grid; gap:6px;}
.rev li{display:flex; align-items:center; gap:9px; font-size:16px; background:var(--card); border:1px solid var(--edge2); border-radius:8px; padding:9px 11px;}
.rev li .n{font-family:var(--mono); font-size:14.5px; font-weight:600; color:var(--warn); background:var(--warn-bg); border-radius:4px; padding:2px 6px;}
.rev .clean{font-size:16px; color:var(--good); background:var(--good-bg); border:1px solid var(--good-line); border-radius:8px; padding:10px 12px;}

.coach{margin-top:16px; border:1px solid var(--accent-soft); background:var(--card2); border-radius:12px; padding:15px;}
.coach h3{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:18px; margin:0 0 6px; color:var(--accent-ink);}
.coach p{margin:0; font-size:16.5px;}
.coach .status{font-family:var(--mono); font-size:16px; color:var(--muted); display:flex; align-items:center; gap:8px;}
.dot{width:7px; height:7px; border-radius:50%; background:var(--accent); animation:pulse 1s infinite;}
@keyframes pulse{0%,100%{opacity:.25;}50%{opacity:1;}}
.coach.err{background:var(--bad-bg); border-color:var(--bad-line);}
.coach .note{font-size:15px; color:var(--muted); margin-top:6px;}

.paste label{font-family:var(--mono); font-size:15px; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); display:block; margin:12px 0 6px;}
.paste textarea{width:100%; min-height:110px; font-family:var(--mono); font-size:15.5px; line-height:1.5; color:var(--ink);
  background:var(--card); border:1px solid var(--edge); border-radius:9px; padding:11px; resize:vertical;}
.paste textarea:focus{outline:2px solid var(--accent); outline-offset:1px;}
.step{display:flex; gap:9px; align-items:flex-start; font-size:16px; margin:10px 0;}
.step .n{font-family:var(--mono); font-size:14.5px; font-weight:600; color:var(--paper2); background:var(--accent);
  border-radius:4px; padding:2px 7px; flex:0 0 auto; margin-top:2px;}

/* ---------- voice commands ---------- */
.voiceoverlay{position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:80;
  display:flex; align-items:flex-end; justify-content:center; padding:0;}
@media(min-width:640px){.voiceoverlay{align-items:center; padding:20px;}}
.voicecard{width:100%; max-width:480px; border-radius:16px 16px 0 0; margin:0;}
@media(min-width:640px){.voicecard{border-radius:14px;}}
.voicecard h3{font-family:var(--display); font-size:20.5px; margin-bottom:8px;}
.voicestatus{text-align:center; padding:8px 0 4px;}
.voicemic{display:inline-flex; color:var(--accent);}
.voicemic.listening{animation:voicepulse 1.1s ease-in-out infinite;}
@keyframes voicepulse{0%,100%{opacity:1; transform:scale(1);} 50%{opacity:.55; transform:scale(1.12);}}
.voicelabel{font-family:var(--mono); font-size:15px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted); margin:10px 0 4px;}
.voicetranscript{font-size:17.5px; color:var(--ink); min-height:1.4em; margin:0;}
.voicecard .actions{flex-wrap:wrap;}
.voicecard .btn{flex:1; min-width:120px;}

.toast{position:fixed; left:50%; bottom:calc(18px + var(--safe-bot)); transform:translateX(-50%);
  background:var(--card2); border:1px solid var(--edge2); color:#fff; font-family:var(--mono); font-size:16px; padding:10px 16px; border-radius:99px;
  opacity:0; pointer-events:none; transition:opacity .25s; z-index:50;}
.toast.show{opacity:1;}

.foot{font-family:var(--mono); color:var(--faint); font-size:15px; text-align:center; margin:26px 8px 0; line-height:1.8;}
.foot a{color:var(--muted);}

@media (prefers-reduced-motion: reduce){
  *{animation:none !important; transition:none !important;}
  .stem mark{background-size:100% 44%;}
}

/* ---------- word check ---------- */
.wordcta{background:var(--card); border:1px solid var(--edge); border-left:5px solid var(--accent);
  border-radius:12px; padding:16px 16px 14px; margin:14px 0 4px;}
.wc-head{display:flex; align-items:baseline; gap:10px;}
.wordcta h3{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:19px; margin:0; letter-spacing:.02em;}
.wc-n{font-family:var(--mono); font-size:14.5px; color:var(--faint); margin-left:auto;}
.wordcta p{font-size:16px; color:var(--muted); margin:6px 0 12px;}
.wordcta p b{color:var(--ink);}
.wordcta .btn{padding:12px 18px;}

.term{font-family:var(--display); text-transform:uppercase; font-weight:600; letter-spacing:.02em;
  font-size:27px; line-height:1.1; margin:12px 0 2px; color:var(--accent-ink);}
.opt.unsure{background:transparent; border-style:dashed; color:var(--muted);}
.opt.unsure .key{background:transparent; border:1px solid var(--edge); color:var(--faint);}
.opt.unsure.wrong{background:var(--warn-bg); border-color:var(--warn-line); border-style:solid; color:var(--ink);}
.opt.unsure.wrong .key{background:var(--warn); color:#16302A; border:0;}
.opt.unsure.wrong .mk{color:var(--warn);}

.why .trap{margin-top:10px; padding-top:9px; border-top:1px solid var(--edge2);}
.why .trap span{display:block; font-family:var(--mono); font-size:14.5px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--bad); margin-bottom:3px;}
.why .topic+.topic{margin-left:5px;}
.chip.word{background:var(--warn-bg); border-color:var(--warn-line); color:var(--warn);}

/* ---------- word usage: tap a topic to see the word in the wild ---------- */
.usewhere{font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--faint); margin:12px 0 7px;}
.tags{display:flex; flex-wrap:wrap; gap:6px;}
.topic.tap{cursor:pointer; border:1px solid var(--accent-soft); background:var(--card2); color:var(--ink);
  font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase;
  padding:5px 9px; border-radius:5px; display:inline-flex; align-items:center; gap:5px; transition:background .15s;}
.topic.tap::after{content:"+"; font-weight:600; color:var(--accent-ink); opacity:.9;}
.topic.tap:hover{background:var(--accent-soft);}
.topic.tap:focus-visible{outline:2px solid var(--accent); outline-offset:2px;}
.topic.tap.open{background:var(--accent); color:var(--paper2); border-color:var(--accent);}
.topic.tap.open::after{content:"–";}
.usage{display:none;}
.usage.show{display:block; margin-top:10px; animation:fade .2s ease;}
.unote{margin:0 0 9px; font-size:16px;}
.unote.soft{color:var(--muted); font-size:15px;}
.uex{background:var(--card); border:1px solid var(--edge); border-radius:9px; padding:11px 12px;}
.ulab{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--faint); margin-bottom:6px;}
.ustem{font-size:16.5px; font-weight:500; line-height:1.4;}
.ustem mark{background-color:transparent; background-image:linear-gradient(var(--accent-soft),var(--accent-soft));
  background-repeat:no-repeat; background-size:100% 44%; background-position:0 86%; padding:0 2px; animation:none;}
.umove{margin-top:9px; padding-top:8px; border-top:1px solid var(--edge2); font-size:15.5px; color:var(--muted);}
.umove span{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--good); margin-bottom:2px;}

/* ---------- word check v2: definition reveal ---------- */
.mixup{background:var(--bad-bg); border:1px solid var(--bad-line); border-radius:8px; padding:9px 11px;
  font-size:16px; margin-bottom:10px;}
.mean{font-size:17px; margin-bottom:11px;}
.illus{background:var(--card); border:1px solid var(--edge); border-radius:9px; padding:11px 12px;}
.ilab{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--faint); margin-bottom:6px;}
.ishow{font-family:var(--mono); font-size:16px; background:var(--paper2); border-radius:6px; padding:8px 10px; margin-bottom:8px;}
.isays{font-size:16px; color:var(--muted); line-height:1.45;}
.why .trap{margin-top:11px;}
.mixrow{background:var(--bad-bg) !important; border-color:var(--bad-line) !important;}
.topic.flat{border:1px solid var(--edge); background:transparent; color:var(--muted);
  font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase;
  padding:5px 9px; border-radius:5px; display:inline-block;}

/* ---------- the review gate ---------- */
.review{margin-top:20px; border-top:1px solid var(--edge2); padding-top:16px;}
.review h3{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:19px; margin:0 0 2px;}
.rsub{font-size:15.5px; color:var(--muted); margin:0 0 12px;}

.ritem{border:1px solid var(--edge); border-radius:10px; margin-bottom:8px; background:var(--card); overflow:hidden;}
.ritem.done{border-color:var(--good-line); background:var(--good-bg);}
.rhead{display:flex; align-items:flex-start; gap:10px; width:100%; text-align:left; background:none; border:0;
  padding:12px 13px; cursor:pointer; color:var(--ink); font:inherit;}
.rhead:focus-visible{outline:2px solid var(--accent); outline-offset:-2px;}
.rtick{flex:0 0 auto; width:19px; height:19px; border-radius:5px; border:1.5px solid var(--faint); margin-top:2px;}
.ritem.done .rtick{background:var(--good); border-color:var(--good); position:relative;}
.ritem.done .rtick::after{content:"✓"; color:#fff; font-size:15.5px; position:absolute; inset:0;
  display:grid; place-items:center; line-height:1;}
.rtext{flex:1; font-size:16.5px; line-height:1.4;}
.rkind{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--accent); margin-bottom:3px;}
.rchev{flex:0 0 auto; color:var(--faint); transition:transform .2s; font-size:18px; margin-top:1px;}
.ritem.open .rchev{transform:rotate(90deg);}

.rbody{display:none; padding:0 13px 13px 42px;}
.ritem.open .rbody{display:block;}
.rbody p{margin:0 0 11px; font-size:16px; line-height:1.5;}
.rwrong,.rright{font-size:16px; border-radius:8px; padding:9px 11px; margin-bottom:7px;}
.rwrong{background:var(--bad-bg); border:1px solid var(--bad-line);}
.rright{background:var(--good-bg); border:1px solid var(--good-line);}
.rwrong span,.rright span{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em;
  text-transform:uppercase; margin-bottom:3px;}
.rwrong span{color:var(--bad);} .rright span{color:var(--good);}
.rack{margin-top:6px; font-family:var(--mono); font-size:15.5px; letter-spacing:.04em; text-transform:uppercase;
  background:var(--accent); color:var(--paper2); border:0; border-radius:8px; padding:9px 16px; cursor:pointer;}
.rack:disabled{background:var(--good); cursor:default;}

.rprog{font-family:var(--mono); font-size:15.5px; color:var(--muted); text-align:center; margin:0 0 10px;}

/* ---------- add-to-home-screen bar ---------- */
.installbar{position:fixed; left:12px; right:12px; bottom:12px; z-index:50;
  display:flex; align-items:center; gap:10px; background:var(--card2); border:1px solid var(--edge2); color:#fff;
  border-radius:12px; padding:10px 12px; box-shadow:0 6px 24px rgba(0,0,0,.45);
  max-width:616px; margin:0 auto;}
.installbar .btn{flex:1; width:auto; margin:0; background:var(--accent); border-color:var(--accent);}
.installbar.ios{font-size:15.5px; line-height:1.45; padding:12px 14px;}
.installbar.ios b{color:#fff;}
.installx{flex:0 0 auto; background:transparent; border:0; color:#fff; opacity:.6;
  font-size:17px; cursor:pointer; padding:6px 8px; line-height:1;}
.installx:hover{opacity:1;}
@supports (padding: max(0px)){ .installbar{bottom:max(12px, env(safe-area-inset-bottom));} }
/* The install sheet: opened from the Account menu, in place. */
.installsheet{position:fixed; inset:0; z-index:70; background:rgba(0,0,0,.5); display:flex; align-items:flex-end; justify-content:center;}
.installsheet-panel{background:var(--card); border:1px solid var(--edge); border-radius:16px 16px 0 0; padding:18px 18px 22px;
  width:100%; max-width:520px; box-shadow:0 -6px 24px rgba(0,0,0,.4);}
.installsheet-panel h3{margin:0 0 6px;}
.installsheet-panel .isub{font-size:15.5px; line-height:1.5;}
.installsheet-panel .actions{margin-top:14px;}
@supports (padding: max(0px)){ .installsheet-panel{padding-bottom:max(22px, env(safe-area-inset-bottom));} }
@media (min-width:640px){ .installsheet{align-items:center;} .installsheet-panel{border-radius:16px;} }

/* ---------- intake ---------- */
.ihead{margin-bottom:14px;}
.ibar{height:4px; background:var(--edge); border-radius:99px; overflow:hidden; margin-top:8px;}
.ibar>i{display:block; height:100%; background:var(--accent); transition:width .3s;}
.iq{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:23.5px; line-height:1.15; margin:0 0 6px;}
.isub{color:var(--muted); font-size:16px; margin:0 0 14px;}
.itest{font-family:var(--mono); font-size:14.5px; letter-spacing:.05em; text-transform:uppercase; color:var(--accent-ink);
  background:var(--accent-soft); border-radius:6px; padding:7px 9px; margin-bottom:14px;}
.iopt{display:block;}
.inote{display:block; font-size:16px; color:var(--muted); margin-top:2px;}
.opt.on{background:var(--accent-soft); border-color:var(--accent);}

/* ---------- worked example (experiment arm) ---------- */
.worked{margin-top:12px; padding-top:11px; border-top:1px dashed var(--edge);}
.wlab{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--faint); margin-bottom:7px;}
.wstem{font-size:16px; font-weight:500; line-height:1.4; margin-bottom:8px;}
.wstem mark{background-image:linear-gradient(var(--accent-soft),var(--accent-soft)); background-repeat:no-repeat;
  background-size:100% 44%; background-position:0 86%; padding:0 2px; animation:none;}
.wmove{font-size:15.5px; color:var(--ink);}
.wmove span{display:block; font-family:var(--mono); font-size:13.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--good); margin-bottom:2px;}
.wwhy{font-size:15px; color:var(--muted); margin-top:6px;}

/* ---------- findings ---------- */
.finding{margin-bottom:12px;}
.fhead{display:flex; justify-content:space-between; align-items:center; gap:10px; margin-bottom:9px;}
.flab{font-family:var(--display); text-transform:uppercase; font-weight:600; font-size:18px;}
.fpill{font-family:var(--mono); font-size:13.5px; letter-spacing:.06em; text-transform:uppercase;
  padding:3px 8px; border-radius:99px; flex:0 0 auto; white-space:nowrap;}
.fpill.wait{background:var(--edge2); color:var(--muted);}
.fpill.null{background:var(--warn-bg); color:var(--warn); border:1px solid var(--warn-line);}
.fpill.win{background:var(--good-bg); color:var(--good); border:1px solid var(--good-line);}
.fclaim{font-size:16px; color:var(--muted); margin:0 0 10px;}
.fbar{height:5px; background:var(--edge); border-radius:99px; overflow:hidden; margin-bottom:9px;}
.fbar>i{display:block; height:100%; background:var(--accent);}
.frow{display:flex; align-items:center; gap:10px; font-size:16.5px; padding:8px 0; border-bottom:1px solid var(--edge2);}
.frow span:first-child{flex:1;}
.fnum{font-family:var(--mono); font-weight:600; font-size:17px;}
.fnum.over{color:var(--bad);} .fnum.under{color:var(--accent);}
.fn{font-family:var(--mono); font-size:14.5px; color:var(--faint);}
.fmsg{font-size:16px; margin:10px 0 0; line-height:1.5;}
.fverdict{margin-top:11px; padding:10px 12px; border-radius:9px; font-size:16px;}
.fverdict.right{background:var(--good-bg); border:1px solid var(--good-line);}
.fverdict.wrong{background:var(--bad-bg); border:1px solid var(--bad-line);}
.fverdict.flat{background:var(--warn-bg); border:1px solid var(--warn-line);}
.findlink{display:flex; align-items:center; justify-content:space-between; width:100%; margin-top:14px;
  background:var(--card); border:1px solid var(--accent-soft); border-radius:12px; padding:15px 16px;
  font-family:var(--mono); font-size:16px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--accent-ink); cursor:pointer;}
.findlink:hover{background:var(--accent-soft);}
.findlink .chev{font-size:19px; opacity:.6;}
.fpill.lean{background:var(--accent-soft); color:var(--accent-ink);}
.frange{font-family:var(--mono); font-size:15.5px; color:var(--muted); margin:8px 0 0; line-height:1.5;}
.challenge{border-left:3px solid var(--accent); padding-left:14px;}
.clab{font-family:var(--mono); font-size:14px; letter-spacing:.08em; text-transform:uppercase; color:var(--accent); display:block; margin-bottom:6px;}
.cask{font-size:17.5px; margin:8px 0 0; line-height:1.5;}
.cwhy{font-size:15.5px; color:var(--muted); margin:10px 0 0; line-height:1.5;}

/* ---------- essay workbench ---------- */
.essaylink{border-color:var(--edge); color:var(--ink);}
.elab{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--faint); margin:14px 0 5px;}
.elab.hot{color:var(--accent); font-weight:600;}
.etext{width:100%; border:1px solid var(--edge); border-radius:9px; padding:10px 11px; font:inherit;
  font-size:17px; line-height:1.5; background:var(--card); resize:vertical; margin-bottom:16px; color:var(--ink);}
.etext:focus{outline:none; border-color:var(--accent);}
/* NATIVE DATE CONTROLS NEED TELLING (2026-08-17). A browser renders an
   unstyled input[type=date] — and critically its calendar-picker icon and
   popup — as light chrome regardless of the surrounding theme; background
   and color alone cannot reach the picker. Same fix already made on
   start.html for the DOB field. First needed in-app for the mark form. */
input[type=date].etext{color-scheme:dark;}
/* input[type=file]'s "Choose File" button is a distinct sub-element
   browsers render natively — setting background/color on .etext itself
   only ever reaches the "No file chosen" text next to it, never the
   button, which is why this kept rendering as a plain white/gray default
   button regardless of .etext being applied. Both selectors needed for
   cross-browser coverage: ::file-selector-button is the modern standard,
   ::-webkit-file-upload-button is the older Safari/Chrome equivalent. */
.etext::file-selector-button, .etext::-webkit-file-upload-button{
  background:var(--card2); color:var(--ink); border:1px solid var(--edge); border-radius:6px;
  padding:6px 12px; font:inherit; font-size:15px; cursor:pointer; margin-right:10px;}
.etext::file-selector-button:hover, .etext::-webkit-file-upload-button:hover{border-color:var(--accent-soft);}

/* Click-to-open calendar — replaces a plain <input type=date>, which on
   some browser/OS combinations rendered as unstyled "yyyy-mm-dd" text
   rather than anything resembling a calendar. */
.dp-wrap{position:relative; margin-bottom:16px;}
.dp-trigger{text-align:left; cursor:pointer; margin-bottom:0;}
.dp-trigger.dp-placeholder{color:var(--muted);}
.dp-popup{position:absolute; top:calc(100% + 6px); left:0; z-index:40; background:var(--card2);
  border:1px solid var(--edge); border-radius:10px; padding:12px; width:280px; max-width:calc(100vw - 32px);
  box-shadow:0 8px 24px rgba(0,0,0,.35);}
.dp-head{display:flex; align-items:center; justify-content:space-between; margin-bottom:8px;}
.dp-label{font-family:var(--mono); font-size:15px; font-weight:600; text-transform:uppercase; letter-spacing:.04em;}
.dp-nav{background:none; border:1px solid var(--edge-control); border-radius:6px; width:28px; height:28px;
  font-size:16px; color:var(--ink); cursor:pointer; line-height:1;}
.dp-nav:hover{border-color:var(--accent-soft); color:var(--accent-ink);}
.dp-grid{display:grid; grid-template-columns:repeat(7, 1fr); gap:3px;}
.dp-dow{font-family:var(--mono); font-size:12.5px; color:var(--faint); text-align:center; padding:4px 0;}
.dp-day{background:none; border:1px solid transparent; border-radius:6px; padding:7px 0; font-size:15.5px;
  color:var(--ink); cursor:pointer;}
.dp-day:hover:not(.dp-disabled){border-color:var(--accent-soft);}
.dp-day.on{background:var(--accent); color:var(--paper2);}
.dp-day.dp-disabled{color:var(--faint); cursor:default; opacity:.35;}
.dp-empty{visibility:hidden;}

.gradepick{display:flex; gap:8px; flex-wrap:wrap; margin-bottom:16px;}
.gradebtn{font-family:var(--mono); font-size:15px; padding:9px 15px; border-radius:8px; border:1px solid var(--edge-control);
  background:var(--card2); color:var(--muted); cursor:pointer;}
.gradebtn.on{background:var(--accent); color:var(--paper2); border-color:var(--accent);}

.accordion{margin-top:6px;}
.problem-row{display:flex; align-items:center; justify-content:space-between; gap:12px;
  width:100%; text-align:left; margin-top:8px; padding:14px 16px; border-radius:12px;}
.problem-row:hover, .problem-row:focus-visible{border-color:var(--accent); background:var(--card);}
.problem-row-text{flex:1;}
.problem-row-time{display:block; margin-top:2px; font-size:14.5px; color:var(--muted);}
.problem-row-arrow{color:var(--accent); font-size:18px; flex-shrink:0; transition:transform .15s;}
.problem-row:hover .problem-row-arrow{transform:translateX(3px);}
.linklike{background:none; border:0; padding:0; margin-top:16px; color:var(--muted); font-size:16px;
  text-decoration:underline; text-underline-offset:2px; cursor:pointer; display:block;}
.linklike:hover{color:var(--ink);}
.linklike.accent{color:var(--accent); font-size:16px; font-weight:600; text-decoration:none;}
.linklike.accent:hover{color:var(--accent-ink);}

/* month calendar — exam hub */
.cal-wrap{background:var(--card); border:1px solid var(--edge); border-radius:14px; padding:18px; margin-bottom:24px;}
.cal-title{font-family:var(--display); font-weight:600; font-size:19px; color:var(--ink); margin-bottom:14px;}
.cal-dow{display:grid; grid-template-columns:repeat(7,1fr); gap:6px; margin-bottom:6px;}
.cal-dow span{font-family:var(--mono); font-size:13px; letter-spacing:.06em; text-transform:uppercase; color:var(--faint); text-align:center;}
.cal-grid{display:grid; grid-template-columns:repeat(7,1fr); gap:6px;}
.cal-cell{
  min-height:76px; background:var(--card2); border:1px solid var(--edge); border-radius:8px;
  padding:6px; display:flex; flex-direction:column; gap:3px; overflow:hidden;
}
.cal-cell--empty{background:transparent; border-color:transparent;}
.cal-daynum{font-family:var(--mono); font-size:14px; color:var(--faint);}
/* 12px, was 9.5 (2026-08-07, Marc: "we can increase the font size on the
   calendar entries"). 9.5px mono was small enough that course names were
   being read by their colour bar rather than actually read. The cells set a
   MIN height and grow to fit, so bigger text costs nothing on a busy day —
   it just makes a quiet one taller. */
.cal-tag{
  font-family:var(--mono); font-size:14px; font-weight:600; letter-spacing:.01em;
  padding:3px 6px; border-radius:4px; line-height:1.35; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.cal-tag--exam{background:var(--good-bg); color:var(--good); border:1px solid var(--good-line);}
.cal-tag--holiday{background:var(--warn-bg); color:var(--warn); border:1px solid var(--warn-line);}
.cal-cell--holiday{border-color:var(--warn-line);}
/* Left alone deliberately (2026-08-07): the cell keeps a neutral border and
   the COURSE colour lives on the chips inside it. Tinting the cell too meant
   a day with two subjects had to pick one of them for its outline, and on a
   grid of 30 cells the competing outlines read as noise. */
.cal-cell--exam{border-color:var(--edge-control);}
.cal-cell--clickable{cursor:pointer; text-align:left; font:inherit; align-items:flex-start; width:100%;}
.cal-cell--clickable:hover{border-color:var(--accent-soft);}
/* Drop target highlight (2026-08-11) — has to be obvious mid-drag, when the
   pointer is holding a chip and the cell under it is the only feedback. */
.cal-cell--dragover{ outline:2px solid var(--accent); outline-offset:-2px; background:var(--card2); }
.cal-cell--today{border-color:var(--accent); border-width:2px;}
.cal-grid--week{grid-template-columns:repeat(7,1fr);}
.cal-cell--week{min-height:120px;}
/* ONE STRIP (2026-09-01, Marc: "put them all on the same line. wasting real
   estate. the list view can go on the right"). + Add, the three period
   buttons and their arrows all live here now; List is pushed to the far
   right because it is a different kind of view from the other three, and a
   gap says that more quietly than a divider would. Wraps on a narrow screen
   rather than overflowing — cal-view-right's auto margin collapses to zero
   once the row wraps, which puts List at the start of the second line
   instead of stranded. */
.cal-controls{display:flex; align-items:center; gap:8px; margin:6px 0 16px; flex-wrap:wrap;}
.cal-controls .cal-add-wrap{margin:0 6px 0 0;}
.cal-view-right{margin-left:auto;}
@media(max-width:600px){ .cal-view-right{margin-left:0;} }
/* The one-day view: rows, not cells — with a whole day of space there is no
   reason to abbreviate anything. */
.cal-daylist{display:flex; flex-direction:column; gap:8px; margin-top:10px;}
.cal-dayrow{display:flex; align-items:center; justify-content:space-between; gap:12px;
  flex-wrap:wrap; padding:10px 12px; border:1px solid var(--edge); border-radius:10px;
  background:var(--card2);}
.cal-dayrow-main{flex:1; min-width:0;}
.cal-nav-btn{background:var(--card2); border:1px solid var(--edge-control); border-radius:8px; width:34px; height:34px;
  font-size:18px; color:var(--ink); cursor:pointer; line-height:1;}
.cal-nav-btn:hover{border-color:var(--accent-soft);}
.cal-view-btn{background:none; border:1px solid var(--edge-control); border-radius:8px; padding:7px 14px;
  font-family:var(--mono); font-size:15.5px; color:var(--muted); cursor:pointer;}
.cal-view-btn.active{background:var(--accent); border-color:var(--accent); color:var(--paper2);}
/* One calendar, with a view you control (2026-08-27). The chips sit between
   the month controls and the grid — read as part of the calendar, not as a
   settings panel you have to go somewhere to find. An unticked chip stays
   legible rather than fading out: the student has to be able to see what
   they've hidden in order to bring it back. */
.cal-filter{display:flex; flex-direction:column; gap:7px; margin:0 0 14px;}
/* SPREAD, NOT LUMPED (2026-08-28, Marc: "spread this out. No need to lump
   it together"). The chips bunched against the left edge of a 1400px row with
   two-thirds of it empty, which read as a fragment rather than a control.
   The label keeps its column and the chips share what is left — so four
   chips sit evenly across the row and eight still wrap cleanly. */
/* THE SPREAD IS NOT SCOPED TO ONE SURFACE (2026-09-02, Marc: "filter is
   still cramped on one side").

   These three rules were written for the dashboard on 2026-08-28 — "spread
   this out. No need to lump it together" — and scoped to .cal-filter-slot, a
   wrapper only the dashboard has. The standalone calendar page and the exam
   planner append the same filter bar with no slot around it, so on those two
   screens the chips kept their natural width and bunched against the left
   edge of a 1400px row: exactly the fragment-not-a-control the original note
   describes, still there on the surfaces nobody re-checked.

   A rule that needs an ancestor to work is a rule that silently does not
   apply somewhere (rule 17). Spreading is how a filter row behaves, so it
   says that. Nothing here is dashboard-specific. */
.cal-filter-row{display:flex; align-items:center; gap:10px; flex-wrap:wrap;}
.cal-filter-lab{flex:0 0 78px;}
.cal-filter-row .calchip{flex:1 1 0; min-width:150px; justify-content:center;}
.cal-filter-lab{font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--faint); min-width:62px;}
.calchip{display:inline-flex; align-items:center; gap:2px; cursor:pointer; user-select:none;
  border:1px solid var(--edge-control); border-radius:99px; padding:5px 11px 5px 8px;
  font-size:15px; color:var(--ink); background:var(--card2);}
.calchip:hover{border-color:var(--accent-soft);}
.calchip input{accent-color:var(--accent); margin:0; cursor:pointer;}
.calchip.off{color:var(--muted); background:none;}
.calchip-n{font-family:var(--mono); font-style:normal; font-size:13px; color:var(--faint); margin-left:5px;}
@media(max-width:600px){ .cal-filter-lab{min-width:0; width:100%;} }

/* The Export button sits beside + Add, not under it (2026-09-01) — the
   wrapper was inline-block, which stacked the two. inline-flex keeps the
   dropdown's absolute positioning working off the same box. */
.cal-add-wrap{position:relative; display:inline-flex; align-items:center; gap:10px;
  flex-wrap:wrap; margin-bottom:16px;}
/* .btn is width:100% by default — inside the flex toolbar it has to size
   to its own text or it takes the whole row and pushes Export beneath it. */
.cal-add-btn{padding:10px 18px; width:auto; flex:0 0 auto;}
.cal-add-menu{display:none; position:absolute; top:calc(100% + 6px); left:0; background:var(--card2);
  border:1px solid var(--edge); border-radius:10px; padding:6px; min-width:200px; z-index:20;
  box-shadow:0 8px 24px rgba(0,0,0,.35);}
.cal-add-menu.open{display:block;}
.cal-add-item{display:block; width:100%; text-align:left; background:none; border:0; border-radius:7px;
  padding:9px 12px; cursor:pointer; font-family:var(--mono); font-size:15.5px; color:var(--ink);}
.cal-add-item:hover{background:var(--edge2);}
@media(max-width:600px){
  .cal-cell{min-height:52px; padding:4px;}
  .cal-daynum{font-size:12.5px;}
  /* 10px on a phone, was 8. Seven cells across a phone is tight, so this
     cannot match the desktop size — but 8px mono was below the point where
     the label was doing any work at all. */
  .cal-tag{font-size:12px; padding:2px 4px;}
}
.grade-sec{border:1px solid var(--edge); border-radius:10px; margin-bottom:9px; overflow:hidden;}
.grade-head{display:flex; align-items:center; justify-content:space-between; padding:13px 16px; cursor:pointer;
  font-family:var(--body); font-weight:600; font-size:16.5px; background:var(--card2);}
.grade-head .cnt{font-family:var(--mono); font-size:14.5px; color:var(--faint); font-weight:400;}
.grade-body{display:none; padding:4px 16px 12px;}
.grade-sec.open .grade-body{display:block;}
.course-row{display:flex; align-items:center; gap:10px; padding:8px 0; border-top:1px solid var(--edge2);}
.course-row:first-child{border-top:0;}
.course-row input[type=checkbox], .course-row input[type=radio]{width:17px; height:17px; flex:0 0 auto; accent-color:var(--accent);}
.course-row label{margin:0; font-weight:500; font-size:16px; cursor:pointer;}
.cnt-inline{font-family:var(--mono); font-size:14.5px; color:var(--muted); font-weight:400;}
.eprompt{background:var(--paper2); border-left:3px solid var(--edge); padding:11px 13px; border-radius:0 8px 8px 0;
  font-size:16.5px; line-height:1.55; margin-bottom:4px;}
.ecalm{background:var(--accent-soft); border-radius:10px; padding:16px; font-size:17px; line-height:1.6;}
.eblock{flex:1; font-size:15px; color:var(--bad); margin:0; line-height:1.45;}
.rubric-analysis{background:var(--paper2); border-left:3px solid var(--edge); padding:16px 18px;
  border-radius:0 8px 8px 0; font-size:16.5px; line-height:1.65; margin-top:8px;}
.ehint{font-size:15px; color:var(--muted); line-height:1.5; margin:8px 0 0;}
.ewarn{background:var(--warn-bg); border:1px solid var(--warn-line); border-radius:9px; padding:12px;
  font-size:16px; line-height:1.55; margin-bottom:10px;}
.edraft{background:var(--paper2); border-radius:8px; padding:10px 12px; font-size:16px; margin:12px 0;}
.edraft span{display:block; font-family:var(--mono); font-size:13.5px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--faint); margin-bottom:3px;}

.cap{border:1px solid var(--edge); border-left:3px solid var(--edge); border-radius:9px; padding:12px; margin-bottom:10px;}
.cap.ok{border-left-color:var(--good);}
.capcol{display:block; margin-bottom:10px;}
.capcol:last-child{margin-bottom:0;}
.capcol label{display:block; font-family:var(--mono); font-size:13.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--faint); margin:8px 0 3px;}
.capcol textarea{width:100%; border:1px solid var(--edge); border-radius:7px; padding:8px 9px;
  font:inherit; font-size:16px; line-height:1.45; resize:vertical;}
.capdel{background:none; border:0; color:var(--faint); font-size:15.5px; cursor:pointer; margin-top:8px; padding:4px 0;}
.capdel:hover{color:var(--bad);}
.ediscard{font-size:15px; color:var(--good); margin-top:8px;}

.pile{border:1px solid var(--edge); border-radius:9px; padding:11px; margin-bottom:9px;}
.pname{width:100%; border:0; border-bottom:1px solid var(--edge-control); padding:4px 0 6px; font:inherit;
  font-weight:600; font-size:17px; margin-bottom:8px;}
.pname:focus{outline:none; border-color:var(--accent);}
.chip{display:inline-block; background:var(--accent-soft); color:var(--accent-ink); border-radius:6px;
  padding:5px 9px; font-size:15px; margin:0 5px 5px 0; cursor:pointer; line-height:1.35; border:1px solid transparent;}
.chip:hover{border-color:var(--accent-soft);}
/* Missing entirely before this fix — the exam-scheduling day picker's JS
   was correctly toggling this exact class on click (selectedDays tracked
   the state fine), but with no .chip.on rule anywhere, nothing ever looked
   different, so it read as completely broken even though it wasn't. */
.chip.on{background:var(--accent); color:var(--paper2); border-color:var(--accent);}
.loose{margin-top:12px; padding-top:11px; border-top:1px dashed var(--edge);}
.loose h4{font-family:var(--mono); font-size:14px; letter-spacing:.05em; text-transform:uppercase;
  color:var(--faint); margin:0 0 7px; font-weight:400;}
.loosechip{background:var(--warn-bg); color:var(--warn);}

/* These five had no styling at all — the essay workbench (capture, cluster,
   choose, thesis, order steps) was rendering with zero custom layout. */
.captures{display:flex; flex-direction:column; gap:14px; margin:14px 0;}
.cluster{display:flex; flex-wrap:wrap; gap:12px; margin:14px 0;}
.cluster .pile{flex:1 1 240px;}
.choose{display:grid; gap:9px; margin:14px 0;}
.ethree{display:flex; flex-wrap:wrap; gap:8px; margin-bottom:16px;}
.orderlist{display:grid; gap:9px; margin:14px 0;}

.skel{border:1px solid var(--edge); border-radius:10px; padding:13px; margin-bottom:12px;}
.skel h4{font-family:var(--display); text-transform:uppercase; font-size:16px; margin:0 0 8px;}
.skelev{margin-bottom:4px;}
.skelplan{background:var(--paper2); border-radius:8px; padding:10px; margin-bottom:10px;}
.skelplan div{font-size:15.5px; line-height:1.45; margin-bottom:6px;}
.skelplan span{display:block; font-family:var(--mono); font-size:13px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--faint);}

.ratio{margin:14px 0;}
/* Mockup 5d (2026-08-19): plan-vs-prose as one split bar, both shares
   labelled inside it, the target named in the corner. Framed as a card so it
   reads as an instrument, not a stray progress bar. */
.ratio2{border:1px solid var(--edge-control); border-radius:10px; padding:14px 16px 6px;
  background:var(--paper2);}
.ratio-head{display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
  font-family:var(--mono); font-size:13px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted); margin-bottom:10px;}
.ratio-head span:first-child{color:var(--accent-ink);}
.rbar2{display:flex; height:26px; border-radius:6px; overflow:hidden; background:var(--card2);}
.rbar2>i{display:flex; align-items:center; height:100%; background:var(--accent);
  font-style:normal; min-width:0;}
.rbar2>i>b{padding:0 10px; font-family:var(--mono); font-size:13px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--paper2); white-space:nowrap;}
.rbar2>span{display:flex; align-items:center; justify-content:flex-end; flex:1; min-width:0;}
.rbar2>span>b{padding:0 10px; font-family:var(--mono); font-size:13px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--muted); white-space:nowrap;}
.checkhead{margin:18px 0 2px;}
.checkhead-n{font-family:var(--mono); font-size:14.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--accent-ink);}
.rbar{height:12px; background:var(--bad-bg); border-radius:99px; overflow:hidden;}
.rbar>i{display:block; height:100%; background:var(--good);}
.rlab{display:flex; justify-content:space-between; font-family:var(--mono); font-size:15px;
  color:var(--muted); margin-top:6px;}
.audit{display:flex; gap:9px; align-items:flex-start; padding:10px 0; border-bottom:1px solid var(--edge2);
  font-size:16px; line-height:1.5;}
.amark{flex:0 0 auto; font-weight:700;}
.audit.pass .amark{color:var(--good);}
.audit.fail .amark{color:var(--bad);}

/* ---------- diagnostic: exam paper, not an app ---------- */
.diaglink{border-color:var(--bad-line); color:var(--bad);}
.dmast{display:flex; justify-content:space-between; align-items:baseline; gap:12px;
  border-bottom:2px solid var(--ink); padding-bottom:9px; margin-bottom:10px;}
.dcourse{font-family:var(--mono); font-weight:600; text-transform:uppercase; letter-spacing:.1em;
  font-size:14.5px; color:var(--ink);}
.dno{font-family:var(--mono); font-size:13.5px; color:var(--faint); letter-spacing:.05em;}
.dtitle{font-family:var(--display); text-transform:uppercase; font-size:23.5px; line-height:1.15;
  margin:0 0 4px; font-weight:600;}
.dcond{border:1px solid var(--edge); border-left:3px solid var(--bad); padding:13px 15px; margin-top:16px;}
.dcond h3{font-family:var(--mono); text-transform:uppercase; letter-spacing:.09em; font-size:14px;
  color:var(--bad); margin:0 0 8px; font-weight:600;}
.dcond ul{margin:0; padding-left:17px; font-size:16.5px; line-height:1.6;}
.dcond li{margin-bottom:4px;}

.dpaper{background:#F3F9F7; --ink:#16302A; --muted:#7FA79C; --faint:#7FA79C; --edge:#A9CBC1; --edge2:#F3F9F7; --card2:#16302A; color:var(--ink);}
.dstory{margin-top:14px;}
.dline{display:grid; grid-template-columns:26px 1fr; column-gap:11px; align-items:baseline; margin-bottom:.95em;}
.dline .dn{font-family:var(--mono); font-size:13.5px; color:#A9CBC1; text-align:right; padding-top:.5em;}
.dline p{margin:0; font-size:18.5px; line-height:1.62;}
.dline em{font-style:italic;}
.dsect{font-family:var(--mono); font-weight:600; letter-spacing:.12em; text-transform:uppercase;
  font-size:14px; color:var(--accent); margin:22px 0 11px; padding-left:37px;}

.dprompt{border:1px solid var(--accent); padding:15px 16px; background:var(--accent-soft);}
.dlead{margin:0 0 10px; font-size:17px; line-height:1.55;}
.dtask{margin:0 0 10px; font-size:18px; line-height:1.5;}
.dnote{margin:0; font-size:15.5px; font-style:italic; color:var(--muted);}
.dpromptmini{font-size:16.5px; line-height:1.5; padding:11px 13px; background:var(--paper2);
  border-radius:8px; margin:0 0 14px;}

.dclock{position:sticky; top:0; z-index:20; display:flex; justify-content:space-between; align-items:center;
  background:var(--card2); border:1px solid var(--edge2); color:#fff; border-radius:10px; padding:9px 13px; margin-bottom:12px;}
.dtime{font-family:var(--mono); font-size:20.5px; font-weight:600; letter-spacing:.04em;}
.dtime.low{color:#EA8280;}
.dtime.over{color:#EA8280;}
.dref{background:rgba(255,255,255,.14); border:0; color:#fff; border-radius:7px; padding:6px 12px;
  font-family:var(--mono); font-size:14.5px; text-transform:uppercase; letter-spacing:.06em; cursor:pointer;}
.dscratch{margin-bottom:12px;}
.dscratch summary{font-family:var(--mono); font-size:14.5px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--faint); cursor:pointer; padding:6px 0;}
.dessay{min-height:340px; font-size:18px; line-height:1.7;}
.dcount{font-family:var(--mono); font-size:14.5px; color:var(--faint); text-align:right; margin-top:6px;}

.dmodal{position:fixed; inset:0; background:rgba(20,23,26,.55); z-index:60; overflow-y:auto; padding:16px;}
.dmodalin{max-width:640px; margin:0 auto; background:#F3F9F7; border-radius:12px; padding:18px;
  --ink:#16302A; --muted:#7FA79C; --faint:#7FA79C; --edge:#A9CBC1; --edge2:#F3F9F7; color:var(--ink);}
.dclose{background:var(--ink); color:#fff; border:0; border-radius:7px; padding:8px 14px;
  font-family:var(--mono); font-size:14.5px; text-transform:uppercase; cursor:pointer; margin-bottom:12px;}

/* ---------- accounts ---------- */
.joincode{font-family:var(--mono); font-size:38px; font-weight:600; letter-spacing:.14em;
  text-align:center; padding:20px; background:var(--accent-soft); color:var(--accent-ink);
  border-radius:12px; margin:14px 0;}
.joininput{font-family:var(--mono); font-size:29px; letter-spacing:.2em; text-align:center;
  text-transform:uppercase; padding:14px;}
.jc{font-family:var(--mono); letter-spacing:.08em;}
.claimnote{background:var(--good-bg); border:1px solid var(--good-line); border-radius:9px;
  padding:12px 14px; font-size:16px; color:var(--ink); text-align:left; margin-top:14px;}
.contract{text-align:left; margin-top:6px;}
.contract h3{font-family:var(--mono); font-size:14px; letter-spacing:.08em; text-transform:uppercase;
  margin:14px 0 7px; font-weight:600;}
.contract ul{margin:0; padding-left:18px; font-size:16.5px; line-height:1.6;}
.contract .see li{color:var(--ink);}
.contract .nosee li{color:var(--good);}
.cfoot{font-size:16px; line-height:1.55; margin-top:14px; padding-top:12px;
  border-top:1px solid var(--edge2); color:var(--muted);}

/* ---------- watch how (video) ---------- */
.watchhowrow{margin-top:12px;}
.watchhow{font-family:var(--mono); font-size:15.5px; letter-spacing:.03em; color:var(--accent-ink);
  background:var(--accent-soft); border-radius:99px; padding:7px 13px; display:inline-block; text-decoration:none;}
.watchhow:hover{filter:brightness(1.1);}

/* ---------- simplify terminology ---------- */
.simplifyrow{margin-top:12px;}
.simplifylink{font-family:var(--mono); font-size:15.5px; letter-spacing:.03em; color:var(--accent-ink);
  background:var(--accent-soft); border:0; border-radius:99px; padding:7px 13px; cursor:pointer;}
.simplifylink:hover{filter:brightness(1.1);}
.simplifylink:disabled{opacity:.6; cursor:default;}
.simplifyout{margin-top:10px; padding:14px 16px; border-radius:10px; background:var(--card2); border:1px solid var(--edge);}
.simplifyout .slab{display:block; font-family:var(--mono); font-size:14px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--accent-ink); margin-bottom:6px;}
.simplifyout p{color:var(--ink); font-size:16px; line-height:1.55; margin:0;}
.simplifyerr{display:block; margin-top:6px; font-family:var(--mono); font-size:15px; color:var(--muted);}

/* ---------- flag a question ---------- */
.flagrow{margin-top:12px;}
.flaglink{background:none; border:0; font-family:var(--mono); font-size:15px; letter-spacing:.04em;
  color:var(--faint); cursor:pointer; padding:4px 0; text-decoration:underline; text-underline-offset:2px;}
.flaglink:hover{color:var(--muted);}
.flagpicker{display:flex; flex-wrap:wrap; gap:7px; margin-top:9px;}
.flagchip{font-family:var(--mono); font-size:15px; letter-spacing:.03em; color:var(--muted);
  background:var(--card2); border:1px solid var(--edge); border-radius:99px; padding:6px 12px; cursor:pointer;}
.flagchip:hover{border-color:var(--bad); color:var(--ink);}
.flagdone{font-family:var(--mono); font-size:15px; color:var(--good); margin-top:9px;}
.card.daily{border-left:3px solid var(--accent);}
.dailyhead{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;}
.dailylab{font-family:var(--mono);font-size:14px;letter-spacing:.08em;text-transform:uppercase;color:var(--accent);}
/* TOMORROW, ON THE CHECK-IN (2026-08-29, Marc: "Daily check-ins should list
   the features and what is planned for tomorrow"). Its own block above the
   buttons, ruled off from the summary so closing the day and opening the next
   one read as two things. */
.evnext{margin-top:18px; padding-top:14px; border-top:1px solid var(--edge);}
.evnext .dailylab{display:block; margin-bottom:8px;}
.evnext-list{display:flex; flex-direction:column; gap:7px;}
.evnext-row{display:flex; align-items:baseline; gap:10px; font-size:16px;}
.evnext-row b{color:var(--ink); font-weight:600;}
.evnext-row span{font-family:var(--mono); font-size:13.5px; color:var(--faint);}
.card.daily .btn.ghost{margin-top:14px;}
.dailyskip{background:none;border:0;font-family:var(--mono);font-size:14.5px;color:var(--faint);
  cursor:pointer;padding:4px 0;letter-spacing:.04em;}
.dailyskip:hover{color:var(--ink);}

/* ---- Flashcards (flip-card recall mode) ---- */
.opt .isub{display:block; margin:4px 0 0; font-size:15px; line-height:1.35; color:var(--muted); text-transform:none; letter-spacing:0;}
.opt.on .isub{color:var(--ink);}
.fc-scene{perspective:1200px; margin:6px 2px 0;}
.fc-flip{position:relative; width:100%; min-height:230px; transition:transform .5s cubic-bezier(.2,.7,.2,1);
  transform-style:preserve-3d; cursor:pointer;}
.fc-flip.is-flipped{transform:rotateY(180deg);}
.fc-face{position:absolute; inset:0; backface-visibility:hidden; -webkit-backface-visibility:hidden;
  display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  background:var(--card); border:1px solid var(--edge); border-radius:16px; padding:26px 22px;}
.fc-front{border-color:var(--accent-soft);}
.fc-back{transform:rotateY(180deg); background:var(--card2); border-color:var(--accent);}
.fc-tag{position:absolute; top:14px; left:16px; font-family:var(--mono); font-size:13.5px; letter-spacing:.18em;
  text-transform:uppercase; color:var(--accent);}
.fc-text{font-family:var(--display); font-size:24px; line-height:1.3; color:var(--ink); max-width:none;}
.fc-back .fc-text{font-family:var(--body); font-size:19px; line-height:1.5;}
.fc-hint{margin-top:16px; font-family:var(--mono); font-size:15.5px; color:var(--muted); letter-spacing:.02em;}
/* An asked-for hint arrives where an Easy hint would have been, so the card
   reads identically once it is there — the difference is only that this one
   was earned (2026-08-24). */
.fc-hint-asked{animation:fc-hint-in .18s ease-out;}
@keyframes fc-hint-in{from{opacity:0; transform:translateY(-3px);} to{opacity:1; transform:none;}}
.fc-hintbtn{width:100%;}
.fc-tap{position:absolute; bottom:14px; left:0; right:0; font-family:var(--mono); font-size:14px;
  letter-spacing:.14em; text-transform:uppercase; color:var(--faint);}
.fc-trap{margin-top:16px; font-size:15.5px; color:var(--muted); line-height:1.45; max-width:none;}
.fc-trap span{display:block; font-family:var(--mono); font-size:13px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--faint); margin-bottom:3px;}
.fc-rate{display:flex; gap:10px; width:100%;}
.fc-rate .btn{flex:1; margin-top:0;}
.fc-voice{width:100%; margin-top:0;}
.fc-voicenote{margin-top:12px; padding:12px 14px; border-radius:12px; font-size:15px; line-height:1.5;
  background:var(--card2); border:1px solid var(--edge);}
.fc-voicenote .lab{display:block; font-family:var(--mono); font-size:13px; letter-spacing:.16em;
  text-transform:uppercase; margin-bottom:4px;}
.fc-voicenote.ok{background:var(--good-bg); border-color:var(--good-line);}
.fc-voicenote.ok .lab{color:var(--good);}
.fc-voicenote.no{background:var(--warn-bg); border-color:var(--warn-line);}
.fc-voicenote.no .lab{color:var(--warn);}
.fc-override{display:block; width:auto; margin-top:10px; padding:9px 15px; font-size:15px;}

/* ---- Step 3 symbol bar + line-by-line work map (2026-07-29) ----
   Fallback chains on every var: this same block is duplicated into
   test-player.html, whose local shim defines a smaller set of tokens than
   app/styles.css does. Without the fallbacks the map renders borderless
   there and the "which line is wrong" highlight — the entire point — is
   invisible on the one page a reviewer looks at it on. */
.symbar{display:flex; flex-wrap:wrap; gap:6px; margin-top:8px;}
.symkey{flex:0 0 auto; min-width:44px; height:44px; display:inline-flex;
  align-items:center; justify-content:center; padding:0 12px;
  background:var(--card); border:1px solid var(--edge); border-radius:9px;
  color:var(--ink); font-family:var(--mono); font-size:16.5px; line-height:1;
  cursor:pointer; user-select:none; -webkit-user-select:none; touch-action:manipulation;}
.symkey:active{background:var(--accent-soft, var(--soft)); border-color:var(--accent);}

.mmap{margin-top:14px; background:var(--card2, var(--card)); border:1px solid var(--edge);
  border-radius:11px; padding:14px 15px;}
.mm-h{font-family:var(--mono); font-size:14.5px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--muted); margin-bottom:9px;}
/* break-word, NOT anywhere (2026-08-16, QA F23: "pasted equation renders one
   character per line").

   The two look interchangeable and are not. `anywhere` is allowed to break
   inside a word when computing the element's MIN-CONTENT width, so an
   element carrying it reports a min-content of one character. Any ancestor
   that sizes to min-content — a flex or grid track that has to shrink — then
   collapses to ~1ch wide and the text renders vertically, one letter per
   line. A long pasted equation is a single unbroken token, which is exactly
   the input that triggers it, and it only shows up when the layout is tight,
   which is why it never reproduced on demand.

   `break-word` breaks the same long tokens at paint time but leaves
   min-content sizing alone, so the container keeps its real width. Same
   visible wrapping, without the collapse. */
.mm-l{font-family:var(--mono); font-size:16px; line-height:1.5; color:var(--ink);
  padding:5px 9px; border-left:3px solid transparent; border-radius:0 6px 6px 0;
  white-space:pre-wrap; overflow-wrap:break-word; min-width:0;}
.mm-l.bad{border-left-color:var(--bad); background:var(--bad-bg, var(--bad-soft, rgba(226,104,90,.14)));}
.mm-note{font-size:15.5px; line-height:1.5; color:var(--bad); margin:3px 0 7px 12px;
  overflow-wrap:break-word; min-width:0;}
.mm-sum{font-size:15.5px; line-height:1.5; color:var(--muted); margin-top:9px;
  padding-top:9px; border-top:1px solid var(--edge);}

/* Skipping is offered, not hidden — a quiet control beside Next rather than a
   link someone has to hunt for. `align-items:center` here is for that skip
   LINK, which is shorter than the button it sits next to.

   Scoped to .actions:has(.iskip) (2026-08-07, Marc: "The fields are not on
   the same level"). Unscoped, it overrode the flex default of `stretch` on
   EVERY button pair in the app — so any two buttons whose labels wrapped to
   different line counts rendered at different heights and were then centred,
   making the mismatch plain. "Pick up where you left off" / "Start fresh" on
   the dashboard was the clearest case. Everywhere without a skip link now
   keeps stretch, so paired buttons match height whatever their labels do. */
.actions:has(.iskip){align-items:center}
.iskip{background:none;border:0;color:var(--muted,#A9CBC1);font-size:15.5px;cursor:pointer;
  text-decoration:underline;padding:8px 0}
.iskip:hover{color:var(--ink,#F3F9F7)}
.ibail{margin:22px auto 0;text-align:center;max-width:520px}
.ibail-btn{background:none;border:1px solid var(--edge-control);color:var(--ink,#F3F9F7);
  border-radius:8px;padding:10px 18px;font-size:15.5px;cursor:pointer}
.ibail-btn:hover{border-color:var(--teal,#3FE0CB);color:var(--teal,#3FE0CB)}
.ibail-note{display:block;margin-top:8px;font-size:14.5px;color:var(--muted,#A9CBC1)}

/* Step 1 is now written rather than picked, so it needs a real field. Matches
   the write-in boxes on the sample lesson pages so the two look like the same
   product. */
.askwrite{margin:10px 0 4px}
.askbox{display:block;width:100%;box-sizing:border-box;border:1px dashed var(--edge-control);
  border-radius:8px;padding:12px 14px;background:var(--bg,#1D3E36);color:var(--ink,#F3F9F7);
  font-size:15px;font-family:inherit;line-height:1.5;resize:vertical}  /* height: /styles/forms.css */
.askbox::placeholder{color:var(--muted,#A9CBC1);font-style:italic}
.askbox:focus{outline:none;border-style:solid;border-color:var(--accent,#3FE0CB)}
.askbox:disabled{opacity:.75}

/* Step-3 help. Offered before the answer, not after it — and the student
   chooses which kind, because being handed the wrong sort of help is its own
   dead end. */
.wio-help{margin-top:14px;padding-top:12px;border-top:1px dashed var(--line,#40766A)}
.wio-help-lab{display:block;font-family:var(--mono,'IBM Plex Mono',monospace);font-size:12.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted,#A9CBC1);margin-bottom:8px}
.wio-help-row{display:flex;gap:8px;flex-wrap:wrap}
.wio-help-btn{background:none;border:1px solid var(--edge-control);color:var(--ink,#F3F9F7);
  border-radius:8px;padding:8px 14px;font-size:15px;cursor:pointer}
.wio-help-btn:hover{border-color:var(--accent,#3FE0CB);color:var(--accent,#3FE0CB)}
.wio-help-btn:disabled{opacity:.45;cursor:default}
.wio-howto{margin-top:10px;padding:12px 14px;border:1px solid var(--line,#40766A);
  border-radius:8px;font-size:15.5px;line-height:1.55;color:var(--ink,#F3F9F7)}
@media(max-width:520px){ .wio-help-row{flex-direction:column} .wio-help-btn{width:100%} }

/* Curated video selection — several links where the prototype had them, so the
   row needs to wrap rather than assuming a single item. */
.watchhow-lab{display:block;font-family:var(--mono,'IBM Plex Mono',monospace);font-size:12.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--muted,#A9CBC1);margin-bottom:6px}
.watchhowrow{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:10px}
.watchhowrow .watchhow{display:inline-block;padding:7px 12px;border:1px solid var(--edge-control);
  border-radius:7px;font-size:15px;color:var(--ink,#F3F9F7);text-decoration:none}
.watchhowrow .watchhow:hover{border-color:var(--accent,#3FE0CB);color:var(--accent,#3FE0CB)}
@media(max-width:520px){ .watchhowrow{flex-direction:column;align-items:stretch}
  .watchhowrow .watchhow{text-align:center} }

/* Optional one-liner after a wrong step-1 pick. Deliberately quiet — it must
   never look like another question they have to answer. */
.corpusbox{margin-top:14px;padding-top:12px;border-top:1px dashed var(--line,#40766A)}
.corpuslab{display:block;font-family:var(--mono,'IBM Plex Mono',monospace);font-size:12.5px;
  letter-spacing:.07em;text-transform:uppercase;color:var(--muted,#A9CBC1);margin-bottom:8px}
.corpusta{display:block;width:100%;box-sizing:border-box;border:1px dashed var(--edge-control);
  border-radius:8px;padding:10px 12px;background:transparent;color:var(--ink,#F3F9F7);
  font:inherit;font-size:15.5px;resize:vertical;margin-bottom:8px}
.corpusta:focus{outline:none;border-style:solid;border-color:var(--accent,#3FE0CB)}

/* Two groups, visually separated. The recommended label carries the accent so
   the distinction reads at a glance — a proven link and an untested one are
   different claims and should not look identical. */
.watchhow-lab.rec{color:var(--accent,#3FE0CB)}
.watchhowrow .watchhow-lab{width:100%;margin-top:10px}
.watchhowrow .watchhow-lab:first-child{margin-top:0}

/* 1-10, next to the link they opened. Ten small targets rather than a slider —
   a slider needs a drag and a release; this takes one tap. Wraps to two rows on
   a narrow phone rather than shrinking below a usable tap size. */
.vidrate{width:100%;margin-top:12px}
.vidrate-q{display:block;font-family:var(--mono,'IBM Plex Mono',monospace);font-size:13px;
  letter-spacing:.05em;color:var(--muted,#A9CBC1);margin-bottom:7px}
.vidrate-scale{display:flex;gap:5px;flex-wrap:wrap}
.vidrate-btn{flex:1 1 34px;min-width:34px;min-height:34px;background:none;
  border:1px solid var(--edge-control);color:var(--ink,#F3F9F7);
  border-radius:7px;font-size:15px;cursor:pointer}
.vidrate-btn:hover:not(:disabled){border-color:var(--accent,#3FE0CB);color:var(--accent,#3FE0CB)}
.vidrate-btn:disabled{opacity:.3;cursor:default}
.vidrate-btn.picked{opacity:1;border-color:var(--accent,#3FE0CB);color:var(--accent,#3FE0CB);font-weight:600}
.vidrate-ends{display:flex;justify-content:space-between;margin-top:5px;
  font-size:12.5px;color:var(--muted,#A9CBC1)}

/* The one line of the day that says she is getting better. Given the weight it
   deserves — but no confetti: it is a record, not a reward. */
.evwin{font-family:'Newsreader',serif;font-size:19px;line-height:1.45;
  color:var(--ink,#F3F9F7);margin:10px 0 4px}
.evslip{color:var(--muted,#A9CBC1);border-top:1px solid var(--line,#40766A);
  padding-top:10px;margin-top:12px}

/* The skills log. The pill carries the state; the row carries the story. */
.logtally{display:flex;gap:16px;flex-wrap:wrap;margin:4px 0 18px}
.lt b{display:block;font-family:'Newsreader',serif;font-size:26px;line-height:1.1}
.lt span{font-size:14.5px;color:var(--muted,#A9CBC1)}
.lt.learned b{color:var(--accent,#3FE0CB)}
.lt.correct b{color:var(--accent,#3FE0CB);opacity:.75}
.lt.learning b{color:var(--gold,#E8A94A)}
.lt.incorrect b{color:var(--bad,#EA8280)}
.lt.untested b{color:var(--muted,#A9CBC1)}
.logrow{display:flex;align-items:flex-start;gap:12px;padding:11px 0;
  border-bottom:1px solid rgba(64,118,106,.4)}
.logrow:last-of-type{border-bottom:0}
.lr-body{flex:1;min-width:0}
.lr-name{font-size:16px}
.lr-meta{font-family:var(--mono,'IBM Plex Mono',monospace);font-size:13px;
  color:var(--muted,#A9CBC1);margin-top:3px}
.lpill{flex:0 0 auto;font-family:var(--mono,'IBM Plex Mono',monospace);font-size:12px;
  letter-spacing:.05em;text-transform:uppercase;padding:3px 9px;border-radius:20px;
  border:1px solid;white-space:nowrap;margin-top:2px}
.lpill.incorrect{border-color:var(--bad,#EA8280);color:var(--bad,#EA8280)}
.lpill.learning{border-color:var(--gold,#E8A94A);color:var(--gold,#E8A94A)}
.lpill.correct{border-color:var(--accent,#3FE0CB);color:var(--accent,#3FE0CB)}
.lpill.learned{border-color:var(--accent,#3FE0CB);background:var(--accent,#3FE0CB);color:#16302A}
.lpill.untested{border-color:var(--line,#40766A);color:var(--muted,#A9CBC1);border-style:dashed}
.logshare{margin-top:22px;padding-top:16px;border-top:1px solid var(--line,#40766A)}

/* Lesson picker on a course page — tick the lessons to practise. Same row
   shape as the flashcards library so the two read as one idea. */
.fcrow{display:flex; align-items:center; gap:10px; padding:10px 4px; cursor:pointer;
  border-radius:8px; border-top:1px solid var(--edge2);}
.fcrow:first-of-type{border-top:none;}
.fcrow:hover{background:var(--card2);}
.fcrow input{width:17px; height:17px; accent-color:var(--accent); flex:0 0 auto; cursor:pointer;}
.fclabel{flex:1; font-size:15px;}
.fccount{font-family:var(--mono); font-size:13.5px; color:var(--faint); white-space:nowrap;}

/* Function uses accordion header inside the weekly report. */
.wr-toggle{background:none; border:0; padding:0; cursor:pointer; display:flex; align-items:center; gap:6px;
  font-family:var(--mono); font-size:14.5px; letter-spacing:.06em; text-transform:uppercase; color:var(--muted);}
.wr-toggle::before{content:"▸"; font-size:12px; transition:transform .12s;}
.wr-toggle.open::before{transform:rotate(90deg);}
.wr-toggle:hover{color:var(--ink);}

/* Month name with its arrows either side — the arrows move the month, so
   they sit with it rather than in the view-toggle strip. */
/* .cal-monthrow is gone with the row it named (2026-09-01, Marc: "these
   items should be on the same line") — the month and its arrows are a group
   inside the control strip now. The class stays defined only if something
   still uses it; nothing does. */
.cal-monthnav{display:flex; align-items:center; gap:8px; margin:0 4px 0 0;}
.cal-monthnav:empty{display:none;}
.cal-monthname{font-family:var(--display); font-weight:600; font-size:19px; white-space:nowrap;}
/* On a narrow screen the strip wraps and the month should lead its own line
   rather than dangling off the end of the add button. */
@media(max-width:700px){ .cal-monthnav{flex:1 0 100%; margin:2px 0 4px;} }

/* Day-by-day study time: the seven days across, minutes underneath each.
   One "minutes a day" number treated every day as the same size, which is
   not how a school week works. */
.dayplan{display:grid; grid-template-columns:repeat(7, 1fr); gap:8px; margin-top:8px}
.dayplan-col{display:grid; gap:6px}
.dayplan-day{font-family:var(--mono); font-size:15.5px; padding:9px 4px; border-radius:8px;
  border:1px solid var(--edge); background:var(--card2); color:var(--muted); cursor:pointer; width:100%}
.dayplan-day.on{background:var(--accent); color:#06201C; border-color:var(--accent); font-weight:600}
.dayplan-mins{width:100%; padding:8px 6px; text-align:center; font-family:var(--mono); font-size:15.5px}
@media(max-width:640px){
  /* Seven columns on a phone leaves each about 40px — too narrow for a
     minutes box. Four across, wrapping to a second row. */
  .dayplan{grid-template-columns:repeat(4, 1fr)}
}

/* Course rows vs the lessons under them. Neither class was styled, so a
   course and its lessons rendered identically flat and the list read as one
   long run of equal items with no visible parent. */
.fcrow.fccourse{font-weight:600;}
.fcrow.fccourse .fclabel{font-family:var(--display); font-size:16.5px;}
.fcnest{padding-left:28px; border-left:1px solid var(--edge2); margin-left:8px;}
.fcnest .fcrow{padding-top:8px; padding-bottom:8px;}
.fcnest .fclabel{font-size:15px; color:var(--muted);}

/* Credits left, Update Courses right — the dashboard's top row. */
/* LEFT-PACKED (2026-08-30, Marc: "move the top buttons to the left").
   space-between plus the courses button's margin-left:auto had the row
   spreading to the right edge; the buttons now group on the left in their
   order — Update Courses, Tokens, Challenges. */
.hub-toprow{display:flex; align-items:center; justify-content:flex-start;
  gap:12px; flex-wrap:wrap; margin-bottom:14px;}
.hub-courses-btn{width:auto;}
/* Account Setup sits at the far right of the row (2026-09-02, Marc: "Add a
   button for account setup on the right"). Auto margin rather than order, so
   a badge added later cannot land beyond it. On a phone the row wraps and it
   takes its own line rather than being squeezed against the last badge. */
.hub-setup-btn{margin-left:auto;}
@media(max-width:600px){ .hub-setup-btn{margin-left:0;} }

/* Find-in-notes. Sits above the pad so it is visible before scrolling into
   a term's worth of text. */
.notefind{display:flex; align-items:center; gap:8px; margin:0 0 10px; flex-wrap:wrap;}
.notefind-in{flex:1; min-width:180px;}
.notefind-btn{width:auto; padding:9px 14px; font-size:16px; line-height:1;}
.notefind-btn:disabled{opacity:.4; cursor:default;}
.notefind-count{font-family:var(--mono); font-size:14.5px; color:var(--muted);
  min-width:78px; text-align:right;}

/* Challenge — the student disputing a step-1 verdict. Deliberately quiet:
   an appeal offered, not a nudge to press it. */
.challenge-btn{width:auto; margin-top:12px; font-size:15.5px; padding:9px 14px;}
.challenge-note{margin-top:12px; font-size:16px; line-height:1.55; color:var(--muted);
  padding-left:12px; border-left:2px solid var(--edge);}
/* A WON CHALLENGE IS THE POINT OF THE FEATURE. The student read a verdict,
   judged it wrong, and was right. That does not get a grey aside. */
.challenge-note.won{color:var(--ink); font-size:16px; line-height:1.6;
  padding:16px 18px; border-left:3px solid var(--good);
  background:var(--good-bg); border-radius:10px;}
.challenge-note.won b{color:var(--good); font-size:18px;}

/* Challenges badge, sharing the credits badge's shape. Only tinted when the
   allowance is genuinely running low. */
.credits-badge.low{border-color:var(--warn-line); color:var(--warn);}


/* Textarea sizing lives in /styles/forms.css, linked by every page — it was
   here, which meant only the app got a floor and the root pages got none. */

/* Notes: an entry list, dated and taggable, that can be dragged into order. */
.noterow{display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:4px;}
@media(max-width:640px){.noterow{grid-template-columns:1fr;}}
.notelist{display:grid; gap:10px; margin-top:14px;}
.noteitem{border:1px solid var(--edge); border-left:3px solid var(--accent);
  border-radius:10px; padding:14px 16px; background:var(--card2); cursor:grab;}
.noteitem.dragging{opacity:.45;}
.noteitem.dropinto{border-color:var(--accent); background:var(--card);}
.note-meta{font-family:var(--mono); font-size:13.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--faint); margin-bottom:8px;}
.note-body{font-size:16.5px; line-height:1.6; white-space:pre-wrap; color:var(--ink);}
.note-tools{display:flex; gap:8px; margin-top:12px;}
.note-tools .notesbtn{width:auto; padding:7px 12px; font-size:15px;}

/* Coach notes (2026-08-26). Deliberately NOT .noteitem: that carries
   cursor:grab and a drag handler, and a generated note is not the
   student's to reorder or delete. Squared left edge and a quieter ground
   so the two lists read as two different kinds of thing at a glance —
   these are observations, theirs are writing. */
.coachnote{border:1px solid var(--edge); border-left:3px solid var(--accent);
  border-radius:10px; padding:14px 16px; background:var(--card2);}
.coachnote p{margin:0; font-size:15.5px; line-height:1.55; color:var(--ink);}
.coachnote .actions{margin-top:9px; display:flex; gap:10px; align-items:center; flex-wrap:wrap;}
.coachnote .btn{width:auto; padding:7px 13px; font-size:15.5px;}
.coachnote .notesaved{font-family:var(--mono); font-size:13.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--faint);}

/* A struck-out note (2026-08-26). Kept, not hidden: these are the things
   the student has beaten, and the pile of them is the point. Dimmed and
   ruled through so a glance separates them from what is still live, but
   still readable — an unreadable trophy is not a trophy. Line-through on
   the CLAIM only; the reason underneath has to stay legible. */
.coachnote.resolved{opacity:.72; border-left-color:var(--faint);}
.coachnote.resolved p{text-decoration:line-through; text-decoration-thickness:1px;
  color:var(--muted);}
.note-done{font-family:var(--mono); font-size:13.5px; line-height:1.5; letter-spacing:.04em;
  color:var(--accent); margin-top:7px; text-decoration:none;}
.coachnote.resolved .note-done{color:var(--faint);}
/* The student's own, marked sorted by them. */
.noteitem.sorted{opacity:.72; border-left-color:var(--faint);}
.noteitem.sorted .note-body{text-decoration:line-through; text-decoration-thickness:1px;
  color:var(--muted);}

/* Subject chips on the check-in setup — a column of full-width buttons made
   a nine-deep stack you had to scroll past to reach the time picker. */
.opts.optwrap{display:flex; flex-wrap:wrap; gap:8px;}
.opts.optwrap .opt{width:auto; padding:9px 14px;}

/* Check-in times: a checkbox, the name, and the actual clock time. Was three
   full-width single-select buttons that never said WHEN. */
.timelist{display:grid; gap:8px; margin-bottom:16px;}
.timerow{display:flex; align-items:center; gap:12px; cursor:pointer;
  border:1px solid var(--edge); border-radius:10px; padding:12px 14px; background:var(--card2);}
.timerow:hover{border-color:var(--faint);}
.timerow input[type=checkbox]{width:18px; height:18px; accent-color:var(--accent); cursor:pointer; margin:0;}
.timename{flex:1; font-size:16px; color:var(--ink);}
.timewhen{font-family:var(--mono); font-size:15.5px; color:var(--muted);}
/* The time is editable now (2026-09-01, Marc: "i can't edit the checkin
   times"). Styled as a field rather than as text, so it reads as something
   you can change — a bare time input inherits neither the mono face nor the
   card's palette and looked like a browser control dropped into the page. */
.timeedit{font-family:var(--mono); font-size:15.5px; color:var(--ink);
  background:var(--card2); border:1px solid var(--edge-control); border-radius:8px;
  padding:6px 9px; cursor:pointer; min-width:112px;}
.timeedit:hover{border-color:var(--accent-soft);}
.timeedit:focus{outline:2px solid var(--accent); outline-offset:1px;}

/* Monthly self-assessment. Sliders, then the comparison. */
.sa-row{padding:14px 0; border-top:1px solid var(--edge);}
.sa-row:first-child{border-top:0;}
.sa-slider{display:flex; align-items:center; gap:14px;}
.sa-slider input[type=range]{flex:1; accent-color:var(--accent);}
.sa-val{font-family:var(--mono); font-size:16px; min-width:2.4em; text-align:right;
  font-variant-numeric:tabular-nums; color:var(--accent);}
.sa-cmphead{display:flex; flex-wrap:wrap; align-items:baseline; gap:8px 14px; margin-bottom:8px;}
.sa-cmphead b{font-family:var(--display); font-size:17px;}
.sa-num{font-family:var(--mono); font-size:15px; color:var(--muted);}
.sa-num.muted{opacity:.7;}
.sa-note{margin:0; font-size:15.5px; line-height:1.6; color:var(--ink);}
.sa-move{margin:8px 0 0; font-family:var(--mono); font-size:14.5px; color:var(--muted);}
/* Mockup 5f (2026-08-19): the one named gap, then wordless reference rows.
   Bar = what the work shows, marker = where the student put themselves;
   amber bar = rated well above measurement. */
.sa-one{border:1px solid var(--edge-control); border-left:3px solid var(--accent);
  border-radius:0 12px 12px 0; background:var(--paper2); padding:18px 20px; margin:6px 0 22px;}
.sa-one-lab{font-family:var(--mono); font-size:13px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent-ink); margin-bottom:8px;}
.sa-one-h{margin:0 0 10px; font-family:var(--display); font-weight:600;
  font-size:clamp(19px,2.6vw,24px); line-height:1.3;}
.sa-axes{margin:8px 0 4px;}
.sa-axes-head{display:flex; justify-content:space-between; align-items:baseline; gap:12px;
  flex-wrap:wrap; margin-bottom:14px;}
.sa-axes-head b{font-family:var(--mono); font-weight:600; font-size:13.5px;
  letter-spacing:.12em; text-transform:uppercase; color:var(--accent-ink);}
.sa-axes-head span{font-size:14.5px; color:var(--muted);}
.sa-axrow{display:grid; grid-template-columns:150px 1fr 150px; gap:14px; align-items:center;
  padding:9px 0;}
.sa-axlab{font-size:16px; font-weight:500;}
.sa-rail{position:relative; height:6px; border-radius:99px; background:var(--card2);}
.sa-rail>i{position:absolute; left:0; top:0; height:100%; border-radius:99px;
  background:var(--good);}
.sa-axrow.over .sa-rail>i{background:var(--warn);}
.sa-rail>b{position:absolute; top:-5px; width:2px; height:16px; background:var(--ink);
  transform:translateX(-1px);}
.sa-axnum{font-family:var(--mono); font-size:14px; letter-spacing:.04em;
  text-transform:uppercase; color:var(--muted); text-align:right;}
.sa-axnum i{font-style:normal; text-transform:none; opacity:.8;}
.sa-legend{display:flex; gap:22px; flex-wrap:wrap; margin-top:14px; font-family:var(--mono);
  font-size:13px; letter-spacing:.08em; text-transform:uppercase; color:var(--muted);}
.sa-legend span{display:inline-flex; align-items:center; gap:8px;}
.sa-legend .sw-bar{width:18px; height:6px; border-radius:99px; background:var(--good);}
.sa-legend .sw-mark{width:2px; height:14px; background:var(--ink);}
@media(max-width:640px){
  .sa-axrow{grid-template-columns:1fr; gap:6px; padding:12px 0;}
  .sa-axnum{text-align:left;}
}

/* THE CHECK-IN COUNTDOWN (2026-08-28, Marc: "Put the countdown at the bottom
   of the academic profile box at the top"). The .selfcount card it replaces
   was a full dashboard row for one number; this is the same number on the
   Academic profile chip's bottom line, with the digits given the weight the
   words around them do not need. */
.cc-count b,.cc-mark b{font-family:var(--display,Newsreader),serif; font-size:19px; color:var(--accent);
  margin-right:3px;}
/* The mark takes the course's own colour, the same one the meter under it
   uses, so the number and the bar read as one fact rather than two. */
.course-chip .cc-mark b{color:var(--sub);}
.profile-chip.due .cc-count{color:var(--accent);}

/* The one-thing-worth-doing card. Leads the dashboard for a student who
   would otherwise close the app. */
.play{border-left:3px solid var(--accent); margin-bottom:14px;}
.play-t{font-family:var(--display); font-size:20px; line-height:1.3; margin:0 0 8px;}
.play-b{margin:0 0 14px; color:var(--muted); font-size:15.5px; line-height:1.6;}
.play .btn{width:auto;}
.play-p{margin:0 0 14px; font-family:var(--display); font-size:16.5px;
  line-height:1.55; color:var(--ink); border-left:2px solid var(--accent);
  padding-left:12px;}

/* ============================================================
   ROOM TO BREATHE ON A COURSE PAGE (2026-08-17, Marc: "this doesn't look
   very good. too cramped together").

   The action grid, the goal card and the assignment heading were stacked
   with only the button grid's own 16px gap between them, so the page read
   as one undifferentiated block of boxes — nothing said where the buttons
   stopped and the actual content started.
   ============================================================ */
.subject-actions-primary{margin-bottom:8px;}
.subject-actions-primary + *{margin-top:24px;}
#app header + .card,
#app .card + h3,
#app .accordion + h3{margin-top:28px;}
#app h3{margin-bottom:12px;}
#app .goalcard{margin:26px 0;}
#app .goalcard + h3{margin-top:30px;}

/* ---------- the course-goal card ---------- */
.goalcard h3{margin-bottom:6px;}
.goal-setrow{display:flex; gap:8px; align-items:center; margin-top:14px; flex-wrap:wrap;}
/* .btn is width:100% by design (it is a form submit nearly everywhere), which
   made "Set my bar" a full-width slab next to a 90px number field. Inline
   here, and in the mark form, it is one control among several. */
.goal-setrow .btn,.goal-tools .btn,.goal-nudge .btn,.markform-actions .btn{width:auto; flex:0 0 auto;}
/* THE RUBRIC FIELD ON THE MARK FORM (2026-09-01) — camera first, because on
   a phone the paper is in the other hand. */
.markform-rubric{display:block; margin-top:14px; padding-top:14px; border-top:1px solid var(--edge2);}
.markform-rubric .isub{margin:4px 0 8px;}
.markform-rubbtns{display:flex; gap:8px; flex-wrap:wrap;}
.markform-rubfiles{display:flex; gap:8px; flex-wrap:wrap; margin-top:10px;}
.markform-rubchip{display:inline-flex; align-items:center; gap:8px; padding:6px 10px;
  border:1px solid var(--edge-control); border-radius:8px; background:var(--card2);
  font-family:var(--mono); font-size:12.5px; color:var(--ink); max-width:100%;}
.markform-rubchip > span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.markform-rubx{background:none; border:0; color:var(--faint); font:inherit; cursor:pointer; padding:0 2px;}
.markform-rubx:hover{color:var(--ink);}
.markform-newevent{margin-top:10px;}

/* THE ONE ROW ON THE PINNED LIST THAT DOES SOMETHING (2026-09-01) — a test
   that was sat a week ago with no mark against it. Pinned rows are a glance;
   this is a door, and it is late, so it reads as a button and sits above
   them. */
.wr-pin-todo{display:flex; justify-content:space-between; align-items:center; gap:10px;
  width:100%; text-align:left; font:inherit; cursor:pointer;
  border:1px solid var(--accent-soft); border-radius:9px; background:var(--card2);
  color:var(--ink); padding:8px 10px; margin-bottom:6px;}
.wr-pin-todo:hover{border-color:var(--accent);}
.wr-pin-todo .wr-pin-t{font-weight:600;}

.goal-tools{display:flex; gap:8px; align-items:center; margin-top:14px; flex-wrap:wrap;}
/* THE RAISE-THE-BAR OFFER (2026-09-01) — a sentence with a button, shown only
   when a student is at or past what they set. Deliberately not styled like
   the tool row above it: it is a moment, not a control, and the accent edge
   is the only thing on this card that congratulates anybody. */
.goal-raise{display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin-top:12px;
  padding:10px 12px; border:1px solid var(--accent-soft); border-radius:10px;
  background:var(--card2);}
.goal-raise p{margin:0; flex:1; min-width:220px; color:var(--ink);}
.goal-tools .notesbtn,.goal-tools .btn{margin-top:0;}
.goal-nudge{display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-top:14px;}
.goal-nudge .btn{margin-top:0;}
/* Practice accuracy is deliberately quieter than the mark it sits under —
   it is context, not the number the student came for. */
.goal-practice{margin-top:16px; padding-top:14px; border-top:1px dashed var(--edge); opacity:.85;}

/* ---------- entering a real mark ---------- */
.markform{background:var(--card2); border:1px solid var(--edge); border-radius:12px; padding:16px 16px 14px; margin-top:14px;}
.markform-h{font-size:15px; margin:0 0 14px;}
.markform-grid{display:grid; grid-template-columns:1fr 1fr; gap:14px;}
@media(max-width:560px){ .markform-grid{grid-template-columns:1fr;} }
.markform-f{display:flex; flex-direction:column; gap:6px;}
.markform-f .elab{font-size:14px;}
.markform-f .etext{width:100%;}
.markform-score{display:flex; align-items:center; gap:8px;}
.markform-score .etext{width:88px;}
.markform-of{font-size:15px; color:var(--muted); white-space:nowrap;}
.markform-live{margin-top:12px; color:var(--accent-ink);}
.markform-err{margin-top:10px; color:var(--warn,#e88); display:none;}
.markform-actions{display:flex; gap:8px; margin-top:16px; flex-wrap:wrap;}
.markform-actions .btn,.markform-actions .notesbtn{margin-top:0;}

/* ---------- marks already entered ---------- */
.markslist{margin-top:14px; display:flex; flex-direction:column; gap:2px;}
.mark-row{display:flex; align-items:center; gap:14px; padding:11px 0; border-top:1px solid var(--edge); flex-wrap:wrap;}
.mark-row:first-child{border-top:none;}
.mark-main{flex:1; min-width:150px;}
.mark-main b{display:block; font-size:16px;}
.mark-meta{display:block; font-size:14px; color:var(--faint); margin-top:3px;}
.mark-score{text-align:right; white-space:nowrap;}
.mark-score b{font-family:var(--mono); font-size:16px; color:var(--accent-ink);}
.mark-score span{display:block; font-size:13.5px; color:var(--faint); margin-top:2px;}
.mark-tools{display:flex; gap:6px;}
.mark-tools .notesbtn{margin-top:0; padding:6px 10px; font-size:14.5px;}
/* The Hide-marks control closing the list — a plain inline button, not a
   full-width slab stretched by the list's flex column. */
.markslist > .notesbtn{align-self:flex-start; margin-top:12px;}

/* ============================================================
   THE UPLOADED ASSIGNMENT, VIEWABLE (2026-08-17, Marc: "when a student
   upload an assignment, they should be able to see the upload file whenever
   they need to"). See homework-files.js.
   ============================================================ */
/* Assignment-Help results heading (mockup 4e, 2026-08-19): course + mode
   eyebrow over a serif "What you uploaded". Sized down from the page-level
   h1 — this is a screen title inside the app shell, not a landing page. */
.hwhelp-head{margin:6px 0 2px;}
.hwhelp-head .eyebrow{font-size:13.5px; letter-spacing:.14em; margin-bottom:2px;}
.hwhelp-head h1{font-size:clamp(26px,5vw,34px); line-height:1.08; margin:0 0 10px;}

.hwfiles{margin:18px 0 22px;}
.hwfiles-h{font-size:15px; margin-bottom:4px;}
.hwfiles-sub{margin-bottom:12px;}
.hwfiles-strip{display:flex; gap:10px; flex-wrap:wrap;}
.hwfile{position:relative; width:104px; padding:0; background:var(--card2); border:1px solid var(--edge-control);
  border-radius:9px; overflow:hidden; cursor:pointer; display:flex; flex-direction:column;}
.hwfile:hover{border-color:var(--accent);}
.hwfile img{width:100%; height:104px; object-fit:cover; display:block;}
.hwfile-doc{display:flex; align-items:center; justify-content:center; height:104px; padding:8px; text-align:center;
  font-size:13.5px; color:var(--muted); word-break:break-word; overflow:hidden;}
.hwfile-n{display:block; font-family:var(--mono); font-size:13px; color:var(--faint); padding:6px 4px;
  border-top:1px solid var(--edge); text-align:center;}
.hwfiles-note{margin-top:10px;}
.hwfiles-flag{color:var(--accent-ink) !important; display:flex; align-items:center; margin-top:4px;}

/* Full size, over everything. A student checking their own handwriting needs
   the whole page, not a 104px tile. */
.hwfile-lightbox{position:fixed; inset:0; z-index:9999; background:rgba(0,0,0,.88);
  display:flex; align-items:center; justify-content:center; padding:28px; overflow:auto;}
.hwfile-lightbox img{max-width:100%; max-height:100%; object-fit:contain; border-radius:8px;}
.hwfile-close{position:fixed; top:16px; right:20px; width:44px; height:44px; border-radius:50%;
  background:var(--card); color:var(--ink); border:1px solid var(--edge-control); font-size:26px; line-height:1;
  cursor:pointer; display:flex; align-items:center; justify-content:center; padding:0;}
.hwfile-close:hover{border-color:var(--accent);}
@media(max-width:480px){ .hwfile{width:88px;} .hwfile img,.hwfile-doc{height:88px;} }

/* ============================================================
   ESSAY WORKBENCH — plain-English help popups, the 3+1 capture
   shape, and the foundational-rules panel (2026-08-17, Marc).
   Content lives in essay-help.js.
   ============================================================ */

/* The ? beside a label. Quiet on purpose — the label keeps the real
   verbiage; this is the standing offer of plain English. */
.ehelp-holder{position:relative; display:inline-block; margin-left:6px; vertical-align:middle;}
.ehelp-btn{width:18px; height:18px; border-radius:50%; border:1px solid var(--edge-control);
  background:transparent; color:var(--accent-ink); font-family:var(--mono); font-size:13px; line-height:1;
  cursor:pointer; display:inline-flex; align-items:center; justify-content:center; padding:0; vertical-align:middle;}
.ehelp-btn:hover,.ehelp-btn.on{background:var(--accent-soft); border-color:var(--accent);}

.ehelp-pop{position:absolute; z-index:60; top:24px; left:0; width:320px; max-width:min(320px,86vw);
  background:var(--paper2); border:1px solid var(--accent); border-radius:11px; padding:14px 15px 12px;
  box-shadow:0 10px 32px rgba(0,0,0,.5); display:none; text-align:left; cursor:default;}
.ehelp-pop.on{display:block;}
.ehelp-pop h5{font-family:var(--mono); font-size:13px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--accent-ink); margin:0 0 7px;}
.ehelp-pop>p{font-size:15.5px; color:var(--ink); margin:0 0 10px; line-height:1.5;
  text-transform:none; letter-spacing:normal; font-family:var(--body); font-weight:400;}
.ehelp-ex{border-top:1px dashed var(--edge-control); padding-top:9px;}
.ehelp-yes,.ehelp-no{display:flex; gap:7px; font-size:15px; margin-bottom:6px; line-height:1.45;
  text-transform:none; letter-spacing:normal; font-family:var(--body); font-weight:400;}
.ehelp-yes i,.ehelp-no i{font-style:normal; flex:0 0 auto;}
.ehelp-yes i{color:var(--good,#5ad48f);} .ehelp-no i{color:var(--warn,#e88);}
.ehelp-yes span,.ehelp-no span{color:var(--muted);}
.ehelp-why{font-size:14px; color:var(--faint); margin:0 0 8px 21px; line-height:1.45;
  text-transform:none; letter-spacing:normal; font-family:var(--body); font-weight:400;}
.ehelp-close{position:absolute; top:5px; right:7px; background:none; border:none; color:var(--faint);
  font-size:15px; cursor:pointer; padding:2px 5px;}
.ehelp-close:hover{color:var(--ink);}

/* 3+1: three thinking columns in a row, the quote as a full-width receipt
   strip under them — the shape itself says "three thoughts, one proof". */
.cap3{display:grid; grid-template-columns:1fr 1fr 1fr; gap:12px;}
@media(max-width:760px){ .cap3{grid-template-columns:1fr;} }
.cap3 .capcol{margin-bottom:0;}
.capreceipt{margin-top:10px; padding-top:10px; border-top:1px dashed var(--edge-control);}
.capreceipt label{color:var(--accent-ink);}

/* The foundational rules, beside the body prose on wide screens. */
.ebodycols{display:grid; grid-template-columns:1.5fr 1fr; gap:18px; align-items:start;}
@media(max-width:860px){ .ebodycols{grid-template-columns:1fr;} }
.erules{background:var(--card2, rgba(255,255,255,.03)); border:1px solid var(--edge); border-radius:11px;
  padding:2px 15px 8px; position:sticky; top:12px;}
.erules-h{font-family:var(--mono); font-size:13px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--accent-ink); padding:12px 0 3px;}
.erule{position:relative; display:flex; align-items:center; gap:8px; padding:8px 0;
  border-top:1px solid var(--edge); font-size:15.5px;}
.erules-h + .erule{border-top:none;}
.erule b{font-weight:600;}
.erule .ehelp-holder{margin-left:auto;}
.erule .ehelp-pop{left:auto; right:0;}
/* On a phone no popover fits beside a mid-row label — anchor it to the
   bottom of the screen instead, sheet-style. !important beats the inline
   left/right the desktop flip logic sets. */
@media(max-width:600px){
  .ehelp-pop{position:fixed; left:12px !important; right:12px !important; top:auto; bottom:14px;
    width:auto; max-width:none; box-shadow:0 -6px 40px rgba(0,0,0,.6);}
}

/* The command-word picker on the decode step (2026-08-17). */
/* Mockup 5a (2026-08-19): the prompt box gets a mono label on the decode
   step, and "Not one of these…" reads as an escape hatch — dashed, not a
   solid control — so the found-in-your-prompt chips stay the main event. */
.eprompt-label{font-family:var(--mono); font-size:12.5px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--accent-ink); margin:2px 0 6px;}
.cw-nota{border-style:dashed; color:var(--muted);}

.cwdetail{margin:12px 0 4px; border-left:3px solid var(--accent); background:var(--card2);
  border-radius:0 9px 9px 0; padding:11px 14px;}
.cwd-asks,.cwd-trap{font-size:16px; line-height:1.5;}
.cwd-trap{margin-top:9px; padding-top:9px; border-top:1px dashed var(--edge); color:var(--muted);}
.cwd-asks span,.cwd-trap span{display:block; font-family:var(--mono); font-size:12.5px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--faint); margin-bottom:3px;}

/* ============================================================
   COURSE PAGE — BANDED ACTIONS (2026-08-19, Marc, from the Claude
   Design mockup). Twelve identical tiles replaced by three labelled
   bands, each tile carrying what it is for underneath its name.
   ============================================================ */
/* SECTION DIVIDERS CARRY A COLOUR (2026-08-28, Marc: "page needs a little
   more color dividers so it doesn't all blend together").

   Every band on the dashboard was the same 13px mono label above the same
   one-pixel grey hairline, so five sections in a row read as one long page
   with words in it. Each band now sets --band and gets three things from it:
   a solid tick before the label, the label itself, and the rule, which is
   thicker and tinted rather than grey.

   ONE VARIABLE, NOT FIVE RULES. A band that sets nothing keeps the accent —
   the formula sheet, the course pages and the parent hub all draw .cband and
   none of them had to be touched. */
.cband{--band:var(--accent-ink);
  display:flex; align-items:center; gap:12px; margin:34px 0 12px;
  font-family:var(--mono); font-size:13px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--band);}
.cband::before{content:""; flex:0 0 auto; width:4px; height:17px; border-radius:2px;
  background:var(--band);}
.cband>span{flex:0 0 auto;}
.cband::after{content:""; flex:1; height:2px; border-radius:2px; background:var(--band); opacity:.3;}
.cband .cband-note{flex:0 0 auto; order:3; font-style:normal; color:var(--faint); letter-spacing:.04em; text-transform:none;}

.ctiles{display:grid; grid-template-columns:repeat(3,1fr); gap:12px;}
.ctiles-lg{display:grid; grid-template-columns:repeat(3,1fr); gap:12px;}
.ctiles-sm{display:flex; flex-wrap:wrap; gap:10px;}
@media(max-width:860px){ .ctiles,.ctiles-lg{grid-template-columns:1fr 1fr;} }
@media(max-width:520px){ .ctiles,.ctiles-lg{grid-template-columns:1fr 1fr; gap:9px;} }

/* A tile is the existing .notesbtn, restacked: icon+label on one line, the
   subtitle under it, left-aligned rather than centred. */
.ctiles .notesbtn,.ctiles-lg .notesbtn{
  display:flex; flex-direction:column; align-items:flex-start; gap:5px; width:100%; margin-top:0;
  padding:14px 15px; border-radius:11px; text-align:left; color:var(--ink); font-size:16px;}
.ctiles-lg .notesbtn{border-color:var(--accent); background:rgba(63,224,203,.06); padding:16px 17px;}
.ctiles .notesbtn:hover,.ctiles-lg .notesbtn:hover{border-color:var(--accent); color:var(--ink);}
.ctile-sub{font-family:var(--body); font-size:14.5px; letter-spacing:0; text-transform:none;
  color:var(--muted); font-weight:400; line-height:1.4;}
.ctiles-sm .notesbtn{margin-top:0;}
@media(max-width:520px){
  .ctiles .notesbtn,.ctiles-lg .notesbtn{padding:12px 11px; font-size:15px;}
  .ctile-sub{font-size:13.5px;}
}

/* ---------- goal card: against-your-bar track ---------- */
.goal-head{display:flex; gap:26px; align-items:flex-start;}
.goal-head>div:first-child{flex:1; min-width:0;}
.goal-track{flex:0 0 210px; padding-top:4px;}
@media(max-width:760px){ .goal-head{flex-direction:column; gap:16px;} .goal-track{flex:1 1 auto; width:100%;} }
.goal-track-lab{font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--faint); margin-bottom:8px;}
.goal-track-rail{position:relative; height:6px; background:var(--edge); border-radius:99px; overflow:visible;}
.goal-track-rail>i{display:block; height:100%; border-radius:99px;}
.goal-track-rail>b{position:absolute; top:-4px; width:2px; height:14px; background:var(--ink); border-radius:1px;}
.goal-track-ends{display:flex; justify-content:space-between; margin-top:7px;
  font-family:var(--mono); font-size:13px; color:var(--muted);}

/* ---------- goal card: the way up ----------
   Sits directly under the standing line and reads as the answer to it, so it
   is set off by a rule and a label rather than boxed away like a footnote. */
.goal-path{margin-top:14px; padding-top:13px; border-top:1px solid var(--edge);}
.goal-path-lab{font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--faint); margin-bottom:8px;}
.goal-path p{margin:0 0 7px; font-size:16px; line-height:1.55; max-width:70ch;}
.goal-path p:last-child{margin-bottom:0; color:var(--muted);}

/* Capture rows carry their own state (2026-08-19, mockup 5b): amber while
   started-but-incomplete, with the missing fields named, green when done. */
.cap.part{border-left-color:var(--warn);}
.capfoot{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:10px;}
.capmissing{font-family:var(--mono); font-size:13px; letter-spacing:.05em; text-transform:uppercase; color:var(--warn);}
.cap.ok .capmissing{display:none;}
.capfoot .capdel{margin:0;}

/* Live mechanical count under each body paragraph (mockup 5c) — the
   quotation rule beside it, actually counted. */
.bodymeter{margin-top:8px; font-family:var(--mono); font-size:13.5px; letter-spacing:.05em;
  text-transform:uppercase; color:var(--faint);}
.bodymeter.over{color:var(--warn);}

/* The rules panel reads as its own card, with its groups labelled (mockup 5c). */
.erules{background:var(--card); border:1px solid var(--edge-control); border-radius:12px; padding:4px 16px 12px;}
.erules-h{color:var(--accent-ink); padding:14px 0 4px;}

/* Mark form + list, per mockup 4c (2026-08-19). */
.markform-eyebrow{font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent-ink); margin-bottom:6px;}
.markform-h{font-family:var(--display); font-size:19px; font-weight:600; margin:0 0 16px;}
.markslist-h{font-family:var(--mono); font-size:12.5px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--faint); margin-bottom:4px;}
/* Each recorded mark reads as its own row-card rather than a table line. */
.mark-row{background:var(--card2); border:1px solid var(--edge); border-radius:10px; padding:11px 13px; margin-bottom:8px;}
.markslist{gap:0;}

/* Metadata moves off --faint on card surfaces (2026-08-19, same note).
   --faint is 3.6:1 on --card and 2.94:1 on --card2 — under the 4.5:1 text
   floor in both. --muted is 5.47:1 and reads as the same weight. */
.mark-meta,.mark-score span,.hwfile-n,.cband .cband-note,.bodymeter{color:var(--muted);}

/* Check results, per mockup 4f (2026-08-19). */
.scorecard{border-left:4px solid var(--edge);}
.scorecard.ok{border-left-color:var(--good);}
.scorecard.warnish{border-left-color:var(--warn);}
.scorecard.bad{border-left-color:var(--bad);}
.qcard{margin-bottom:10px;}
.qcard-head{display:flex; align-items:center; gap:10px; margin-bottom:8px; flex-wrap:wrap;}
.qcard-head b{font-size:15.5px;}
.qpill{font-family:var(--mono); font-size:12.5px; letter-spacing:.08em; text-transform:uppercase;
  border:1px solid; border-radius:6px; padding:3px 9px; white-space:nowrap; background:transparent;}

/* ============================================================
   PARENT OVERVIEW ROWS (2026-08-19, mockup 3d) — "every number names
   its own source". A solid track means real marks; a HATCHED track
   means practice accuracy, which is not a grade. The texture is read
   before the words are.
   ============================================================ */
.povlist{display:flex; flex-direction:column; gap:0; margin-top:10px;}
.povrow{display:flex; align-items:center; gap:12px; padding:13px 0; border-top:1px solid var(--edge); flex-wrap:wrap;}
.povrow:first-child{border-top:none;}
.povdot{flex:0 0 auto; width:9px; height:9px; border-radius:50%;}
.povmain{flex:1 1 240px; min-width:0;}
.povmain>b{display:block; font-size:15px; margin-bottom:3px;}
.povmain .isub{display:block;}
.povmain .isub b{color:var(--ink); font-weight:600;}
.povtrack{flex:0 0 230px;}
@media(max-width:640px){ .povtrack{flex:1 1 100%;} }
.povrail{position:relative; height:6px; background:var(--edge); border-radius:99px;}
.povrail>i{display:block; height:100%; border-radius:99px;}
.povrail>u{position:absolute; top:-4px; width:2px; height:14px; background:var(--ink); border-radius:1px;}
/* Hatched = derived from practice, not from a mark anyone was given. */
.povrail.hatched{background:repeating-linear-gradient(135deg,
  var(--edge) 0 5px, var(--warn-bg) 5px 10px);}
.povrail.hatched>i{background:repeating-linear-gradient(135deg,
  var(--warn) 0 5px, rgba(232,169,74,.45) 5px 10px) !important;}
.povnote{display:block; margin-top:6px; font-family:var(--mono); font-size:12.5px;
  letter-spacing:.07em; text-transform:uppercase; color:var(--muted);}
.povnote.soft{color:var(--warn);}
/* Causes sit inside the row they explain (mockup 3d). */
.povwhy{flex:1 1 100%; margin-top:10px; border-left:3px solid var(--bad); background:var(--bad-bg);
  border-radius:0 9px 9px 0; padding:11px 14px;}
.povwhy-h{font-family:var(--mono); font-size:12.5px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--bad); margin-bottom:7px;}
.povwhy p{margin:0 0 5px;}
.povwhy p:last-child{margin-bottom:0;}

/* Dashboard hero — "start with X" (2026-08-19, mockup 3b). */
.hubhero{margin:6px 0 26px;}
.hubhero-main .eyebrow{margin-bottom:6px;}
.hubhero-main h1{margin:0 0 8px;}
.hubhero-main .lede{color:var(--muted); max-width:620px; margin:0;}
.hubhero-act{display:flex; gap:10px; margin-top:18px; flex-wrap:wrap;}
.hubhero-act .btn{width:auto; flex:0 0 auto;}
.hubhero-act .notesbtn{margin-top:0;}
/* Non-coursework calendar items (sports/extracurricular/appointment/other),
   split out of the "Start with X" hero (2026-08-20, Marc: "That's an event,
   not part of his courses. It should be under upcoming events"). */
.upcoming-events h3{font-size:16px;}
.ue-row{display:flex; justify-content:space-between; align-items:center; gap:12px;
  padding:9px 0; border-top:1px solid var(--edge2);}
.ue-row:first-of-type{border-top:none;}
.ue-when{color:var(--muted); font-size:15.5px; white-space:nowrap; flex:0 0 auto;}
/* Upload: three courses across, and the picked one reads as picked (4d). */
@media(max-width:640px){ #hwSubjectGrid{grid-template-columns:1fr 1fr !important;} }

/* ============================================================
   TOUR GRAPHICS (2026-08-28, Marc: "Each slide needs a graphic with just a
   little text that shows the feature").

   Each slide's picture is a small mock of the real screen, built from the
   app's own tokens — no images and no external assets, so a slow school
   connection cannot leave a tour slide blank. The card the tour draws in is
   centred; the mock is left-aligned inside it, because it is standing in for
   an interface and interfaces are not centred.
   ============================================================ */
.tourart{max-width:400px; margin:16px auto 10px; text-align:left; background:var(--card2);
  border:1px solid var(--edge); border-radius:14px; padding:15px 16px;
  display:flex; flex-direction:column; gap:10px;}
.tourart .ta-head{display:flex; align-items:center; font-family:var(--mono); font-size:12.5px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--faint);}

/* Stand-in text: the shape of a paragraph without words nobody is meant to
   read. Never used to stand in for something a student needs to understand. */
.ta-shot{display:flex; flex-direction:column; gap:7px;}
.ta-line{display:block; height:8px; border-radius:99px; background:var(--edge);}
.ta-line.mid{width:76%;}
.ta-line.short{width:52%;}

/* What the app says back — the one thing on every mock that is real text. */
.ta-note{background:var(--accent-soft); border:1px solid var(--edge); border-radius:11px;
  padding:11px 13px; font-size:15px; line-height:1.45; color:var(--ink);}

.ta-tick{display:flex; align-items:center; gap:9px; font-size:15px; color:var(--ink);}
.ta-tick.ok{color:var(--good);}
.ta-tick.flag{color:var(--accent-ink);}
.ta-tick span{color:var(--muted);}

.ta-cal{display:grid; grid-template-columns:repeat(7,1fr); gap:5px;}
.ta-cal span{aspect-ratio:1; border-radius:6px; background:var(--card); border:1px solid var(--edge2);
  display:flex; align-items:center; justify-content:center;}
.ta-cal span.on{border-color:var(--accent);}
.ta-cal span.on::after{content:""; width:7px; height:7px; border-radius:99px; background:var(--accent);}
/* A DAY WITH WORK BOOKED ON IT (2026-08-29, Marc: "Study guides should show a
   calendar with the scheduled study times on it"). The same cell, carrying
   how long instead of a dot — so a month of dots becomes a plan you can read.
   The exam day is filled rather than outlined: a deadline that looks like the
   work is the thing that gets misread at a glance. */
.ta-cal span.on:not(:empty)::after{display:none;}
.ta-cal span{font-family:var(--mono); font-size:11px; color:var(--accent-ink);}
.ta-cal span.exam{background:var(--accent); border-color:var(--accent); color:var(--paper2);
  font-weight:600; font-size:10px;}
/* Day names above the grid (2026-08-29, Marc: "on study guide, add the days of
   the week above"). A plan with no days on it is a plan you cannot read. */
.ta-cal>b{font-family:var(--mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--faint); text-align:center; align-self:end; padding-bottom:2px;}

/* A WEEK WITH WORDS ON IT (2026-08-29, Marc: "on the calendar, use colors for
   each type of entry. instead of just dots put in words and make it actually
   7 columns wide"). Seven columns with their day names, a date in each cell
   and the entry itself named and coloured by type — a row of dots said there
   were events without saying what any of them was, which is the one thing a
   picture of a calendar is for. The colours are the ones the app already
   gives each type. */
.ta-week{display:grid; grid-template-columns:repeat(7,1fr); gap:6px; width:100%;}
.ta-week>b{font-family:var(--mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--faint); text-align:center; padding-bottom:2px;}
.ta-week>span{min-height:62px; border-radius:7px; background:var(--card); border:1px solid var(--edge2);
  padding:5px 5px 6px; display:flex; flex-direction:column; gap:5px;}
.ta-week u{text-decoration:none; font-family:var(--mono); font-size:12px; color:var(--faint);}
.ta-week i{font-style:normal; font-size:11.5px; line-height:1.25; border-radius:5px; padding:4px 5px;
  color:var(--paper2); font-weight:600;}
/* THE TIME UNDER THE TOPIC (2026-08-30, Marc: "add times for each session").
   Its own line rather than appended: "Photosynthesis 4:30 – 5:15" on one line
   wraps awkwardly in a narrow day cell and the topic stops being scannable,
   which is the thing a student reads the grid for. A time RANGE rather than a
   duration, because the range is the appointment and the duration is only a
   quantity — and it shows the weekend sessions are the long ones without
   needing to say so.

   <s> is used for the shape, not the semantics, so the line-through has to go. */
.ta-week i s{display:block; text-decoration:none; font-family:var(--mono);
  font-size:10px; font-weight:500; opacity:.82; margin-top:2px; letter-spacing:-.01em;}
.t-exam{background:#e57368;} .t-assign{background:#5db8f0;} .t-study{background:#45d6b5;}
.t-sport{background:#5cbd77;} .t-chores{background:#d9a944;}
/* THE STUDY PLAN IS COLOURED BY LESSON (2026-08-29, Marc: "study guide image
   needs more color and make it bigger"). It was grey cells reading 30m and
   45m — a plan that told you there was work without saying what the work was.
   Each lesson keeps one colour from the grid to the list underneath, which is
   what makes "three sessions on photosynthesis" something you can see rather
   than count. */
.t-enz{background:#5db8f0;} .t-photo{background:#e8912f;} .t-cell{background:#45d6b5;}
.t-mix{background:#8b7fd6;}
/* The swatch beside each lesson in the list below the grid. */
.ta-mk em, .ta-pri em{display:inline-block; width:10px; height:10px; border-radius:3px; margin-right:9px;
  vertical-align:baseline; flex:0 0 auto;}

.ta-chips{display:flex; flex-wrap:wrap; gap:7px;}
.ta-chip{font-family:var(--mono); font-style:normal; font-size:12.5px; padding:5px 10px;
  border-radius:99px; border:1px solid var(--edge); color:var(--faint); background:var(--card);}
.ta-chip.on{border-color:var(--accent); color:var(--accent-ink);}

.ta-bar{display:flex; align-items:center; gap:10px; font-size:14px; color:var(--muted);}
.ta-bar u{text-decoration:none; flex:0 0 118px;}
.ta-bar div{flex:1; height:8px; border-radius:99px; background:var(--edge); overflow:hidden;}
.ta-bar div i{display:block; height:100%; background:var(--accent);}
.ta-rail{height:8px; border-radius:99px; background:var(--edge); overflow:hidden;}
.ta-rail i{display:block; height:100%; background:var(--accent);}

/* Two cards, one behind the other — a deck rather than a single card, which
   is the only thing that says "there are more of these". */
.ta-stack{position:relative; padding-top:8px;}
.ta-card{background:var(--card); border:1px solid var(--edge); border-radius:12px; padding:16px 16px 18px;}
.ta-card.back{position:absolute; inset:0 12px auto 12px; height:100%; transform:translateY(-8px);}
.ta-card.front{position:relative;}
.ta-card.front b{display:block; font-family:var(--display,Newsreader),serif; font-size:22px; color:var(--ink);}
.ta-card.front span{display:block; margin-top:6px; font-size:13.5px; color:var(--faint);}

.ta-step{display:flex; align-items:center; gap:9px; font-size:15px; color:var(--faint);
  padding-left:2px;}
.ta-step.done{color:var(--good);}
.ta-step.done span{color:var(--muted);}
.ta-step.now{color:var(--accent-ink);}
.ta-step.now::before{content:"›"; font-family:var(--mono); color:var(--accent);}
.ta-step:not(.done):not(.now)::before{content:"·"; font-family:var(--mono); width:14px; text-align:center;}

/* A DEVICE WITH THE ASSIGNMENT ON IT (2026-08-28, Marc: "For assignment help
   show a graphic of a math assignment on a phone or ipad"). A tablet outline
   with a sheet of work inside it — the object the student is actually holding
   when they use the feature. Drawn in the app's own colours rather than as a
   white page, because a white rectangle on this theme reads as a rendering
   fault, not as paper. */
.ta-device{border:2px solid var(--edge); border-radius:16px; padding:14px 12px 12px;
  background:var(--board); position:relative;}
.ta-device::before{content:""; position:absolute; top:6px; left:50%; transform:translateX(-50%);
  width:5px; height:5px; border-radius:99px; background:var(--edge);}
.ta-paper{background:var(--card); border:1px solid var(--edge2); border-radius:9px; padding:12px 14px;
  border-left:3px solid var(--accent-soft);}
.ta-paper-h{font-family:var(--mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--faint); margin-bottom:9px;}
.ta-paper-h b{color:var(--accent); letter-spacing:.04em;}
.ta-qn{margin:0 0 10px; font-size:14.5px; line-height:1.45; color:var(--muted);}
.ta-qn b{color:var(--ink);}
/* The student's working, one step a line, in the mono face the rest of the
   app uses for anything that is a number rather than a sentence. */
.ta-work{display:flex; flex-direction:column; gap:5px; font-family:var(--mono); font-size:14px;
  color:var(--muted); padding-left:10px; border-left:2px solid var(--edge2);}
.ta-work .pen{color:var(--accent-ink);}
/* THE LINE WHERE IT WENT WRONG (2026-08-29, Marc: "Assignment help should
   show a line in red where a mistake happens. This isn't useful if we're not
   correcting mistakes"). The picture showed a student getting it right, which
   is a picture of nothing — the feature is the catch. Marked, not corrected:
   the note beside it names the line and hands it back, which is the same
   stance the Ask slide states outright. */
.ta-work .bad{color:var(--bad); position:relative; padding-left:14px;}
.ta-work .bad::before{content:"›"; position:absolute; left:0; color:var(--bad);}
.ta-mk.bad i{color:var(--bad);}
.ta-mk.bad span{color:var(--ink);}

/* THE MARKED PAPER (2026-08-28, Marc: "assignment check, show a graphic of a
   chemistry assignment with marks"). Marks per question and a total, the
   shape one comes back from a teacher in. */
.ta-paper.marked{border-left-color:var(--good-line);}
.ta-mk{display:flex; align-items:flex-start; gap:10px; font-size:14.5px; color:var(--muted);
  padding:7px 0; border-top:1px solid var(--edge2);}
.ta-mk:first-of-type{border-top:none;}
.ta-mk span{flex:1;}
.ta-mk i{font-style:normal; font-family:var(--mono); font-size:14px; flex:0 0 auto;}
.ta-mk.ok i{color:var(--good);}
.ta-mk.part i{color:var(--accent-ink);}

/* PRIORITY ROWS ON THE STUDY-GUIDE SLIDE (2026-08-30, Marc: "different
   sections get different priority levels. Indicated by the number of scheduled
   lessons and the mark in that lesson").

   Four columns in a fixed order, so the eye reads down each one rather than
   across three different shapes: what it is, the mark, the sessions drawn, the
   sessions counted. Ordered weakest first in the markup, which is the rule
   itself made visible — nothing has to explain it.

   THE MARK IS COLOURED, THE NAME IS NOT. Colouring the whole row would make
   the weak section read as an error rather than as where the work is going. */
.ta-pri{display:flex; align-items:center; gap:12px; font-size:14.5px; color:var(--ink);
  padding:8px 0; border-top:1px solid var(--edge2);}
.ta-pri:first-of-type{border-top:none;}
.ta-pri span{flex:1; display:flex; align-items:center;}
.ta-pri b{font-family:var(--mono); font-size:14.5px; font-weight:600; min-width:3.4em; text-align:right;}
/* The dots ARE the session count, drawn. Three dots against one is a
   comparison you make without reading, which "3" against "1" is not. */
.ta-pri u{text-decoration:none; font-size:11px; letter-spacing:2px; min-width:4.2em;}
.ta-pri i{font-style:normal; font-family:var(--mono); font-size:12.5px; color:var(--faint);
  min-width:6.4em; text-align:right;}
.ta-pri.low b, .ta-pri.low u{color:var(--bad);}
.ta-pri.mid b, .ta-pri.mid u{color:var(--accent-ink);}
.ta-pri.ok  b, .ta-pri.ok  u{color:var(--good);}
.ta-prinote{font-family:var(--mono); font-size:12px; color:var(--faint); margin-top:10px;}
/* The swatch ties each row to its blocks on the calendar above — without it
   the list and the plan read as two unrelated pictures, and the whole point is
   that the three sessions in the list ARE the orange blocks in the week.
   The colours come from .t-photo/.t-enz/.t-cell above, which the calendar
   chips already use; repeating the hex values here is how the two drift. */
@media (max-width:620px){
  /* The four columns collapse to two lines rather than shrinking to
     illegibility — the same rule the week grid follows on a phone. */
  .ta-pri{flex-wrap:wrap; gap:6px 10px;}
  .ta-pri span{flex:1 0 100%;}
  .ta-pri i{margin-left:auto;}
}

/* THE TIME BAR (2026-08-29, Marc: "academic assessment - use the graph
   image"). One stacked bar and its legend — the only picture in the app that
   shows where the minutes of a test actually go. */
.ta-stackbar{display:flex; height:17px; border-radius:6px; overflow:hidden;}
.ta-stackbar i{display:block; height:100%;}
.ta-legend{display:flex; flex-wrap:wrap; gap:7px 16px; font-size:13.5px; color:var(--muted);}
.ta-legend span{display:inline-flex; align-items:center; gap:6px;}
.ta-legend b{width:10px; height:10px; border-radius:3px; flex:0 0 auto;}
.ta-legend u{text-decoration:none; font-family:var(--mono); color:var(--ink);}

/* The create-event form, as it looks on the calendar page. */
.ta-form{display:flex; flex-direction:column; gap:8px;}
.ta-field{background:var(--card); border:1px solid var(--edge); border-radius:9px; padding:9px 12px;
  font-size:14.5px; color:var(--ink);}
.ta-field.empty{color:var(--faint);}
.ta-check{display:flex; align-items:center; gap:9px; font-size:14px; color:var(--muted);}
.ta-check i{flex:0 0 auto; width:15px; height:15px; border-radius:4px; border:1.5px solid var(--accent);
  display:inline-block; position:relative;}
.ta-check.on i{background:var(--accent);}

/* A second block inside a mock — "Tomorrow" on the check-in, the two asks
   under a recognition stem. Ruled off so the picture reads as two parts. */
.ta-next{border-top:1px solid var(--edge2); padding-top:11px; display:flex; flex-direction:column; gap:8px;}
.ta-next .ta-head{margin-bottom:2px; line-height:1.4; white-space:normal;}
/* A button inside a mock. Looks like the real one and does nothing — the
   whole card is a picture, and a tour that started navigating out of itself
   would lose the student's place in it. */
.ta-btn{align-self:flex-start; font-family:var(--mono); font-weight:600; font-size:14px;
  letter-spacing:.04em; text-transform:uppercase; padding:10px 16px; border-radius:9px;
  background:var(--accent); color:var(--paper2);}

/* THE CARD, SPLIT (2026-08-29, Marc: "Osmosis - add a horizontal slash and a
   description on the right"). The term stays the thing you see first; the
   rule under it and the definition beside it are what a flashcard looks like
   the moment it is turned over. */
.ta-card.front.split{display:grid; grid-template-columns:auto 1fr; align-items:center; gap:0 16px;}
.ta-card.front.split b{grid-column:1; padding-right:16px; border-right:1px solid var(--edge);}
.ta-card.front.split p{grid-column:2; margin:0; font-size:14.5px; line-height:1.45; color:var(--muted);}

/* THE PROFILE WHEEL, AS IT IS ON THE HOME PAGE (2026-08-29, Marc: "make the
   academic profile graphic the one from the home page").

   The same eight axes, the same hex colours and the same wedge geometry as
   graphics/profile-chart-flat.html — the wedge paths were generated with that
   file's own wedgePath() rather than drawn by eye, so the tour cannot show a
   different shape from the chart it is a picture of. Static SVG, not the
   iframe the home page uses: the live one pulls Google Fonts and a slider
   panel, and a tour slide that waits on a webfont on school wifi is a blank
   slide. */
.ta-wheelrow{display:flex; align-items:center; gap:22px; flex-wrap:wrap;}
.ta-wheel{flex:0 0 auto; width:268px; max-width:100%; height:auto;}
.ta-axes{flex:1 1 240px; display:flex; flex-direction:column; gap:8px; min-width:220px;}
.ta-axis{display:grid; grid-template-columns:112px 1fr 30px; align-items:center; gap:10px;
  font-size:14.5px; color:var(--muted);}
.ta-axis u{text-decoration:none;}
.ta-axis div{height:7px; border-radius:99px; background:var(--edge); overflow:hidden;}
.ta-axis i{display:block; height:100%; border-radius:99px;}
/* The number in ink, not in the axis colour. On the home page these sit on a
   white panel where #0d7a6e and #4A6FA5 read fine; on this card they are dark
   on dark. The bar beside it already carries the colour. */
.ta-axis b{font-family:var(--mono); font-size:14px; text-align:right; color:var(--ink);}
@media (max-width:600px){
  .ta-wheelrow{gap:14px;}
  .ta-wheel{width:100%;}
  .ta-axis{grid-template-columns:96px 1fr 28px; font-size:13.5px;}
}

/* The closing graph (2026-08-29). Two lines, no numbers — see the slide's own
   comment for why it carries none. */
.ta-graph{display:block; width:100%; height:auto;}
/* Full width (2026-08-29, Marc: "This still looks very basic") — a 620px cap
   put a small chart in the middle of a wide card, which is most of what
   "basic" was. */
.ta-graph.big{max-width:none; width:100%;}
/* THE TWO MARKS (2026-08-29, Marc: "this has to be impactful and inspiring.
   Indicate that the 65 is a percentage from grade 10 and the 83 is the mark in
   grade 11"). The numbers are the point of the picture, so they are set at
   display size on the line itself rather than as ticks up an axis — an axis
   makes a reader do arithmetic, two marks and two school years do not. */
/* SIX COURSES, ON A REAL AXIS (2026-08-29, Marc: "Put the axis back in. This
   still looks very basic. Maybe use 6 lines for the core courses"). The
   gridlines are what make a climb readable as marks rather than as a shape —
   two big numbers on an empty field were dramatic and said nothing about
   where 83 sits. Each line ends at its own mark, in its own colour. */
.tg-axis{font-family:var(--mono); font-size:13px; fill:var(--faint);}
.tg-year{font-family:var(--mono); font-size:13.5px; letter-spacing:.1em; text-transform:uppercase;
  fill:var(--faint);}

/* THE TWO REPORT CARDS (2026-08-29, Marc: "I want a kid to look at this and
   think. Holy shit, that could be me").

   Gridlines do not do that. Two averages a year apart, at a size you cannot
   miss, do — because 65 is a mark a struggling student recognises as theirs
   and 83 is the one they have never had. The chart underneath is the evidence
   for the pair; the pair is the sentence. */
.tg-head{display:flex; align-items:center; justify-content:center; gap:26px; margin-bottom:6px;}
.tg-side{text-align:center;}
.tg-side b{display:block; font-family:var(--display,Newsreader),serif; font-size:58px; line-height:1;
  color:var(--muted); font-weight:600;}
.tg-side span{display:block; margin-top:6px; font-family:var(--mono); font-size:12px;
  letter-spacing:.12em; text-transform:uppercase; color:var(--faint);}
.tg-side.to b{color:var(--accent); font-size:76px;}
.tg-side.to span{color:var(--accent-ink);}
/* The doors each average opens (Marc: "65 equals trades and maybe a college,
   83 offers university"). A sentence under each number, not a verdict —
   both name real destinations. */
.tg-side i{display:block; font-style:normal; margin-top:5px; font-size:14.5px; color:var(--muted);}
.tg-side.to i{color:var(--ink); font-weight:600;}
.tg-axis.uni{fill:var(--accent-ink);}
.tg-uni{font-family:var(--mono); font-size:12px; letter-spacing:.08em; text-transform:uppercase;
  fill:var(--accent-ink);}
.tg-arrow{color:var(--accent); opacity:.8; margin-top:-14px;}

/* Every course's own climb, under the chart. */
.tg-courses{display:grid; grid-template-columns:repeat(3,auto); justify-content:space-between; gap:11px 26px;
  border-top:1px solid var(--edge2); padding-top:14px;}
.tg-course{display:flex; align-items:baseline; gap:9px; font-size:15px; color:var(--muted);}
.tg-course i{width:10px; height:10px; border-radius:3px; flex:0 0 auto; align-self:center;}
/* The name and the pair of marks read as one unit. flex:1 on the name pushed
   the numbers to the far right of a wide column, so "English" and "63 → 83"
   stopped looking like the same fact. */
.tg-course b{color:var(--ink); font-weight:600;}
.tg-course span{font-family:var(--mono); font-size:14.5px; color:var(--ink); white-space:nowrap;}
.tg-course em{font-style:normal; color:var(--faint); margin:0 2px;}
.bigart{padding:24px 26px 22px;}

/* THE THREE BEATS AS BOXES (2026-08-29, Marc: "Instead of three long sentences
   create three boxes side by side with short impactful messages"). The
   headline carries the beat; the line under it is support, not a second
   message. Accent-edged like the goal band, because these are the three
   sentences the whole tour was arguing for. */
.tg-boxes{display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin-top:16px;}
.tg-box{background:var(--card); border:1px solid var(--edge); border-top:3px solid var(--accent);
  border-radius:12px; padding:16px 16px 15px;}
.tg-box b{display:block; font-family:var(--display,Newsreader),serif; font-size:20px; line-height:1.2;
  color:var(--ink); margin-bottom:7px;}
.tg-box span{display:block; font-size:14.5px; line-height:1.5; color:var(--muted);}
@media (max-width:620px){ .tg-boxes{grid-template-columns:1fr;} }
@media (max-width:620px){
  .tg-head{gap:16px;}
  .tg-side b{font-size:42px;}
  .tg-side.to b{font-size:54px;}
  .tg-courses{grid-template-columns:repeat(2,1fr);}
}
.ta-tick{font-family:var(--mono); font-size:10px; fill:var(--faint);}
.ta-tick.end{fill:var(--accent); font-size:11px; font-weight:600;}
/* The legend belongs under the picture it explains (2026-08-29, Marc), with a
   rule between them so it does not read as part of the plot. */
.ta-legend.under{border-top:1px solid var(--edge2); padding-top:11px; justify-content:center;}

/* THE PICTURE IS THE SLIDE (2026-08-29, Marc: "we have these huge back and
   next buttons but tiny graphics. reverse that").

   He is right about the proportions and about which way round they should be.
   Two full-width buttons at 54px each were the largest thing on every screen,
   under a 400px mock floating in an 880px card — so the loudest element on a
   tour of ten features was the word NEXT.

   The graphic now takes the card's width and everything inside it steps up a
   size; the buttons become what they are, a way to move on. Back and Next
   still match each other (2026-08-28: "make all the buttons the same size") —
   they are both smaller now, not one of them.

   SCOPED TO .tourcard, not to .card.done, which seven other screens use. */
.tourcard .tourart{max-width:none; padding:22px 24px; gap:13px;}
.tourcard .tourart .ta-head{font-size:13.5px;}
.tourcard .ta-note{font-size:17px; padding:14px 16px;}
.tourcard .ta-qn{font-size:16.5px;}
.tourcard .ta-work{font-size:16px; gap:7px;}
.tourcard .ta-mk{font-size:16.5px; padding:9px 0;}
.tourcard .ta-mk i{font-size:15.5px;}
.tourcard .ta-tick{font-size:16.5px;}
.tourcard .ta-step{font-size:17px; padding:2px 0;}
.tourcard .ta-q{font-size:19px;}
.tourcard .ta-ask,.tourcard .ta-field{font-size:16.5px; padding:12px 15px;}
.tourcard .ta-chip{font-size:13.5px; padding:6px 12px;}
.tourcard .ta-legend{font-size:14.5px;}
.tourcard .ta-stackbar{height:22px;}
.tourcard .ta-card.front b{font-size:27px;}
.tourcard .ta-card.front.split p{font-size:16.5px;}
.tourcard .ta-paper{padding:16px 18px;}
/* The month is capped rather than stretched. Full width, the cells are square
   by aspect-ratio and become 90px boxes — a calendar taking half a slide to
   say "there are days". */
.tourcard .ta-cal{gap:7px; max-width:540px; margin:0 auto; width:100%;}
.tourcard .ta-cal span{font-size:13px;}
.tourcard .ta-check{font-size:15.5px;}
.tourcard .ta-btn{font-size:15px; padding:12px 18px;}
/* The graph gets real height rather than whatever its viewBox scales to.
   THE CAP IS WHY IT LOOKED SMALL (2026-08-29). An SVG with a fixed viewBox and
   a max-height does not crop — it shrinks to fit and centres, so a 230px cap
   on a 520x254 drawing left the chart floating in the middle of a wide card
   with air down both sides. That was most of "this still looks very basic".
   The six-course version gets the height its aspect ratio asks for. */
.tourcard .ta-graph{max-height:230px;}
.tourcard .ta-graph.big{max-height:none;}
/* Buttons: sized to their labels, at the end of the row, still identical.
   BACK SITS ALONE ON THE LEFT (2026-08-29, Marc: "Move back button to the
   left") — the way back and the way forward are different kinds of act and
   should not share a corner. :first-child.ghost so slide one's lone Next
   button, which is first but solid, stays right where it is. */
.tourcard .actions{justify-content:flex-end; margin-top:20px;}
.tourcard .actions .btn{flex:0 0 auto; min-width:152px; padding:12px 22px; font-size:15px;}
.tourcard .actions .btn.ghost:first-child{margin-right:auto;}

/* The line above the closer's buttons (2026-08-29, Marc: "something that says
   things change today"). Display face, centred, and close enough to the
   buttons to read as their caption. */
/* Right-aligned over the pair it questions (2026-08-29, Marc: "move the cta
   above the buttons" — THE TWO buttons: Go to dashboard and Complete setup,
   which sit at the row's right edge with Back alone on the left). Centred, it
   floated over the whole row; over its two answers, it reads as their
   question. */
.tour-cta{font-family:var(--display,Newsreader),serif; font-size:24px; color:var(--ink);
  text-align:right; margin:26px 0 -8px;}
/* THE QUIETER WAYS OUT OF THE CLOSER (2026-09-01). The assessment is the one
   pill; the dashboard and setup are lines under it. Right-aligned so they
   hang below the button they are the alternative to, and small enough that
   the eye reaches the button first. */
.tour-alt{text-align:right; margin:12px 0 0; font-size:14.5px; color:var(--muted,#6b6b6b);}
.tour-alt a{color:inherit; text-decoration:underline; text-underline-offset:3px;}
.tour-alt a:hover{color:var(--ink);}
/* THE WEEK GRIDS SCROLL ON A PHONE (2026-08-29, Marc's iPhone screenshots of
   the shared deck: the study-guide plan was CLIPPED at Wednesday — Thursday
   half-drawn, Friday and the exam day simply gone, on the one slide whose
   whole point is the days leading to the exam).

   Seven labelled columns cannot fit in 390px at a readable size, and a 1fr
   grid clamps at min-content and overflows instead of shrinking — the same
   trap the home page hit. Neither shrinking nor clipping is honest here, so
   the grid keeps its natural width and SCROLLS inside its own container, the
   same treatment the feature pages give wide diagrams. The app tour on a
   phone had this bug too, not just the export. */
@media (max-width:620px){
  .ta-week, .ta-cal{overflow-x:auto; -webkit-overflow-scrolling:touch;
    grid-template-columns:repeat(7, minmax(76px, 1fr)); padding-bottom:6px;
    scrollbar-width:thin;}
}
@media (max-width:600px){
  .tourcard .tourart{padding:16px 15px;}
  .tourcard .actions .btn{flex:1 1 0; min-width:0;}
}

/* THE CONTENTS GRID (2026-08-29). Ten tiles, the numbers small and the names
   doing the work — a student reads this as "there are ten of these and here
   is what they are", which is the sentence directly above it. Five across on
   a laptop, two on a phone; never one, because a ten-item column is a list
   nobody reads to the end of. */
.toolgrid{display:grid; grid-template-columns:repeat(5,1fr); gap:10px; padding:18px;}
.toolgrid .tool{position:relative; background:var(--card); border:1px solid var(--edge2);
  border-radius:11px; padding:16px 10px 13px; text-align:center;
  display:flex; flex-direction:column; align-items:center; gap:8px;}
.toolgrid .tool b{font-size:13.5px; line-height:1.3; color:var(--ink); font-weight:600;}
.toolgrid .tool-n{position:absolute; top:6px; left:9px; font-family:var(--mono); font-size:11px;
  color:var(--faint);}
.tourcard .toolgrid .tool b{font-size:14.5px;}
@media (max-width:820px){ .toolgrid{grid-template-columns:repeat(3,1fr);} }
@media (max-width:520px){ .toolgrid{grid-template-columns:repeat(2,1fr); padding:13px;} }

/* THE WELCOME SLIDE, TIDIED (2026-08-29, Marc, on a screenshot of it: "messy
   page").

   It was the only slide with no graphic, and without one the alignments it
   had been getting away with all showed at once: a left-aligned eyebrow under
   a centred heading, two centred paragraphs, a left-aligned skip note, and a
   button hard right across a wide empty card. Four different edges on one
   screen.

   One centred column, one measure, and rhythm between the parts. The lead-in
   line is set apart because it is a hinge — everything after this slide is
   the list it introduces. */
.tour-intro{max-width:700px; margin:0 auto; text-align:center;}
/* Wide enough for the four-solve eyebrow on one line (2026-08-29, Marc:
   "Tour intro Eyebrow with three dots") — at .14em tracking it broke after
   the third dot and orphaned OPEN / DOORS onto its own line. */
.tour-sub{font-family:var(--mono); font-size:13px; letter-spacing:.11em; text-transform:uppercase;
  color:var(--accent); margin:0 0 16px; text-align:center;}
.tour-sub .nb{white-space:nowrap;}
.tour-intro .msg{margin:0 auto; font-size:17.5px; line-height:1.6;}
.tour-lead{font-family:var(--display,Newsreader),serif; font-size:20px; color:var(--ink);
  margin:22px 0 0; padding-top:20px; border-top:1px solid var(--edge);}
.tour-skipnote{margin:14px 0 0; color:var(--faint); text-align:center;}

/* THE SHAPE OF THE ESSAY, BESIDE THE ORDER IT IS BUILT IN (2026-08-29, Marc:
   "essay building needs a graphic like the outline of an essay"). The step
   list says what you do; this says what you end up with — five blocks, the
   thesis marked in the first one, three bodies, and the so-what. Two columns
   on a laptop, stacked on a phone. */
.ta-split{display:flex; gap:20px; flex-wrap:wrap; align-items:flex-start;}
.ta-steps{flex:1 1 260px; display:flex; flex-direction:column; gap:8px; min-width:240px;}
.ta-essay{flex:1 1 240px; min-width:220px; background:var(--card); border:1px solid var(--edge2);
  border-radius:9px; padding:12px 13px; display:flex; flex-direction:column; gap:9px;}
.ta-para{border-left:2px solid var(--edge); padding-left:10px; display:flex; flex-direction:column; gap:4px;}
.ta-para.thesis{border-left-color:var(--accent);}
.ta-para b{font-size:14px; color:var(--ink);}
.ta-para em{font-style:normal; font-family:var(--mono); font-size:11.5px; letter-spacing:.04em;
  color:var(--faint);}
.ta-para.thesis em{color:var(--accent-ink);}
.ta-para .ta-line{height:5px; margin-top:1px;}

.ta-q{font-size:16px; line-height:1.45; color:var(--ink);}
.ta-q b{color:var(--accent-ink); border-bottom:2px solid var(--accent-soft);}
.ta-ask{background:var(--card); border:1px solid var(--edge); border-radius:11px; padding:11px 13px;
  font-size:15px; color:var(--ink);}
@media (max-width:600px){
  .tourart{padding:13px 13px;}
  .ta-bar u{flex:0 0 96px; font-size:13px;}
}

/* Check-in advice + control panel (2026-08-30) */
.evadvice{margin-top:18px; padding-top:14px; border-top:1px solid var(--edge);}
.evadvice .dailylab{display:block; margin-bottom:8px;}
.evadvice-title{margin:0 0 4px;}
.evadvice-rm{margin-top:8px;}
.evset-row{display:flex; align-items:center; gap:10px; margin:10px 0;}
.evset-removed{margin-top:18px; padding-top:14px; border-top:1px solid var(--edge);}
.evset-removed .dailylab{display:block; margin-bottom:8px;}
.evset-removed .evset-row{justify-content:space-between;}

/* Mark note (2026-08-31) */
.mark-row .mark-note{flex-basis:100%; margin:4px 0 0;}

/* Per-page remove on the upload strip (2026-08-31) — opt-in per call site */
.hwfile{position:relative;}
.hwfile-rm{position:absolute; top:4px; right:4px; width:24px; height:24px; line-height:1;
  border:1px solid var(--edge); border-radius:99px; background:var(--card); color:var(--muted);
  font-size:15px; cursor:pointer;}
.hwfile-rm:hover{color:var(--ink); border-color:var(--faint);}

/* THE OPEN DAY, UNDER THE CALENDAR (2026-09-01, Marc: "i clicked an event and
   the calendar disappeared"). A panel, not a replacement — set apart from the
   grid above it so it reads as a drawer rather than another card. */
.cal-daypanel{margin-top:14px; padding:14px 16px; background:var(--card2, var(--card));
  border:1px solid var(--edge); border-radius:12px;}
.cal-dayhead{display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-bottom:10px;}
.cal-dayhead .cal-title{margin:0;}

/* ASSIGNMENT WORKBENCH — the coverage strip under each answer box
   (2026-09-01). Three states with three meanings, and the colours are the
   ones already carrying those meanings everywhere else in the app:

     empty/thin   neutral — this is a prompt, not a fault. A student who has
                  typed six words has not done anything wrong yet.
     partial      warn — something the question asked for is not there.
     answered     good — the part is covered. Never "well done": coverage
                  knows what is present, not whether it is any good.

   Nothing here is a mark, so nothing here uses --bad. */
.wb-cover{margin-top:8px;}
.wb-cover p{margin:0;}
.wb-cover.wb-partial{background:var(--warn-bg); border-left:3px solid var(--warn-line);
  border-radius:0 8px 8px 0; padding:9px 12px;}
.wb-cover.wb-partial b{color:var(--warn);}
.wb-cover.wb-answered{background:var(--good-bg); border-left:3px solid var(--good-line);
  border-radius:0 8px 8px 0; padding:9px 12px;}
.wb-cover.wb-answered p{color:var(--good);}
.wb-cover.wb-empty{padding:2px 0;}
.wb-cover.wb-empty b{color:var(--accent-ink);}
/* The assignment's own question, quoted. Same display face as .iq and
   deliberately NOT uppercased — see the note in workbench-ui.js. */
.wb-head{font-family:var(--display); font-weight:600; font-size:20px; line-height:1.25;
  margin:0 0 6px; color:var(--ink);}

/* THE NOTICE, MOVED OFF THE WRITING SCREEN (2026-09-01, Marc: "I don't want
   it in their face. I'd rather they think I broke their trust after instead
   of deciding to not say anything").

   I had put it above the box a student types into, and he is right that it
   was the wrong place. A line saying "we may tell a parent" directly above
   the box where a kid is about to write about their year does not inform
   them — it edits them. The kid who most needs to be noticed is exactly the
   one who reads that and writes something blander instead, and a student we
   never hear from is a worse outcome than a student who is angry with us
   afterwards. The consent that matters legally is the parent's, at signup.

   So it lives on their account screen: findable by anyone who looks, in
   front of nobody who does not. Not advertised, and not hidden either —
   if a student ever asks, the answer has to already be true and already be
   somewhere they could have read it. */
.wb-notice{margin-top:12px; padding-left:11px; border-left:2px solid var(--edge);
  font-size:13px; line-height:1.6; color:var(--faint);}

/* ============================================================
   PAY FOR A FAMILY WHO CAN'T (2026-09-01, Marc: "this doesn't stand out at
   all. add some color between it and the text above. use a graphic")

   It sat directly under the auto-top-up block wearing the same clothes — an
   .elab and a grey .isub, on the same flat card, with the same 16px gap. Two
   identical-looking blocks read as one form, and the eye ran past this one to
   the Subscribe button. Nothing here is about the person paying, and that was
   the one block with nothing to say so.

   AMBER, WHICH THE PALETTE ALREADY OWNS. --warn/--warn-bg/--warn-line are the
   existing warm trio and the screen around them is entirely green, so the
   panel separates on colour before a word is read — no new token, no
   one-off hex. The rule above it is the "some color between it and the text
   above" Marc asked for: a real break, not just more margin.
   ============================================================ */
.givecard{display:grid; grid-template-columns:auto 1fr; gap:0 15px; align-items:start;
  margin-top:26px; padding:17px 18px 16px; border-radius:12px;
  background:var(--warn-bg); border:1px solid var(--warn-line);
  border-left:3px solid var(--warn);}
.givemark{color:var(--warn); line-height:0; padding-top:2px;}
.givemark svg{display:block;}
/* The label loses the muted grey it shares with every other field label —
   in here it is the panel's headline, so it reads as one. */
.givecard .elab{color:var(--warn); margin-bottom:6px;}
.givecard .isub{margin:0; font-size:15.5px; line-height:1.5;}
/* Input and closing note run the full width under both columns — the mark
   introduces the ask, it does not need to indent the field. */
.giverow,.givenote{grid-column:1 / -1;}
.giverow{margin-top:13px;}
.giverow .etext{border-color:var(--warn-line);}
.giverow .etext:focus{outline:none; border-color:var(--warn);}
.givenote{margin-top:9px !important; font-size:14.5px; color:var(--faint);}
@media (max-width:520px){
  /* One column on a phone: the mark goes above the words rather than
     squeezing them into a strip too narrow to read. */
  .givecard{grid-template-columns:1fr; gap:9px;}
  .giverow,.givenote{grid-column:auto;}
}

/* ============================================================
   WHAT THIS COSTS A MONTH (2026-09-01, Marc: "add the monthly token
   purchases, donations and this creates a total at the bottom")

   A receipt, not a form field: label left, amount right, one line per thing
   that will appear on the invoice, and the sum ruled off below them. The
   amounts are monospace and right-aligned so the digits line up in a column
   a parent can actually add up themselves — a total nobody can check is a
   total nobody trusts.
   ============================================================ */
.billtotal{margin-top:22px; padding-top:15px; border-top:1px solid var(--edge2);}
.billrow{display:flex; align-items:baseline; gap:12px; padding:5px 0;}
.billlabel{flex:1 1 auto; color:var(--muted); font-size:15.5px; min-width:0;}
.billamt{flex:0 0 auto; font-family:var(--mono); font-size:15.5px; color:var(--ink);
  font-variant-numeric:tabular-nums;}
.billsum{margin-top:9px; padding-top:11px; border-top:1px solid var(--edge);}
.billsum .billlabel{color:var(--ink); font-weight:650; font-size:16.5px;}
.billsum .billamt{color:var(--accent); font-size:19px; font-weight:650;}
.billstatus{margin:16px 0 0;}

/* ============================================================
   THE TOUR'S CLOSING CTA (2026-09-01, Marc: "put the academic assessment
   graph on this page with a cta to complete it and leave the go to dashboard
   button on the bottom")

   The button that asks for the assessment sits with the wheel it is asking
   about, not in the row at the foot of the card — that row is now only the
   way back and the way out. Full width so it reads as the slide's own action
   rather than as a third pill competing with them.
   ============================================================ */
.tour-closer-note{margin:14px 0 0; font-size:16px; line-height:1.55; color:var(--muted);}
.tourcard .tour-cta-btn{display:block; width:100%; margin-top:16px; text-align:center;}

/* DELETE ON THE EVENT FORM (2026-09-01, Marc: "there should be a delete
   button on the events edit screen"). Ghost and left, away from Save: the
   destructive control should never be the one a thumb lands on by accident,
   and it must not read as the second half of a pair with the primary. Armed,
   it turns red and says what it is about to remove. */
.caldel{margin-right:auto; border-color:var(--bad-line); color:var(--bad); background:none;}
.caldel:hover{border-color:var(--bad);}
.caldel.armed{background:var(--bad-bg); border-color:var(--bad); color:var(--bad);}

/* The action pair on a study-guide row (2026-09-02, Marc: "the delete button
   should be on the right like the other events"). .btn is width:100%, so
   without a group of its own Start studying filled the row and pushed Delete
   onto its own line at the far left. */
.exam-row-acts{display:flex; align-items:center; gap:8px; margin-left:auto;}
.exam-row-acts .btn{width:auto;}

/* THE NEXT-STEPS BLOCK (2026-09-02, Marc: "create better instruction").
   Used on the end of the parent's setup, where the one thing that matters is
   the handoff to the student's own device. Set apart from the prose around it
   because it is an instruction to follow, not a paragraph to read. */
.nextsteps{background:var(--card2,#1A4A43); border:1px solid var(--edge,#2A5A4E);
  border-radius:12px; padding:16px 18px; margin:14px 0 6px;}
.nextsteps .tour-lead{font-size:17px;}
.nextlist{margin:0; padding-left:20px;}
.nextlist li{margin:0 0 7px; line-height:1.55; font-size:15.5px;}
.nextlist li:last-child{margin-bottom:0;}
/* Three steps, not five: the parent grid is its own so widening the student
   one to fit never silently reflows this. */
.parent-toolgrid{grid-template-columns:repeat(3,1fr);}
@media (max-width:520px){ .parent-toolgrid{grid-template-columns:1fr;} }

/* THE "SET IT UP" LINK INSIDE A ? POPUP (2026-09-02, Marc: "question marks
   with popups explaining what each feature does and links to set it up").
   Sits at the foot of the popup, visually separated from the explanation —
   it is the one thing in there you act on. */
.ehelp-go{display:inline-block; margin-top:12px; padding-top:10px;
  border-top:1px solid var(--edge); width:100%;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--accent); text-decoration:none;}
.ehelp-go:hover{text-decoration:underline;}
/* The ? on a dashboard sits in a row of buttons rather than inside a label,
   so it must not stretch to the row's height the way a flex child would. */
.hub-actions-lg .ehelp-holder,
.row-buttons .ehelp-holder,
.actions .ehelp-holder{align-self:center; flex:0 0 auto;}

/* A TILE PLUS ITS "?" AS ONE GRID CELL (2026-09-02). The wrapper takes the
   cell; the tile fills it and the question mark floats at the top-right
   corner, over the tile rather than stealing a row from it. */
.ctile-wrap{position:relative; display:flex;}
.ctile-wrap > .notesbtn{flex:1 1 auto; width:100%;}
.ctile-wrap > .ehelp-holder{position:absolute; top:6px; right:7px; z-index:3;}
/* ROOM FOR IT (2026-09-02). The corner is absolute, so on a compact
   Reference tile — "Ask me", "Notes" — it landed on top of the label. The
   tile reserves the corner instead of the ? trying to avoid it. */
.ctile-wrap > .notesbtn{padding-right:30px;}
/* On the small tiles the label is vertically centred and short, so the ?
   sits beside it rather than above. */
.ctiles-sm .ctile-wrap > .ehelp-holder{top:50%; transform:translateY(-50%);}
/* The popup must escape the tile, not be clipped by it. */
.ctile-wrap > .ehelp-holder .ehelp-pop{z-index:60;}
