/* ═══════════════════════════════════════════════════════════════════════════
   SOFT.CSS - the sidebar and Settings, rebuilt to the shape of the app.

   Home and Mastery settled on one language: a soft canvas, content that lives
   on rounded floating cards, a hairline instead of a rule, and controls that
   answer a press by giving slightly. Two surfaces never got the memo.

     The SIDEBAR was a flat column against a hard 1px right edge, with nav
     items that changed colour on hover and nothing else.

     SETTINGS was worse, and for an instructive reason. Three separate
     redesigns had each had a go at `.set-row`: redesign.css gives every row
     its own full border and a 10px margin (fourteen floating cards down the
     page), styles.css:31378 then tries to group the same rows into ONE panel
     with `:first-of-type` / `:last-child` corner radii and shared separators,
     and redesign.css:555 rounds every row to `--r-card` regardless, which
     beats the grouping. What shipped was neither: a stack of detached cards
     with a section heading floating above each run, no grouping, and a pane
     that scrolled sideways because nothing capped the control column.

   This file settles it, in one place, for both surfaces:

     · A run of rows is ONE panel with hairline separators, not N cards.
       `:has()` finds where each run starts and ends, so the grouping follows
       the markup instead of being re-declared every time a row is added.
     · The control column has a width, so a long label and a wide input can
       never push the pane wider than itself.
     · Everything a student touches is a pill that gives under the press and
       springs back - the vocabulary feel.css already defined and these two
       surfaces never spent.

   Loads after fit.css, before rounded.css. The `!important`s are not
   decoration: the rules above are themselves `!important` across three
   layers, so a plain declaration here would lose to a 2023 override.

   ── MEASURED, AND THIS IS NOT ENOUGH ──────────────────────────────────────

   `!important` does not settle a contest, it moves the contest into
   specificity, and a narrower `!important` selector earlier in the cascade
   still wins. `scripts/skin_audit.py` removes each declaration from the live
   CSSOM and reads the screen before and after, across three widths, both
   themes and sixteen views. Of 281 declarations in the four skin sheets,
   132 reach the screen, 71 are redundant, and SEVENTEEN lose - every one of
   them in this file, and twelve of those carry `!important`:

     .nav-item and friends      asks 999px, screen draws 26px
                                asks 10px 14px padding, screen draws 5px 12px
     .settings-tab              asks 999px, screen draws 26px
     .settings-easy             asks 999px, screen draws 20px
     .account-card              asks 26px, screen draws 20px
                                asks 10px 12px padding, screen draws 8px 9px
     .hw-meter / .nav-count …   asks 999px, screen draws 12px
     .set-row:last-child        asks square top corners, screen rounds all four
     .set-section-title         asks uppercase + 0.04em, screen draws neither
     six `transition` shorthands, every one replaced by a 200ms one

   None of these is a broken screen: 26px on a 38px-tall nav item clamps to a
   pill anyway, and sentence-case section headings read better than tracked
   uppercase. They are listed because the file currently reads as though it
   decides these things and it does not, and the next person to change a
   radius here will change nothing and not know it.

   Run the audit before editing this file, and again after:

       .venv/bin/python scripts/skin_audit.py --sheets soft.css

   The instrument has its own calibration in the gate
   (tests/browser_skin_audit_calibration.py) because an audit that says "this
   rule is dead" has to be right - the deletion it invites is the bug.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · Where the values live ───────────────────────────────────────────────
   `--soft-panel`, `--soft-row`, `--soft-control`, `--soft-press` and
   `--soft-rail-w` are declared in redesign.css, beside the radius ladder they
   extend. This sheet spends them and mints nothing, for
   the same reason rounded.css does: shape has one source, and
   tests/test_beta_redesign.py holds that line. */


/* ═══════════════════════════════════════════════════════════════════════════
   2 · THE SIDEBAR

   Round and squishy: the nav items are pills, the whole column floats on the
   canvas instead of being welded to it by a 1px rule, and every item answers
   a press.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Stated at `body[data-theme]` specificity because styles.css:10310 and
   dashboard.css:88 both paint this element with `!important` at (0,2,1); a
   bare `.sidebar` loses to them however many bangs it carries, and the panel
   below would be an outline drawn on top of a column that is still painted. */
.sidebar,
html[data-theme] .sidebar,
body[data-theme] .sidebar {
  /* The hard right edge goes. A column that ends in a hairline reads as a
     frame; one that ends in a gap reads as a panel resting on the page -
     which is the same thing every card in the app already does. */
  border-right: 0 !important;
  background: transparent !important;
  padding: var(--s-3) !important;
  gap: var(--s-2) !important;
}

/* The panel is a child of the column rather than the column itself, so the
   scrollbar still belongs to the list and the rounded corners are not cut off
   by the viewport. */
.sidebar::before {
  content: "";
  position: absolute;
  inset: var(--s-2) 0 var(--s-2) var(--s-2);
  z-index: -1;
  border-radius: var(--soft-panel);
  background: var(--bg-sidebar);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm, 0 1px 2px rgb(31 41 36 / 0.04));
  pointer-events: none;
}
/* This has to stay above the drawer breakpoint. soft.css loads AFTER
   styles.css, so an unconditional `position: relative` here beat
   styles.css's `@media (max-width: 900px) { .sidebar { position: fixed } }`
   and the off-canvas drawer stopped being taken out of flow. It was still
   translated sideways (x = -264) so nobody saw a sidebar - but it kept its
   row in #app-shell's grid, and that row pushed the whole app down.
   Measured on the seeded app: main-content started at y=508 at 768x1024,
   y=552 at 834x1112, y=508 at 900x1024 - half an iPad screen, blank, on
   every view. Correct at 760 and below (the phone path) and at 901 and above,
   so the broken band was exactly 761-900px: tablet portrait.
   `isolation: isolate` rides along because it is only needed where the
   sidebar actually paints in flow. */
@media (min-width: 901px) {
  .sidebar { position: relative; isolation: isolate; }
}

/* ── composing with blend.css ────────────────────────────────────────────────
   blend.css (loaded after this sheet) exists so the sidebar's two sticky caps
   - the brand row and the search + account block - stop painting a white
   rectangle on a pale-green column. It solves that by painting them
   `--bg-sidebar` and EXTENDING each one past its own edge (`bottom: 100%` on
   the brand, `top: 100%` on the footer) to cover the sidebar's padding.

   That is exactly right for a full-height column and exactly wrong for a
   panel: the extension paints over the rounded top and bottom the panel just
   drew, and what is left is a square-topped column with a stray curved
   hairline down its left side.

   The extensions are not needed here at all - the panel behind them (the
   `::before` above) already paints that padding in the same colour - so they
   go, and the caps take the panel's corners instead. blend.css's argument is
   kept: the caps still paint the column's own fill, so there is still no
   rectangle and still no seam. */
.sidebar > .brand::before,
.sidebar > .sidebar-footer::after { display: none !important; }

.sidebar > .brand {
  border-radius: var(--soft-panel) var(--soft-panel) 0 0 !important;
}
.sidebar > .sidebar-footer {
  border-radius: 0 0 var(--soft-panel) var(--soft-panel) !important;
}

/* The brand no longer needs a rule under it: the gap does that job, and a
   full-width hairline inside a rounded panel is the one edge that cannot
   follow the corner. */
.brand {
  border-bottom: 0 !important;
  padding: var(--s-2) var(--s-2) var(--s-3) !important;
}

/* ── nav items ── */
.nav-item,
.sidebar-customize,
.nav-more-toggle,
.footer-search {
  border-radius: var(--soft-control) !important;
  padding: 10px 14px !important;
  transition: background 160ms var(--ease-out, ease),
              color 160ms var(--ease-out, ease),
              transform var(--press-out, 380ms) var(--ease-settle, ease) !important;
}

.nav-item:active,
.sidebar-customize:active,
.nav-more-toggle:active,
.footer-search:active,
.account-card:active {
  transform: scale(var(--soft-press));
  transition-duration: var(--press-in, 90ms);
  transition-timing-function: var(--ease-press, ease);
}

/* The active item is a filled pill, not a colour change plus a 2px tick in
   the gutter. A pill is legible at a glance and it is the same shape as the
   thing the student just tapped. */
.nav-item.active {
  background: var(--accent-soft) !important;
  color: var(--text) !important;
  font-weight: 600 !important;
}
/* styles.css:2496 paints a hairline indicator in the left gutter. Inside a
   pill it lands on the fill and reads as a scratch. */
.nav-item::before { display: none !important; }

.nav-item:hover:not(.active) {
  background: rgb(var(--accent-rgb) / 0.06) !important;
}

/* ── the account card at the foot ── */
.account-card {
  border-radius: var(--soft-panel) !important;
  padding: 10px 12px !important;
  border: 1px solid var(--border) !important;
  background: var(--bg-elev-1) !important;
  transition: background 160ms var(--ease-out, ease),
              border-color 160ms var(--ease-out, ease),
              transform var(--press-out, 380ms) var(--ease-settle, ease) !important;
}
.account-card:hover { border-color: var(--border-strong) !important; }

.account-popover { border-radius: var(--soft-panel) !important; }
.account-popover button,
.account-popover a { border-radius: var(--soft-control) !important; }

/* The dividers between sidebar sections. A rule that touches both walls of a
   rounded panel is the one straight line the eye finds; inset and softened,
   it reads as a break instead. */
.nav-more-rule,
.sidebar-section + .sidebar-section { border-top-color: transparent !important; }

.sidebar-header span {
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 10.5px;
  font-weight: 650;
}

/* Recents and pinned rows are list items, so they get the row radius rather
   than a full pill - a pill around a two-line preview is a lozenge. */
.recent-chat-item,
.project-item { border-radius: var(--soft-row) !important; }

/* The rail (collapsed sidebar) is all circles: at 72px wide there is no room
   for a label, so every item is its icon and the icon's target should look
   like what it is. */
.sidebar.rail .nav-item,
.sidebar[data-rail="true"] .nav-item { border-radius: 50% !important; }


/* ═══════════════════════════════════════════════════════════════════════════
   3 · SETTINGS

   The pane is a column of GROUPED panels: a section heading, then the rows it
   names welded into one rounded surface. That is how Home reads, and it is
   the thing the three previous passes were each reaching for.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the rail ── */
body[data-view="settings"] .settings-shell {
  gap: var(--s-3);
  padding: var(--s-3);
  background: var(--bg) !important;
}

body[data-view="settings"] .settings-tabs {
  border-right: 0 !important;
  border-radius: var(--soft-panel) !important;
  background: var(--bg-sidebar) !important;
  border: 1px solid var(--border) !important;
  padding: var(--s-3) var(--s-3) var(--s-4) !important;
  gap: 2px !important;
}

/* A rail is only a rail where there is room for one.
   `grid-template-columns` and the sideways-scroll lock used to sit out here
   with no media query. This sheet loads after styles.css and redesign.css at
   the same specificity, so those two declarations quietly beat every phone
   rule the app had already written - four of them, at styles.css:31524,
   :31637, :31870 and redesign.css:1635, each asking for a single column.
   A 248px rail stayed on a 390px phone, leaving 66px of readable pane inside
   a shell with `overflow: hidden`, so nothing could scroll to recover it.
   The heading rendered as "Genera" and body copy wrapped two words to a line.
   Gating them at the same 760px breakpoint the rest of the app uses hands the
   phone layout back to the rules that were always meant to own it. */
@media (min-width: 761px) {
  body[data-view="settings"] .settings-shell {
    grid-template-columns: var(--soft-rail-w) minmax(0, 1fr) !important;
  }
  body[data-view="settings"] .settings-tabs {
    /* The rail scrolled SIDEWAYS - 69px of it, measured - because the tab
       labels would not wrap and nothing said they could. A rail is a vertical
       list; there is nothing to its right to reach. Below 761px the tabs are
       a horizontal strip instead, where scrolling sideways is the point. */
    overflow-x: hidden !important;
  }
}

body[data-view="settings"] .settings-tab {
  border-radius: var(--soft-control) !important;
  padding: 9px 14px !important;
  /* The 10.5px uppercase-tracked treatment from an older pass reads as a
     legend, not a destination. These are the nine places a student can go. */
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--text-muted) !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background 160ms var(--ease-out, ease),
              color 160ms var(--ease-out, ease),
              transform var(--press-out, 380ms) var(--ease-settle, ease) !important;
}
body[data-view="settings"] .settings-tab:hover {
  background: rgb(var(--accent-rgb) / 0.06) !important;
  color: var(--text) !important;
}
body[data-view="settings"] .settings-tab.active {
  background: var(--accent-soft) !important;
  color: var(--text) !important;
  font-weight: 600 !important;
  box-shadow: none !important;
}
body[data-view="settings"] .settings-tab:active { transform: scale(var(--soft-press)); }
/* The glowing 3px bar in the gutter belonged to the flat list. Inside a
   filled pill it is a smear on the fill. */
body[data-view="settings"] .settings-tab.active::before { display: none !important; }

body[data-view="settings"] .settings-tabs-divider {
  font-size: 10px !important;
  letter-spacing: 0.1em !important;
  opacity: 1 !important;
  color: var(--text-dim) !important;
  padding: var(--s-4) 14px var(--s-1) !important;
  border-top: 0 !important;
  margin-top: 0 !important;
}
body[data-view="settings"] .settings-tabs-divider.first { padding-top: var(--s-2) !important; }

body[data-view="settings"] .settings-back,
body[data-view="settings"] .settings-search {
  border-radius: var(--soft-control) !important;
}
body[data-view="settings"] .settings-back {
  padding: 8px 14px !important;
  background: var(--bg-elev-2) !important;
  border: 1px solid transparent !important;
  margin-bottom: var(--s-2);
}
body[data-view="settings"] .settings-back:hover { border-color: var(--border-strong) !important; }

/* Sign out / reset / delete. They were three lines of bare text under a
   hairline, which is how an unfinished page looks. They are controls; they
   get the shape of one. */
.settings-tabs .settings-easy {
  border-radius: var(--soft-control) !important;
  padding: 9px 14px !important;
  font-size: 13px !important;
  transform: none !important;
  transition: background 160ms var(--ease-out, ease), color 160ms var(--ease-out, ease) !important;
}
.settings-tabs .settings-easy:hover {
  background: rgb(var(--accent-rgb) / 0.07) !important;
  color: var(--text) !important;
  transform: none !important;
}
.settings-tabs .settings-easy-danger:hover {
  background: rgb(var(--danger-rgb) / 0.10) !important;
  color: var(--danger) !important;
  box-shadow: none !important;
}
.settings-tabs .settings-easy-rule {
  border: 0 !important;
  height: 1px;
  background: var(--border);
  margin: var(--s-3) 14px !important;
}
/* The block reads as a footnote, not as three controls, because nothing under
   it has an edge until you hover. A quiet inset surface says "these three
   belong together and they are not navigation". */
.settings-tabs .settings-easy-block {
  margin-top: auto;
  padding-top: var(--s-2);
}
.settings-tabs .settings-easy-holds { gap: 2px !important; }

/* ── the pane ── */
body[data-view="settings"] .settings-pane {
  padding: var(--s-6) clamp(var(--s-5), 4vw, 56px) 64px !important;
  /* Both axes, because the pane was scrolling sideways by up to 373px: a row
     whose label and control together wanted more width than the pane had, and
     a grid that would rather be wide than wrap. */
  overflow-x: hidden !important;
}
body[data-view="settings"] .settings-tab-content { max-width: 780px !important; }
body[data-view="settings"] .settings-tab-content::before {
  font-size: 26px !important;
  font-weight: 600 !important;
  letter-spacing: -0.02em;
  margin-bottom: var(--s-5) !important;
}

