/* ===================================================================================================
   THE CALCULATOR PANEL — shared by quiz/shell.html (practice mode) and /calculator/.

   ⚠ VERSION-NAMED ON PURPOSE, AND _headers SERVES IT immutable FOR A YEAR BECAUSE OF THAT.
   /nav-user.js is deliberately unversioned and cached for an hour, justified there by "a stale copy
   is harmless in the only direction it can fail". That sentence is FALSE for a calculator: a stale
   copy computes a wrong answer. Versioning was refused there because eleven pages would need editing
   to ship a fix; this file has TWO consumers, so a version bump costs two edits.
   ⚠ TO CHANGE THIS FILE: bump BOTH names to -v2 and update both pages and _headers together.

   ⚠ .calc-btn IS NOT HERE. It lives in quiz/shell.html because it is positioned against that page's
   nav (--nav-tools-inset) and means nothing on a page with no nav rail.

   Needs five variables from the host page — --accent --bg --border --muted --text — and two fonts,
   Fraunces and Inter. Inter is otherwise declared only in admin/index.html, so a new host page must
   declare it or the display silently falls back.
   =================================================================================================== */

/* ⚠ position:fixed IS LOAD-BEARING, not tidiness. Anything that takes vertical space in this layout
   re-runs scaleFrame(), so a panel in the flow would make the card visibly jump the instant it
   opened and again when it closed — the same rule the zoom hint and the phone clock are built
   around. Fixed also keeps it clear of .card-area's touch-action:none, so its keys cannot be
   swallowed by the pinch/pan handlers bound in there.
   z-index sits above the card (which has none) and below .leave-wall's 2000, so a leave prompt still
   lands on top of it. */
/* ===================== PRACTICE CALCULATOR ========================================
   Key LAYOUT follows the on-screen calculator GED provides in the real test (a Texas Instruments
   TI-30XS MultiView), so a student's hands learn the right positions. Referenced descriptively, for
   compatibility only.

   ⚠ THE LOOK IS THIS SITE'S, NOT THEIRS, AND DELIBERATELY SO. An earlier pass reproduced the
   hardware's slate-and-green colouring; it was replaced because copying a product's trade dress is
   the other half of the trademark question the name raised, and because monochrome and sharp is the
   house format everywhere else in this app. Layout is function and is kept; colour was decoration
   and is not. Do not reintroduce their palette.

   ⚠ position:fixed is load-bearing, not tidiness. Anything that takes vertical space in this layout
   re-runs scaleFrame(), so a panel in the flow would make the card jump the instant it opened — the
   same rule the zoom hint and the phone clock are built around. Fixed also keeps it clear of
   .card-area's touch-action:none, so its keys cannot be swallowed by the pinch/pan handlers. */
.calc-pop{display:none;position:fixed;z-index:1500;width:280px;padding:16px;
  /* Frame border is a soft grey, not --text black. The panel already reads as lifted from a soft
   drop shadow; a hard black outline on top of that made it look cut out rather than resting on
   the page, and it clashed with the softened display border inside it.
   ⚠ ~~#c6ccd4~~ → #b4bec9, 2026-09-03 at the user's direction — the frame was reading as too muted
   to hold the panel together. One step down, the same size of step that took the keys from #dde1e6
   to #ccd2da, so the three lines keep their spacing.
   ⚠ THE ORDERING IS THE RULE, NOT THE VALUE: the frame must stay the DARKEST line on the panel,
   below the keys (#dde1e6 in the shell, #ccd2da standalone) and the display's underline. Darken the
   keys past this and the panel stops reading as one object with a boundary. Both other values are
   quoted in the .calc-standalone block below — change one, re-check all three. */
  background:#fafafb;border:1px solid #b4bec9;border-radius:14px;
  box-shadow:0 8px 26px rgba(0,0,0,0.16)}
.calc-pop.on{display:block}
/* ⚠ THE HEADER STAYS EVEN WITHOUT ITS TITLE. It is the drag handle (calc-head is what the
   pointerdown listener binds to) and it carries the 2nd and DEG flags and the close button.
   Deleting the row, rather than just its label, would leave the panel unmovable and unclosable. */
/* Indicators only. The close button was removed — the toolbar's calculator icon toggles the
   panel, so a second way to shut it was one control too many. ⚠ closeCalc() itself STAYS and is
   still called by toggleCalc, by syncCalcBtn when the button hides, and by 2nd+mode (quit). */

