:root {
  --bg:#f6f6f7; --card:#fff; --ink:#1b1c1e; --dim:#6b7076; --line:#e2e4e7;
  --idle:#8c9196; --active:#3378d9; --attention:#d48c1a; --good:#219459; --bad:#c7403d; --done:#6659b8;
  --commonapp:#7a1f35;
  --pink:#d6337c;
  /* The four weights a hint can carry: brown, maroon, orange, green - a suggestion up to a rule. */
  --w1:#8b5a2b; --w2:#7a1f2e; --w3:#d48c1a; --w4:#219459;
  /* The ask a Claude pass was given, wherever a version or a snapshot prints it. */
  --vask:#8a3fa8;
  /* Early Action on the tracker: maroon, early but not binding. */
  --maroon:#7a1f2e;
}
/* Dark is a choice now, not a guess. It used to follow prefers-color-scheme, which meant
   the tracker went dark because a phone was on night mode at eleven at night - and a
   deadline table is read in whatever light the room has, not the one iOS assumes. Light is
   the default; Admin has the switch; the body carries the answer as a class. */
body.dark {
  --bg:#131416; --card:#1c1e21; --ink:#eceef0; --dim:#9aa0a6; --line:#2b2e33;
  --commonapp:#a8455f; --vask:#c48ae0; --maroon:#c2566c;
  /* The parts of a control the browser draws itself - an open select popup, the
     scrollbars, the number stepper, the caret, the focus ring - are reached by none of the
     colours above. color-scheme is the one property that says which set to draw, and
     without it a dark page on a light Mac opened a white popup menu over itself. On the
     class rather than from prefers-color-scheme, for the same reason the colours are. */
  color-scheme:dark;
}
* { box-sizing:border-box; -webkit-text-size-adjust:100%; }
body { margin:0; background:var(--bg); color:var(--ink); color-scheme:light;
       font:15px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
header { position:sticky; top:0; z-index:5; display:flex; align-items:center; gap:14px;
         padding:10px 14px; background:var(--card); border-bottom:1px solid var(--line); }
.brand { font-weight:700; text-decoration:none; color:var(--ink); font-size:15px; }
.brandnote { margin-left:auto; color:var(--dim); font-size:11px; }
/* The two capture buttons, in the bar so they are on every screen at once. Outlined and
   small: they are a tool, not the thing any screen wants you to do next. */
/* In the middle of the bar and twice the size - asked for. They were a small pair
   tucked against the brand, and on a phone that is the hardest spot to hit. */
.shotbtns { display:inline-flex; gap:10px; margin:0 auto; }
button.shotbtn { width:auto; margin:0; padding:7px 18px; font-size:15px; font-weight:700;
                 border-radius:999px; background:none; border:1.5px solid var(--line);
                 color:var(--dim); cursor:pointer; }
button.shotbtn:hover { color:var(--active); border-color:var(--active); }
.brand { white-space:nowrap; }
@media (max-width: 480px) {
  /* The brand wrapped to two lines under the two capture buttons. The build date is the
     least useful thing in a 400px header and gives way; the buttons keep their words. */
  .shotbtns { gap:6px; } button.shotbtn { padding:5px 12px; font-size:13px; white-space:nowrap; }
  .brandnote { display:none; }
}
.brandmark { height:22px; width:auto; vertical-align:-5px; margin-right:7px; }
.copyright { color:var(--dim); font-size:11px; }
/* A tab bar, not a row of links: the mark above its word, the selected one in the accent
   colour, fixed to the bottom where a thumb reaches it. */
nav.tabbar { position:fixed; left:0; right:0; bottom:0; z-index:40; display:flex;
             justify-content:space-around; align-items:flex-start; gap:2px;
             padding:7px 4px calc(7px + env(safe-area-inset-bottom));
             background:var(--card); border-top:1px solid var(--line); }
nav.tabbar a { flex:1 1 0; display:flex; flex-direction:column; align-items:center;
               gap:3px; text-decoration:none; color:var(--dim); font-size:11px;
               padding:2px 0; min-width:0; }
nav.tabbar a.on { color:var(--active); font-weight:600; }
nav.tabbar a span { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
.glyphwrap { position:relative; display:inline-flex; }
.badge { position:absolute; top:-4px; right:-7px; min-width:15px; height:15px;
         border-radius:999px; background:var(--bad); color:#fff; font-size:9px;
         font-style:normal; font-weight:700; display:flex; align-items:center;
         justify-content:center; padding:0 3px; }
/* Phone first: 12px gutters and a cap that never bites below 900px. The desktop rule
   below removes the cap - a laptop was showing a 900px column in a 1500px window with the
   tables scrolling inside it.

   The bottom gutter is a LONGHAND and it is written after the shorthand, because the bar
   sits over the page and the page needs room to scroll past it. It used to be a rule of
   its own ABOVE this one, and this shorthand reset it to 12px - so the reserve never
   applied on any surface, and the footer sat under the bar on every page since. Measured:
   the bar is 60px on a Mac and 94px on an iPhone, where env(safe-area-inset-bottom) adds
   the home indicator.

   The side gutters take the safe-area insets too. viewport-fit=cover is in the meta tag so
   the bar can reach under the home indicator, and the same flag puts the page under the
   sensor housing when the phone is turned sideways. Every inset is 0 on a Mac, which is
   why none of this shows in Chrome. */
main { padding:12px; max-width:900px; margin:0 auto;
       padding-bottom:calc(78px + env(safe-area-inset-bottom));
       padding-left:calc(12px + env(safe-area-inset-left));
       padding-right:calc(12px + env(safe-area-inset-right)); }
header { padding-left:calc(14px + env(safe-area-inset-left));
         padding-right:calc(14px + env(safe-area-inset-right)); }
nav.tabbar { padding-left:calc(4px + env(safe-area-inset-left));
             padding-right:calc(4px + env(safe-area-inset-right)); }
footer { padding:16px 14px 28px; color:var(--dim); font-size:11px; text-align:center; }
footer a { color:var(--dim); }
h1 { font-size:19px; margin:4px 0 10px; }
h1.titlebtn { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
h1.titlebtn .btn { font-size:13px; font-weight:500; }
/* A page reached from a title, as a link rather than a button (Ari's Source, 2026-10-24). */
h1.titlebtn a.titlelink { font-size:15px; font-weight:500; color:var(--active); text-decoration:underline; text-underline-offset:3px; }
h1.titlebtn .clip { min-width:0; }
/* The print glyph on a school's title line: a small blue button holding only the printer. */
.btn.printglyph { width:auto; min-width:0; flex:none; padding:2px 8px; font-size:15px; line-height:1.2; font-weight:500; }
.roundmeta .short { display:none; }
@media (max-width: 480px) {
  summary.roundhead { flex-wrap:nowrap; align-items:center; }
  .roundhead .roundname.grouphead { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .roundhead .roundmeta { flex:none; margin-left:auto; }
  .roundmeta .long { display:none; } .roundmeta .short { display:inline; }
}
.ppfoot .btn { font-size:13px; font-weight:500; width:auto; min-width:0; flex:none; text-transform:none; letter-spacing:normal; }
dialog.printpick { border:1px solid var(--line); border-radius:10px; background:var(--card); color:var(--ink);
                   padding:0; width:min(520px, calc(100vw - 32px)); max-height:min(80vh, 720px); }
dialog.printpick::backdrop { background:rgba(10,11,13,.35); }
dialog.printpick form { display:flex; flex-direction:column; max-height:min(80vh, 720px); margin:0; }
.pphead, .ppfoot { display:flex; align-items:center; gap:12px; padding:12px 14px; font-size:15px; }
.pphead b { flex:1; } .ppfoot { justify-content:flex-end; border-top:1px solid var(--line); }
.pplist { overflow-y:auto; padding:0 14px; border-top:1px solid var(--line); }
.pprow { display:flex; align-items:flex-start; gap:10px; padding:9px 0; border-bottom:1px solid var(--line); cursor:pointer;
         font-weight:400; font-size:15px; text-transform:none; letter-spacing:normal; color:var(--ink); }
.pprow .title { font-weight:600; } .pphead b { text-transform:none; letter-spacing:normal; }
.pprow:last-child { border-bottom:none; }
.pprow input { min-width:0; width:auto; margin-top:3px; flex:none; }
.pprow .grow { display:flex; flex-direction:column; min-width:0; }
h2 { font-size:13px; text-transform:uppercase; letter-spacing:.04em; color:var(--dim);
     margin:18px 0 8px; }
.card { background:var(--card); border:1px solid var(--line); border-radius:12px;
        padding:12px; margin-bottom:10px; }
.row { display:flex; align-items:center; gap:10px; }
.row + .row { margin-top:8px; border-top:1px solid var(--line); padding-top:8px; }
/* A labelled paragraph inside a card: the label on its own line, the text beneath it at
   full width. For answers too long to sit at the right of a row. */
.pf { margin-top:8px; border-top:1px solid var(--line); padding-top:8px; }
.pf:first-child { margin-top:0; border-top:0; padding-top:0; }
.pfk { font-size:12px; color:var(--dim); margin-bottom:3px; }
.pfv { line-height:1.45; white-space:pre-line; }
.row + .pf, .pf + .row { margin-top:8px; border-top:1px solid var(--line); padding-top:8px; }
/* The Activities tab. */
.act { position:relative; }
.act.below { opacity:.92; border-style:dashed; }
.act .acthead { flex-wrap:wrap; gap:8px 10px; }
.act .ranklab { display:inline-flex; align-items:center; gap:4px; font-weight:600; color:var(--dim); }
/* Written as .card.act so they outrank the laptop rule input:not([type=checkbox]):not([type=radio])
   { min-width:260px } further down, which is what gave the rank box 260px. */
.card.act input.rank { width:3.6em; min-width:0; padding:4px 6px; text-align:center; }
.act select.acttype { min-width:0; width:auto; max-width:100%; }
.act .tick { margin-left:auto; font-size:12px; color:var(--dim); white-space:nowrap; }
.act .tick input { width:auto; margin:0 4px 0 0; }
.card.act .pf input[type=text], .card.act .pf textarea { width:100%; min-width:0; box-sizing:border-box; }
.act .cnt, table.formtab .cnt { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11px; color:var(--dim); margin-left:6px; }
.act .cnt.over, table.formtab .cnt.over { color:var(--bad); font-weight:700; }
.act .actgrid { flex-wrap:wrap; gap:6px 12px; align-items:center; }
.act .actgrid .lab { font-size:12px; color:var(--dim); min-width:52px; }
.act .actgrid .opts { display:flex; flex-wrap:wrap; gap:4px 12px; }
.act .actgrid .opts label, .act .actgrid label.num { font-size:13px; white-space:nowrap; display:inline-flex; align-items:center; gap:4px; margin:0; }
.act .actgrid .opts input { width:auto; margin:0; }
.card.act .actgrid label.num input, .card.act .actgrid label.num select { width:5.5em; min-width:0; padding:4px 6px; }
.act .actfoot { align-items:center; }
.act .saved { min-height:1em; } .act .saved.warn { color:var(--bad); }
.act.flash { outline:2px solid var(--active); }
.cutline { display:flex; align-items:center; gap:10px; margin:14px 0; color:var(--bad); font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.04em; }
.cutline::before, .cutline::after { content:""; flex:1; border-top:2px dashed var(--bad); }
.sugg { align-items:flex-start; flex-wrap:wrap; }
.sugg .pill { flex:0 0 auto; }
.pill.sug-combine { background:color-mix(in srgb, var(--active) 18%, transparent); color:var(--active); }
.pill.sug-tighten { background:color-mix(in srgb, var(--bad) 18%, transparent); color:var(--bad); }
.pill.sug-cut { background:color-mix(in srgb, var(--attention) 18%, transparent); color:var(--attention); }
.pill.sug-complete, .pill.sug-order { background:color-mix(in srgb, var(--idle) 22%, transparent); color:var(--ink); }
.formtext { white-space:pre-wrap; font-size:12.5px; line-height:1.45; margin:8px 0 0; max-height:420px; overflow:auto; }
.portcard .row { flex-wrap:wrap; }
.portcard .row .grow { flex:1 1 220px; }
.grow { flex:1; min-width:0; }
.title { font-weight:600; font-size:15px; }
.sub { color:var(--dim); font-size:12px; }
.clip { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Without this, every plain link fell back to the browser's default blue, which on this
   background is almost black. Seen in Chrome: the similar-prompt list and the Drive link
   were legible only by selecting them. */
a { color:var(--active); }
a.block { text-decoration:none; color:inherit; display:block; }
.pill { display:inline-block; padding:2px 8px; border-radius:999px; font-size:11px;
        font-weight:600; white-space:nowrap; }
/* The activity filter: a pill that is also a link, and the one in force. */
.pill.on { background:rgba(51,120,217,.18); color:var(--active); }
a.pill { text-decoration:none; background:rgba(140,145,150,.12); color:var(--ink); }
.nowrap { white-space:nowrap; }
.idle{background:rgba(140,145,150,.16);color:var(--idle)}
.active{background:rgba(51,120,217,.16);color:var(--active)}
.attention{background:rgba(212,140,26,.18);color:var(--attention)}
.good{background:rgba(33,148,89,.16);color:var(--good)}
.bad{background:rgba(199,64,61,.16);color:var(--bad)}
.done{background:rgba(102,89,184,.16);color:var(--done)}
.tile { width:30px; height:30px; border-radius:8px; display:flex; align-items:center;
        justify-content:center; color:#fff; font-weight:700; font-size:12px; flex:none; }
.mono { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:12px; }
label { display:block; font-size:12px; color:var(--dim); margin:10px 0 4px; }
input, select, textarea, button {
  font:inherit; color:var(--ink); background:var(--card);
  border:1px solid var(--line); border-radius:9px; padding:9px 10px; width:100%;
}
/* Half the viewport is right for the one textarea that holds an essay, and absurd for a
   three-line setting: the Claude Context boxes were inheriting it and pushing the rest of
   Admin off the screen. Height belongs to the editor, not to the element. */
textarea { line-height:1.5; resize:vertical; min-height:4.5em; }
.edit textarea { min-height:46vh; }
button, .btn { background:var(--active); color:#fff; border:none; font-weight:600;
               text-align:center; text-decoration:none; display:inline-block; }
button.ghost { background:transparent; color:var(--active); border:1px solid var(--line); }
/* Pressed, and focused. There was no :active anywhere in this sheet, so a press on a phone
   said nothing back until the page returned - and on a keyboard nothing said which control
   Return was about to press. Both answers are drawn here, once, for every control rather
   than per page. */
button:active, .btn:active, a.slice:active, button.linky:active, button.vennbtn:active,
button.setfold:active, a.block:active, details.pop > summary:active,
details.grp > summary:active { transform:translateY(1px); }
/* A button behaves like one: it lifts a little under the pointer and presses down when
   pushed, on top of going darker. Asked for after the glyph buttons read as labels. */
button:hover, .btn:hover { filter:brightness(1.06); box-shadow:0 2px 6px rgba(10,11,13,.18); }
button:active, .btn:active { filter:brightness(.88); transform:translateY(1px); box-shadow:none; }
.tint-good { color:var(--good); font-weight:600; }
.tint-active { color:var(--active); font-weight:600; }
.tint-attention { color:var(--attention); font-weight:600; }
.tint-bad { color:var(--bad); font-weight:600; }
.tint-idle { color:var(--dim); }
.tint-done { color:var(--done); font-weight:600; }
/* The score, right under the text: two short bars, not a card of their own. */
/* The version note on the left, the score on its right - not on top of it. The score is
   three columns kept together on one line each: what was scored, its bar, its number; the
   scoring notes wrap underneath the pair. On a phone the two stack. */
.noterow { display:flex; flex-wrap:wrap; gap:6px 18px; align-items:flex-start; margin-top:6px; }
.noterow .notecol { flex:0 1 320px; min-width:0; }
.noterow .notecol label { margin-top:4px; }
.noterow .notecol input { margin:0; }
.scorestrip { flex:1 1 300px; max-width:640px; display:grid; grid-template-columns:auto minmax(80px,200px) auto;
              gap:4px 10px; align-items:center; margin-top:4px; font-size:13px; }
.scorestrip .bar { width:100%; }
.scorestrip .sub { grid-column:1 / -1; margin:0; white-space:normal; overflow-wrap:anywhere; }
.vcurrent { background:rgba(51,120,217,.06); }
/* The picture count on a task's camera glyph: an iOS badge, a red disc on the top-right
   corner, only when there is more than one picture. */
.devgrid a.shotlink { position:relative; display:inline-block; }
.devgrid a.shotlink .shotn { position:absolute; top:-7px; right:-9px; min-width:15px; height:15px; padding:0 4px;
                             border-radius:999px; background:var(--bad); color:#fff; font-size:9px; line-height:15px;
                             font-weight:700; text-align:center; font-variant-numeric:tabular-nums; }
/* The Generation tab as tiles: three across, each as tall as its text, none scrolling. */
.htiles { display:grid; grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); gap:10px; }
body.adminsettings main:has(.htiles) { max-width:1500px; }
body.adminsettings main > #ctxform, body.adminsettings main > .htiles { max-width:none; }
.htile .thead { display:flex; flex-wrap:wrap; align-items:center; gap:4px 10px; }
.htile .thead label { flex:1 1 140px; }
.htile .thead .wpick { margin-left:auto; }
@container (max-width: 999px) { .htiles { grid-template-columns:repeat(2, minmax(0,1fr)); } }
@container (max-width: 640px) { .htiles { grid-template-columns:minmax(0,1fr); } }
.htile { border:1px solid var(--line); border-radius:12px; padding:8px 10px; background:var(--card);
        display:flex; flex-direction:column; gap:4px; min-width:0; }
.htile label { margin:0; }
.htile textarea, .htile input.ttitle { margin:0; resize:none; overflow:hidden; min-height:40px; }
.htile input.ttitle { font-weight:600; min-height:0; padding:4px 6px; }
.htile input { min-width:0; }
.htile .taskmodel { gap:4px 6px; }
.htile .taskmodel .tname { flex:0 0 56px; font-size:12px; color:var(--dim); }
.htile .taskmodel .models { display:inline-flex; gap:4px; flex-wrap:wrap; }
.htile .taskmodel .modelpick { padding:2px 7px; font-size:12px; }
.htile .trow { display:flex; flex-wrap:wrap; align-items:center; gap:4px 8px; margin-top:2px; }
.htile .trow .vbtn { margin-left:auto; }
.htile .trow .vbtn + .vbtn { margin-left:0; }
.htile.archived { opacity:.55; flex-direction:row; align-items:center; gap:8px; padding:5px 10px; }
.htile.archived .tsum { flex:1 1 auto; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-size:12.5px; }
.htile.saving { border-color:var(--active); }
.htile.saved { border-color:var(--good); }
/* Weight: four radios drawn as dots, the chosen one filled - brown, maroon, orange, green. */
.wpick { display:inline-flex; gap:4px; align-items:center; }
.wpick label { display:inline-flex; align-items:center; gap:3px; margin:0; font-size:11px; cursor:pointer; color:var(--dim); }
.wpick input { position:absolute; opacity:0; width:0; height:0; margin:0; }
.wpick .dot { width:14px; height:14px; border-radius:50%; border:2px solid var(--w3); box-sizing:border-box; }
.wpick .w1 .dot { border-color:var(--w1); } .wpick .w2 .dot { border-color:var(--w2); }
.wpick .w3 .dot { border-color:var(--w3); } .wpick .w4 .dot { border-color:var(--w4); }
.wpick .w1 input:checked + .dot { background:var(--w1); } .wpick .w2 input:checked + .dot { background:var(--w2); }
.wpick .w3 input:checked + .dot { background:var(--w3); } .wpick .w4 input:checked + .dot { background:var(--w4); }
.wpick input:checked ~ .wname { color:var(--ink); font-weight:600; }
/* Activity: the accounts down the left, everything on the right. */
.actone h3, .actpane h3 { margin:0 0 6px; font-size:12px; letter-spacing:.06em; text-transform:uppercase; color:var(--dim); }
/* The Account screen is wide enough for both halves: the list side keeps its cards at
   their natural width, the pane takes the rest of a laptop. */
/* Account is a split screen: the settings cards on the LEFT at their own width, left-
   aligned; Activity - the picked account's table, then everybody's - in the pane on the
   RIGHT, which scrolls on its own. The pane is a plain panel, not a frame. */
.actwho { display:flex; flex-wrap:nowrap; overflow-x:auto; gap:4px 12px; margin:0 0 8px; white-space:nowrap; }
.actwho .actpick { display:inline-flex; align-items:center; gap:4px; margin:0; font-size:13px; color:var(--ink); cursor:pointer; }
.actwho .actpick input { margin:0; width:auto; }
.actwho .actpick .n { color:var(--dim); font-variant-numeric:tabular-nums; }
.acttwo { display:grid; grid-template-columns:minmax(0,1fr); gap:12px; align-items:start; }
.acttwo .tablewrap { overflow-x:auto; }
/* Courses and grades on the Common App page. Eleven columns are wider than a phone, so a
   year's table scrolls inside its own box and the page itself never scrolls sideways. A
   row to check or a missing one is tinted in its verdict's colour. */
.gradescard .gradeshead { margin:0 0 4px; font-weight:600; }
.gradescard .subrow { gap:6px; }
h3.gradesyear { margin:16px 0 2px; font-size:14px; }
.gradesfrom { margin:0 0 6px; }
.gradeswrap { overflow-x:auto; max-width:100%; -webkit-overflow-scrolling:touch; }
table.grades { min-width:900px; font-size:12.5px; }
/* The MIT and Honors tables: the activities one wide enough for a description, the short
   ones (summers, awards, honors) no wider than the phone. */
table.grades.formtab { min-width:640px; }
table.grades.formtab.narrow { min-width:0; }
table.stats.grades.formtab td:first-child { min-width:0; width:24px; }
/* Cells wrap here: table.stats cells are nowrap (and come later, so this names both classes
   to outrank them), and with long course names and notes
   that made this one nearly 1,900px wide - a phone scrolled sideways for every grade. */
table.stats.grades th, table.stats.grades td { padding:5px 8px 5px 0; white-space:normal; vertical-align:top; }
table.stats.grades td:first-child { min-width:120px; max-width:200px; }
table.grades .c { text-align:center; }
table.grades td.gnote { min-width:220px; color:var(--dim); }
table.grades tr.gr-check td { background:color-mix(in srgb, var(--attention) 12%, transparent); }
table.grades tr.gr-missing td { background:color-mix(in srgb, var(--bad) 12%, transparent); }
table.grades .pill { padding:1px 7px; }
.gradesrc { margin:4px 0 0; padding-left:18px; color:var(--dim); font-size:12px; overflow-wrap:anywhere; }
body.adminsettings main > .split.actsplit { max-width:none; }
.split.actsplit { --list-cap:780px; }
.split.actsplit > .listpane > * { max-width:760px; }
.split.actsplit > .detailpane.actpane { overflow:auto; padding-right:4px; }
.split.actsplit > .detailpane.actpane h2:first-child { margin-top:0; }
.actsplit .tablewrap { overflow-x:auto; }
@container (max-width: 640px) { .actsplit { grid-template-columns:minmax(0,1fr); } }
/* (the per-account column list that stood here is gone: the checkboxes above the one table replaced it) */
/* Who is signing in: the names on one row. */
.whorow { display:flex; flex-wrap:wrap; gap:6px 14px; margin:0 0 4px; }
.whopick { display:inline-flex; align-items:center; gap:4px; margin:0; font-size:14px; color:var(--ink); cursor:pointer; }
.whopick input { margin:0; width:auto; }
/* A button this person may not press: still there, still says what it does, dimmed, and
   the press explains instead of failing. */
button.denied, .btn.denied { opacity:.45; cursor:not-allowed; }
.permit .blockcard { max-width:360px; }
.permit .permitwho { font-weight:700; }
.permit .permitmsg { margin-top:6px; }
.permit #permitok { margin-top:10px; }
/* The users panel: one row a person, five switches the way a phone draws them. */
.userrow { display:flex; flex-wrap:wrap; align-items:center; gap:6px 14px; padding:8px 0; border-top:1px solid var(--line); }
.userrow:first-of-type { border-top:0; }
.userrow .uname { flex:0 0 80px; font-weight:600; }
.userrow .ulast { flex:1 1 100%; order:9; margin-top:-2px; }
.userrow form.uform { display:contents; }
.userrow .sw { display:inline-flex; width:auto; align-items:center; gap:6px; margin:0; font-size:12px; color:var(--ink); cursor:pointer; position:relative; }
.userrow .sw input { position:absolute; opacity:0; width:0; height:0; margin:0; }
.sw .knob { width:34px; height:20px; border-radius:999px; background:rgba(140,145,150,.35); position:relative; transition:background .15s; flex:0 0 auto; }
.sw .knob::after { content:""; position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:var(--card); box-shadow:0 1px 2px rgba(10,11,13,.3); transition:left .15s; }
.sw input:checked + .knob { background:var(--good); }
.sw input:checked + .knob::after { left:16px; }
.sw input:disabled + .knob { opacity:.5; }
.userrow .uremove { margin-left:auto; }
/* The current version, right under the text: one dense block, no card, no white space.
   Line one is what the version is; the note or the ask follows; the scores are two short
   bars on one line each; the score comment wraps under them. */
/* Under the text: three cells across - what the version is, its two scores, the score
   comment - with no white space between them. Auto tracks stretch by default, which is
   what put a hand's width between "Overall" and its bar; the grid is told not to. */
.curgrid { display:grid; grid-template-columns:max-content max-content minmax(0,1fr);
           gap:4px 14px; align-items:start; justify-content:start; margin-top:6px; font-size:12.5px; line-height:1.35; }
.curgrid .curwhat { max-width:min(100%, 420px); }
.curgrid .curnotebox { width:100%; min-width:0; margin:4px 0 0; padding:5px 8px; font-size:12.5px; }
@container (max-width: 760px) { .curgrid { grid-template-columns:minmax(0,1fr); } }
.curcell { min-width:0; }
.curgrid .curhead .vnum { margin-right:4px; }
.curgrid .curnote { color:var(--dim); overflow-wrap:anywhere; margin-top:2px; }
.curgrid .curnote b { color:var(--ink); font-weight:600; }
.curgrid .curnote .vbtn { padding:1px 7px; font-size:11px; }
.curscores { display:grid; grid-template-columns:max-content 120px max-content; gap:2px 6px; align-items:center; justify-content:start; }
.curscores .bar { width:120px; }
.curcomment { color:var(--dim); overflow-wrap:anywhere; }
/* The essay's subtitle: school, limit, similar prompts, Drive folder, status - one line,
   dot-separated, wrapping on a phone. The similar-prompts table opens under the line. */
.subrow { display:flex; flex-wrap:wrap; align-items:center; gap:2px 5px; margin:4px 0 8px; }
.subrow details.pop { display:contents; }
.subrow details.pop > summary { display:inline-flex; align-items:center; gap:3px; cursor:pointer; list-style:none; }
.subrow details.pop > summary::-webkit-details-marker { display:none; }
.subrow details.pop > .card { flex-basis:100%; margin-top:6px; }
.subrow form.statusform { display:inline; margin:0; }
.subrow form.statusform input[type=date] { margin:0 0 0 6px; padding:2px 6px; font-size:12px; min-width:0; width:auto; }
.datesrow { flex-wrap:wrap; gap:8px 0; }
.datesrow label { display:inline-flex; align-items:center; gap:8px; margin:0 16px 0 0; width:auto; }
.datesrow input[type=date] { min-width:0; width:auto; margin:0; }
.subrow form.statusform select { margin:0; padding:2px 22px 2px 6px; font-size:12px; min-width:0; width:auto;
                                 height:auto; min-height:0; line-height:1.3; -webkit-appearance:none; appearance:none;
                                 background:var(--card) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%236b7076' stroke-width='1.5'/></svg>") no-repeat right 7px center; }
.curscores.stale .bar i { background:var(--idle) !important; }
.curscores.stale, .curscores.stale span, .curscores.stale b { color:var(--idle); }
.curscores .stalenote { grid-column:1 / -1; color:var(--dim); }
.curcomment.stale { color:var(--idle); }
/* Scoring runs in the background: the button spins, nothing is blocked. */
@keyframes ctspin { to { transform:rotate(360deg); } }
button.busy { opacity:.55; cursor:progress; }
button[disabled]:not(.busy):not(.denied) { opacity:.45; cursor:default; }
button.busy .g { display:inline-block; animation:ctspin 1s linear infinite; }
@media (prefers-reduced-motion: reduce) { button.busy .g { animation:none; } }
.curbox { flex:1 1 320px; min-width:0; font-size:12.5px; line-height:1.35; display:grid;
          grid-template-columns:auto minmax(80px,180px) auto; gap:2px 8px; align-items:center;
          margin-top:4px; }
.curbox .wide { grid-column:1 / -1; }
.curbox .curhead { color:var(--ink); }
.curbox .curhead .vnum { margin-right:4px; }
.curbox .curnote { color:var(--dim); overflow-wrap:anywhere; }
.curbox .curnote b { color:var(--ink); font-weight:600; }
.curbox .bar { width:100%; }
.curbox .curcomment { color:var(--dim); overflow-wrap:anywhere; }
.curbox .vbtn { padding:1px 7px; font-size:11px; }
/* The versions as a list that is a list: one row a version, the columns the household
   asked for by name. Cards on a phone, the way the development grid does it. */
table.stats.vtable { width:100%; table-layout:auto; }
table.stats.vtable td { white-space:normal; vertical-align:top; padding:6px 6px; font-size:12.5px; }
table.stats.vtable th { font-size:10px; }
table.stats.vtable td.vt { width:22px; padding-right:0; }
table.stats.vtable td.vt input { margin:0; width:auto; }
table.stats.vtable td.vn { width:24px; }
table.stats.vtable td.vw { white-space:nowrap; }
table.stats.vtable td.vd { min-width:180px; }
table.stats.vtable td.vd .vmade { margin-top:1px; }
table.stats.vtable td.va { text-align:right; white-space:nowrap; }
table.stats.vtable .vacts { display:flex; flex-wrap:wrap; gap:4px; justify-content:flex-end; margin:0; }
table.stats.vtable .num { text-align:right; white-space:nowrap; }
@container (max-width: 999px) {
  .vtable thead { display:none; }
  .vtable, .vtable tbody, .vtable tr, .vtable td { display:block; width:auto; }
  .vtable tr { border:1px solid var(--line); border-radius:10px; padding:6px 8px; margin:0 0 8px;
               display:grid; grid-template-columns:auto 1fr 1fr; gap:2px 8px; align-items:start; }
  .vtable td { border:0; padding:2px 0; background:none; }
  .vtable td.vt { grid-row:1; }
  .vtable td.vn { grid-row:1; }
  .vtable td.vd, .vtable td.va { grid-column:1 / -1; }
  .vtable td.va .vacts { justify-content:flex-start; }
  .vtable td[data-label]::before {
    content:attr(data-label); display:block; color:var(--dim); font-size:9px;
    font-weight:600; letter-spacing:.06em; text-transform:uppercase; margin-bottom:1px;
  }
  .vtable td.vd[data-label]::before, .vtable td.vn::before, .vtable td.vt::before { display:none; }
  table.stats.vtable td.num, table.stats.vtable td.va { text-align:left; }
}
.vmodal .vmtools { display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin-top:6px; }
.vmodal .vbody .mk { background:rgba(212,140,26,.22); border-bottom:2px solid var(--attention); }
.vmodal .vbody.prompt { font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px; }
button.ghost:active, a.slice:active, button.linky:active, button.setfold:active,
button.vennbtn:active { background:rgba(51,120,217,.16); }
a.slice.on:active { background:var(--active); }
/* Glyphs that act as buttons press like buttons. The camera on a task, the fold triangle,
   the direction arrow and the flag badge are links or bare buttons drawn as a single
   character, and a character that does nothing when pressed reads as decoration - which
   is exactly the complaint. Same drop and tint as every other control. */
a.shotlink, a.flagbadge, button.dirbtn, button.setfold, button.blockask, a.pill {
  display:inline-block; cursor:pointer; }
a.shotlink:active, a.flagbadge:active, button.dirbtn:active, button.blockask:active,
a.pill:active { transform:translateY(1px); filter:brightness(.88); }
a.shotlink:hover { filter:brightness(1.15); }
button:focus-visible, .btn:focus-visible, a:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, summary:focus-visible {
  outline:2px solid var(--active); outline-offset:2px; }
.inline { display:flex; gap:8px; align-items:center; }
/* A menu is as wide as its longest option and no wider - always. The laptop rule below
   used to give every select the text field's 260px minimum, so on a phone the Order menu
   and the status menu ran edge to edge and read as headings rather than controls. A text
   field wants a usable minimum; a menu's width is already decided by what is in it. */
select { width:auto; min-width:0; max-width:100%; }
.inline select { flex:0 1 auto; }
.inline button { width:auto; padding:9px 14px; }
.bar { height:6px; border-radius:999px; background:rgba(140,145,150,.2); overflow:hidden; }
.bar > i { display:block; height:100%; border-radius:999px; }
.flash { background:rgba(33,148,89,.14); color:var(--good); padding:8px 10px;
         border-radius:9px; font-size:13px; margin-bottom:10px; }
.warn { background:rgba(212,140,26,.14); color:var(--attention); padding:8px 10px;
        border-radius:9px; font-size:13px; margin-bottom:10px; }
.mismatch { background:rgba(214,51,124,.14); color:var(--pink); padding:8px 10px;
            border-radius:9px; font-size:13px; margin-bottom:10px;
            border-left:3px solid var(--pink); font-weight:600; }
/* The editor is a transparent textarea over a mirrored backdrop: the backdrop carries the
   pink marks, the textarea carries the caret. Both must share font, padding and wrapping
   or the highlight drifts off the words. */
.edit { position:relative; }
.edit .hl, .edit textarea { font:inherit; line-height:1.5; padding:9px 10px;
        border:1px solid transparent; border-radius:9px; width:100%; min-height:46vh;
        white-space:pre-wrap; overflow-wrap:break-word; margin:0; }
.edit .hl { position:absolute; inset:0; overflow:hidden; color:transparent;
            background:var(--card); border-color:var(--line); pointer-events:none; }
.edit textarea { position:relative; background:transparent; border-color:var(--line); }
mark.mm { background:rgba(214,51,124,.32); color:inherit; border-radius:3px; padding:0; }
.edit .hl mark.mm { color:transparent; }
/* Samples are practice text, not work - a colour of their own so a row cannot be mistaken
   for a real draft, and first in every list so they are never scrolled past. */
.sample, b.sample, h1.sample { color:var(--done); }
button.linky { background:none; border:none; color:var(--active); font-size:12px;
               padding:0 0 0 8px; width:auto; text-decoration:underline; cursor:pointer; }
/* The plate a logo sits on. It is white because logos are drawn for white, not because
   the theme says so - but it still belongs in one named place, not in 230 style
   attributes where nothing can find it. */
:root { --plate:#fff; }
.logo { background:var(--plate); border-radius:5px; object-fit:contain; padding:1px;
        vertical-align:middle; margin-right:8px; }
.logo-22 { width:22px; height:22px; }
.logoplate { background:var(--plate); object-fit:contain; padding:2px; }
.assumed { color:var(--done); }
.charlimit { color:var(--active); }
.dirtydot { color:var(--attention); font-size:16px; line-height:0; vertical-align:middle; }
.setrow { color:var(--active); font-size:12px; font-weight:600; padding:6px 2px 2px; }
/* The selection reads as a note beside the rule, not as part of it: grey, regular weight. */
.setrow .setpicked { color:var(--dim); font-weight:500; }
.setrow .setpicked.none { opacity:.7; }
/* Room between the selection and "clear", so the link is not read as part of the list. */
.setrow .clearpick { margin-left:14px; }
/* Indented one character so the choice line starts inside the rows it governs rather
   than flush with the table edge. Written as `table.stats td.setrow` because
   `table.stats td` sets the padding later in this sheet and outranked the plain
   `td.setrow` - the first attempt at this shift computed to 0px and changed nothing. */
table.stats td.setrow { padding:8px 6px 4px 1ch; }
/* A table wider than the screen scrolls sideways, and on a phone there was nothing to say
   so: the right-hand columns were simply cut off at the card edge, indistinguishable from
   a table that ends there. The Colleges tracker loses SAT, Reads and Essays that way, and
   the Essays list loses everything from Words to Status.

   Two gradients per edge, pinned with background-attachment. The white one travels with
   the content (local) and the shadow stays with the box (scroll), so the shadow is only
   visible while there is something beyond that edge - it appears and disappears by itself
   as you scroll, with no script and nothing to keep in step. */
.scroll {
  overflow-x:auto;
  background:
    linear-gradient(to right, var(--card) 40%, rgba(255,255,255,0)) left center,
    linear-gradient(to left,  var(--card) 40%, rgba(255,255,255,0)) right center,
    radial-gradient(farthest-side at 0 50%,   rgba(10,11,13,.16), rgba(10,11,13,0)) left center,
    radial-gradient(farthest-side at 100% 50%, rgba(10,11,13,.16), rgba(10,11,13,0)) right center;
  background-repeat:no-repeat;
  background-size:26px 100%, 26px 100%, 13px 100%, 13px 100%;
  background-attachment:local, local, scroll, scroll;
}
.roundhead { display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
             margin:18px 0 8px; padding:10px 12px; border-radius:10px;
             background:var(--card); border:1px solid var(--line);
             border-left:4px solid var(--active); }
/* display:flex outranks the `hidden` attribute, the same way it did on the blocker overlay.
   list.js hides a round whose colleges the filter took, and without this the heading stayed
   while its card went - a heading standing over nothing, which is the one thing that code
   exists to prevent. */
.roundhead[hidden] { display:none; }
.roundname { font-size:19px; font-weight:700; letter-spacing:-.01em; }
/* The count sits at the end of the heading row, after the sentence that says what the
   round is. `margin-left:auto` inside the flex heading rather than a float. */
.roundcount { margin-left:auto; font-size:12px; color:var(--dim); }
/* The list controls: one row, left-aligned, wrapping on a phone rather than overflowing. */
.lrow.controls { display:flex; flex-wrap:wrap; align-items:center; gap:8px 10px; }
.lrow.controls input[type=search] { min-width:0; width:260px; max-width:100%; }
.lrow.controls label { margin:0; font-size:12px; color:var(--dim); }
.dirbtn { width:auto; padding:4px 10px; font-size:13px; line-height:1; }
/* A checkbox with its words beside it. Not `.pick`, which is a fixed 32x30 cell for an
   essay's option radio and breaks any label put inside it across two lines. */
.checkline { display:inline-flex; align-items:center; gap:6px; white-space:nowrap; }
.checkline input { width:auto; }
/* Group headers over a table sit one step below a round header. Named here rather than
   written into the markup: an inline size is invisible to every sibling that should match
   it, which is how the Essays page ended up with a heading nothing else shared. */
.roundname.grouphead { font-size:15px; }
.rfilter { display:inline; margin-right:10px; font-size:12px; }
.promptbody { font-size:13px; }
/* The prompt above the editor is the question being answered, and at the 12px every other
   note on the page uses it was the smallest thing on the screen. Half again: 18px. */
.sub.prompttext { font-size:18px; line-height:1.45; }
.chosen { color:var(--active); font-weight:600; }
.stale { color:var(--attention); }
/* Admin reads left to right: the number first, its name beside it, nothing pushed to the
   far edge of a wide card where the two halves of one fact end up a screen apart. */
/* A screen with no second pane still stops spreading. More and the Admin settings are
   short pages of short rows, and across 1450px their two sides end up a hand apart with
   nothing between them. They are capped at the width their own content reads at, and the
   surplus is left as margin rather than poured into the gaps inside a row. The
   Development grid is deliberately not capped: eight columns use every pixel they get. */
@media (min-width: 1000px) {
  body.more main > *, body.adminsettings main > * { max-width:760px; }
}
/* Split view. A laptop has room to keep the list and the essay on screen together, and
   losing the list every time you open a draft is what made the app feel like a phone in a
   window. Below this width there is no room for two of anything, so the pane is not drawn
   and a row is an ordinary link again. */
body.bare main { padding:10px; max-width:none; padding-bottom:10px; }
.split { display:block; }
/* A lazy split keeps its whole width for the list until something is opened beside it.
   The development grid has eight columns and nothing to show on the right until a
   screenshot is clicked; halving it permanently for an empty pane would be the white space
   the split exists to remove. pane.js marks the split open on the first click. */
@media (min-width: 1000px) {
  main { max-width:none; padding:14px 18px;
         padding-bottom:calc(78px + env(safe-area-inset-bottom)); }
  /* Not two equal halves. The list has a width at which it is finished: its widest table
     measures 749px, and with the card's 12px gutters and hairline that is 780px. Past
     that the list is only growing white space, so the cap hands every further pixel to
     the essay beside it - at 1920 the pane is 1090px rather than 920. Below the cap the
     list still needs the room, so it keeps its share and nothing changes at 1000 or 1400.
     A grid rather than two flex bases, because a cap is what is being said. */
  /* The list grows to the width its rows need and stops there; every further pixel is the
     draft's. Written as two tracks rather than a percentage because a percentage is a
     50/50 split wearing a cap: min(52%, 780px) only stopped behaving as half the window
     above about 1512px, so on a 1440 laptop the list was still 749px - five short of what
     its own table needs - while the pane beside it took 677. The first track stops at the
     list's natural width, the second has a floor it cannot be squeezed below, and the
     surplus goes to the second because only it can use it. */
  /* The cap is a measurement, and every screen has a different one, so the screen states
     it: --list-cap, defaulting to the Essays list's 780. Colleges measures 740 - its
     control bar, which is the widest thing in it; its tracker tables are 500. Stretched to
     a 1447px card those tables were three times their natural width, which is what "white
     space is unacceptable on resizing" means: the columns do not get more readable, they
     just get further apart. */
  .split { display:grid;
           grid-template-columns:minmax(0, var(--list-cap, 780px)) minmax(420px, 1fr);
           align-items:start; gap:14px; }
  .split.lazy:not(.open) { grid-template-columns:1fr 0; gap:0; }
  .split.lazy:not(.open) > .detailpane { display:none; }
  /* Open, the list keeps the larger share. The default cap gave the Development grid 780px
     beside a screenshot - exactly its seven fixed columns - and the Task column collapsed to
     a sliver one letter wide, with the notes spilling across the row. Photographed by the
     applicant, in Safari, from the pane the picture had just opened in. */
  .split.lazy.open { grid-template-columns:minmax(0, 1fr) minmax(380px, 40%); }
  .split > .listpane { min-width:0; }
  .split > .detailpane { min-width:0; position:sticky; top:12px;
                         height:calc(100vh - 150px); border:1px solid var(--line);
                         border-radius:12px; background:var(--card); overflow:hidden; }
  .split > .detailpane iframe { width:100%; height:100%; border:0; display:block; }
  .detailpane .empty { padding:18px; color:var(--dim); font-size:13px; }
}
.arow { display:flex; align-items:baseline; gap:8px; justify-content:flex-start;
        padding:5px 0; border-top:1px solid var(--line); }
.arow:first-of-type { border-top:0; }
.arow b { order:-1; font-size:14px; }
.alabel { color:var(--dim); font-size:12px; }
/* Sorts, chips and buttons line up on the same left edge as everything else. */
.card.legend .lrow, .marktools .lrow { justify-content:flex-start; }
.card form > button, .card form > .slice { margin-right: 8px; }
/* Full-width controls are a phone's answer, and this page is read on a laptop too. From
   the width where a thumb stops being the pointer, a button is as wide as its words and
   sits on the left with everything else. */
@media (min-width: 700px) {
  button, .btn { width:auto; padding:9px 16px; text-align:left; }
  /* A text field wants a usable minimum on a laptop. A tick box does not: this rule read
     `input` for a year, so every checkbox and radio on a wide screen was a 260px box laid
     across whatever sat beside it - invisible on a phone, which is where those pages are
     usually read, and the real cause of the "missing" radios on the Essays page. */
  input:not([type=checkbox]):not([type=radio]) { width:auto; min-width:260px; }
  input[type=checkbox], input[type=radio] { width:auto; min-width:0; }
  /* A date field is a control whose width its content decides, like a menu. */
  input[type=date] { min-width:0; }
  textarea { width:100%; }
  .card form { display:flex; flex-wrap:wrap; align-items:center; gap:8px 10px; }
  .card form > label { width:100%; margin:4px 0 0; }
  .card form > p, .card form > .lrow, .card form > .grow { width:100%; }
}
/* The development grid. A read-only cell is drawn as a record rather than as a field:
   nothing in it looks typeable, because the four Claude columns are what happened, and a
   cell that looks like a box and refuses typing is worse than one that never looked.

   After the wide-screen block on purpose. That block gives every text field a 260px
   minimum, which is right for a form and wrong for a grid - it made the priority box and
   the status menu each four times the width of what they hold. The selectors there and
   here weigh the same, so the only thing that decides between them is which comes last. */
/* A heading with a control on its right: the word first, the button at the end of the
   line, both on one baseline. */
h2.hrow { display:flex; align-items:center; justify-content:flex-start; gap:12px; }
h1.hrow { display:flex; align-items:center; justify-content:flex-start; gap:12px; }
h2.hrow .btn.small, h2.hrow button.small { width:auto; margin:0; padding:5px 12px;
                                           font-size:12px; text-transform:none;
                                           letter-spacing:0; background:var(--active);
                                           color:#fff; border:1px solid var(--active); }
/* A row of buttons that stays a row on a phone. The base rule makes every button the width
   of the screen below 700px - right for one button under a form, wrong for four in a row:
   the writing actions stacked into a block, and each mark's four became four rows. */
.btnrow { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
.btnrow > button, .btnrow > .btn { width:auto; flex:1 1 auto; margin:0; padding:9px 12px;
                                   text-align:center; white-space:nowrap; }
.btnrow .g { margin-right:4px; }
@media (min-width: 700px) { .btnrow > button, .btnrow > .btn { flex:0 0 auto; } }
.tabrow { margin:0 0 10px; }
/* The three models as a row of ranked cards: a crown on the first, each in its own tint,
   the trade in a word. A free-text box asked for a name nobody could remember. */
.models { display:flex; flex-wrap:wrap; gap:8px; margin:4px 0 8px; }
.modelpick { display:inline-flex; align-items:center; gap:6px; margin:0; padding:6px 12px;
             border:1.5px solid var(--line); border-radius:999px; cursor:pointer;
             font-size:13px; }
/* The chosen one is said by its ring and the ticked radio, not by a fill - the fill read as
   a second colour on a card that already has one. */
.modelpick.on { box-shadow:inset 0 0 0 1px currentColor; }
.modelpick input { width:auto; margin:0; }
/* The words that summon the list, beside its name. Monospaced because they are typed
   literally, and dimmed because they are a hint rather than a heading of their own. */
.kwhint { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11px;
          font-weight:600; letter-spacing:.04em; color:var(--dim); margin-left:8px;
          text-transform:none; white-space:nowrap; }
.devgrid { table-layout:fixed; width:100%; }
.devgrid td { vertical-align:top; }
.devgrid th.ro, .devgrid td.ro { background:rgba(140,145,150,.06); }
/* The stamps wrap inside their own column rather than widening it. A date, a time and the
   letters ET is more than fits on one line at 116px, and the alternative was four columns
   each wide enough for a sentence. */
/* Every cell wraps. The tracker's own rule keeps a cell on one line, which is right for a
   deadline and wrong for a sentence: Claude's note under a task inherited it and ran off
   the right edge of the page, past the status menu, into a horizontal scrollbar - the
   exact complaint "comments not wrapping". Written with the table's own two classes so it
   outranks `table.stats td`, which is declared later in this sheet and says nowrap: a
   plain `.devgrid td` lost to it and the stamps in every finished row overlapped. */
table.stats.devgrid td, table.stats.devgrid th { white-space:normal; word-break:normal;
                                                 overflow-wrap:anywhere; }
.devgrid .devnote, .devgrid .worker { white-space:normal; max-width:100%; }
.devgrid .devtaskcell { min-width:0; }
/* No fixed height and no inner scrollbar: a task that wraps to four lines is four lines
   tall, and the row grows with it. A box you have to scroll to read is a box that hides
   what somebody asked for - and these are requests, not notes. The height is set by the
   script from the content; this is only the floor and the look. */
.devgrid textarea.devtask { width:100%; min-width:0; min-height:0; font-size:13px;
                            line-height:1.4; resize:none; overflow:hidden; margin:0;
                            padding:6px 8px; display:block; }
/* Claude's note on a task, in its own face and colour so it cannot be read as the task. */
.devgrid .devnote, .devgrid tr[data-user-status] td .devnote { margin-top:4px; font-style:normal; color:var(--done);
                    font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:11px; line-height:1.4; }
/* Which thread has this row. Three run at once, and "Working" on three rows with nothing
   to tell them apart cannot answer the only question anybody asks of the column. */
.devgrid .worker { margin-top:3px; font-size:10px; font-weight:600; letter-spacing:.03em; }
/* The three answers to a block. Outlined rather than filled: they are a question being put
   to somebody, not the thing the screen wants them to do next. */
.devgrid .blockasks { margin-top:6px; display:flex; flex-wrap:wrap; gap:6px; }
.devgrid button.blockask { width:auto; margin:0; padding:4px 9px; font-size:11px;
                           font-weight:600; border-radius:999px; background:none;
                           border:1px solid var(--attention); color:var(--attention); }
.devgrid button.blockask.on { background:var(--attention); color:#fff; }
.devgrid select { width:auto; min-width:0; font-size:12px; padding:5px 8px; }
.devgrid input.devpri { width:64px; min-width:0; margin:0; text-align:right;
                        padding:6px 8px; }
.devgrid .linky { padding:0 6px 0 0; }
/* Where a row stands, said by the whole row rather than by the menu at the end of it. On a
   list this wide the menu is the furthest thing from the task it describes, and a colour
   three feet to the right of the words it applies to is a colour nobody reads. Every cell,
   including the ones that set a colour of their own. */
.devgrid tr[data-user-status="review"],
.devgrid tr[data-user-status="review"] td,
.devgrid tr[data-user-status="review"] .sub,
.devgrid tr[data-user-status="review"] input,
.devgrid tr[data-user-status="review"] select,
.devgrid tr[data-user-status="review"] textarea { color:var(--good); }
.devgrid tr[data-user-status="complete"],
.devgrid tr[data-user-status="complete"] td,
.devgrid tr[data-user-status="complete"] .sub,
.devgrid tr[data-user-status="complete"] input,
.devgrid tr[data-user-status="complete"] select,
.devgrid tr[data-user-status="complete"] textarea { color:var(--done); }
/* The head of the queue. Three rows, because a queue with a head of one is a queue with no
   head: the next thing and the thing after it are what somebody plans around. The number
   carries the colour rather than the whole row - a red row reads as a row in trouble - and
   it is written after the status colours so it survives them: where a row sits in the
   queue is a different fact from where it stands. */
.devgrid tr[data-top="1"] input.devpri { color:var(--bad); font-weight:700;
                                         border-color:var(--bad); }
/* Typed and kept. A tick that fades, so somebody can see the row took what they typed
   without a banner appearing and disappearing on every keystroke. */
.devgrid td.saved::after { content:" ✓"; color:var(--good); font-weight:700; }
.devgrid td.saving::after { content:" …"; color:var(--dim); }
/* On a phone the grid stops being a grid. Eight columns in 390px put the status menu -
   the one control somebody actually reaches for on a phone, because marking a row Review
   or Complete is the whole of their half - behind a sideways scroll, with the task box
   clipped mid-word at the card edge. So each row becomes a card and each cell says what
   it is. The labels come from the same DevSpec.columns titles the header row uses; they
   are written onto the cells as data-label rather than repeated here. */
/* 999 and not 899: DevSpec.fixedWidth is 780 and `main` is capped at 900 below 1000px, so
   between 900 and 999 the grid drew eight columns with 70px left for the task - measured at
   956, which is an iPhone Plus or Max turned sideways, and the request text came out one
   word per line. The cards have to run right up to the width at which `main` loses its cap. */
/* The grid measures the box it is IN, not the window. It sat at 1456px in a window and
   still had 780px beside an open screenshot pane, so a rule keyed to the viewport never
   fired; the cards below are keyed to the list pane's own width with a container query.
   Container queries are in every Safari and Chrome the household runs (Safari 16, 2022). */
main, .split > .listpane { container-type:inline-size; }
@container (max-width: 999px) {
  .devgrid { table-layout:auto; }
  .devgrid colgroup { display:none; }
  .devgrid, .devgrid tbody, .devgrid tr, .devgrid td { display:block; width:auto; }
  /* And again here. Without it the Development filter and Hide completed did nothing on a
     phone: devlog.js sets row.hidden and the row went on being a 322px card, with the count
     above it disagreeing with the rows beneath. */
  .devgrid tr[hidden], .devgrid td[hidden] { display:none; }
  .devgrid tr:first-child { display:none; }
  .devgrid tr { border:1px solid var(--line); border-radius:10px;
                padding:8px 10px; margin:0 0 10px; }
  .devgrid td { border:0; padding:3px 0; background:none; }
  .devgrid td[data-label]::before {
    content:attr(data-label); display:block; color:var(--dim); font-size:9px;
    font-weight:600; letter-spacing:.06em; text-transform:uppercase; margin-bottom:2px;
  }
  /* The three that are a dash almost all of the time do not each need a line of their
     own on a screen this narrow. They sit on one, labelled, and wrap. */
  /* The five stamps were inline boxes of different heights - the Claude cell carries a
     worker line, the others do not - so they fell into a ragged 2-2-1 and nothing lined
     up. The card is a two-column grid: the stamps take a column each, everything else
     spans both. */
  .devgrid tr { display:grid; grid-template-columns:1fr 1fr; column-gap:12px; }
  .devgrid td { grid-column:1 / -1; }
  .devgrid td.stamp { grid-column:auto; display:block; margin:0; min-width:0; }
  .devgrid .devtaskcell { min-width:0; width:auto; }
  .devgrid select, .devgrid input.devpri { font-size:14px; }
}
/* Says the binary changed under this page. Across the top, above everything, because it is
   about the page rather than about anything on it - and it is the whole bar that reloads,
   so there is nothing to aim at. */
/* The model on a Claude button, and the ask box that Re-work and Correct open. The box is
   a card under the buttons rather than a modal: the draft stays in view while the
   instruction is typed, which is the whole reason for asking. */
button .model { font-weight:400; opacity:.75; font-size:.86em; margin-left:6px; }
.askbox { margin:10px 0 0; padding:10px 12px; border:1px solid var(--active);
          border-radius:10px; background:var(--card); }
.askbox label { margin:0 0 6px; font-weight:600; }
/* Written as input[type=text] to weigh the same as the laptop rule's `input:not(...)`,
   which otherwise wins and pins the box at 260px - not wide enough for its own hint. */
.askbox input[type=text] { width:100%; min-width:0; }
.askbox .row { display:flex; gap:8px; margin-top:8px; flex-wrap:wrap; }
.askbox .row button { width:auto; margin:0; }
.rebuilt { position:sticky; top:0; z-index:60; }
.rebuilt button { display:block; width:100%; border:0; border-radius:0; margin:0;
                  padding:9px 12px; text-align:center; cursor:pointer;
                  background:var(--active); color:#fff; font-size:13px; font-weight:700;
                  letter-spacing:.02em; }
.rebuilt button:hover { filter:brightness(1.08); }
.review .reviewbody { font-size:15px; line-height:1.7; white-space:pre-wrap; word-break:break-word; }
.mk { text-decoration:none; color:inherit; border-radius:3px; padding:0 1px; }
.mk.note { background:rgba(51,120,217,.18); box-shadow:inset 0 -2px 0 var(--active); }
.mk.highlight { background:rgba(212,140,26,.22); }
.mk.suggestion { background:rgba(102,89,184,.18); box-shadow:inset 0 -2px 0 var(--done); }
.mk.settled { opacity:.5; }
/* A deletion is a suggestion with nothing to put in its place, and it reads as one: the
   words stay where they are and are struck through, so what is being removed is still
   legible next to the reason for removing it. */
.mk.del { text-decoration:line-through; text-decoration-thickness:2px; }
/* The marking tools are two buttons at the selection now, not a form under the editor.
   Fixed rather than absolute because the popover lives outside the editor's own <form> -
   a form cannot be nested inside another - and is placed from the selection's rectangle. */
.marktools { position:fixed; z-index:55; max-width:320px;
             background:var(--card); border:1px solid var(--line); border-radius:10px;
             padding:6px; box-shadow:0 6px 18px rgba(10,11,13,.22); }
.marktools .markbtns { display:flex; gap:6px; }
/* display:flex outranks the `hidden` attribute, which is how the blocker overlay once kept
   covering the page after it was hidden. Said again here, where the note box swaps places
   with the two buttons. */
.marktools [hidden] { display:none; }
.marktools button { width:auto; padding:6px 14px; }
.marktools .marknote { margin-top:4px; }
.marktools .marknote input { width:100%; margin:6px 0; min-width:0; }
.marktools .mquote { max-width:300px; overflow:hidden; text-overflow:ellipsis;
                     white-space:nowrap; }
.marktools input[type=text], .marktools input:not([type]) { width:100%; margin-top:6px; }
.markkind.del { color:var(--bad); }
/* The flag a reader raises on a mark, shown on the row in the essay list so the essay that
   needs somebody's attention can be found without opening it. */
svg.flag { color:var(--bad); vertical-align:-2px; margin-right:4px; }
/* An optional set folds. Collapsed it shows only the options somebody has written in, so a
   three-option set nobody has touched is one line instead of four. */
button.setfold { background:none; border:none; width:auto; padding:0; margin:0;
                 color:inherit; font:inherit; font-weight:600; text-align:left;
                 cursor:pointer; }
.foldglyph { display:inline-block; color:var(--dim); margin-right:5px;
             transition:transform .12s; font-size:18px; }
button.setfold[aria-expanded="true"] .foldglyph { transform:rotate(90deg); }
.setpicked { color:var(--active); }
/* A set nobody has chosen from says so, in the quiet colour - a bright "Selected:" with
   nothing after it reads as a value that failed to load. */
.setpicked.none { color:var(--dim); font-weight:400; }
/* The place an option holds in its set, on the row. The headline above says "Selected: 1,3"
   and the rows beneath it said nothing, so the only way to tell which row was the third
   option was to count down the table - and a practice copy sitting in the set made that
   count wrong. Tabular figures so a column of them lines up under each other. */
.optnum { color:var(--dim); font-size:11px; font-weight:600; margin-right:6px;
          font-variant-numeric:tabular-nums; }
/* A mark is a paragraph with buttons, not a single line: the quote, the note field and
   three buttons cannot share one row on a phone, and .row squeezed them into a column of
   one word per line. */
.markrow { display:block; }
.markrow .grow { display:block; width:100%; }
.markrow input { width:100%; margin-top:6px; }
.markrow button { margin:8px 8px 0 0; }
.markquote { margin:4px 0; padding-left:9px; border-left:2px solid var(--line);
             color:var(--dim); font-size:13px; }
.markkind { font-weight:600; }
.markkind.note { color:var(--active); }
.markkind.highlight { color:var(--attention); }
.markkind.suggestion { color:var(--done); }
.markdone { color:var(--good); font-weight:600; }
.diff { font-size:14px; line-height:1.55; }
.diff .dline { padding:1px 0; white-space:pre-wrap; word-break:break-word; }
.diff .hunk { color:var(--dim); font-size:11px; margin:10px 0 4px; }
.diff ins { background:rgba(33,148,89,.18); color:var(--good); text-decoration:none; }
.diff del { background:rgba(199,64,61,.16); color:var(--bad); }
.diff .plus { background:rgba(33,148,89,.10); }
.diff .minus { background:rgba(199,64,61,.10); }
.warnink { color:var(--bad); }
.goodink { color:var(--good); }
tr.loginrow td { background:rgba(33,148,89,.10); }
.figglyph { font-size:26px; line-height:1; }
.figglyph.gear { font-size:30px; }
.cellglyph { font-size:26px; line-height:0; }
.roundmeta { font-size:12px; color:var(--dim); }
a.back { font-size:13px; color:var(--dim); text-decoration:none; }
a.slice { display:inline-block; padding:2px 10px; margin-right:6px; border-radius:999px;
          border:1px solid var(--line); text-decoration:none; color:var(--dim); font-size:12px; }
a.slice.on { background:var(--active); border-color:var(--active); color:#fff; }
/* display:inline-block outranks the `hidden` attribute, the same way display:flex did on
   the blocker overlay - a chip that is hidden has to say so louder than its own layout. */
a.slice[hidden] { display:none; }
details.pop > summary { cursor:pointer; list-style:none; font-size:20px; color:var(--active);
                       padding:4px 0; }
details.pop > summary::-webkit-details-marker { display:none; }
details.pop > summary .sub { font-size:12px; margin-left:6px; }
svg.venn { vertical-align:middle; color:var(--active); }
svg.target { color:var(--commonapp); vertical-align:-2px; margin-right:5px; }
svg.target.bare { margin-right:0; vertical-align:middle; }
tr:target, .block.row:target { background:rgba(51,120,217,.12); }
details.grp > summary { cursor:pointer; list-style:none; }
/* The practice page: a problem is a row with its tick on the left; its answer folds under
   the statement the way a popover does, but inline, so a phone reads it in place. */
body.practice main > * { max-width:760px; }
body.practice details.grp { margin-top:14px; }
body.practice details.grp > summary .sub { margin-left:6px; }
.prob { align-items:flex-start; padding:10px 0; border-top:1px solid var(--line); }
.prob:first-child { border-top:0; }
.prob form.donef { margin:0; flex:0 0 auto; padding-top:2px; }
.prob form.donef input[type=checkbox] { width:auto; min-width:0; margin:0; }
.prob .ptext { line-height:1.5; }
.prob .pn { color:var(--dim); margin-right:4px; }
.prob.done .ptext { color:var(--dim); }
.prob details.ans { margin-top:4px; }
.prob details.ans > summary { cursor:pointer; list-style:none; display:inline-block; padding:2px 10px;
  border-radius:999px; border:1px solid var(--line); color:var(--dim); font-size:12px; }
.prob details.ans > summary::-webkit-details-marker { display:none; }
.prob details.ans[open] > summary { background:var(--active); border-color:var(--active); color:#fff; }
.prob .abody { margin-top:6px; line-height:1.5; }
.prob .abody .sub { margin-top:4px; }
.prob .ink { margin-top:8px; }
.prob canvas.hw { display:block; width:100%; height:300px; border:1px solid var(--line); border-radius:8px;
  background:#fff; touch-action:none; cursor:crosshair;
  /* iPad Safari: a held finger or pencil otherwise raises the Copy / Look Up callout and
     the selection magnifier over the box. */
  -webkit-touch-callout:none; -webkit-user-select:none; user-select:none; }
.prob .ink { -webkit-touch-callout:none; -webkit-user-select:none; user-select:none; }
.prob .inkbar { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:6px; }
.prob .inkbar > button { width:auto; flex:0 0 auto; margin:0; padding:5px 12px; font-size:12px; }
.prob .inkbar > button.erase[aria-pressed="true"] { background:var(--bad); }
.prob canvas.hw.erasing { cursor:cell; }
.prob .inkbar .inkmsg { margin-left:4px; }
.prob .verdict { margin-top:6px; line-height:1.5; }
.prob .verdict .vtext { margin-left:4px; }
details.grp > summary::-webkit-details-marker { display:none; }
details.grp > summary::before { content:"▸"; color:var(--dim); margin-right:8px;
                                display:inline-block; transition:transform .12s; }
details.grp[open] > summary::before { transform:rotate(90deg); }
.legend { font-size:11px; color:var(--dim); padding:10px 12px; }
/* The legend has to show the mark at a size you can recognise it by. At the legend's own
   11px the gear and the atom were specks next to 26px marks in the column. */
.legend .mark { font-size:17px; line-height:0; vertical-align:-3px; }
.pickcell { display:inline-block; width:34px; vertical-align:middle; text-align:center; }
.ring { vertical-align:-1px; margin-right:5px; }
/* The search takes a couple of seconds and hits nothing until it lands, so the screen is
   held rather than left looking unresponsive. */
/* display:flex in the base rule beat the `hidden` attribute, so the overlay kept
   covering the page after it was "hidden" and swallowed every click. The visible state
   is a class; hidden is the default. */
.blocker { position:fixed; inset:0; z-index:60; display:none; align-items:center;
           justify-content:center; background:rgba(10,11,13,.72); }
.blocker.on { display:flex; }
.blockcard { background:var(--card); border:1px solid var(--line); border-radius:14px;
             padding:22px 26px; text-align:center; min-width:210px; }
.blockcard > div { margin-top:8px; font-size:13px; }
/* The attribution question: the busy overlay's card, read left to right, its choices one
   to a line and scrolling inside the card when a school has many essays. */
.asker { z-index:70; padding:16px; }
.askcard { text-align:left; width:100%; max-width:440px; max-height:86vh; overflow:auto; }
.askcard .asktitle { font-weight:600; font-size:15px; }
.askchoices { display:flex; flex-direction:column; gap:10px; margin:14px 0 4px; }
.askchoices .whopick { align-items:flex-start; }
.askchoices .whopick input { margin-top:2px; }
.askbtns { gap:8px; flex-wrap:wrap; margin-top:14px; }
/* Score All: one line under the essay's own score that opens into the whole reading. */
.schoolrev { margin:8px 0 2px; font-size:13px; }
.schoolrev > summary { cursor:pointer; color:var(--ink); }
.schoolrevbody { padding:6px 0 0 14px; }
.schoolrevbody h4 { margin:12px 0 4px; font-size:13px; }
.schoolrevbody ul.findings { margin:0; padding-left:18px; display:flex; flex-direction:column; gap:8px; }
.schoolrevbody .quote { color:var(--dim); font-style:italic; margin-top:2px; }
.schoolrevbody tr.mine td { background:rgba(120,130,150,.10); }
/* The notes wrap: the stats table's cells keep to one line elsewhere, and here a sentence
   per piece pushed the page sideways. */
.schoolrevbody table.stats { width:100%; }
.schoolrevbody table.stats td { white-space:normal; vertical-align:top; }
.spinner { width:26px; height:26px; margin:0 auto; border-radius:50%;
           border:3px solid var(--line); border-top-color:var(--active);
           animation:spin .8s linear infinite; }
@keyframes spin { to { transform:rotate(360deg); } }
.blink { color:var(--active); font-size:12px; animation:blink 1s steps(2, start) infinite; }
@keyframes blink { to { visibility:hidden; } }
.simtime { color:var(--good); }
sup.sup { font-size:8px; margin-left:2px; color:var(--dim); vertical-align:super; }
/* The label is a plain inline-block, NOT an inline-flex box. WebKit does not paint a sized
   form control inside an inline-flex label inside a table cell: Safari drew nothing at all
   on every row of every option set - no radio, no tick, just the indent where the control
   should be - while Chrome drew them, so the Common App prompt could not be chosen in
   Safari on either the phone or the laptop. The same markup renders in both browsers
   outside a table, which is why it survived review. Centring is line-height and
   vertical-align instead, and the 32x30 tap target - the size a thumb needs, and the
   reason the label exists at all - is unchanged. */
.pick { display:inline-block; width:32px; height:30px; line-height:30px; text-align:center;
        margin:-7px 0; cursor:pointer; }
/* min-width:0 for the same reason as .vtick input below: from 700px up this sheet gives
   every `input` a 260px minimum, and a width of 19px does not undo a minimum. On a laptop
   every pick control in every option set was a 260px box laid across the essay titles
   beside it - invisible on a phone, which is where this page is usually read. */
.pick input { width:19px; height:19px; min-width:0; margin:0; vertical-align:middle;
              accent-color:var(--active); cursor:pointer; }
/* Its own column, first after the essay name: the marks line up vertically so the rows
   that share a question can be found by scanning down rather than reading across. */
.vcol { width:34px; text-align:center; }
button.vennbtn { background:none; border:none; width:auto; padding:0;
                 color:var(--active); cursor:pointer; vertical-align:middle; }
tr.simrow > td { background:rgba(120,130,150,.08); padding:6px 10px 10px; }
.legend .d { display:inline-block; width:8px; height:8px; border-radius:50%;
             margin:0 4px 0 10px; vertical-align:middle; }
.legend .lrow { display:flex; align-items:baseline; gap:8px; margin-top:4px; }
.legend .lrow:first-child { margin-top:0; }
.legend .lfield { flex:0 0 46px; font-weight:600; color:var(--ink); }
.legend .litems { flex:1; }
.legend .litems .d:first-child { margin-left:0; }
.legend .ca, .legend .es, .legend .su, .legend .rl { background:var(--dim); }
.legend .st { background:var(--active); }
table.stats { width:100%; border-collapse:collapse; font-size:13px; }
table.stats th { text-align:left; font-size:10px; text-transform:uppercase; letter-spacing:.04em;
                 color:var(--dim); font-weight:600; padding:0 10px 6px 0; white-space:nowrap; }
table.stats td { padding:7px 10px 7px 0; border-top:1px solid var(--line); vertical-align:top;
                 white-space:nowrap; }
/* The SAT and Statistics tables sit above each other, so their columns are pinned to the
   same widths - a label column, then equal data columns. */
table.figures { table-layout:fixed; width:100%; }
table.figures td:nth-child(1), table.figures th:nth-child(1) { width:96px; }
table.figures td:nth-child(2), table.figures th:nth-child(2) { width:110px; }
table.figures td:nth-child(3), table.figures th:nth-child(3) { width:110px; }
table.figures td:nth-child(4), table.figures th:nth-child(4) { width:auto; }
/* Fixed columns, so a long value wraps inside its column instead of running into the
   next one - "All sittings required" crossed into Self-report on a phone. The Source
   column keeps its single line and the card scrolls to it: letting it wrap squeezed a
   link into one letter per line. */
table.figures { min-width:430px; }
table.figures td:nth-child(2), table.figures td:nth-child(3) { white-space:normal; vertical-align:top; }
/* On a phone the pinned columns left a 96px empty first column, two 110px columns and a
   Source squeezed to a letter a line, with white space everywhere else. The phone gets
   its own column plan and no scrolling; the laptop keeps the pinned widths above -
   asked for: fix the phone, do not touch the regular web. */
@media (max-width: 600px) {
  table.figures { min-width:0; }
  table.figures td:nth-child(1), table.figures th:nth-child(1) { width:36px; padding-right:4px; }
  /* The Dates table names its rows in words - RD, EA, Decision, EA decision - so its first
     column holds text, not the feather or gear the other two put there. At 36px
     "Decision" ran straight across the date beside it on a phone (2026-10-07). */
  table.figures.datesfig td:nth-child(1), table.figures.datesfig th:nth-child(1) {
    width:30%; padding-right:8px; white-space:normal; overflow-wrap:anywhere; }
  table.figures.datesfig td:nth-child(2), table.figures.datesfig th:nth-child(2) { width:26%; }
  table.figures.datesfig td:nth-child(3), table.figures.datesfig th:nth-child(3) { width:0; padding:0; }
  table.figures td:nth-child(2), table.figures th:nth-child(2) { width:31%; }
  table.figures td:nth-child(3), table.figures th:nth-child(3) { width:21%; }
  table.figures td:nth-child(4) { white-space:normal; }
  table.figures td { padding-right:6px; }
  table.figures th { white-space:normal; padding-right:6px; }
}
table.stats tr:first-child td { border-top:none; }
table.tracker td, table.tracker th { padding-right:14px; }
table.tracker a { text-decoration:none; color:var(--ink); }
table.tracker .pill { padding:1px 6px; }
table.tracker .d { display:inline-block; width:9px; height:9px; border-radius:50%; margin-right:3px; }
.legend .idle { background:var(--idle); }
.legend .act { background:var(--attention); }
.legend .good { background:var(--good); }
.legend .na { background:transparent; border:1px solid rgba(140,145,150,.6); }
.d.sat-bad { background:var(--bad); } .d.sat-active { background:var(--active); }
.d.sat-idle { background:var(--idle); } .d.sat-attention { background:var(--attention); }
.d.sat-good { background:var(--good); }
table.tracker .d { display:inline-block; width:9px; height:9px; border-radius:50%; }
/* The version rolodex. One row per version, with its own controls, so a version can be
   looked at, put back, ticked against another or moved under the cut without leaving the
   essay it belongs to. */
.vrow { flex-wrap:wrap; align-items:flex-start; }
.vrow .grow { min-width:160px; }
.vmeta { margin-top:2px; }
/* Its own line so a long subject never squeezes the reading off the row. */
.vmeta .band-high { color:var(--bad); font-weight:600; }
.vmeta .band-some { color:var(--attention); font-weight:600; }
.vmeta .band-low { color:var(--good); font-weight:600; }
/* A sized form control must not sit in an inline-flex box - WebKit paints nothing at all,
   which is what hid every option-set radio in Safari. Same rule, same answer: inline-block,
   with line-height doing the centring and a 32x30 target for a thumb. */
.vtick { display:inline-block; width:32px; height:30px; line-height:30px; text-align:center;
         margin:0; cursor:pointer; flex:none; }
/* min-width:0 is load-bearing. From 700px up this sheet gives every `input` a 260px
   minimum - right for a text field on a laptop, and it makes a 19px checkbox 260px wide,
   which laid the tick straight across the version's own words. A width alone does not
   undo a minimum. */
.vtick input { width:19px; height:19px; min-width:0; margin:0; vertical-align:middle;
               accent-color:var(--active); cursor:pointer; }
form.vacts { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:0; }
button.vbtn { background:none; border:1px solid var(--line); color:var(--dim);
              width:auto; padding:2px 10px; margin:0; border-radius:999px;
              font-size:12px; font-weight:600; text-align:center; cursor:pointer; }
button.vbtn:active { background:rgba(51,120,217,.16); transform:translateY(1px); }
.card .vacts > button, .card .vacts > .slice { margin-right:0; }
.vcompare { color:var(--dim); font-size:12px; }
/* The mark a version imported from Ari's Source carries. A circled capital A, which is the
   author name the import writes - not a sentence about Google Drive on every second row.

   Every measurement is the old one plus a fifth: 18 -> 21.6, 12 -> 14.4, 1.5 -> 1.8. It is
   the only thing on a version row that is not words, and at 18px beside 14px text it read
   as punctuation rather than as a mark. The ring carries the weight as much as the letter
   does, so the border grows with it. */
/* The version's number, in a circle like the source's A, one step smaller than it so the
   two read as a pair rather than as one mark twice. */
.vnum { display:inline-block; min-width:20px; height:20px; line-height:18px; padding:0 4px;
        text-align:center; border:1.5px solid currentColor; border-radius:999px;
        font-size:12px; font-weight:700; color:var(--dim); vertical-align:-3px;
        margin-right:6px; font-variant-numeric:tabular-nums; }
/* A prompt is italic and its own colour on every version and snapshot line. */
.vask { font-style:italic; color:var(--vask); }
/* The filter fields say what they are: a small label and a glass inside the box, asked
   for on 2026-10-07. The glass is positioned against .searchwrap, and the field keeps its
   own left padding so the text never runs under it. */
.searchlab { font-size:11px; color:var(--dim); text-transform:uppercase; letter-spacing:.05em;
             font-weight:600; margin:0 6px 0 0; }
.searchwrap { position:relative; display:inline-flex; align-items:center; flex:1 1 220px; min-width:0; }
.searchwrap svg { position:absolute; left:9px; pointer-events:none; color:var(--dim); }
.searchwrap input[type=search] { padding-left:30px; width:100%; min-width:0; }
.lookrow { gap:8px; flex-wrap:wrap; align-items:center; }
.lookrow .btn.ghost { width:auto; }
/* Whether the server is still copying the essays to Drive. Read on a phone, so it wraps
   rather than scrolling, and the colour carries as much as the words. */
.mirrorbar { margin:0 0 10px; padding:9px 12px; border-radius:9px; font-size:13px;
             font-weight:600; line-height:1.4; overflow-wrap:anywhere; }
.mirrorbar.ok  { background:color-mix(in srgb, var(--good) 14%, transparent); color:var(--good); }
.mirrorbar.bad { background:color-mix(in srgb, var(--bad) 16%, transparent); color:var(--bad); }
/* Why Ari's Drive shows a later date than the newest version taken from it. */
.srctouch { color:var(--attention); }
/* A document in Ari's Drive changed in the last three days. The letter is the same A the
   source's own versions wear, so the two read as one mark in two places. */
.srcbadge { display:inline-block; height:15px; line-height:15px; margin-left:6px;
            border-radius:8px; color:#fff; font-size:10px; font-weight:700; text-align:center;
            vertical-align:1px; padding:0 5px; letter-spacing:.02em; white-space:nowrap; }
table.stats.srctable td { white-space:normal; vertical-align:top; }
/* Ari's Source by school: a heading row over each school's documents. */
.srctable tr.srcgroup th { text-align:left; font-size:15px; font-weight:700; text-transform:none; letter-spacing:normal;
                           color:var(--ink); padding-top:18px; border-bottom:1px solid var(--line); }
.srctable tr.srcgroup:first-of-type th { padding-top:8px; }
.srcmove { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:6px 0 0; }
.srcmove select { min-width:0; width:auto; max-width:100%; }
.srcmove button { width:auto; min-width:0; flex:none; }
table.stats.srctable td:nth-child(4), table.stats.srctable th:nth-child(4) { text-align:right; }
/* Where a version came from, in one colour per hand - the Type cell and the snapshot tag. */
.vo-drive { color:var(--attention); } .vo-claude { color:var(--active); }
.vo-person { color:var(--good); } .vo-restore { color:var(--done); }
.vkind { font-size:10px; text-transform:uppercase; letter-spacing:.04em; font-weight:600;
         border:1px solid currentColor; border-radius:4px; padding:0 5px; vertical-align:1px; }
.amark { display:inline-block; width:21.6px; height:21.6px; line-height:19.2px;
         text-align:center; border:1.8px solid currentColor; border-radius:50%;
         font-size:14.4px; font-weight:800; color:var(--done); vertical-align:-3px;
         margin-right:6px; }
/* Read-only, and it says so. Built like .blocker: the visible state is a class, because
   display:flex in a base rule outranks the `hidden` attribute. */
.vmodal { position:fixed; inset:0; z-index:58; display:none; align-items:center;
          justify-content:center; background:rgba(10,11,13,.72); padding:14px; }
.vmodal.on { display:flex; }
.vmodal .vcard { background:var(--card); border:1px solid var(--line); border-radius:14px;
                 padding:14px; width:100%; max-width:760px; max-height:86vh;
                 display:flex; flex-direction:column; }
.vmodal .vbody { margin-top:10px; overflow:auto; white-space:pre-wrap; word-break:break-word;
                 font-size:15px; line-height:1.6; }
/* Every height in this sheet written in vh is, on iOS Safari, a fraction of the LARGE
   viewport - the height the page would have with the toolbars hidden - so the box is
   taller than the screen it is on while they are showing: the essay editor runs under the
   keyboard and the read-only modal loses a slice top and bottom. dvh is the height actually
   visible. Written as an override so the vh values stay as the fallback. */
@supports (height: 1dvh) {
  .edit .hl, .edit textarea { min-height:46dvh; }
  .split > .detailpane { height:calc(100dvh - 150px); }
  .vmodal .vcard { max-height:86dvh; }
}