/* ── a run of rows is one panel ──────────────────────────────────────────────
   Every `.set-row` gets the shared surface and a separator above it. The run's
   first and last rows round their outer corners and drop the separator.

   `:has()` is what makes this follow the markup: "a row that is NOT preceded
   by a row" opens a run and "a row not followed by a row" closes it, however
   the tab is ordered and however many rows a future tab adds. The plain-
   sibling fallback under it covers the first and last row of the tab, which
   is the common case, so a browser without `:has()` still gets a panel with
   correctly rounded ends rather than a stack of squares. */
body[data-view="settings"] .set-row {
  margin: 0 !important;
  padding: 14px var(--s-5) !important;
  min-height: 56px;
  gap: var(--s-5) !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  border-top-width: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transition: background 160ms var(--ease-out, ease) !important;
}
body[data-view="settings"] .set-row:hover { background: var(--bg-elev-1) !important; }

/* run opens */
body[data-view="settings"] .set-row:first-child,
body[data-view="settings"] *:not(.set-row) + .set-row {
  border-top-width: 1px !important;
  border-radius: var(--soft-panel) var(--soft-panel) 0 0 !important;
  margin-top: var(--s-3) !important;
}
/* run closes */
body[data-view="settings"] .set-row:last-child {
  border-radius: 0 0 var(--soft-panel) var(--soft-panel) !important;
}
@supports selector(:has(*)) {
  body[data-view="settings"] .set-row:has(+ *:not(.set-row)) {
    border-radius: 0 0 var(--soft-panel) var(--soft-panel) !important;
  }
  /* A run of exactly one row is a panel on its own, so it rounds both ends. */
  body[data-view="settings"] *:not(.set-row) + .set-row:has(+ *:not(.set-row)),
  body[data-view="settings"] .set-row:first-child:has(+ *:not(.set-row)) {
    border-radius: var(--soft-panel) !important;
  }
  body[data-view="settings"] .set-row:last-child:not(.set-row + .set-row) {
    border-radius: var(--soft-panel) !important;
  }
}

/* The section heading names the panel under it, so it sits on the canvas
   rather than on a rule of its own. */
body[data-view="settings"] .set-section-title {
  margin: var(--s-6) 0 var(--s-2) !important;
  padding: 0 var(--s-2) !important;
  border: 0 !important;
  font-size: 13px !important;
  font-weight: 650 !important;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim) !important;
}
body[data-view="settings"] .set-section-title:first-child { margin-top: 0 !important; }

/* ── the control column ──────────────────────────────────────────────────────
   The pane scrolled sideways because a row was a flex with two children that
   both wanted to be wide. Naming a width for the control - and letting the
   label take whatever is left - is what stops that, and it also lines every
   control on the page up with the one above it, which was the other thing
   wrong with this page. */
body[data-view="settings"] .set-row > :first-child { min-width: 0; flex: 1 1 auto; }
/* The control keeps its 300px and the label gives way: with both allowed to
   shrink, a row with a long explanation ("Classes that are hard") took a
   pixel from its input, and General's two textareas sat 49px left of and
   35px right of the column (349 and 265 wide). A phone stacks the row and
   lets the control fill it (phone.css). */
body[data-view="settings"] .set-input,
body[data-view="settings"] .set-readonly,
body[data-view="settings"] select.set-input {
  flex: 0 0 300px !important;
  max-width: 300px !important;
  min-width: 0 !important;
  min-height: 42px;
  border-radius: 16px !important;
  background: var(--bg-elev-2) !important;
  border: 1px solid var(--border) !important;
  box-shadow: none !important;
}
body[data-view="settings"] .set-textarea {
  flex: 0 0 300px !important;
  max-width: 300px !important;
  min-width: 0 !important;
  border-radius: 18px !important;
  /* the browser's grip in the corner was the one native mark on the page */
  resize: none !important;
}
body[data-view="settings"] .set-row.tall .set-textarea { min-width: 0 !important; }

body[data-view="settings"] .set-input:focus,
body[data-view="settings"] .set-textarea:focus {
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / 0.18) !important;
}

/* A button in a row keeps its label on one line and its shape a pill - and,
   crucially, does not shrink below the label. "Sign out" was rendering 11px
   narrower than the word inside it. */
body[data-view="settings"] .set-row > .ghost-btn,
body[data-view="settings"] .set-row > .primary-btn,
body[data-view="settings"] .set-row .hold-confirm-btn,
body[data-view="settings"] .set-callout .ghost-btn,
/* The signed-in-devices list is its own row type and was missed by the
   `.set-row` rules above, so its "Sign out" rendered 73px wide around a 72px
   label with 24px of padding - the word was cut off at BOTH ends. */
body[data-view="settings"] .set-session-row .ghost-btn,
body[data-view="settings"] .set-session-row .danger-btn,
body[data-view="settings"] .set-session-row .primary-btn {
  flex: 0 0 auto !important;
  width: auto !important;
  min-width: max-content !important;
  white-space: nowrap !important;
  border-radius: var(--soft-control) !important;
  padding: 9px 18px !important;
}

/* ── the callout at the top of a tab ── */
body[data-view="settings"] .set-callout {
  border-radius: var(--soft-panel) !important;
  padding: var(--s-4) var(--s-5) !important;
  margin-bottom: var(--s-4) !important;
  gap: var(--s-4);
  border-left-width: 1px !important;
  padding-left: var(--s-5) !important;
  background: rgb(var(--accent-rgb) / 0.05) !important;
  border-color: rgb(var(--accent-rgb) / 0.18) !important;
}
/* styles.css:15116 draws a 2px accent bar at `left: 0` - which is ON the
   callout's own rounded border, so at both ends the bar cuts across the curve
   and reads as the sharpest corner on the page. The tint above says the same
   thing ("this one is different") across the whole surface, with no edge. */
body[data-view="settings"] .set-callout::before { display: none !important; }

/* Data controls: a destructive group reads as one panel, softly tinted, not
   as a red box with square corners. */
body[data-view="settings"] .set-data-controls {
  border-radius: var(--soft-panel) !important;
  padding: var(--s-4) !important;
  background: rgb(var(--danger-rgb) / 0.04) !important;
  border-color: rgb(var(--danger-rgb) / 0.20) !important;
}


/* ═══════════════════════════════════════════════════════════════════════════
   4 · THE SHARP EDGES THE SHAPE LAYER COULD NOT REACH

   rounded.css rounds anything that declared a radius of its own or matches
   one of its name patterns. These are the ones that do neither: they paint a
   band, a rule or a tint with no box at all, so there was nothing to round -
   the corner came from the paint itself.
   ═══════════════════════════════════════════════════════════════════════════ */

/* A dashed hairline is a sharp edge repeated forty times. Every empty state in
   the app wore one. Softened to a tinted surface with a solid hairline: still
   reads as "nothing here yet", with no corners and no dotted noise. */
.dash-empty,
.hub-empty-mini,
.hub-empty-mini.dash-empty {
  border-style: solid !important;
  border-color: transparent !important;
  background: var(--bg-elev-2) !important;
  border-radius: var(--dash-radius-md, 24px) !important;
}
.dash-empty button,
.hub-empty-mini button { border-radius: 999px !important; }

/* "CURRENT PLAN" on the billing tab. It is a `::before` on `.plan-hero`, and
   styles.css:10355 gives it an opaque `--bg-elev-1` fill so the label does not
   sit on the hero's border. It has no padding and no radius, so that fill is a
   bare white rectangle with four right angles printed across a tinted
   gradient - the sharpest edge in Settings, and the one the eye lands on
   first because it is at the top of the page.

   The hero already reserves 30px of top padding for the label (styles.css:5704),
   so there is no border to hide from: the fill has nothing to do. */
/* Stated at the specificity of the rule it is correcting: styles.css:13285 is
   `body[data-theme="light"][data-view="settings"] .plan-hero::before`, and a
   bare `.plan-hero::before` loses to it even carrying `!important`. */
.plan-hero::before,
body[data-theme] .plan-hero::before,
body[data-theme][data-view="settings"] .plan-hero::before {
  background: transparent !important;
  border-radius: 999px !important;
  padding-inline: 0 !important;
}
.plan-kicker,
.set-kicker,
[class*="-kicker"] {
  border-radius: 999px !important;
  padding-inline: 8px;
}

/* Anything the app paints as a strip: a progress track, a fill, a rule that
   stands in for a divider. */
.hw-meter, .hw-meter > i,
.trial-banner,
.ai-status-pill,
.nav-count,
.nav-kbd { border-radius: 999px !important; }

/* Selection and focus. A square focus ring on a pill is the corner the user
   sees most often, because it only appears when they are looking at it.

   This used to read `:focus-visible { border-radius: inherit; }`, which does
   not shape the RING - it reshapes the ELEMENT, to whatever its parent
   happens to be. Measured in the browser, 18 controls changed shape the
   moment they took focus: a Home widget went 26px to 18px, a dashboard button
   0px to 4px. A card that changes its corners when you tab to it reads as
   broken, and it only ever does it while the student is looking straight at
   it.

   Nothing is needed in its place. Chromium and Safari already draw `outline`
   following the element's own border-radius, so a pill gets a pill-shaped
   ring for free. The extension hit this first and removed the same line -
   see the note at extension/sidepanel.css:198. */

/* Native controls the shape layer lists but the settings overrides re-square
   with `!important`. */
body[data-view="settings"] :where(input, select, textarea) {
  border-radius: 16px !important;
}
body[data-view="settings"] :where(input[type="checkbox"], input[type="radio"]) {
  border-radius: 50% !important;
}


/* ═══════════════════════════════════════════════════════════════════════════
   5 · THE CORNER BELONGS TO THE PAGE

   Lumi's badge used to rest 24px from the top-right of the VIEWPORT, the same
   corner as every header's main action and Home's right-aligned date, so this
   section spent a 104px lane on both to keep them out from under it. The cost
   was that "+ New session", "+ Add assignment" and every button like them sat
   a lane short of the corner - and kept sitting there when the student had
   dragged the badge somewhere else, or it was hidden, because the lane never
   asked whether the badge was actually there.

   The badge now rests bottom-right at every width (lumi.css), and lumi.js
   keeps a dragged position below the header, so nothing floats in this corner
   and there is no lane to reserve. The header's own `--gutter` is the only
   inset its actions carry.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 901px) {
  /* The date should never be the thing that gives. */
  .dash-hero-top .dash-date { flex: 0 0 auto; white-space: nowrap; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   6 · DASHED FRAMES

   A dashed hairline is the drawing convention for "not real yet" - a
   wireframe, a drop target, a placeholder. Aluma spends it on forty-odd boxes
   that ARE real: Mastery's empty state, the billing toggle, the trial banner,
   the plan-your-week card. The result is a finished product that looks like a
   mockup of itself, and at a 1px dash on a rounded corner the dashes break
   the curve into a row of ticks - which is where "sharp edges" comes from on
   a page with no square corners in it.

   Softened to a solid hairline over a tinted surface. Same message ("this is
   an empty or optional thing"), stated with colour rather than with a broken
   line, and the corner stays a corner.

   NOT touched, because the convention is doing real work there:
     · The Home board's drop slot and resize ghost (home-widgets.css:699/716).
       They mark where a tile you are DRAGGING will land - the definition of
       provisional.
     · The calendar's planned-work column and its "planned" rules
       (calendar.css:274/612). Dashed is what separates planned from
       scheduled, and that distinction is the column's whole point.
   ═══════════════════════════════════════════════════════════════════════════ */

.learn-empty,
.trial-banner,
.billing-toggle,
.plan-current,
.tp-mode-card.tp-mode-more,
.tp-custom-class-other,
.set-ai-connect {
  border-style: solid !important;
  border-color: var(--border) !important;
}

/* Where the frame carried the whole message on its own, the tint has to take
   over or the box disappears into the page. */
.learn-empty {
  background: var(--bg-elev-1) !important;
  border-radius: var(--r-card, 26px) !important;
}
.trial-banner,
.billing-toggle {
  border-color: rgb(var(--accent-rgb) / 0.20) !important;
  background: rgb(var(--accent-rgb) / 0.05) !important;
}

/* The sidebar's own dashed rules (styles.css:5034/5061/5212) draw a broken
   line across a panel that now has rounded ends, so the dashes run straight
   off the curve. Section 2 already removed the ones between sections; these
   are the two left.

   Stated as a whole border, not as `border-style`. A bare
   `border-top-style: solid` on an element with no top border MATERIALISES
   one at the initial width and colour - `medium` and `currentColor` - which
   on `.brand` drew a 3px near-black line across the top of the panel. */
/* `.brand` keeps the no-border decision section 2 made - a full-width
   hairline is the one edge that cannot follow a rounded corner - so here it
   only has to lose the dashes it would otherwise still be drawing. */
.brand { border: 0 !important; }
.nav-more-rule { border-top: 1px solid var(--border) !important; border-bottom: 0 !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   7 · THE QUIET TABS OF SETTINGS

   Sections 3 and 4 settled the shell and the ordinary row. What they did not
   reach were the tabs nobody opens twice - Usage, Billing, the device list,
   Privacy's data controls - and each of those was still wearing a costume
   from an earlier pass: values in the terminal-era mono, a usage grid with
   fixed 220px and 84px columns that crushed its own bar to 2px on a phone
   and pushed the percentage 16px into the gutter, rows ruled off with a
   bottom border that curls into a smile at a 22px radius, and a device list
   that was the one stack of rows on the page not drawn as a panel.

   One vocabulary for all of them, the same one section 3 uses: a run of rows
   is a panel with hairline separators, a value is set in the app's sans with
   tabular figures, and a separator inside a rounded box is either a full
   border on every side of the row or no border at all.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── hidden rows never decide where a run starts or ends ─────────────────────
   Several rows ship with `style="display:none"` and are switched on by app.js
   (the API key card in General, Memory's import status and clear rows). The
   run logic above reads siblings, and a hidden sibling is still a sibling: in
   General the "Full name" row opened its run behind a hidden row and drew no
   top edge, and Memory's only visible row never closed its panel. These read
   THROUGH up to two hidden rows. Longhands, so a run of one visible row keeps
   the top corners from the opener and the bottom ones from the closer. */
body[data-view="settings"] :not(.set-row) + .set-row:is([style*="display:none"], [style*="display: none"]) + .set-row,
body[data-view="settings"] :not(.set-row) + .set-row:is([style*="display:none"], [style*="display: none"]) + .set-row:is([style*="display:none"], [style*="display: none"]) + .set-row,
body[data-view="settings"] .set-row:first-child:is([style*="display:none"], [style*="display: none"]) + .set-row {
  border-top-width: 1px !important;
  border-top-left-radius: var(--soft-panel) !important;
  border-top-right-radius: var(--soft-panel) !important;
  margin-top: var(--s-3) !important;
}
@supports selector(:has(*)) {
  body[data-view="settings"] .set-row:has(+ .set-row:is([style*="display:none"], [style*="display: none"]):last-child),
  body[data-view="settings"] .set-row:has(+ .set-row:is([style*="display:none"], [style*="display: none"]) + .set-row:is([style*="display:none"], [style*="display: none"]):last-child),
  body[data-view="settings"] .set-row:has(+ .set-row:is([style*="display:none"], [style*="display: none"]) + :not(.set-row)),
  body[data-view="settings"] .set-row:has(+ .set-row:is([style*="display:none"], [style*="display: none"]) + .set-row:is([style*="display:none"], [style*="display: none"]) + :not(.set-row)) {
    border-bottom-left-radius: var(--soft-panel) !important;
    border-bottom-right-radius: var(--soft-panel) !important;
  }
}

/* ── values are words, not terminal output ───────────────────────────────────
   Email, dates, the user id, the privacy answers ("On your device") and the
   version were Geist Mono at 13px beside 13px sans labels - the one place in
   the app where a sentence and its answer were in two different typefaces.
   Tabular figures keep the dates and the id lined up, which is the only thing
   the mono was ever doing for them. The two keyboard shortcuts on the Lumi
   Anywhere tab keep theirs: a key cap is the one value here that IS
   something you type. */
body[data-view="settings"] .set-readonly:not(.mono),
body[data-view="settings"] #set-uid {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  letter-spacing: 0 !important;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary) !important;
  overflow-wrap: anywhere;
}

/* Links. A ghost or primary pill that is an <a> inherited the page's link
   underline, so "Install free", "Privacy" and "Terms" were underlined words
   inside a pill. Prose links read as accent words, the way Home's "All
   classes" does. */
body[data-view="settings"] :is(a.ghost-btn, a.primary-btn) { text-decoration: none !important; }
body[data-view="settings"] :is(.set-sub, .set-callout, .set-hint) a:not(.ghost-btn):not(.primary-btn) {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 0 !important;   /* an older pass drew the underline as a border */
}
body[data-view="settings"] :is(.set-sub, .set-callout, .set-hint) a:not(.ghost-btn):not(.primary-btn):hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* An off switch in dark was a grey knob on a near-black track - you had to
   know it was a switch. The track takes the raised surface and the knob the
   secondary ink, so "off" still reads as a control, just a quiet one. */
html[data-theme="dark"] body[data-view="settings"] .set-toggle:not(.on),
body[data-theme="dark"][data-view="settings"] .set-toggle:not(.on) {
  background: var(--bg-elev-4) !important;
}
html[data-theme="dark"] body[data-view="settings"] .set-toggle:not(.on) .seg-knob,
body[data-theme="dark"][data-view="settings"] .set-toggle:not(.on) .seg-knob {
  background: var(--text-secondary) !important;
}

/* ── Usage ───────────────────────────────────────────────────────────────── */
body[data-view="settings"] .usage-row {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr) minmax(96px, 2fr) auto !important;
  gap: var(--s-4) !important;
  align-items: center;
  padding: 14px var(--s-5) !important;
  min-height: 56px;
  margin: 0 !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  border-top-width: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}
/* run opens / closes - the same reading section 3 does for `.set-row` */
body[data-view="settings"] .usage-row:first-child,
body[data-view="settings"] :not(.usage-row) + .usage-row {
  border-top-width: 1px !important;
  border-top-left-radius: var(--soft-panel) !important;
  border-top-right-radius: var(--soft-panel) !important;
  margin-top: var(--s-3) !important;
}
body[data-view="settings"] .usage-row:last-child {
  border-bottom-left-radius: var(--soft-panel) !important;
  border-bottom-right-radius: var(--soft-panel) !important;
}
@supports selector(:has(*)) {
  body[data-view="settings"] .usage-row:has(+ :not(.usage-row)) {
    border-bottom-left-radius: var(--soft-panel) !important;
    border-bottom-right-radius: var(--soft-panel) !important;
  }
  /* Refresh is an action under the panel, not a row of it. It sat in a grid
     cell and was stretched to 220px around a 60px word. */
  body[data-view="settings"] .usage-row:has(#usage-refresh) {
    display: flex !important;
    background: none !important;
    border: 0 !important;
    min-height: 0;
    padding: var(--s-4) 0 0 !important;
    margin-top: 0 !important;
  }
  /* "Today 15% used" over "Messages today 6 of 40" said the same thing on
     two rows and left the second one's right half empty. app.js writes the
     count into the first row ("6 of 40 messages"), which keeps its bar and
     its %, and the second row steps out. It stays in the markup, ids and
     all, because it is still filled. */
  body[data-view="settings"] .usage-row:has(#usage-count-label) { display: none !important; }
  body[data-view="settings"] .usage-row:has(#usage-fill-today) {
    border-top-width: 1px !important;
    border-radius: var(--soft-panel) !important;
  }
}
body[data-view="settings"] #usage-refresh {
  width: auto !important;
  flex: 0 0 auto !important;
  padding: 9px 18px !important;
}
body[data-view="settings"] :is(.usage-label, .usage-sub, .usage-sub .dim, .usage-pct) {
  font-family: var(--font-sans) !important;
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-variant-numeric: tabular-nums;
}
body[data-view="settings"] .usage-label { font-size: 13px !important; font-weight: 500 !important; color: var(--text) !important; }
body[data-view="settings"] .usage-sub { font-size: 11.5px !important; color: var(--text-dim) !important; margin-top: 3px; }
body[data-view="settings"] .usage-pct {
  font-size: 12px !important;
  font-weight: 650 !important;
  color: var(--text-secondary) !important;
  text-align: right;
  white-space: nowrap;
}
body[data-view="settings"] .usage-bar {
  height: 8px !important;
  min-width: 0;
  border: 0 !important;
  border-radius: 999px !important;
  background: rgb(var(--accent-rgb) / 0.12) !important;
  box-shadow: none !important;
  overflow: hidden;
}
body[data-view="settings"] .usage-fill {
  border-radius: 999px !important;
  background: var(--accent) !important;
  box-shadow: none !important;
}
/* The plan name beside the heading is a quiet chip, not loose grey text. */
body[data-view="settings"] #usage-plan-name {
  display: inline-flex;
  align-items: center;
  margin-left: var(--s-2);
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--text);
  font-size: 12px;
  font-weight: 650;
  vertical-align: 1px;
}
body[data-view="settings"] #usage-plan-name:empty { display: none; }