/* visibility, not display: the 2nd flag reserves its space so the header cannot reflow when it
   arms, which would nudge the panel under the student's finger mid-press. */
.calc-flag{font-family:'Inter',sans-serif;font-size:8px;font-weight:700;letter-spacing:0.08em;
  padding:1px 4px}
/* Absolute, inside the frame's 16px padding, so it occupies space nothing else wanted. */
#calcModeFlag{position:absolute;top:9px;right:11px;background:var(--bg);color:var(--muted);
  border:1px solid var(--border);border-radius:3px;pointer-events:none}
/* ⚠ HISTORY NEEDS A MARK, AND IT IS NOT DECORATION — `enter` MEANS SOMETHING ELSE WHILE IT IS UP.
   Scrolled back one step, the screen was byte-identical to the live one: same expression, same
   answer, nothing to say that enter would now PASTE rather than evaluate. Found by looking at the
   real page after four ▲ presses; the suite could not have caught it, because every value it reads
   was already right. Same lesson as `neg` printing as the word "neg" and the menu rendering
   right-to-left — see the working rules.
   The MARK is the hardware's (p.6: "An entry is stored in memory before and/or after the active
   screen. Press # and $ to scroll" — a scroll indicator); its DRAWING is a choice made here, like
   every other rendering decision in this panel. The word is needed because the arrows alone go
   silent in the case that needs them most: at a lone entry there is nothing above or below, so a
   direction-only indicator would show nothing at all. The hardware does not have that problem —
   its four-line screen shows the neighbouring entries — and this one line cannot.
   Absolute in the frame's own padding like the DEG flag, and for the same two reasons: it cannot
   add height to `.calc-screen` (whose 104px is derived, not chosen) and it cannot reflow the panel
   under a finger mid-press. No border — DEG is boxed because it is always present and has to read
   as a persistent status; this appears and disappears, and a box around something transient draws
   more attention than the state deserves. */
#calcHistFlag{position:absolute;top:9px;left:11px;color:var(--muted);pointer-events:none;
  font-weight:600;letter-spacing:0.1em}

/* Two lines: what she typed, and the answer beneath it. That pairing is the point — an answer with
   no visible expression cannot be checked, which is exactly what a student needs when their working
   disagrees with the card. */
/* ⚠ NO BOX. The readout sits open on the panel and a single rule under the status row separates
   it from the keypad — an outlined, inset, rounded screen inside an outlined rounded frame was
   two nested boxes saying the same thing. The horizontal padding is 2px rather than 0 so the
   expression lines up with the outer edge of the first and last key columns.
   ⚠ IT IS STILL THE DRAG HANDLE (id calcHead) even without a border, which is why cursor:move
   and touch-action:none stay — losing them would leave the panel unmovable. */
.calc-screen{background:transparent;border:none;border-bottom:1px solid #dde1e6;cursor:move;
  -webkit-user-select:none;user-select:none;touch-action:none;
  /* ⚠ 104px IS DERIVED FROM THE MENU, NOT CHOSEN. ~~93px~~ left 69px once the title and padding
     were taken, and a bordered menu row is 20px — 3.45 rows, so the fourth was sliced in half and
     the list read as broken rather than scrolled. 104 = 2 (pad) + 13 (title + its margin) + 80
     (FOUR whole rows) + 9 (pad). Four is the hardware's own screen depth, and 80 also clears the
     MODE grid's four rows (76px), so one window serves both.
     ⚠ **RE-DERIVE THIS WHENEVER THE MENU TYPE SIZE, ROW PADDING OR BORDER CHANGES.** A half-row is
     the symptom and it has already appeared twice — the second time because dropping the row border
     took the row from 20px to 18px and nothing here moved with it. */
  padding:2px 2px 9px;margin-bottom:0;min-height:104px;
  display:flex;flex-direction:column;justify-content:space-between}
/* ⚠ direction:rtl ANCHORS THE BOX, AND THE CONTENT MUST BE WRAPPED LTR OR IT READS BACKWARDS.
   rtl is here so a long expression keeps its TAIL visible — the digits being typed — rather than
   its head. But + − × ÷ ( ) are bidi-NEUTRAL, so under rtl they reorder: `2 + 3 × 4` rendered as
   `4 × 3 + 2`. Seen on screen, not in a test. calcEntryHTML wraps the whole line in <bdi dir="ltr">,
   which restores reading order inside a right-anchored box. */