/* ── Billing ─────────────────────────────────────────────────────────────── */
body[data-view="settings"] .plan-hero {
  border-radius: var(--soft-panel) !important;
  padding: 34px var(--s-5) var(--s-5) !important;
  gap: var(--s-4);
}
body[data-theme][data-view="settings"] .plan-hero::before {
  content: "Current plan" !important;
  font-family: var(--font-sans) !important;
  font-size: 12px !important;
  font-weight: 650 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--text-secondary) !important;
  opacity: 1 !important;
  top: 14px !important;
  left: var(--s-5) !important;
}
/* "Adjust plan" was the old deep-blue fill with white ink in both themes -
   in dark, a mid-teal pill unlike every other primary. It is the primary. */
body[data-theme][data-view="settings"] .plan-hero .primary-btn {
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
}
body[data-view="settings"] .plan-hero-sub {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  letter-spacing: 0 !important;
  color: var(--text-secondary) !important;
}
body[data-view="settings"] .referral-link-wrap input,
body[data-view="settings"] #referral-link {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  letter-spacing: 0 !important;
  border-radius: var(--r-field) !important;
  min-height: 42px;
  min-width: 0;
  padding: 0 14px !important;
}
/* Payment method is a label and a sentence, not a two-column row: every
   other row stacks its explanation under its label. */
body[data-view="settings"] #set-payment-row {
  flex-direction: column !important;
  align-items: flex-start !important;
  justify-content: center;
  gap: 3px !important;
}
/* In a column the label's `flex: 1 1 auto` (section 3) grows it DOWN. */
body[data-view="settings"] #set-payment-row > * { flex: 0 0 auto !important; margin: 0 !important; }

/* ── Account: the signed-in devices are a panel like every other run ────── */
body[data-view="settings"] .set-sessions-list { gap: 0 !important; margin: var(--s-3) 0 var(--s-2) !important; }
body[data-view="settings"] .set-session-row {
  padding: 12px var(--s-5) !important;
  min-height: 56px;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  border-top-width: 0 !important;
  border-radius: 0 !important;
}
body[data-view="settings"] .set-session-row:first-child {
  border-top-width: 1px !important;
  border-top-left-radius: var(--soft-panel) !important;
  border-top-right-radius: var(--soft-panel) !important;
}
body[data-view="settings"] .set-session-row:last-child {
  border-bottom-left-radius: var(--soft-panel) !important;
  border-bottom-right-radius: var(--soft-panel) !important;
}
body[data-view="settings"] .set-sessions-empty {
  padding: var(--s-4) var(--s-5) !important;
  border-radius: var(--soft-panel);
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  font-size: 13px !important;
}
/* "This device" in dark was deep teal on a 28% wash over the dark surface:
   about 1.8:1. The accent on its own soft fill is the app's chip. */
html[data-theme="dark"] .set-session-badge,
body[data-theme="dark"] .set-session-badge {
  color: var(--accent) !important;
  background: var(--accent-soft) !important;
}
.set-session-badge { font-weight: 650 !important; padding: 2px 9px !important; }

/* ── Privacy: data controls are one run, not a panel inside a panel ──────── */
body[data-view="settings"] .set-data-controls {
  padding: 0 !important;
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
}
body[data-view="settings"] .set-data-controls .set-section-title { color: var(--danger) !important; }
body[data-view="settings"] .set-data-controls .set-row.danger {
  background: rgb(var(--danger-rgb) / 0.04) !important;
  border-color: rgb(var(--danger-rgb) / 0.20) !important;
}

/* Reset and Delete share one row (one hold-row, two hold buttons). The row
   centred both buttons side by side against both labels stacked, so neither
   button sat beside the thing it does. The two wrappers step aside
   (`display: contents`) and each button takes the line of its own label:
   the markup and its order are untouched. */
body[data-view="settings"] .set-row.set-row-holds {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--s-5);
  row-gap: var(--s-5);
  align-items: center !important;
  padding-block: var(--s-4) !important;
}
body[data-view="settings"] .set-row-holds > :is(.set-hold-copy, .set-hold-actions) { display: contents !important; }
body[data-view="settings"] .set-row-holds .set-hold-copy > :nth-child(1) { grid-area: 1 / 1; }
body[data-view="settings"] .set-row-holds .set-hold-copy > :nth-child(2) { grid-area: 2 / 1; }
body[data-view="settings"] .set-row-holds .set-hold-actions > :nth-child(1) { grid-area: 1 / 2; justify-self: stretch; }
body[data-view="settings"] .set-row-holds .set-hold-actions > :nth-child(2) { grid-area: 2 / 2; justify-self: stretch; }
/* The two buttons share one column, so they take its width: "Hold to reset"
   (145px) and "Hold to delete" (152px) started 7px apart. And the two rows
   are two rows, ruled apart like every other pair in the panel - the
   hairline runs edge to edge through the middle of the gap. */
body[data-view="settings"] .set-row-holds .set-hold-actions > .hold-confirm-btn { justify-content: flex-start; }
body[data-view="settings"] .set-row.set-row-holds { position: relative; }
body[data-view="settings"] .set-row.set-row-holds::after {
  content: "";
  grid-area: 2 / 1 / 3 / -1;
  align-self: start;
  margin-top: calc(var(--s-5) / -2);
  margin-inline: calc(-1 * var(--s-5));
  border-top: 1px solid rgb(var(--danger-rgb) / 0.20);
  pointer-events: none;
}
@media (max-width: 560px) {
  body[data-view="settings"] .set-row.set-row-holds { grid-template-columns: minmax(0, 1fr); row-gap: var(--s-3); }
  body[data-view="settings"] .set-row-holds .set-hold-copy > :nth-child(1) { grid-area: 1 / 1; }
  body[data-view="settings"] .set-row-holds .set-hold-actions > :nth-child(1) { grid-area: 2 / 1; justify-self: start; }
  body[data-view="settings"] .set-row-holds .set-hold-copy > :nth-child(2) { grid-area: 3 / 1; margin-top: var(--s-2); }
  body[data-view="settings"] .set-row-holds .set-hold-actions > :nth-child(2) { grid-area: 4 / 1; justify-self: start; }
  /* stacked, the second pair starts on row 3: the row's 8px gap (phone.css)
     above it and its own 8px margin inside it, so the rule sits on the line */
  body[data-view="settings"] .set-row.set-row-holds::after {
    grid-area: 3 / 1 / 4 / -1;
    margin-top: 0;
  }
}

/* Memory's callout is a label, a sentence and an action, the shape of every
   row under it - so its action sits on the right like theirs ("Start import"
   just below), not under the text. */
body[data-view="settings"] .set-callout:has(> div + .ghost-btn) {
  display: flex !important;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
}
body[data-view="settings"] .set-callout:has(> div + .ghost-btn) > div { flex: 1 1 auto; min-width: 0; }
/* On a phone a row's action drops under its text, so this one does too. */
@media (max-width: 560px) {
  body[data-view="settings"] .set-callout:has(> div + .ghost-btn) { flex-wrap: wrap; }
}

/* ── the title of a tab is the app's page title ─────────────────────────── */
body[data-view="settings"] .settings-tab-content::before {
  font-size: var(--t-page-size) !important;
  font-weight: 650 !important;
  letter-spacing: -0.015em !important;
  line-height: 1.15;
}

@media (max-width: 760px) {
  /* The bar gets its own full-width line under the label and the figure, so
     it is never the thing that gives. It measured 2px at 390. */
  body[data-view="settings"] .usage-row {
    grid-template-columns: minmax(0, 1fr) auto !important;
    row-gap: var(--s-3) !important;
  }
  body[data-view="settings"] .usage-bar { grid-column: 1 / -1; order: 3; }
  body[data-view="settings"] .settings-tab-content::before { font-size: 21px !important; }

  body[data-view="settings"] .plan-hero { flex-wrap: wrap !important; row-gap: var(--s-3); }
  body[data-view="settings"] .plan-hero-text { flex: 1 1 0; min-width: 0; }
  body[data-view="settings"] .plan-hero-title { font-size: 18px !important; }
  body[data-view="settings"] #set-adjust-plan { flex: 1 1 100% !important; }
  body[data-view="settings"] .referral-link-wrap { flex-wrap: wrap; }
  body[data-view="settings"] .referral-link-wrap input { flex: 1 1 100%; }

  /* The device's name and meta take the row; "Sign out" drops under them,
     right-aligned, instead of squeezing the meta to three lines. */
  body[data-view="settings"] .set-session-row { flex-wrap: wrap; row-gap: var(--s-2) !important; }
  body[data-view="settings"] .set-session-info { flex: 1 1 100% !important; }
  body[data-view="settings"] .set-session-row .ghost-btn { margin-left: auto; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   8 · THE PLANS SCREEN

   The paywall was the last full "terminal HUD" surface: plan names, badges,
   the Monthly/Annual toggle, the CTAs and "Explore first" all in uppercase
   tracked mono, 18px cards on a 28px ladder, a pulsing green glow on the
   discount, and two badges stacked in Max's corner - one straddling the
   border. It is the screen a student reaches from "Adjust plan" and from the
   last slide of the tutorial, so it gets the app's own voice: sentence case,
   the sans, 28px cards with the card shadow, and the badges in one row at
   the head of the card (app.js renders them into `.pw-badges`).

   `#paywall-overlay` is the scope because the rules being answered carry
   `!important` at two-class weight across four older blocks; an id outranks
   every one of them without a selector war.
   ═══════════════════════════════════════════════════════════════════════════ */
/* The plans screen, the tutorial and setup replayed from Settings borrow the
   sign-in screen's `.auth-overlay`, and redesign.css paints that with the
   sign-in's light mint wash at `!important`. Sign-in is light by decision
   (app.js lockAuthLightTheme stamps it), so the wash is right there; these
   three open inside the signed-in app, in the student's own theme, and in
   dark they drew a near-white frame round a dark sheet. A dark document gets
   the dark canvas with the same soft mint glow. The sign-in overlays can
   never match: their document is always stamped light while they show. */
html[data-theme="dark"] :is(#paywall-overlay, #tutorial-overlay, #onboard-overlay).auth-overlay,
body[data-theme="dark"] :is(#paywall-overlay, #tutorial-overlay, #onboard-overlay).auth-overlay {
  background:
    radial-gradient(42% 36% at 50% 40%, rgb(var(--accent-rgb) / 0.10), transparent 72%),
    radial-gradient(130% 100% at 50% -10%, var(--bg-elev-1) 0%, var(--bg) 60%) !important;
}

#paywall-overlay :is(.pw-name, .pw-tag, .pw-popular, .pw-cmp-h, .billing-toggle button, .bt-save,
                     #paywall-back, .pw-card .primary-btn, .pw-price span, .pw-card ul li,
                     table.pw-cmp th, table.pw-cmp td) {
  font-family: var(--font-sans) !important;
  text-transform: none !important;
  letter-spacing: 0 !important;
}
#paywall-overlay .pw-card {
  border-radius: var(--r-card) !important;
  padding: var(--s-5) var(--s-5) var(--s-5) !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  box-shadow: var(--card-shadow) !important;
  transform: none !important;
}
#paywall-overlay .pw-card::before { display: none !important; }
/* Hover changes the fill, never the shape. */
#paywall-overlay .pw-card:hover {
  transform: none !important;
  border-color: var(--border-strong) !important;
}
#paywall-overlay .pw-card.featured {
  background: linear-gradient(180deg, rgb(var(--accent-rgb) / 0.09), var(--bg-elev-1) 46%) !important;
  border-color: rgb(var(--accent-rgb) / 0.32) !important;
}
#paywall-overlay .pw-card.current { opacity: 1 !important; }
#paywall-overlay .pw-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  min-height: 24px;
  margin-bottom: var(--s-3);
}
/* Side by side, an empty badge row keeps every plan's name on one line.
   Stacked on a phone there is nothing to line up with. */
@media (max-width: 820px) {
  #paywall-overlay .pw-badges:empty { display: none; }
}
#paywall-overlay :is(.pw-tag, .pw-popular) {
  position: static !important;
  transform: none !important;
  display: inline-flex !important;
  align-items: center;
  height: 24px;
  padding: 0 10px !important;
  border-radius: 999px !important;
  border: 0 !important;
  box-shadow: none !important;
  animation: none !important;
  font-size: 12px !important;
  font-weight: 700 !important;
  white-space: nowrap;
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
}
#paywall-overlay .pw-popular {
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
}
#paywall-overlay .pw-name {
  padding-right: 0 !important;
  margin: 0 0 2px !important;
  font-size: var(--t-card-size) !important;
  font-weight: 780 !important;
  color: var(--text) !important;
  -webkit-text-fill-color: currentColor !important;
  background: none !important;
}
#paywall-overlay .pw-card ul li {
  font-size: 13px !important;
  line-height: 1.5;
  color: var(--text-secondary) !important;
  /* A line that wraps hangs under its words, not under the check. */
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  column-gap: var(--s-2);
  align-items: baseline;
  padding-left: 0 !important;
}
#paywall-overlay .pw-card ul li::before { margin-right: 0 !important; }
/* On a phone the sheet's 38px sides left each plan 296px of a 390px screen;
   the cards are the sheet's content, so the sheet pads like a page. */
@media (max-width: 560px) {
  #paywall-overlay .paywall-wrap {
    padding-left: var(--s-4) !important;
    padding-right: var(--s-4) !important;
  }
}
#paywall-overlay .pw-card .primary-btn {
  border-radius: var(--r-touch) !important;
  min-height: var(--ctl-h);
  font-size: 13px !important;
  font-weight: 700 !important;
}
#paywall-overlay .pw-card .primary-btn:disabled { opacity: 0.72 !important; }
/* The card buttons were the old teal with white ink (styles.css, with
   bangs), the one filled primary in the app that is not the accent with its
   own ink. Frozen, at .72 over the dark canvas, "Coming soon" measured about
   3.3:1. A button that cannot be pressed yet is the soft fill with accent
   ink at full strength: it reads in both themes and does not pose as the
   live primary beside it. */
#paywall-overlay .pw-card:is(.pro, .featured) .primary-btn:not(:disabled) {
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
}
#paywall-overlay .pw-card:not(.current) .primary-btn:disabled {
  opacity: 1 !important;
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
  border: 0 !important;
  box-shadow: none !important;
  cursor: default;
}

/* Compare every plan, on a phone: the feature column kept its one-line
   width (317px of a 340px scroller), so the screen was a list of feature
   names with every value off to the right and nothing saying so. The names
   wrap in a 124px column that stays pinned, each plan gets 96px, two plans
   show beside the names, and /pricing's own hint says the rest is a swipe
   away. */
#paywall-overlay .pw-cmp-swipe { display: none; }
@media (max-width: 767px) {
  #paywall-overlay .pw-cmp-swipe {
    display: block;
    margin: calc(-1 * var(--s-1)) 0 var(--s-2);
    text-align: right;
    font-size: 12px;
    color: var(--text-dim);
  }
  #paywall-overlay table.pw-cmp { min-width: 0; width: auto; }
  #paywall-overlay table.pw-cmp :is(th, td) {
    white-space: normal;
    width: 96px;
    min-width: 96px;
    padding: 10px 8px;
    line-height: 1.35;
  }
  #paywall-overlay table.pw-cmp .lab {
    width: 124px;
    min-width: 124px;
    max-width: 124px;
    padding-left: 12px;
  }
}

/* Monthly / Annual: a segmented pill, and the discount a chip that reads in
   both themes (it was white on a 12% mint over a near-white toggle). */
#paywall-overlay .billing-toggle {
  border-style: solid !important;
  border-color: var(--border) !important;
  background: var(--bg-elev-2) !important;
  box-shadow: none !important;
}
#paywall-overlay .billing-toggle button {
  font-size: 13px !important;
  font-weight: 650 !important;
  padding: 8px 16px !important;
}
#paywall-overlay .billing-toggle button.on {
  background: var(--bg-elev-1) !important;
  color: var(--text) !important;
  box-shadow: 0 2px 0 var(--lip-quiet), 0 10px 20px -12px rgba(19, 32, 27, 0.3) !important;
}
#paywall-overlay .billing-toggle .bt-save,
#paywall-overlay .billing-toggle button.on .bt-save {
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
  font-size: 11px !important;
  font-weight: 700 !important;
  padding: 2px 8px !important;
  box-shadow: none !important;
  animation: none !important;
}
#paywall-overlay #paywall-back {
  font-size: 13px !important;
  font-weight: 600;
  padding: 8px 14px !important;
  border-radius: var(--r-touch) !important;
  color: var(--text-secondary) !important;
}
#paywall-overlay #paywall-back:hover { background: var(--bg-elev-2) !important; color: var(--text) !important; }
#paywall-overlay .pw-cmp-h {
  font-size: 13px !important;
  font-weight: 650 !important;
  color: var(--text-dim) !important;
}
#paywall-overlay table.pw-cmp thead th {
  font-size: 12.5px !important;
  font-weight: 700 !important;
}
#paywall-overlay .pw-beta-note {
  border: 1px solid var(--border) !important;
  background: var(--bg-elev-2) !important;
  border-radius: var(--r-card) !important;
  padding: var(--s-4) var(--s-5) !important;
}


/* ═══════════════════════════════════════════════════════════════════════════
   9 · THE OTHER TABS

   Home, Mastery and Calendar set the language; the views a student opens
   once a week never caught up. What they shared, measured on every one:

     · a one-sided border on a rounded box. A rule under a header with a 28px
       corner, or a 3px colour bar down a 22px row, does not draw a line: it
       draws a smile or a "(" that follows the curve. A separator inside a
       rounded box is a full border or no border; a marker is a fill or a dot.
     · values and labels in the terminal-era mono, uppercase and tracked.
     · 12-18px cards where the ladder says 28.
     · empty states floating on the canvas with no panel and no next step.

   Every rule here is presentation. `body:not(#_)` is the same one-id step
   clean.css uses, because the rules answered are `!important` and several
   classes deep in styles.css.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── one page edge ──────────────────────────────────────────────────────── */
/* Every page title sits on the gutter (redesign.css: `.view > .topbar`
   pads by --gutter), and Home's cards start right under it. The other tabs
   each had their own inset from an earlier pass: a 3vw clamp (42px at 1440)
   on Mastery, Assignments and Grades, 28px on Voice and Skills, 3vw again on
   Connectors, and Classes added a second 28px inside the page's own 32. At
   1440 their first card started at 306, 292, 307 and 324 under a title at
   296. Content starts where the title does on every tab. Phones keep their
   own 16px gutters (phone.css), so this is the docked layout only. */