/* ⚠ max-height IS WHAT LETS A NESTED FRACTION BE LEGIBLE. The two requirements fight: 0.66em per
   level compounds to 2.4px at four levels (unreadable), and not compounding makes the line 70.6px,
   which pushes `.calc-screen` from its derived 104 to 115.8 and the PANEL from 538 to 550 — the
   documented "keypad moves down under the finger that just pressed the key".
   Measured both ways; no shrink ratio satisfies both, because the ones that fit the box are all
   below ~5.4px. So the display becomes a fixed WINDOW and tall content scrolls inside it, which is
   what the hardware's four-line screen does and what `.cm-list` already does two hundred lines
   below. 58px is 104 minus everything else on the screen, derived the same way that 104 was.
   ⚠ RE-DERIVE THIS IF THE ANSWER LINE'S TYPE SIZE CHANGES — it is 104 − (answer + padding). */
.calc-entry{font-family:'Inter',sans-serif;font-size:0.8rem;color:var(--text);min-height:1.15em;
  max-height:58px;
  text-align:left;overflow:hidden;white-space:nowrap;direction:rtl}
.calc-entry bdi{direction:ltr;unicode-bidi:isolate}
/* The caret. A hairline between two tokens, not a box over one: this entry model addresses
   TOKENS, so `123` is one thing and a cursor sitting ON it would suggest typing replaces all
   three digits. Between-tokens is the honest shape for what the keys actually do. */
.cf-caret{display:inline-block;width:1px;height:1em;vertical-align:-0.15em;margin:0 1px;
  background:var(--text)}
.calc-entry sup{font-size:0.62em;vertical-align:super}
.calc-ans sup{font-size:0.52em;vertical-align:super;font-weight:600}
/* The vinculum — the bar over a radicand. Without it `√32` is unreadable: the eye cannot tell
   √3 × 2 from √32, and an exact answer that cannot be read is worse than the decimal it replaced.
   A border-top on the radicand alone, so it stops where the number stops. */
.cf-rad{border-top:1px solid currentColor;padding:0 1px 0 1px;margin-left:1px}
/* The ANSWER is Fraunces — the same display face the score screen already sets its numbers in,
   so a result here reads as part of this site rather than as a generic readout. The ENTRY line
   above stays Inter: it carries operators, brackets and superscripts, which a display serif
   sets poorly at 0.8rem, and it is read as text rather than looked at as a figure.
   ⚠ tabular-nums is kept even though Fraunces may not ship that feature — where it is absent
   the declaration is inert, and where it is present it stops the answer shifting width as the
   digits change, which is the whole reason it is here. */
.calc-ans{font-family:'Fraunces',Georgia,serif;font-size:1.45rem;font-weight:600;color:var(--text);
  text-align:right;min-height:1.25em;line-height:1.05;letter-spacing:-0.02em;
  font-variant-numeric:tabular-nums;overflow:hidden;white-space:nowrap}

/* Row gap and column gap are set apart on purpose: the 2nd labels sit ABOVE each key in the row
   gap, so that value is spoken for, while the column gap is free to breathe. */
.calc-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:5px 9px;margin-top:9px}
/* The arrow pad sits where the hardware puts it, beside 2nd/mode/delete. Inert for now — cursor
   editing is not built — so it is aria-hidden and takes no press. */
/* The arrow pad sits where the hardware puts it, beside 2nd/mode/delete. It is a REAL 4-way pad:
   ▲▼ move between the boxes of a fraction template, ◄► step in and out of one. It replaced both the
   inert white placeholder that used to sit here AND the invented ◄► key that stood in for it in the
   bottom row — the hardware has forty keys and one double-height enter, which is what this now is.
   ⚠ The three-column mini-grid is what makes the pad read as a pad: the four arrows sit on the
   cross, the corners stay empty. Do not collapse it to a 2x2. */
.calc-pad{grid-column:span 2;grid-row:span 2;display:grid;
  grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);
  gap:3px;margin-top:10px;align-self:stretch}