@media (min-width: 901px) {
  body:not(#_) :is(.view-school .school-shell, .view-tasks .tasks-body, .view-autopilot .ap-dash,
                   .view-memories .mem-feed, .projects-page, .learn-shell, .voice-page,
                   .skills-page, #tp-root) {
    padding-left: var(--gutter) !important;
    padding-right: var(--gutter) !important;
  }
  body:not(#_) .view-projects .projects-grid {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  /* A class page padded its two columns by 28px under a header padded by
     the gutter: the title and tabs started at 292 and the Instructions card
     ended at 1402, against 296 and 1398 on every other tab. */
  body:not(#_) .view-project .project-page {
    padding-left: var(--gutter) !important;
    padding-right: var(--gutter) !important;
  }

  /* One header on every tab. The bell was 44px where it sat beside a 44px
     action and 34px where it sat alone (Discover, Voice, Chat), so it moved
     10px and the bar lost 4px between tabs; Assignments and Test Prep kept
     taller bars of their own (72 and 74px, not 60), so the title dropped 6px
     on the way in. The bell is the action row's height everywhere but beside
     a tutoring session's 34px Mark done, and every bar is the same 60px. */
  body:not(#_) .view > header.topbar .topbar-right:not(:has(.th-done:not([hidden]))) .notif-bell-btn {
    width: var(--ctl-h);
    height: var(--ctl-h);
    min-height: var(--ctl-h);
  }
  body:not(#_) :is(.view-tasks, .view-test-prep) > header.topbar {
    min-height: var(--topbar-h) !important;
    padding-top: 8px !important;
    padding-bottom: 8px !important;
  }
  body:not(#_) .view-test-prep > header.topbar .page-title {
    line-height: 1.3 !important;
    padding-bottom: 0.12em !important;
  }
  body:not(#_) .view-connectors :is(.conn-grid, .conn-toolbar) {
    padding-left: var(--gutter) !important;
    padding-right: var(--gutter) !important;
  }
  /* the section title was inset to the old grid edge */
  body:not(#_) .view-connectors .conn-section-title { padding-inline: var(--gutter) !important; }
}

/* Connectors centred its search and chips under a page whose title,
   headings and cards start at the gutter. The row starts where they do,
   like the Assignments filters - on a laptop and on a phone. (A tablet in
   portrait centres its page title, and the row stays under it.) */
@media (min-width: 901px), (max-width: 767px) {
  body:not(#_) .view-connectors :is(.conn-toolbar, .conn-filters) { justify-content: flex-start !important; }
}

/* ── type: mono only for code ──────────────────────────────────────────── */
body:not(#_) :is(#project-conv-count .badge, #project-conv-count, #context-body .label,
                 .view-tasks .task-due, .view-tasks .fp-count, .view-tasks .ts-count,
                 .conn-tile-status, .conn-tile-badge, .conn-row-state,
                 .ap-group-count, .tut-text, .modal-sub, .recents-label) {
  font-family: var(--font-sans) !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  font-variant-numeric: tabular-nums;
}
body:not(#_) .tut-text {
  font-size: var(--t-body-size) !important;
  line-height: var(--t-body-lh) !important;
  color: var(--text-secondary) !important;
}
body:not(#_) #tut-next {
  font-family: var(--font-sans) !important;
  text-transform: none !important;
  letter-spacing: 0 !important;
}
/* On a phone the card's 32px sides left its buttons 276px, and the first
   slide's row (Skip, "Back to sign in", Next, plus the hidden Back's slot,
   now gone - app.js) needed 309: Next ran onto the card's edge. The card
   pads 24px like the other first-run sheets, and if a row still cannot fit
   it wraps, Next keeping the right edge. */
@media (max-width: 560px) {
  body:not(#_) .tutorial-card { padding-left: var(--s-5) !important; padding-right: var(--s-5) !important; }
  body:not(#_) .tut-nav { flex-wrap: wrap; row-gap: var(--s-2); }
}
/* The progress dots were white at 10% on a white card in light: only the
   active one showed, so the deck had no visible length. */
html[data-theme="light"] .tut-dots .dot:not(.on),
body[data-theme="light"] .tut-dots .dot:not(.on) { background: var(--border-strong) !important; }

/* ── the sidebar and the palette: a marker is a fill, never a bar ───────── */
/* styles.css:17342 paints a 2px accent bar at left:0 on the active nav pill,
   which in dark is a teal "(" on every view. The rail's tooltip is also an
   ::after, so the rail keeps it. */
body:not(.rail) .nav-item::after { display: none !important; }
.project-item::before { display: none !important; }
body:not(#_) #palette-backdrop .palette-item.sel {
  box-shadow: none !important;
  background: var(--accent-soft) !important;
}
html[data-theme="light"] #palette-backdrop,
body[data-theme="light"] #palette-backdrop { background: rgba(19, 32, 27, 0.28) !important; }

/* ── class page ─────────────────────────────────────────────────────────── */
/* The active tab was a 2px underline on a 22px-radius tab: a curved smile
   under the label. Every other tab strip in the app is a filled pill. */
body:not(#_) .project-tabs { border-bottom: 0 !important; gap: 2px; }
body:not(#_) .project-tab {
  border-bottom: 0 !important;
  border-radius: var(--soft-control) !important;
  padding: 8px 14px !important;
  margin-bottom: 0 !important;
  box-shadow: none !important;
}
body:not(#_) .project-tab:hover:not(.active) { background: rgb(var(--accent-rgb) / 0.06) !important; }
body:not(#_) .project-tab.active {
  background: var(--accent-soft) !important;
  color: var(--text) !important;
  font-weight: 600 !important;
}
body:not(#_) .project-tab.active::after,
body:not(#_) .project-tab.active::before { display: none !important; }
body:not(#_) .aside-card {
  border-radius: var(--r-card) !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  box-shadow: var(--card-shadow) !important;
}
body:not(#_) .aside-card-header { border-bottom-color: transparent !important; }
/* `.aside-card-body` is pre-wrap so a class's own instructions and memory
   keep their line breaks. Mastery and Settings are built from indented
   markup, and pre-wrap printed that indentation: a hanging indent in the
   Settings paragraph and a blank line above every Mastery row. */
body:not(#_) :is(#project-mastery-body, #project-settings-body) { white-space: normal !important; }
body:not(#_) .aside-card-body :is(p, .set-sub) { white-space: normal; }
body:not(#_) .pm-row { border-radius: 0 !important; }
body:not(#_) .new-conv-row { border-style: solid !important; }
/* On the one-column tabs the grid stretched its two rows to fill the page,
   which left 50-90px of nothing between the tab strip and the card. */
body:not(#_) .project-page[data-active-ptab] { align-content: start !important; }

/* ── Grades ─────────────────────────────────────────────────────────────── */
body:not(#_) :is(.ag-tile, .ag-table) {
  border-radius: var(--r-card) !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  box-shadow: var(--card-shadow) !important;
}
body:not(#_) .ag-tile { padding: var(--s-4) var(--s-5) !important; }
body:not(#_) .ag-table { overflow: hidden; padding: var(--s-2) var(--s-2) !important; }
/* Rows are soft pills with a hover fill and no rule between them: a bottom
   border on a 22px-radius row curls up at both ends. */
body:not(#_) .ag-row {
  border-left-width: 0 !important;
  border-bottom-color: transparent !important;
  border-radius: var(--soft-row) !important;
}
body:not(#_) .ag-headrow > span {
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-size: 12px !important;
  font-weight: 650 !important;
  color: var(--text-dim) !important;
}
body:not(#_) .ag-row[style*="--ag-edge"] .ag-name::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 10px;
  border-radius: 50%;
  background: var(--ag-edge);
  vertical-align: 1px;
  flex: none;
}
body:not(#_) :is(.ag-grade b, .pc-letter, .gb-overall-letter) { border-radius: 999px !important; }

/* ── Assignments ────────────────────────────────────────────────────────── */
body:not(#_) .view-tasks .task-due::before { display: none !important; }
body:not(#_) .view-tasks .task-due { font-size: 12px !important; font-weight: 650 !important; }
/* One chip row. The class was 20px tall in 10px type, the kind 22px in
   9.5px, the due date 27px in 12px, and an overdue date pulsed a green 2-4px
   ring round its red pill, which in light read as a second outline. Three
   chips of one height, one type size and one shape; overdue is the red fill
   and nothing else. */
body:not(#_) .view-tasks .task-head > :is(.task-subject, .task-kind, .task-due) {
  display: inline-flex !important;
  align-items: center;
  height: 22px;
  min-height: 22px;
  padding: 0 9px !important;
  border-radius: 999px !important;
  font-size: 11.5px !important;
  font-weight: 650 !important;
  line-height: 1 !important;
  letter-spacing: 0 !important;
  box-shadow: none !important;
  animation: none !important;
}
/* The subject stripe was a 3px bar down the card's rounded left edge. The
   class chip on the card already carries the subject's colour as a dot. */
body:not(#_) .view-tasks .task-card::before { display: none !important; }
/* One dot per heading: the head and its label each drew one. */
body:not(#_) .view-tasks .task-section-head::before { display: none !important; }
/* "Did you finish these?" wore a 3px warning edge on an 18px corner. The
   warning is a tint on its head instead, and the strip is a card. */
body:not(#_) .confirm-strip {
  border: 1px solid rgb(var(--warning-rgb) / 0.30) !important;
  border-radius: var(--r-card) !important;
  box-shadow: var(--card-shadow) !important;
}
body:not(#_) .confirm-strip .cs-head { background: rgb(var(--warning-rgb) / 0.08); }
body:not(#_) .confirm-strip .cs-row { border-radius: 0 !important; }
body:not(#_) .view-tasks .task-section-head .ts-label {
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-size: 13px !important;
  font-weight: 700 !important;
}
body:not(#_) .view-tasks .task-section-head::after { display: none !important; }
/* The drawer takes focus when it opens (tabindex=-1, so a screen reader
   lands in it). It is a container, not a control, so the 2px ring drawn
   round its 28px corners was a green "(" down the page's right third. The
   controls inside keep their rings. */
body:not(#_) #task-detail:focus,
body:not(#_) #task-detail:focus-visible { outline: none !important; }

/* ── one filled primary ─────────────────────────────────────────────────── */
/* `.primary-btn` is the accent with the accent's own ink: near-black on the
   dark theme's mint, white on the light theme's teal. Five other filled
   buttons had their own recipe from an older pass: "Done" on the "Did you
   finish" card and Home's "Walk me through" and "Ask" were white on the
   dark mint (about 1.7:1), and the task card's "Tutor" and a connector's
   "Connect" were a third, darker teal. They are all the one primary now. */
body:not(#_) :is(.cs-acts .cs-yes, .dash-btn-tutor, .dash-tutor-send,
                 .task-actions .do-it, .conn-tile-actions .primary):not(:disabled),
body:not(#_) :is(.cs-acts .cs-yes, .dash-btn-tutor, .dash-tutor-send,
                 .task-actions .do-it, .conn-tile-actions .primary):not(:disabled):hover {
  background-color: var(--accent) !important;
  color: var(--accent-ink) !important;
}

/* ── Connectors ─────────────────────────────────────────────────────────── */
body:not(#_) :is(.conn-tile-status, .conn-tile-badge, .conn-row-state) {
  font-size: 11.5px !important;
  font-weight: 650 !important;
}
body:not(#_) .conn-tile-status::after { font-family: var(--font-sans) !important; }
/* The tier chip ("Recommended", "Special") sat across the card's top border,
   the ribbon the plans screen dropped, and Recommended was a yellow-gold
   gradient pill. It is a chip at the head of the card now, in the plans
   screen's two weights: Recommended is the filled one, like "Most popular",
   and Special the soft one, like a trial tag. */
body:not(#_) .view-connectors .conn-tile-badge {
  position: static !important;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  height: 22px;
  max-width: 100%;
  margin: 0 0 var(--s-3) !important;
  padding: 0 10px !important;
  border: 0 !important;
  border-radius: 999px !important;
  box-shadow: none !important;
  background: var(--accent-soft) !important;
  color: var(--accent) !important;
  font-size: 11.5px !important;
  font-weight: 700 !important;
}
body:not(#_) .view-connectors .conn-tile-badge-recommended {
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
}
/* Side by side, a card without a chip keeps the chip's row empty, so every
   card's name starts on the same line (the plans screen does the same). One
   column has nothing to line up with. */
@media (min-width: 901px) {
  body:not(#_) .view-connectors .conn-grid:has(.conn-tile-badge) .conn-tile:not(:has(> .conn-tile-badge)) > .conn-tile-head {
    margin-top: calc(22px + var(--s-3));
  }
}
/* The expand chevron stood in its own column beside the name and took 29px
   from it, so "Google Classroom" broke onto a second line on a four-up row
   and pushed its status and description a line below its neighbours'. It
   sits beside the status line instead, which is short, and the name has the
   card's width. */
body:not(#_) .view-connectors .conn-tile-head { position: relative; }
body:not(#_) .view-connectors .conn-tile-head > .conn-tile-chev {
  position: absolute;
  right: 0;
  bottom: 1px;
}
body:not(#_) .view-connectors .conn-tile-name { letter-spacing: -0.015em; }
body:not(#_) .conn-tile-actions { border-top-color: transparent !important; }
body:not(#_) .view-connectors .conn-section-title {
  text-align: left !important;
  font-size: var(--t-card-size) !important;
  font-weight: 750 !important;
  letter-spacing: -0.01em !important;
  text-transform: none !important;
  color: var(--text) !important;
  /* the grid under it is inset by the gutter; the title starts where the
     first card does (it sat 4px in, at 300 over cards and a search box at
     296) */
  padding-inline: var(--gutter) !important;
  border: 0 !important;
}
body:not(#_) .view-connectors .conn-section-title::before,
body:not(#_) .view-connectors .conn-section-title::after { display: none !important; }
body:not(#_) .view-connectors :is(.conn-section-divider, .conn-section-rule, hr) { display: none !important; }
body:not(#_) .view-connectors .conn-search :is(input, #conn-search-input) {
  height: var(--ctl-h-compact) !important;
  border-radius: var(--r-touch) !important;
}
body:not(#_) .conn-browser-head { border-bottom-color: transparent !important; }
/* On a phone the browser's rows are ruled apart with a top border; a ruled
   row is square, so the rule runs straight instead of curling at 16px. */
@media (max-width: 560px) {
  body:not(#_) .conn-row { border-radius: 0 !important; }
}
/* The row's description is a text box, but its class has "row" in it, so
   rounded.css's last sweep gives it a 22px corner. With the `overflow:
   hidden` it needs for its ellipsis, that corner clipped the first letter
   of each line ("Sync" lost the top of its S, "materials" its m). A box that
   paints nothing has no corner to round. */
.conn-row-desc { border-radius: 0; }

/* ── Test Prep ──────────────────────────────────────────────────────────── */
body:not(#_) #tp-progression { border-bottom-color: transparent !important; }
body:not(#_) .ap-group {
  border: 1px solid var(--border) !important;
  background: var(--bg-elev-1) !important;
  border-radius: var(--r-card) !important;
  box-shadow: var(--shadow-sm);
  padding: 0 var(--s-5) !important;
  margin: 0 0 var(--s-3) !important;
}
body:not(#_) .ap-group[open] { padding-bottom: var(--s-4) !important; }
body:not(#_) .ap-group-title {
  border-left: 0 !important;
  min-height: 56px;
  padding-left: 0 !important;
  margin: 0 !important;
  display: flex;
  align-items: center;
}
body:not(#_) .view-test-prep .tp-pill:not(.active):not([aria-pressed="true"]) {
  background: var(--bg-elev-1) !important;
  border-color: var(--border-strong) !important;
  color: var(--text) !important;
}
body:not(#_) .tp-mode-card:not(.tp-mode-more) {
  background: var(--bg-elev-1) !important;
  box-shadow: var(--card-shadow) !important;
  border-color: var(--border) !important;
}

/* ── History, Memory, Tutor: bars and empty states ──────────────────────── */
body:not(#_) .view-history .hist-bar,
body:not(#_) .view-memories .mem-feed-bar {
  border-bottom: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
}
body:not(#_) :is(.hist-search, .mem-feed-search) {
  border-radius: var(--r-field) !important;
  background: var(--bg-elev-1) !important;
}
/* ── one empty state ────────────────────────────────────────────────────── */
/* Mastery's is the reference: a panel the width of the page, a title, one
   sentence and the next step as the primary button. The others had drifted
   to 390, 520, 530 and 720px wide, two carried an icon and three did not,
   History's button was a flat 38px pill beside Memory's 44px one on its
   lip, and Tutor's had been hidden as a repeat of "+ New session" - while
   History, Memory and Mastery all repeat their header's action, because an
   empty page is where the next step belongs. All five are now the one shape. */
body:not(#_) :is(.learn-empty, .hist-empty, .mem-empty, .tt-empty, .ag-empty) {
  grid-column: 1 / -1;
  display: grid !important;
  place-content: center;
  justify-items: center;
  gap: var(--s-3);
  width: auto;
  max-width: none !important;
  min-height: 320px !important;
  margin: 0 !important;
  padding: var(--s-8) var(--s-6) !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--r-card) !important;
  box-shadow: var(--card-shadow) !important;
  text-align: center;
}
body:not(#_) :is(.hist-empty, .mem-empty, .tt-empty) { margin-top: var(--s-2) !important; }
body:not(#_) .mem-empty { align-self: stretch; }
body:not(#_) :is(.learn-empty h2, .hist-empty h3, .mem-empty h3, .tt-empty h3, .ag-empty > strong) {
  margin: 0 !important;
  font-family: var(--font-sans) !important;
  font-size: 16px !important;
  font-weight: 750 !important;
  letter-spacing: -0.01em !important;
  text-transform: none !important;
  color: var(--text) !important;
}
body:not(#_) :is(.learn-empty p, .hist-empty p, .mem-empty p, .tt-empty p, .ag-empty > span) {
  max-width: 470px;
  margin: 0 !important;
  font-size: 13px !important;
  line-height: 1.55 !important;
  color: var(--text-secondary) !important;
}
body:not(#_) :is(.hist-empty .ico, .mem-empty .empty-icon) { display: none !important; }
body:not(#_) :is(.learn-empty-actions, .mem-empty-cta, .ag-empty .primary-btn) { margin-top: var(--s-2) !important; }
/* the button is a button, the same two weights as everywhere else */
body:not(#_) :is(.hist-empty-cta, .tt-empty-cta) {
  min-height: var(--ctl-h) !important;
  margin-top: var(--s-2) !important;
  padding: 0 var(--s-5) !important;
  border-radius: var(--r-touch) !important;
  border: 1px solid var(--border-strong) !important;
  background: var(--bg-elev-1) !important;
  color: var(--text) !important;
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  font-weight: 650 !important;
  box-shadow: 0 2px 0 0 var(--lip-quiet) !important;
}
body:not(#_) :is(.hist-empty-cta, .tt-empty-cta).primary {
  border-color: transparent !important;
  background: var(--accent) !important;
  color: var(--accent-ink) !important;
  font-weight: 700 !important;
  box-shadow: 0 var(--lip-sm) 0 0 var(--lip-color), inset 0 1px 0 rgb(255 255 255 / 0.16) !important;
}
body:not(#_) :is(.hist-empty-cta, .tt-empty-cta):active:not(:disabled) { box-shadow: 0 1px 0 0 var(--lip-quiet) !important; }
body:not(#_) :is(.hist-empty-cta, .tt-empty-cta).primary:active:not(:disabled) { box-shadow: 0 1px 0 0 var(--lip-color) !important; }
/* clean.css (which loads later) took Tutor's down to one sentence on no
   panel; `html` is the one extra step that answers it. */
html body:not(#_) .view-autopilot .tt-empty {
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  box-shadow: var(--card-shadow) !important;
}
html body:not(#_) .view-autopilot #tt-empty-new { display: inline-flex !important; align-items: center; }

/* ── Classes ────────────────────────────────────────────────────────────── */
body:not(#_) .view-projects .project-card {
  border-radius: var(--r-card) !important;
}
/* The subject's colour was a 3px bar down the card's rounded left edge; it
   moves to the class icon, which already names the subject. */
body:not(#_) .view-projects .project-card::before { display: none !important; }
body:not(#_) .view-projects .project-card[class*="subj-"] .pc-name-ico { color: var(--subj-ink, var(--subj)); }
body:not(#_) .view-projects .pc-name-txt {
  font-size: var(--t-card-size) !important;
  font-weight: 780 !important;
}
body:not(#_) .pc-grade.no-grade { font-variant-numeric: tabular-nums; }

/* ── Voice and Skills ───────────────────────────────────────────────────── */
body:not(#_) .view-voice .voice-card {
  border-radius: var(--r-card) !important;
  background: var(--bg-elev-1) !important;
  border-color: var(--border) !important;
}
body:not(#_) .view-voice .voice-hero {
  border: 0 !important;
  padding: 0 !important;
  background: none !important;
  box-shadow: none !important;
  /* under the page title it is a section heading, not a second page title */
  font-size: var(--t-section-size) !important;
  font-weight: 760 !important;
}
body:not(#_) .voice-import-or {
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-size: 12.5px !important;
}
body:not(#_) .view-skills .set-callout {
  border-radius: var(--r-card) !important;
  background: rgb(var(--accent-rgb) / 0.05) !important;
  border-color: rgb(var(--accent-rgb) / 0.18) !important;
}
body:not(#_) .view-skills .skill-card {
  background: var(--bg-elev-1) !important;
  box-shadow: var(--card-shadow) !important;
}

/* ── Discover ───────────────────────────────────────────────────────────── */
body:not(#_) .view-discover .disc-hero {
  border-bottom: 0 !important;
  padding-bottom: var(--s-2) !important;
}
/* "3x + 2 = 11" and "25:00" in the cards' little pictures were the last
   terminal type on the tab. A sum and a clock are numbers, not code. */
body:not(#_) .view-discover :is(.dv-math, .dv-math span, .dv-count b) {
  font-family: var(--font-sans) !important;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0 !important;
}

/* ── notifications and toasts ───────────────────────────────────────────── */
/* The rule under the panel's head is a straight line: the head keeps the
   panel's top corners and squares its own bottom ones. */
body:not(#_) .notif-panel-head {
  border-bottom-left-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
}
body:not(#_) #notif-panel-list {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  padding: var(--s-2) var(--s-2) var(--s-3) !important;
}
body:not(#_) .toast {
  border-radius: var(--soft-row) !important;
  padding: 12px var(--s-4) !important;
}
/* The stack rested on Lumi's badge, bottom-right at every width (lumi.css).
   It rises clear of it on a desktop. Below the dock width it sat on the
   bottom tab bar, and Lumi's badge showed through the gaps between toasts:
   the stack sits just above the bar instead, and while a toast is up the
   badge steps aside, the way it already waits out the storage notice on a
   phone (redesign.css) - there is no room for both. */
@media (min-width: 901px) {
  body:not(#_) #toast-wrap { bottom: 100px !important; }
}
@media (max-width: 900px) {
  body:not(#_) #toast-wrap {
    bottom: calc(var(--mnav-h) + var(--mnav-gap) + var(--s-3) + env(safe-area-inset-bottom, 0px)) !important;
  }
  body:not(#_):has(#toast-wrap > .toast) .lumi-fab {
    opacity: 0 !important;
    pointer-events: none !important;
  }
}
@media (max-width: 600px) {
  body:not(#_) #toast-wrap { left: var(--s-4) !important; right: var(--s-4) !important; }
}
body:not(#_) .toast.toast-error,
body:not(#_) .toast.error {
  background: rgb(var(--danger-rgb) / 0.10) !important;
  border-color: rgb(var(--danger-rgb) / 0.24) !important;
}

/* ── the phone's More sheet: grouped rows, like Settings ─────────────────── */
/* It was a list of bare text lines under floating labels, the one list on
   the phone that was not drawn as a panel. The sheet takes the canvas and
   each group becomes one run of rows - the same `:has()` reading section 3
   does - with a chevron saying each row goes somewhere. Rows hidden on a
   phone (`data-mm-study`) take no space, so they never break a run's
   separators; the run's ends are read from the labels around it. */
body:not(#_) .mms-panel,
body:not(#_) .mms-head { background: var(--bg) !important; }
body:not(#_) .mms-panel { padding-inline: var(--s-4) !important; }
body:not(#_) .mms-group-label { padding: var(--s-5) var(--s-2) var(--s-2) !important; font-size: 13px !important; font-weight: 650 !important; }
body:not(#_) .mms-item {
  min-height: 52px;
  padding: 0 var(--s-5) !important;
  background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important;
  border-top-width: 0 !important;
  border-radius: 0 !important;
  font-weight: 550 !important;
  gap: var(--s-3);
}
body:not(#_) .mms-item::after {
  content: "›";
  margin-left: auto;
  color: var(--text-dim);
  font-size: 20px;
  line-height: 1;
}
body:not(#_) .mms-item:hover { background: var(--bg-elev-2) !important; }
body:not(#_) .mms-group-label + .mms-item,
body:not(#_) .mms-head + .mms-item {
  border-top-width: 1px !important;
  border-top-left-radius: var(--soft-panel) !important;
  border-top-right-radius: var(--soft-panel) !important;
}
body:not(#_) .mms-item:last-child {
  border-bottom-left-radius: var(--soft-panel) !important;
  border-bottom-right-radius: var(--soft-panel) !important;
}
@supports selector(:has(*)) {
  body:not(#_) .mms-item:has(+ .mms-group-label) {
    border-bottom-left-radius: var(--soft-panel) !important;
    border-bottom-right-radius: var(--soft-panel) !important;
  }
}

/* ── the walkthrough's coachmark ────────────────────────────────────────── */
/* It was an 18px card with "STEP 1 OF 11" in tracked 10.5px capitals, and
   one row for Skip, eleven dots, Back and Next: 320px of controls in a 268px
   column, so Next hung 1px past the card's edge. The step is a quiet label
   in sentence case, the dots get a row of their own above the buttons, and
   the card takes the menu radius. */
body:not(#_) .tour-pop {
  width: 320px;
  max-width: calc(100vw - 2 * var(--s-4));
  border-radius: var(--r-surface) !important;
  border-color: var(--border) !important;
  padding: var(--s-5) var(--s-5) var(--s-4) !important;
}
body:not(#_) .tour-step {
  font-size: 12px !important;
  font-weight: 650 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}
body:not(#_) .tour-title { font-size: 17px; font-weight: 750; letter-spacing: -0.01em; }
body:not(#_) .tour-text { font-size: var(--t-small-size); color: var(--text-secondary); }
body:not(#_) .tour-nav { flex-wrap: wrap; row-gap: var(--s-4); margin-top: var(--s-4) !important; }
body:not(#_) .tour-dots { order: -1; flex: 1 1 100%; margin: 0; }
body:not(#_) .tour-skip { padding: 8px 4px; font-size: 13px; }
body:not(#_) .tour-prev { margin-left: auto; }
/* On a phone the card is the page's width less its two 16px gutters, so it
   sits even under any tab (positionTour keeps 16px from each edge). It was
   320px pinned 12px from the left and 58px from the right. */
@media (max-width: 767px) {
  body:not(#_) .tour-pop { width: calc(100vw - 2 * var(--s-4)); }
}

/* ── small modals: native controls in the app's shape ───────────────────── */
/* A round check, the same one Settings uses, in place of the browser's
   square box on the sign-up consent and the feedback screenshot opt-in. */
/* `.auth-card .auth-consent input` and clean.css's
   `body:not(#_) .modal input[type=checkbox]` size it `auto !important`,
   hence the card and the id step in the selectors and the bangs on the box.
   phone.css gives every control in an overlay a 44px touch floor, which
   stretched the 20px circle into a 20x44 oval on a phone. The floor is for
   the thing you tap, and here that is the whole <label> around the box. */
.auth-card .auth-consent input[type="checkbox"],
.auth-consent input[type="checkbox"],
body:not(#_) #feedback-backdrop input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 20px !important;
  height: 20px !important;
  min-width: 0 !important;
  min-height: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  flex: 0 0 auto;
  border-radius: 50% !important;
  border: 1.5px solid rgb(var(--accent-rgb) / 0.5) !important;
  background: var(--bg-elev-1);
  display: inline-grid;
  place-content: center;
  cursor: pointer;
  transition: background-color 160ms var(--ease-out, ease), border-color 160ms var(--ease-out, ease);
}
.auth-consent input[type="checkbox"]::after,
#feedback-backdrop input[type="checkbox"]::after {
  content: "";
  width: 10px;
  height: 6px;
  border-left: 2px solid var(--accent-ink);
  border-bottom: 2px solid var(--accent-ink);
  transform: translateY(-1px) rotate(-45deg) scale(0);
  transition: transform 160ms var(--ease-out, ease);
}
.auth-consent input[type="checkbox"]:checked,
#feedback-backdrop input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent) !important;
}
.auth-consent input[type="checkbox"]:checked::after,
#feedback-backdrop input[type="checkbox"]:checked::after { transform: translateY(-1px) rotate(-45deg) scale(1); }
.auth-consent-group > :first-child { text-align: left; }
/* "Not a student?" between its two hairlines was set in tracked capitals by
   family.css, the eyebrow style the rest of the app retired. */
#auth-overlay .auth-doors-head {
  text-transform: none !important;
  letter-spacing: 0 !important;
  font-size: 12px;
  font-weight: 650;
}
#feedback-route { border-style: solid !important; background: var(--bg-elev-2) !important; }
/* A footer with more buttons than its column has room for overflowed to
   the LEFT (it is right-aligned): Feedback's Cancel, Copy report and Open
   email started 21px outside the column the fields sat in at 390. On a
   phone the row wraps instead, and Feedback's three share the width. */
@media (max-width: 560px) {
  body:not(#_) .modal .modal-actions { flex-wrap: wrap; row-gap: var(--s-2); }
  body:not(#_) #feedback-backdrop .modal-actions > * { flex: 1 1 auto; }
}
#task-modal-backdrop input[type="date"] { color-scheme: light dark; border-radius: var(--r-field) !important; }
/* Add assignment: the fields stood 24, 14, 24 and 24px apart (each input
   carried its own 14px top and 10px bottom margin; the class picker only the
   top one), and the date field was 2px taller than its neighbours. One gap,
   one height. */
body:not(#_) #task-modal-backdrop .modal { gap: var(--s-3); }
body:not(#_) #task-modal-backdrop .modal > :is(input, select, textarea) { margin: 0 !important; }
body:not(#_) #task-modal-backdrop .modal > :is(input, select) { height: var(--ctl-h); min-height: var(--ctl-h); }
body:not(#_) #task-modal-backdrop .modal > .modal-title { margin-bottom: var(--s-1) !important; }
body:not(#_) #task-modal-backdrop .modal > .modal-actions { margin-top: var(--s-2) !important; }
#task-modal-backdrop input[type="date"]::-webkit-calendar-picker-indicator { opacity: 0.55; cursor: pointer; }
.modal textarea { resize: vertical; }
/* Add assignment's description is a field like the four above it; the grip
   in its corner was the browser's, not the app's. */
#task-modal-backdrop textarea { resize: none; }

/* The due date. A bare date input showed the browser's black "mm/dd/yyyy"
   and its calendar icon among fields that show a soft placeholder. It stays
   a native input - typing, the screen reader and a phone's own wheel all
   keep working - inside a field drawn like its neighbours: "Due date" at
   the start in placeholder ink, the date at the end, and the app's own
   calendar glyph (the tab bar's) where the browser's was. Unset, the date
   is in placeholder ink too (app.js syncDateField). */
/* `:not(#_)` twice: clean.css zeroes the side padding of every label in a
   modal with a one-id selector and a bang. */
body:not(#_) .modal > .date-field:not(#_) {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: var(--ctl-h);
  /* the 10px every input in a modal keeps under it; Add assignment spaces
     its fields with the column's gap instead (below) */
  margin: 0 0 10px;
  padding: 0 var(--s-3) 0 14px !important;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  background: rgb(255 255 255 / 0.03);
  cursor: text;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
body:not(#_) #task-modal-backdrop .modal > .date-field:not(#_) { margin: 0; }
body:not(#_) .modal > .date-field:not(#_):focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / 0.18);
}
.date-field-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  color: var(--text-dim);
  white-space: nowrap;
}
body:not(#_) .modal .date-field input[type="date"] {
  flex: 0 0 auto;
  width: auto;
  height: calc(var(--ctl-h) - 2px);
  min-height: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  outline: none !important;
  font: inherit;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  text-align: right;
}
.date-field input[type="date"][data-empty]::-webkit-datetime-edit { color: var(--text-dim); }
.date-field input[type="date"]::-webkit-calendar-picker-indicator {
  width: 18px;
  height: 18px;
  margin: 0 0 0 var(--s-2);
  padding: 0;
  background: var(--text-secondary);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='16' rx='2'/%3E%3Cline x1='3' y1='9.5' x2='21' y2='9.5'/%3E%3Cline x1='8' y1='2.5' x2='8' y2='6.5'/%3E%3Cline x1='16' y1='2.5' x2='16' y2='6.5'/%3E%3C/svg%3E") center / 18px 18px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='16' rx='2'/%3E%3Cline x1='3' y1='9.5' x2='21' y2='9.5'/%3E%3Cline x1='8' y1='2.5' x2='8' y2='6.5'/%3E%3Cline x1='16' y1='2.5' x2='16' y2='6.5'/%3E%3C/svg%3E") center / 18px 18px no-repeat;
  opacity: 0.8;
  cursor: pointer;
}
.date-field input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; background: var(--accent); }

/* One underline. An unclassed link gets a text underline AND a 1px
   border-bottom (styles.css, two passes that never met). Inline, the two
   ran together into one heavy rule; on a phone, where these two links
   carry a 44px touch box (phone.css), the border fell to the bottom of the
   box and drew a second line about 20px under the word. The storage
   notice's link and the plans screen's "Sign out" are the first links a new
   student meets. */
#storage-notice p a,
#paywall-signout,
:is(.modal-backdrop, .auth-overlay, .paywall-overlay, .tutorial-overlay, .onboard-overlay) a[id]:not([class]) {
  border-bottom: 0 !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ADMIN - the dashboard in the app's own language.

   Admin was the last surface still dressed like a 2023 ops page: 16px
   rectangles, a flat table, browser prompts. Here it gets what Home and
   Mastery have: floating rounded panels on the soft canvas, pills that give
   under a press and spring back (feel.css's --press-* tokens, so reduced
   motion still flattens it), and charts in one hue with a hover tip on every
   mark. `body:not(#_)` is the same specificity step clean.css uses: three
   older sheets set .stat-card with `!important`, and this has to outrank them
   in both themes, not just load later.
   ═══════════════════════════════════════════════════════════════════════════ */
body:not(#_) .admin-page { padding: 28px 32px 96px !important; max-width: 1360px; }
body:not(#_) .admin-hero-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-6);
}
body:not(#_) .admin-hero { margin: 0 !important; }
body:not(#_) .admin-live {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px; border-radius: var(--soft-control);
  background: rgb(var(--accent-rgb) / 0.08); border: 1px solid rgb(var(--accent-rgb) / 0.18);
  color: var(--text-muted); font-size: 12.5px; font-weight: 600;
}
body:not(#_) .admin-live-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 0 rgb(var(--accent-rgb) / 0.5); animation: adm-pulse 2.4s var(--ease-out, ease-out) infinite;
}
body:not(#_) .admin-live-bad { background: rgb(var(--danger-rgb) / 0.08); border-color: rgb(var(--danger-rgb) / 0.25); }
body:not(#_) .admin-live-bad .admin-live-dot { background: rgb(var(--danger-rgb)); animation: none; }
@keyframes adm-pulse { 0% { box-shadow: 0 0 0 0 rgb(var(--accent-rgb) / 0.45); } 70%, 100% { box-shadow: 0 0 0 8px rgb(var(--accent-rgb) / 0); } }
@media (prefers-reduced-motion: reduce) { body:not(#_) .admin-live-dot { animation: none; } }

/* KPI tiles: soft cards that lift on hover and give under a press. */
body:not(#_) .admin-page .stat-grid {
  max-width: none; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: 14px;
}
body:not(#_) .admin-page .stat-card {
  border-radius: var(--soft-panel) !important; padding: 18px 20px 16px !important;
  background: var(--bg-elev-1) !important; border: 1px solid var(--border) !important;
  box-shadow: var(--shadow-sm) !important; min-width: 0;
  transition: transform var(--press-out) var(--ease-settle), box-shadow var(--press-out) var(--ease-settle) !important;
}
body:not(#_) .admin-page .stat-card::before { display: none; }
body:not(#_) .admin-page .stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md) !important; }
body:not(#_) .admin-page .stat-card:active { transform: scale(var(--press-scale)); transition-duration: var(--press-in) !important; }
body:not(#_) .admin-page .stat-label { color: var(--text-dim); text-transform: none; letter-spacing: 0; font-size: 12.5px; }
body:not(#_) .admin-page .stat-value {
  font-size: clamp(22px, 2.4vw, 30px) !important; line-height: 1.15; margin-top: 6px;
  overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
body:not(#_) .admin-page .stat-neg .stat-value { color: rgb(var(--danger-rgb)); -webkit-text-fill-color: rgb(var(--danger-rgb)); }
body:not(#_) .admin-page .stat-sub { line-height: 1.4; margin-top: 6px; }

/* Panels. Two columns on a wide screen; the wide ones span both. */
body:not(#_) .admin-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: var(--s-6); align-items: start;
}
body:not(#_) .admin-grid .admin-section { margin-top: 0; }
body:not(#_) .admin-panel-wide { grid-column: 1 / -1; }
@media (max-width: 900px) { body:not(#_) .admin-grid { grid-template-columns: minmax(0, 1fr); } }
body:not(#_) .admin-page .admin-section {
  border-radius: var(--soft-panel) !important; background: var(--bg-elev-1) !important;
  border: 1px solid var(--border) !important; box-shadow: var(--shadow-sm); min-width: 0;
}
body:not(#_) .admin-section-header { flex-wrap: wrap; margin-bottom: var(--s-4); }
body:not(#_) .admin-panel-sub { color: var(--text-dim); font-size: 12.5px; }
body:not(#_) .admin-title-dim { color: var(--text-dim); font-weight: 500; }
body:not(#_) .adm-muted { color: var(--text-dim); }

/* Bar chart: thin rounded bars on a hairline baseline, 2px apart. */
body:not(#_) .adm-chart { position: relative; padding-top: 18px; }
body:not(#_) .adm-chart-empty {
  display: grid; place-items: center; min-height: 120px; color: var(--text-dim); font-size: 13px;
  border-radius: var(--soft-row); background: rgb(var(--accent-rgb) / 0.04);
}
body:not(#_) .adm-chart-max { position: absolute; top: 0; left: 0; font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
body:not(#_) .adm-bars {
  display: flex; align-items: flex-end; gap: 2px; height: 128px;
  border-bottom: 1px solid var(--border); border-top: 1px dashed rgb(var(--accent-rgb) / 0.12);
}
body:not(#_) .adm-bar-hit { flex: 1 1 0; min-width: 0; height: 100%; display: flex; align-items: flex-end; cursor: default; border-radius: 6px 6px 0 0; }
body:not(#_) .adm-bar-hit:hover { background: rgb(var(--accent-rgb) / 0.06); }
body:not(#_) .adm-bar {
  width: 100%; max-width: 28px; margin: 0 auto; border-radius: 4px 4px 0 0;
  background: var(--accent); opacity: 0.85;
  transform-origin: bottom; transition: opacity 0.15s ease, transform var(--press-out) var(--ease-settle);
}
body:not(#_) .adm-bar-hit:hover .adm-bar { opacity: 1; transform: scaleY(1.03); }
body:not(#_) .adm-bar-zero { height: 2px !important; background: var(--border); opacity: 1; }
body:not(#_) .adm-chart-axis { display: flex; justify-content: space-between; margin-top: 6px; font-size: 11px; color: var(--text-dim); }

/* Mini stats row under a chart. */
body:not(#_) .adm-minis { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 120px), 1fr)); gap: 10px; margin: 14px 0; }
body:not(#_) .adm-minis > div {
  display: flex; flex-direction: column; gap: 2px; padding: 10px 14px;
  border-radius: var(--soft-row); background: rgb(var(--accent-rgb) / 0.05); min-width: 0;
}
body:not(#_) .adm-minis b { font-size: 18px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
body:not(#_) .adm-minis span { font-size: 12px; color: var(--text-dim); }

/* Ranked mix bars. */
body:not(#_) .adm-mix { margin-bottom: 16px; }
body:not(#_) .adm-mix-title { font-size: 12px; font-weight: 700; color: var(--text-muted); margin: 14px 0 8px; letter-spacing: 0.02em; }
body:not(#_) .adm-mix > .adm-mix-title:first-child { margin-top: 0; }
body:not(#_) .adm-mix-row {
  display: grid; grid-template-columns: minmax(70px, 30%) minmax(0, 1fr) 104px; align-items: center;
  gap: 10px; padding: 5px 8px; border-radius: 12px; font-size: 13px;
}
body:not(#_) .adm-mix-row:hover { background: rgb(var(--accent-rgb) / 0.06); }
body:not(#_) .adm-mix-label { overflow-wrap: anywhere; min-width: 0; }
body:not(#_) .adm-mix-track { height: 8px; border-radius: 999px; background: rgb(var(--accent-rgb) / 0.10); overflow: hidden; }
body:not(#_) .adm-mix-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
body:not(#_) .adm-mix-num { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; text-align: right; }

/* Lists (top users, deploys). */
body:not(#_) .adm-list { display: flex; flex-direction: column; gap: 4px; }
body:not(#_) .adm-list-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 14px;
  background: rgb(var(--accent-rgb) / 0.04); font-size: 13px; min-width: 0; flex-wrap: wrap;
}
body:not(#_) .adm-list-main { flex: 1 1 160px; min-width: 0; overflow-wrap: anywhere; }
body:not(#_) .adm-list-num { font-variant-numeric: tabular-nums; white-space: nowrap; }
body:not(#_) .adm-rank {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: rgb(var(--accent-rgb) / 0.14); color: var(--accent); font-size: 11px; font-weight: 700;
}
body:not(#_) .adm-dep { padding: 2px 10px; border-radius: 999px; font-size: 11px; font-weight: 700; text-transform: capitalize; background: rgb(var(--accent-rgb) / 0.12); color: var(--text-muted); }
body:not(#_) .adm-dep-live { background: rgb(var(--success-rgb) / 0.18); color: var(--text); }
body:not(#_) .adm-dep-build_failed, body:not(#_) .adm-dep-update_failed { background: rgb(var(--danger-rgb) / 0.16); color: var(--text); }

/* Server: chips, health pills (icon + word, never colour alone), meters. */
body:not(#_) .adm-chips, body:not(#_) .adm-health { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
body:not(#_) .adm-chip {
  padding: 5px 12px; border-radius: var(--soft-control); font-size: 12px; max-width: 100%; overflow-wrap: anywhere;
  background: var(--bg-elev-2); border: 1px solid var(--border); font-family: var(--font-mono);
}
body:not(#_) .adm-hc { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: var(--soft-control); font-size: 12.5px; font-weight: 600; }
body:not(#_) .adm-hc-ok { background: rgb(var(--success-rgb) / 0.14); }
body:not(#_) .adm-hc-bad { background: rgb(var(--warning-rgb) / 0.18); }
body:not(#_) .adm-hc-word { color: var(--text-dim); font-weight: 500; }
body:not(#_) .adm-meters { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 12px; margin: 4px 0 8px; }
body:not(#_) .adm-meter { padding: 12px 14px; border-radius: var(--soft-row); background: rgb(var(--accent-rgb) / 0.04); min-width: 0; }
body:not(#_) .adm-meter-head { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; font-weight: 600; flex-wrap: wrap; }
body:not(#_) .adm-state { font-size: 11px; font-weight: 600; color: var(--text-dim); }
body:not(#_) .adm-meter-track { height: 10px; border-radius: 999px; background: rgb(var(--accent-rgb) / 0.10); overflow: hidden; margin: 8px 0 6px; }
body:not(#_) .adm-meter-fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width 0.6s var(--ease-settle); }
body:not(#_) .adm-meter-warn .adm-meter-fill { background: rgb(var(--warning-rgb)); }
body:not(#_) .adm-meter-crit .adm-meter-fill { background: rgb(var(--danger-rgb)); }
body:not(#_) .adm-meter-detail { font-size: 11.5px; overflow-wrap: anywhere; }
body:not(#_) .adm-notes { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }
body:not(#_) .adm-note { padding: 8px 12px; border-radius: 14px; font-size: 12.5px; overflow-wrap: anywhere; }
body:not(#_) .adm-note-warn { background: rgb(var(--warning-rgb) / 0.14); }
body:not(#_) .adm-note-crit { background: rgb(var(--danger-rgb) / 0.12); }
body:not(#_) .adm-split { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 24px; }
@media (max-width: 760px) { body:not(#_) .adm-split { grid-template-columns: minmax(0, 1fr); } }

/* The one shared hover bubble. */
.adm-tip {
  position: fixed; z-index: 9999; pointer-events: none; max-width: 280px;
  padding: 6px 12px; border-radius: 12px; font-size: 12px; font-weight: 600;
  background: var(--text); color: var(--bg, #fff); box-shadow: var(--shadow-md);
}

/* Users table: soft rows, pill actions that squish. */
body:not(#_) .admin-users-container { border-radius: var(--soft-row); }
body:not(#_) .admin-users-table thead { background: rgb(var(--accent-rgb) / 0.05) !important; border-bottom: 0 !important; }
body:not(#_) .admin-users-table thead th:first-child { border-radius: 14px 0 0 14px; }
body:not(#_) .admin-users-table thead th:last-child { border-radius: 0 14px 14px 0; }
body:not(#_) .admin-users-table tbody tr.admin-user-row:hover { background: rgb(var(--accent-rgb) / 0.05) !important; }
body:not(#_) .admin-users-table tbody tr.admin-user-row td:first-child { border-radius: 14px 0 0 14px; }
body:not(#_) .admin-users-table tbody tr.admin-user-row td:last-child { border-radius: 0 14px 14px 0; }
body:not(#_) .admin-cell-email { min-width: 200px; }
body:not(#_) .admin-email-text { overflow-wrap: anywhere; margin-right: 6px; }
body:not(#_) .admin-tag {
  display: inline-block; margin: 2px 4px 0 0; padding: 1px 8px; border-radius: 999px; font-family: var(--font-sans, inherit);
  font-size: 10.5px; font-weight: 600; color: var(--text-muted); background: rgb(var(--accent-rgb) / 0.10); text-transform: capitalize;
}
body:not(#_) .admin-badge { border-radius: 999px !important; padding: 3px 10px !important; }
body:not(#_) .admin-badge-comp { background: rgb(var(--warning-rgb) / 0.22); color: var(--text); }
body:not(#_) .admin-act, body:not(#_) .admin-users-more, body:not(#_) .admin-plan-opt,
body:not(#_) .admin-search-box, body:not(#_) .admin-log-filter {
  border-radius: var(--soft-control) !important;
}
body:not(#_) .admin-act { border-color: var(--border) !important; padding: 5px 12px !important; }
body:not(#_) .admin-act, body:not(#_) .admin-users-more, body:not(#_) .admin-plan-opt, body:not(#_) #admin-refresh {
  transition: transform var(--press-out) var(--ease-settle), background 0.15s ease, border-color 0.15s ease, color 0.15s ease !important;
}
body:not(#_) .admin-act:active, body:not(#_) .admin-users-more:active, body:not(#_) .admin-plan-opt:active, body:not(#_) #admin-refresh:active {
  transform: scale(var(--press-scale-sm)); transition-duration: var(--press-in) !important; transition-timing-function: var(--ease-press) !important;
}
body:not(#_) .admin-search-box { padding: 9px 16px !important; }
body:not(#_) .admin-log-entry { border-radius: 16px !important; border-left-width: 3px !important; }

/* Plan picker. */
body:not(#_) .admin-plan-options { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; margin: 14px 0 6px; }
body:not(#_) .admin-plan-opt {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 12px 16px; cursor: pointer;
  background: var(--bg-elev-2); border: 1px solid var(--border); color: var(--text); font: inherit; text-align: left;
}
body:not(#_) .admin-plan-opt:hover { border-color: rgb(var(--accent-rgb) / 0.45); background: rgb(var(--accent-rgb) / 0.08); }
body:not(#_) .admin-plan-opt.is-current { border-color: var(--accent); }
body:not(#_) .admin-plan-name { font-weight: 700; font-size: 14px; }
body:not(#_) .admin-plan-sub { font-size: 11.5px; color: var(--text-dim); }

/* Lumi's badge floats 24px from the bottom-right corner (lumi.css) and
   stays put while the page scrolls, so on a wide screen the page keeps a
   lane for it: the right-most numbers (top schools' counts, the leader
   boards) never sit under it. A phone keeps its full width and scrolls the
   last row clear of the badge instead (the 120px below). */
@media (min-width: 641px) {
  body:not(#_) .admin-page { padding-right: calc(64px + var(--s-6, 24px) + 16px) !important; }
}
@media (max-width: 640px) {
  body:not(#_) .admin-page { padding: 18px 14px 120px !important; }
  body:not(#_) .admin-page .admin-section { padding: 16px !important; }
  body:not(#_) .adm-bars { height: 96px; }
}

/* Admin insights: the Top users metric picker, clickable emails, the
   "what these numbers mean" glossaries, and the per-user report drawer. */
body:not(#_) .adm-seg { display: flex; flex-wrap: wrap; gap: 6px; }
body:not(#_) .adm-seg-btn {
  padding: 6px 12px; border-radius: var(--soft-control) !important; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 600;
  background: var(--bg-elev-2); border: 1px solid var(--border); color: var(--text-muted);
  transition: transform var(--press-out) var(--ease-settle), background 0.15s ease, color 0.15s ease !important;
}
body:not(#_) .adm-seg-btn:hover { color: var(--text); border-color: rgb(var(--accent-rgb) / 0.35); }
body:not(#_) .adm-seg-btn.is-on { background: var(--accent); border-color: var(--accent); color: var(--bg, #fff); }
body:not(#_) .adm-seg-btn:active { transform: scale(var(--press-scale-sm)); transition-duration: var(--press-in) !important; }
body:not(#_) .adm-what { color: var(--text-dim); font-size: 12.5px; line-height: 1.5; margin: 0 0 12px; }
body:not(#_) .adm-leaders { display: flex; flex-direction: column; gap: 2px; }
body:not(#_) .adm-leader {
  display: grid; grid-template-columns: 22px minmax(0, 34%) minmax(0, 1fr) 120px; align-items: center;
  gap: 10px; padding: 6px 8px; border-radius: 12px; font-size: 13px;
}
body:not(#_) .adm-leader:hover { background: rgb(var(--accent-rgb) / 0.06); }
body:not(#_) .admin-email-link {
  background: none; border: 0; padding: 0; margin: 0 6px 0 0; font: inherit; color: var(--accent); cursor: pointer;
  text-align: left; overflow-wrap: anywhere; border-radius: 6px !important;
}
body:not(#_) .admin-email-link:hover { text-decoration: underline; text-underline-offset: 3px; }
body:not(#_) .admin-cell-email .admin-email-link { font-family: var(--font-mono); font-size: var(--fs-xs); }
body:not(#_) .adm-leader-name { min-width: 0; }
body:not(#_) .admin-user-name { display: block; font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
body:not(#_) .admin-cell-links { white-space: nowrap; }
body:not(#_) .admin-link-chip {
  display: inline-block; margin-right: 4px; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 600;
  background: rgb(var(--accent-rgb) / 0.10); color: var(--text-muted);
}
body:not(#_) .adm-explain { margin-top: 14px; border-radius: var(--soft-row); background: rgb(var(--accent-rgb) / 0.04); padding: 4px 14px; }
body:not(#_) .adm-explain summary { cursor: pointer; padding: 8px 0; font-size: 12.5px; font-weight: 700; color: var(--text-muted); }
body:not(#_) .adm-explain dl { margin: 0 0 10px; display: grid; grid-template-columns: minmax(120px, 30%) minmax(0, 1fr); gap: 6px 14px; font-size: 12.5px; }
body:not(#_) .adm-explain dt { font-weight: 600; }
body:not(#_) .adm-explain dd { margin: 0; color: var(--text-dim); line-height: 1.5; }
body:not(#_) .adm-bar-none {
  height: 6px !important; opacity: 1; background: repeating-linear-gradient(90deg, var(--border) 0 3px, transparent 3px 6px);
}

/* The report drawer: a soft sheet sliding in from the right. */
.adm-drawer-back {
  position: fixed; inset: 0; z-index: 9000; background: rgb(0 0 0 / 0.28);
  display: flex; justify-content: flex-end; animation: adm-fade 0.18s ease-out;
}
.adm-drawer-back.exiting { animation: adm-fade 0.18s ease-in reverse forwards; }
/* A confirm opened from the drawer (Grant trial, Set plan, Delete account,
   Send Family announcement) is appended after it, and sits over it. At the
   modal layer's own z-index it opened behind the drawer, where it could be
   neither read nor pressed. */
body .adm-drawer-back ~ .confirm-dialog-backdrop { z-index: 9100; }
.adm-drawer {
  width: min(820px, 100vw); height: 100%; overflow-y: auto; background: var(--bg);
  border-radius: 28px 0 0 28px; box-shadow: var(--shadow-xl, 0 28px 72px rgba(0,0,0,0.34));
  animation: adm-slide 0.32s var(--ease-settle, ease-out);
}
.adm-drawer-back.exiting .adm-drawer { animation: adm-slide 0.18s ease-in reverse forwards; }
@keyframes adm-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes adm-slide { from { transform: translateX(40px); opacity: 0.4; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .adm-drawer-back, .adm-drawer { animation: none !important; } }
.adm-drawer-body { padding: 26px 28px 40px; color: var(--text); }
.adm-drawer-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; margin-bottom: 12px; }
.adm-drawer-email { font-size: 20px; font-weight: 700; overflow-wrap: anywhere; }
.adm-drawer-sub { color: var(--text-dim); font-size: 13px; margin-top: 2px; text-transform: capitalize; }
.adm-drawer-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }
.adm-drawer-tools { display: flex; gap: 6px; flex: none; }
.adm-x {
  width: 34px; height: 34px; border-radius: 50% !important; border: 1px solid var(--border); background: var(--bg-elev-1);
  color: var(--text-muted); cursor: pointer; font-size: 15px; display: grid; place-items: center;
  transition: transform var(--press-out, 380ms) var(--ease-settle, ease) !important;
}
.adm-x:hover { color: var(--text); }
.adm-x:active { transform: scale(var(--press-scale-sm, 0.94)); transition-duration: var(--press-in, 90ms) !important; }
.adm-story {
  margin: 4px 0 14px; padding: 14px 16px; border-radius: 20px; font-size: 14px; line-height: 1.6;
  background: rgb(var(--accent-rgb) / 0.07); border: 1px solid rgb(var(--accent-rgb) / 0.14);
}
.adm-rsec {
  margin-top: 14px; padding: 16px 18px; border-radius: 24px; background: var(--bg-elev-1);
  border: 1px solid var(--border); box-shadow: var(--shadow-sm); min-width: 0;
}
.adm-drawer .adm-split { gap: 14px; }
.adm-drawer .adm-split > .adm-rsec { margin-top: 14px; }
.adm-rsec h3 { margin: 0 0 12px; font-size: 15px; font-weight: 700; }
.adm-rsec h3 .adm-muted { font-weight: 500; font-size: 12px; }
.adm-kv { display: grid; grid-template-columns: minmax(110px, 42%) minmax(0, 1fr); gap: 7px 12px; margin: 0; font-size: 13px; }
.adm-kv dt { color: var(--text-dim); }
.adm-kv dd { margin: 0; overflow-wrap: anywhere; }
.adm-yes { color: var(--text); font-weight: 600; }
.adm-no { color: var(--text-dim); }
.adm-table-wrap { overflow-x: auto; }
.adm-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.adm-table th { text-align: left; color: var(--text-dim); font-weight: 600; padding: 6px 8px; white-space: nowrap; }
.adm-table td { padding: 8px; border-top: 1px solid var(--border); }
.adm-pill { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 600; background: var(--bg-elev-2); white-space: nowrap; }
.adm-pill-ok { background: rgb(var(--success-rgb) / 0.16); }
.adm-pill-warn { background: rgb(var(--warning-rgb) / 0.22); }
.adm-drawer-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.adm-drawer .admin-act { padding: 8px 16px !important; font-size: 12.5px; }
/* "Family is here" (core/family_announce.py): its state, then what each
   channel did after a send, one line each. */
.adm-announce-state { margin: 0 0 10px; font-size: 13px; font-weight: 600; }
.adm-announce-lines {
  display: grid; gap: 4px; margin: 0 0 12px; padding: 10px 14px 10px 30px; border-radius: 16px;
  font-size: 13px; line-height: 1.5; background: rgb(var(--success-rgb) / 0.12);
}
.adm-announce-lines.is-error { background: rgb(var(--danger-rgb) / 0.12); }
.adm-announce-row { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 640px) {
  .adm-drawer { border-radius: 0; }
  .adm-drawer-body { padding: 18px 16px 32px; }
  body:not(#_) .adm-leader { grid-template-columns: 22px minmax(0, 1fr) 90px; }
  body:not(#_) .adm-leader .adm-mix-track { display: none; }
}

/* The users table carries nine columns now: tighter cells, dates on one
   line, compact actions, so it fits the card at desktop widths. */
body:not(#_) .admin-users-table th, body:not(#_) .admin-users-table td { padding: 10px 10px !important; }
body:not(#_) .admin-users-table .admin-cell-date { white-space: nowrap; }
body:not(#_) .admin-cell-email { min-width: 170px; max-width: 260px; }
body:not(#_) .admin-users-table .admin-act { padding: 4px 9px !important; margin-right: 2px; font-size: 10.5px; }

/* School: Settings row, dialogs, the setup step, the admin review list
   (core/school_profile.py). The picker itself is school_picker.css. */
body:not(#_) .set-school-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
body:not(#_) .set-school-status { margin-top: 2px; }
body:not(#_) .school-modal-label { display: block; font-size: 13px; font-weight: 600; margin: 4px 0 6px; }
body:not(#_) .school-modal-search .set-input,
body:not(#_) .school-modal-add .set-input,
body:not(#_) .school-verify-modal .set-input { width: 100%; box-sizing: border-box; }
/* Settings caps every .set-input at 300px for its rows; the dialogs' fields
   take the dialog's width. */
body[data-view="settings"] .school-modal .set-input,
body[data-view="settings"] .school-verify-modal .set-input {
  flex: none !important; max-width: none !important; width: 100% !important;
}
body:not(#_) .school-modal-error, body:not(#_) .onboard-school-error { min-height: 1.4em; color: var(--danger); font-size: 13px; margin: 8px 0 0; }
body:not(#_) .onboard-school-hint { color: var(--text-dim); font-size: 12.5px; margin: 6px 0 0; }
body:not(#_) .onboard-school-add { margin-top: 4px; }
body:not(#_) .school-remove { margin-right: auto; }
body:not(#_) .school-verify-sent { margin: 0 0 10px; font-size: 13.5px; overflow-wrap: anywhere; }
body:not(#_) #school-verify-resend { margin-top: 8px; }
body:not(#_) .school-modal, body:not(#_) .school-verify-modal { max-width: 460px; width: 100%; }
.account-popover-user .ac-menu-school { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body:not(#_) .adm-added-main { flex: 1 1 220px; min-width: 0; display: grid; gap: 2px; overflow-wrap: anywhere; }
body:not(#_) .adm-added-actions { display: flex; gap: 6px; flex-wrap: wrap; }
body:not(#_) .adm-added-merge { flex: 1 1 100%; display: grid; gap: 8px; padding-top: 6px; }
body:not(#_) .adm-added-merge[hidden] { display: none; }
body:not(#_) .adm-added-merge-actions { display: flex; gap: 6px; }
body:not(#_) .adm-learned-title { margin-top: 18px; }
body:not(#_) .adm-learned-note { font-size: 12.5px; margin: 2px 0 8px; }

/* Schools panel (D9). The steps of one hue every ordered quantity here uses
   (the level ring and the state tiles), chosen per theme rather than flipped:
   one hue, lightness in order, the lightest step at 2:1 or more on the panel
   (light 2.10:1, dark 2.30:1). --adm-none is "not known yet": a neutral far
   enough from both ends of the ramp that it never reads as a step (the ring
   wraps, so it touches the lightest and the darkest). Each step names the ink
   a label inside it is written in. */
body:not(#_) .admin-page {
  --adm-q1: rgb(var(--accent-rgb) / 0.50); --adm-q2: rgb(var(--accent-rgb) / 0.66);
  --adm-q3: rgb(var(--accent-rgb) / 0.82); --adm-q4: rgb(var(--accent-rgb));
  --adm-q1-ink: var(--text); --adm-q2-ink: var(--text); --adm-q3-ink: var(--text); --adm-q4-ink: var(--accent-ink);
  --adm-none: #DFE3E0;
}
html[data-theme="dark"] body:not(#_) .admin-page {
  --adm-q1: rgb(var(--accent-rgb) / 0.34); --adm-q2: rgb(var(--accent-rgb) / 0.52);
  --adm-q3: rgb(var(--accent-rgb) / 0.74); --adm-q4: rgb(var(--accent-rgb));
  --adm-q1-ink: var(--text); --adm-q2-ink: var(--text); --adm-q3-ink: var(--accent-ink); --adm-q4-ink: var(--accent-ink);
  --adm-none: #848D88;
}
/* The panel reflows on its own width, not the window's: at 768 the window
   is a tablet but the card is 600px, too narrow for two columns. */
body:not(#_) #admin-schools-body { container-type: inline-size; container-name: admschools; }
body:not(#_) .adm-split-rev { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
body:not(#_) .adm-split-even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 760px) { body:not(#_) .adm-split-rev, body:not(#_) .adm-split-even { grid-template-columns: minmax(0, 1fr); } }
@container admschools (max-width: 820px) {
  body:not(#_) #admin-schools-body > .adm-split { grid-template-columns: minmax(0, 1fr); }
}
body:not(#_) #admin-schools-body > .adm-split { margin-top: 22px; align-items: start; }
body:not(#_) .adm-school-cell { min-width: 0; }
body:not(#_) .adm-school-cell > .adm-mix-title:first-child { margin-top: 0; }
body:not(#_) .adm-mix-more { font-size: 12px; padding: 2px 8px 0; }

/* The level ring: the legend beside it while there is room, under it after. */
body:not(#_) .adm-donut { display: flex; flex-wrap: wrap; gap: 16px 20px; align-items: center; justify-content: center; }
body:not(#_) .adm-donut svg { width: 148px; height: 148px; flex: none; display: block; overflow: visible; }
body:not(#_) .adm-donut-seg { fill: none; stroke-width: 16; cursor: default; transition: opacity 0.15s ease, stroke-width 0.15s ease; }
body:not(#_) .adm-donut-seg:hover { stroke-width: 19; }
body:not(#_) .adm-donut-q1 { stroke: var(--adm-q1); }
body:not(#_) .adm-donut-q2 { stroke: var(--adm-q2); }
body:not(#_) .adm-donut-q3 { stroke: var(--adm-q3); }
body:not(#_) .adm-donut-q4 { stroke: var(--adm-q4); }
body:not(#_) .adm-donut-q0 { stroke: var(--adm-none); }
body:not(#_) .adm-donut-total { font-size: 21px; font-weight: 700; fill: var(--text); }
body:not(#_) .adm-donut-sub { font-size: 9.5px; fill: var(--text-dim); }
body:not(#_) .adm-donut-legend { display: flex; flex-direction: column; gap: 2px; font-size: 13px; flex: 1 1 220px; min-width: min(100%, 220px); }
body:not(#_) .adm-donut-row {
  display: grid; grid-template-columns: 12px minmax(0, 1fr) auto; align-items: center; gap: 8px;
  padding: 5px 8px; border-radius: 12px;
}
body:not(#_) .adm-donut-row:hover { background: rgb(var(--accent-rgb) / 0.06); }
body:not(#_) .adm-donut-row.is-zero .adm-donut-label, body:not(#_) .adm-donut-row.is-zero .adm-mix-num { color: var(--text-dim); font-weight: 500; }
body:not(#_) .adm-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 4px; flex: none; vertical-align: middle; }
body:not(#_) .adm-swatch-q1 { background: var(--adm-q1); }
body:not(#_) .adm-swatch-q2 { background: var(--adm-q2); }
body:not(#_) .adm-swatch-q3 { background: var(--adm-q3); }
body:not(#_) .adm-swatch-q4 { background: var(--adm-q4); }
body:not(#_) .adm-swatch-q0 { background: var(--adm-none); }
body:not(#_) .adm-swatch-none { background: transparent; box-shadow: inset 0 0 0 1px var(--border-strong); }

/* Top schools: the leaderboard row, a two-line name and a two-line count. */
body:not(#_) .adm-school-row { grid-template-columns: 22px minmax(0, 46%) minmax(0, 1fr) 96px; }
body:not(#_) .adm-school-who { display: grid; gap: 1px; min-width: 0; }
/* One line per name: a long name ends in an ellipsis (the hover tip carries
   it whole) so the "added" tag stays beside it and every row is one height. */
body:not(#_) .adm-school-name { font-weight: 600; display: flex; align-items: baseline; gap: 6px; min-width: 0; }
body:not(#_) .adm-school-name-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body:not(#_) .adm-school-name .admin-tag { flex: none; margin: 0; line-height: 1.4; }
body:not(#_) .adm-school-place { font-size: 11.5px; overflow-wrap: anywhere; }
body:not(#_) .adm-school-num { display: grid; justify-items: end; line-height: 1.25; }
body:not(#_) .adm-school-share { font-size: 11.5px; font-weight: 500; }
@media (max-width: 640px) {
  /* The bar keeps its own row under the name on a phone (the generic
     leaderboard hides its track there, which left this chart barless). */
  body:not(#_) .adm-school-row {
    grid-template-columns: 22px minmax(0, 1fr) 84px;
    grid-template-areas: "rank who num" ". bar bar"; row-gap: 6px;
  }
  body:not(#_) .adm-school-row .adm-rank { grid-area: rank; }
  body:not(#_) .adm-school-row .adm-school-who { grid-area: who; }
  body:not(#_) .adm-school-row .adm-school-num { grid-area: num; }
  body:not(#_) .adm-school-row .adm-mix-track { display: block; grid-area: bar; }
  /* A phone has no hover tip to show a cut name, so the name wraps there and
     the tag runs on after it. */
  body:not(#_) .adm-school-name { display: block; }
  body:not(#_) .adm-school-name-text { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
  body:not(#_) .adm-school-name .admin-tag { margin-left: 6px; vertical-align: 1px; }
}

/* The state tiles. */
body:not(#_) .adm-tiles { display: grid; grid-template-columns: repeat(11, minmax(0, 1fr)); gap: 3px; max-width: 560px; }
body:not(#_) .adm-tile {
  aspect-ratio: 1; display: grid; place-items: center; border-radius: 6px; min-width: 0;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.01em; cursor: default;
  transition: transform var(--press-out) var(--ease-settle);
}
body:not(#_) .adm-tile:hover { transform: scale(1.08); box-shadow: 0 0 0 2px var(--bg-elev-1), 0 0 0 3px rgb(var(--accent-rgb) / 0.55); }
body:not(#_) .adm-tile-q0 { background: transparent; box-shadow: inset 0 0 0 1px var(--border-strong); color: var(--text-dim); font-weight: 600; }
body:not(#_) .adm-tile-q1 { background: var(--adm-q1); color: var(--adm-q1-ink); }
body:not(#_) .adm-tile-q2 { background: var(--adm-q2); color: var(--adm-q2-ink); }
body:not(#_) .adm-tile-q3 { background: var(--adm-q3); color: var(--adm-q3-ink); }
body:not(#_) .adm-tile-q4 { background: var(--adm-q4); color: var(--adm-q4-ink); }
@media (max-width: 520px) { body:not(#_) .adm-tile { font-size: 8.5px; border-radius: 4px; } body:not(#_) .adm-tiles { gap: 2px; } }
body:not(#_) .adm-tiles-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin-top: 10px;
  font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums;
}
body:not(#_) .adm-tiles-legend > span { display: inline-flex; align-items: center; gap: 4px; }
body:not(#_) .adm-tiles-scale > span:first-child { margin-right: 2px; }
body:not(#_) .adm-tiles-scale > span:last-child { margin-left: 2px; }
@media (prefers-reduced-motion: reduce) {
  body:not(#_) .adm-tile, body:not(#_) .adm-donut-seg { transition: none; }
  body:not(#_) .adm-tile:hover { transform: none; }
}