.calc-key.calc-arrow{height:auto;margin-top:0;font-size:0.6rem;color:var(--muted)}
.calc-pad .a-up{grid-area:1/2}
.calc-pad .a-left{grid-area:2/1}
.calc-pad .a-right{grid-area:2/3}
.calc-pad .a-down{grid-area:3/2}
/* ~~.calc-key.k-tall{grid-row:span 2}~~ — enter briefly spanned two rows to absorb the cell left
   by the ◄► key. That key turned out to be the hardware's Answer Toggle, not an invention; it is
   back in its slot and nothing in this grid spans anything. */

/* ⚠ THE 2nd LABEL IS A PSEUDO-ELEMENT ABOVE THE KEY, not a child, so it cannot be a tap target and
   cannot change the button's own layout. Keys carrying one get top margin to make room; without it
   the labels overlap the row above. */
/* White keys with a light hairline, and `enter` filled black. Tried per-group greys (operators
   darker than functions) and then flat borderless grey; both were reverted. The LAYOUT already
   encodes the grouping — operators are the whole right-hand column — so per-group tone repeated what
   position said, and the borderless version leaned entirely on fill contrast to separate one key
   from the next. ⚠ The hairline IS the separation here: the keys are the same white as the panel is
   near, so removing the border again would merge them into one field. */
/* ⚠ ROUNDED KEYS ARE A DELIBERATE EXCEPTION to the house sharp-corner rule, asked for directly.
   Everything else in this panel stays square — the frame, the display, the flags — so the radius
   reads as 'these are keys' rather than as the panel drifting away from the rest of the app. */
.calc-key{position:relative;border:1px solid #dde1e6;border-radius:7px;cursor:pointer;
  height:29px;margin-top:10px;padding:0;font-family:'Inter',sans-serif;font-size:0.68rem;
  font-weight:600;line-height:1;background:#fff;color:var(--text);touch-action:manipulation}
.calc-key[data-2nd]:not([data-2nd=""])::before{content:attr(data-2nd);position:absolute;
  left:0;right:0;top:-10px;font-size:7.5px;font-weight:600;letter-spacing:0.01em;
  color:var(--muted);white-space:nowrap;overflow:hidden;pointer-events:none}
.calc-key i{font-style:italic}
.calc-key:hover{background:#f2f4f6}
.calc-key:active{background:var(--accent);color:#fff}
.calc-key.k-num{font-size:0.78rem}
.calc-key.k-op{font-size:0.74rem}
.calc-key.k-enter{background:var(--accent);color:#fff}
/* The 2nd key takes the same grey as every other key — no override. Only its ARMED state fills,
   because that is a state the student needs to see, not a category. */
.calc-key.k-2nd.armed{background:var(--accent);color:#fff}
/* Stacked fractions in the READOUT (.cf) — numerator over denominator with a rule between, which
   is how the student wrote it on paper. vertical-align:middle keeps it sitting on the same optical
   line as the operators either side of it rather than dropping below the baseline. */
.cf{display:inline-flex;flex-direction:column;align-items:center;vertical-align:middle;
  line-height:1.05;font-size:0.66em;margin:0 1px}
.cf i{font-style:normal;padding:0 3px}
.cf i:first-child{border-bottom:1px solid currentColor}
.cf-w{display:inline-block;width:3px}
/* The ENTRY-LINE template — what n/d opens, before anything is typed into it. Same stacked shape as
   the readout .cf above, but every box is drawn: dotted while it is waiting for digits, and the one
   the arrow pad is pointing at carries a solid accent edge so the student can see where a digit will
   land. ⚠ The box keeps its size when it fills (min-width/min-height, not width) — a slot that
   collapsed as soon as it held a digit would make the fraction jump under her fingers. */
/* ⚠ BIGGER THAN THE .cf READOUT ABOVE, DELIBERATELY. .cf draws a finished ANSWER at 0.66em and
   that is right for it. This is the thing she is TYPING INTO, and at 0.66em the boxes measured
   11x10px against a 12.8px entry line — a fraction visibly smaller than the digits either side of
   it, on the one element the cursor is inside. MathPrint draws the template at very nearly full
   digit height, so this does too. */
/* ⚠ 0.66em — THE ORIGINAL, restored at the user's direction. ~~Raised to 0.92em on the reasoning
   that the thing being TYPED INTO should be near digit height.~~ Reverted: it read as too big beside
   the rest of the line. The legibility problem it was aimed at was never really the size — it was
   the bar and the box drawing on the same pixel, which the <b> below fixes at any size. */
.cft{display:inline-flex;flex-direction:column;align-items:stretch;vertical-align:middle;
  line-height:1.08;font-size:0.66em;margin:0 2px}
/* ⚠ THE 0.66em SHRINK MUST NOT COMPOUND, AND IT DID THE MOMENT NESTING SHIPPED. `em` is relative to
   the parent, so a fraction inside a fraction inside a fraction inside a fraction rendered at
   0.66⁴ of the entry line: measured 8.4px → 5.6 → 3.7 → **2.4px**, and the innermost `4/5` was two
   and a half pixels tall. Every test passed; the display was unreadable. Found by looking, which is
   now four for four on rendering faults in this panel.
   One step down is the MathPrint look and is worth its cost — it says "this is a sub-expression".
   A second step buys nothing: the stacked bars already say it, and legibility is not negotiable on
   a phone. So deeper levels hold the size the first one set. */
.cft .cft{font-size:1em}
.cft > i{font-style:normal;padding:0 3px;display:flex;align-items:center;justify-content:center;
  min-width:0.95em;min-height:1.2em}
/* ⚠ THE FRACTION BAR IS ITS OWN ELEMENT, NOT THE NUMERATOR'S border-bottom.
   ~~`.cft i:first-child{border-bottom:1px solid currentColor}`~~ — with the numerator ALSO carrying
   a dashed box, the box's bottom edge and the bar were the same pixel: the rule overrode the dash,
   so the box looked open at the bottom and the fraction line looked like part of the box. Reported
   as the boxes overlapping the line and neither being visible. A separate bar with 2px of air
   either side lets both read as themselves. `.cf` (the READOUT) keeps its border-bottom — it has no
   boxes to collide with. */
.cft > b{display:block;align-self:stretch;height:1px;background:currentColor;margin:2px 0}
.cft > i.sl{border:1px dashed var(--muted);border-radius:2px}
.cft > i.on{border:1px solid var(--accent);color:var(--accent)}
/* The standalone waiting-box, drawn after ^ or an opened function. Same dotted edge and the same
   size as a fraction slot, because it means the same thing: a number goes here next. */
/* A menu, drawn in the entry area — the display is the only surface this panel has. The title is
   muted and small; the selected row is the accent fill, which is the same "this one is current"
   language the 2nd key and the focused fraction box already use. */
.cm-t{display:block;font-size:8px;letter-spacing:0.08em;color:var(--muted);margin-bottom:3px}
/* ⚠ A VERTICAL LIST, BECAUSE ▲▼ ARE WHAT MOVE THROUGH IT. ~~display:inline-block~~ laid the items
   in a row while the only navigation keys are up and down — the affordance contradicted the
   control, and it is a row of boxes where the hardware (and the guidebook's own menu chart, p.5)
   prints a stacked list. Reported by eye, not by a test: the suite reads the DOM order, which was
   right the whole time. */
.cm-i{display:block;font-size:0.72rem;padding:1px 5px;margin:0 0 2px;
  border:1px solid var(--border);border-radius:3px;background:#fff;width:max-content;min-width:4.5em}
/* ⚠ FOUR ROWS AND IT SCROLLS — the panel must not change height when a menu opens. Uncapped, the
   seven-item RECALL list grew the panel 532px → 628px, which moves the whole keypad down under the
   finger that just pressed the key, and on a short viewport pushes `enter` off the bottom. Four is
   the hardware's own screen depth (guidebook p.1: "a maximum of four lines"), so the window that
   keeps the panel still is also the faithful one. calcShow scrolls the selection into it. */
.cm-list{display:block;position:relative;max-height:80px;overflow:hidden}
/* MODE rows: one setting per line, its options along it. `set` is what is in force, `cur` is where
   the arrow pad is — two different things, and both have to be visible at once. */
/* ⚠ THE ROW YOU ARE ON IS AT FULL STRENGTH; THE OTHER CATEGORIES RECEDE. Each row is a separate
   SETTING, so dimming per row is what says "this is the one you are changing" — without it four
   rows of equal weight all read as live at once and the cursor is the only clue, on a screen where
   the cursor is a 1px outline. Opacity rather than a colour swap so the black `set` fill recedes
   WITH its row: a full-strength fill in a dimmed row would go on shouting the loudest thing on
   screen. What is set stays legible either way — you can still read off every current setting
   without moving. */
.cm-row{display:block;white-space:nowrap;margin:0 0 2px;font-size:0.62rem;line-height:1.5;
  opacity:0.42;transition:opacity 0.12s ease}
.cm-row.cur{opacity:1}
.cm-o{display:inline-block;padding:0 3px;margin-right:2px;border:1px solid transparent;border-radius:2px}
/* THE DATA EDITOR GRID. ⚠ Its row height is the SAME 19px the MODE rows use, and that is not a
   coincidence to be tidied away: `.calc-screen`'s 104px is derived from FOUR rows of the menu
   window (see the note there), and this screen spends all four — a header plus three data rows.
   Change the type size or padding here and the fourth row is sliced in half, which is the symptom
   that has already appeared twice in this panel.
   ⚠ NO dimming, unlike `.cm-row`. MODE dims because each row is a separate SETTING and only one is
   being changed; here every row is the same kind of thing — data — and the cursor is a single cell,
   so dimming rows would say a row was selected when a cell is. */
/* ⚠ font-style:normal IS NOT COSMETIC HOUSEKEEPING — the cells are <i> elements and <i> is ITALIC
   by default. The whole grid, numbers and column headers alike, shipped slanted; seen on the real
   page, and no test could have asked about it because every value it reads was correct. The tag is
   <i> to match the fraction template's markup, which the test harness already knows how to read. */
.cd-row{display:block;white-space:nowrap;margin:0 0 2px;font-size:0.62rem;line-height:1.5}
.cd-head{color:var(--muted);letter-spacing:0.06em}
/* p.31's highlighted author line: the one mark saying this column is computed, not typed. Filled
   rather than outlined, because the outline in this panel already means "the cursor is here". */
/* ⚠ `display:block`, NOT inline-block, AND THAT IS MEASURED. `.cm-t` is a block; making the
   highlighted variant inline-block gives it a line box with half-leading and `.calc-screen` grew
   from 104 to 104.5 — half a pixel, which slices nothing today and is exactly the kind of drift
   that has twice ended in a half-row here. `width:max-content` shrink-wraps a block the same way,
   so the highlight still fits its text instead of running the full width. */
.cm-t.cm-frml{background:var(--text);color:var(--bg);padding:0 3px;border-radius:2px;
  display:block;width:max-content}
/* Fixed widths, or a column jumps sideways as digits are typed into it and the eye loses the cell
   it was reading. tabular-nums for the same reason the answer line has it.
   ⚠ vertical-align:top IS LOAD-BEARING AND COSTS 1.8px PER ROW. An inline-block with
   `overflow:hidden` takes its BASELINE from its bottom margin edge rather than its text, so the
   line box grows by the descender space underneath it: rows measured 20.8px against the 19px the
   MODE rows get from identical font-size, line-height and border. Four of those plus margins is
   89px in an 80px window — the FOURTH ROW WAS SLICED IN HALF, which is the same symptom this panel
   has now produced three times. Measured, not guessed. Do not drop this to "tidy up", and re-measure
   if `overflow` here ever changes. */
/* ⚠ font-style:normal MUST SIT ON THE CELLS THEMSELVES, NOT ON `.cd-row`. `<i>` carries the user
   agent's own `font-style:italic`, and a declaration on the parent is only INHERITED — the UA rule
   on the element wins. Put on the row it looked right in the stylesheet and changed nothing on
   screen, which is the worst kind of fix. */
.cd-n{display:inline-block;vertical-align:top;font-style:normal;width:2.4em;color:var(--muted);
  text-align:right;padding-right:4px}
.cd-c{display:inline-block;vertical-align:top;font-style:normal;width:4.6em;padding:0 3px;
  margin-right:2px;overflow:hidden;border:1px solid transparent;border-radius:2px;
  font-variant-numeric:tabular-nums}
/* ⚠ THE STAT PICKER'S GUTTER HOLDS WORDS, NOT ROW NUMBERS, AND 2.4em IS NOT ENOUGH FOR THEM.
   `.cd-n` is 2.4em because the data editor puts 1..42 in it. `xDATA` is five characters and ran
   straight over the `L1` chip beside it — on screen row 2 read `yDATAL1`. Measuring found no
   overlap and said so, because the ELEMENT boxes do not overlap; it is the TEXT that overflows a
   fixed-width inline-block. Seen by looking, like the italics and the sliced row before it.
   Fixed width rather than shrink-to-fit, so all three rows' options still start at one x. */
.cd-lab{width:4.3em}
/* The cursor is an outline, the same one MODE uses, so one visual language covers both screens. */
.cd-c.cur{border-color:var(--text)}
/* ⚠ ONE OUTLINE ON SCREEN, NOT TWO. The header's active column was drawn with the same box as the
   cell cursor, so `L1` and the cell under it were both outlined at equal weight and read as two
   cursors — on a screen where the cursor is the only thing saying where a keypress will land. Seen
   on the page; nothing in the suite could ask about it, because both classes were correct.
   Unlike MODE there is no second thing to say here: MODE needs `set` AND `cur` because what is in
   force and where the arrow pad is are genuinely different, whereas this grid has one cursor and
   the author line above already names its column. So the header marks its column by WEIGHT, coming
   up from muted to full strength, and the outline is left to mean one thing. */
.cd-head .cd-c.cur{border-color:transparent;color:var(--text);font-weight:600}
.cm-o.set{background:var(--accent);color:#fff}
.cm-o.cur{border-color:var(--accent)}
/* An accent outline on a black fill is invisible, so the cursor-on-the-set-item case borrows the
   muted grey instead. Reachable constantly: the cursor LANDS on the set item on every row change. */
.cm-o.set.cur{border-color:var(--muted)}
/* ⚠ WHILE A MENU IS OPEN THE ANSWER LINE GIVES UP ITS RESERVED HEIGHT. `.calc-screen` already
   reserves 93px, but `.calc-ans{min-height:1.25em}` holds ~23px of it even when blank — which the
   menu then has to grow past, moving the whole keypad down under the finger that just pressed the
   key (measured: 527px panel → 555px). The answer line is empty during a menu anyway. */
.calc-screen.menu-on .calc-ans{min-height:0}
/* ⚠ AND THE ENTRY'S 58px CAP MUST COME OFF WITH IT — IT WAS SLICING EVERY MENU IN THE CALCULATOR.
   That cap exists for NESTED TEMPLATES on the live entry line: four levels of fractions would
   otherwise grow the panel, so the display became a fixed window with the content scrolling inside
   it. A menu is not that. It REPLACES the entry line and does its own scrolling in `.cm-list`
   (max-height:80px — four 20px rows, the same derivation `.calc-screen`'s 104 comes from), and with
   the parent capped at 58px that 80px budget could never be reached.
   Measured before this rule, every menu clipped at the bottom: MODE by 31px, RECALL by 35, the DATA
   CLEAR menu by 35, the data editor by 25, PRB by 15, TABLE SETUP by 12 — each leaving a half-row
   hanging under the cut. Reported from the real page as "the display feels cut in the middle".
   ⚠ THE FOURTH TIME A SLICED ROW HAS SHIPPED IN THIS PANEL, and the first three are recorded above.
   ⚠ AND IT SURVIVED A VERIFICATION PASS BECAUSE THE WRONG BOX WAS MEASURED: `.calc-screen` stayed a
   correct 104px throughout, so every check of the screen passed while the content inside it was
   being cut. Measure `.calc-entry`'s scrollHeight against its clientHeight, not the frame. */
.calc-screen.menu-on .calc-entry{max-height:none;overflow:visible}
/* ⚠ THE HISTORY FLAG SITS IN THE CORNER THE EXPRESSION STARTS IN, so the entry has to step down for
   it. Measured: both flags hang below the screen's top edge — DEG to +7, ▲HIST to +5 — while the
   entry's text starts at +2. DEG is harmless because it is far right and a long expression stops at
   200px against its 222px; ▲HIST is top-LEFT, exactly where the text begins, so the flag and the
   expression under it OVERLAPPED BY 3px. Reported from the real page as "too close to each other".
   ⚠ SCOPED TO .hist-on, NOT APPLIED ALWAYS. The flag is only up while browsing history, and padding
   every expression down 7px would move the entry line in every other state for no reason.
   ⚠ AND IT COSTS THE SCREEN NOTHING: .calc-screen is min-height:104px, so the padding eats into the
   entry's own space rather than growing the frame — verified by adding 7px and re-measuring 104. */
.calc-screen.hist-on .calc-entry{padding-top:7px}
.cm-i.on{background:var(--accent);color:#fff;border-color:var(--accent)}
.cft-slot{display:inline-block;font-style:normal;min-width:0.8em;height:1.1em;vertical-align:middle;
  border:1px dashed var(--muted);border-radius:2px;margin:0 1px}
/* The whole-number box of a mixed template sits BESIDE the fraction, not above it. */
.cft-u{display:inline-flex;align-items:center;vertical-align:middle;margin:0 1px}
/* ⚠ min-height IS WHAT MAKES THE EMPTY WHOLE BOX VISIBLE. Without it an unfilled unit box has no
   content and no height, so it rendered as a 1px dash beside a full-height fraction — reported as
   the whole number not being in a dotted box at all. Sized to match a fraction slot so the three
   boxes of `U n/d` read as one template. */
.cft-u > i{font-style:normal;padding:0 3px;display:inline-flex;align-items:center;
  justify-content:center;min-width:0.95em;min-height:1.2em;margin-right:2px}
.cft-u > i.sl{border:1px dashed var(--muted);border-radius:2px}
.cft-u > i.on{border:1px solid var(--accent);color:var(--accent)}
.calc-frac{display:inline-flex;flex-direction:column;line-height:0.8;font-size:0.72em}
.calc-frac i:first-child{border-bottom:1px solid currentColor}
.calc-sub{font-size:0.62em;vertical-align:sub}
/* Named rather than silent: a key that does nothing reads as broken; one that says what it is reads
   as unfinished, which is the truth. Set by calcPress when a key has no implementation yet. */
/* ⚠ :empty COLLAPSES IT. The note reserved min-height even with nothing in it, so an unwritten
   message showed up as a band of dead padding under the bottom row of keys — reported as exactly
   that. It takes space only when it has something to say. */
.calc-note{margin-top:7px;font-family:'Inter',sans-serif;font-size:8.5px;
  letter-spacing:0.02em;color:var(--muted);text-align:center}
.calc-note:empty{display:none}
/* ~~.calc-key.tall{grid-row:span 2}~~ — nothing spans rows now. C runs across the top three columns
   and the operators sit one per row down the right, so every other key is a single cell. */

/* ⚠ THE STANDALONE VARIANT. On /calculator/ there is no question to drag the panel off, so it sits
   in normal flow instead of fixed and draggable — the drag listeners are simply not wired up there.
   Everything else is byte-identical, which is the whole point: the keypad a student learns here is
   the keypad she meets in the exam room.

   ⚠ position:relative, NEVER static — AND THIS SHIPPED WRONG FOR AN HOUR. #calcModeFlag (DEG, FIX2,
   ENG…) and #calcHistFlag are position:absolute, so they resolve against the nearest POSITIONED
   ancestor. In the shell that is .calc-pop itself, which is fixed. Setting `static` here removed
   the containing block, so the flags climbed the tree and pinned DEG to the corner of the PAGE —
   reported on sight, and invisible to all 520 tests because every value on the screen was correct.
   `relative` takes the panel out of fixed positioning without taking away the containing block. */
/* ⚠ NO SHADOW HERE — STROKES ONLY, at the user's direction. In the shell the drop shadow is what
   lifts the panel off the question card it is floating over; on its own page there is nothing to
   float above, so the shadow is pure decoration and the 1px #b4bec9 frame does the whole job. */
.calc-pop.calc-standalone{position:relative;display:block;margin:0 auto;box-shadow:none}
/* ⚠ THE KEY AND DISPLAY RULES GO A STEP DARKER HERE, AND ONLY HERE. #dde1e6 is right in the shell,
   where the panel sits lifted above a question card and the card behind it supplies the contrast —
   the user confirmed it looks right there. On /calculator/ the panel is the only thing on a white
   page, and at that lightness the keys read as barely separated at all. #ccd2da is one step down,
   still clearly a soft grey and still lighter than the panel's own #b4bec9 frame, so the frame
   stays the strongest line on the panel. Scoped to .calc-standalone so the shell is untouched. */
.calc-pop.calc-standalone .calc-key{border-color:#ccd2da}
.calc-pop.calc-standalone .calc-screen{border-bottom-color:#ccd2da}
/* Nothing to drag it off, so it must not advertise that it can be dragged. */
.calc-pop.calc-standalone .calc-screen{cursor:default}
