/* Lattice — carried from the Nocturne canvas, screen set 1b.
   Two layouts, not one that shrinks. `data-vp` on <html> is set by core.js
   from the same 860px query the media blocks use, so the markup the shell
   builds and the rules that style it can never disagree. Anything purely
   structural keys off the attribute; anything purely dimensional keys off
   the media query. */

:root {
  --bg:            #0f1018;
  --chrome:        #161826;
  --surface:       #171926;
  --inset:         #1b1d2a;
  --inset-2:       #1b1d2a;
  --line:          rgba(233, 233, 237, .08);
  --line-card:     rgba(233, 233, 237, .09);
  --line-strong:   rgba(233, 233, 237, .12);
  --edge:          rgba(233, 233, 237, .10);
  --edge-2:        #3f424d;

  --text:          #e9e9ed;
  --text-1:        rgba(233, 233, 237, .78);
  --text-2:        rgba(233, 233, 237, .62);
  --text-3:        rgba(233, 233, 237, .45);
  --text-4:        rgba(233, 233, 237, .38);

  --accent:        #7ea6c4;
  --accent-soft:   #a8c6dc;
  --accent-deep:   #4c7391;
  --accent-ink:    #2f4c60;
  --accent-wash:   #22333f;
  --on-accent:     #12141c;

  --danger:        #d98d8d;
  --warn:          #d9c08d;
  --ok:            #8dd9a4;

  --r-sm: 5px; --r-md: 6px; --r-lg: 8px;

  /* Desktop bar height; the mobile block below overrides both. */
  --nav-h: 56px;
  --tabbar-h: 0px;

  /* Home-screen web apps run edge to edge under `viewport-fit=cover`, so the
     notch, status bar and home indicator all overlap the page unless these
     insets are honoured. They are 0 everywhere that has no cutouts. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  --pad-x: 32px;
  --font: Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;
}

@media (max-width: 860px) {
  :root { --nav-h: 50px; --tabbar-h: 74px; --pad-x: 16px; }
}

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--font); font-size: 14px; line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  overscroll-behavior-y: none;
}
h1, h2, h3, h4 { margin: 0; font-weight: 400; letter-spacing: -.02em; line-height: 1.2; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-soft); }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
[hidden] { display: none !important; }

/* The design's repeated eyebrow: 11px 600 weight, wide tracking, quiet. */
.kicker, .panel-title, .cc-code, .cc-label, .course-chip,
.section-head h4, .list-divider, .settings-side .t, .stat .t, .headroom .k {
  font-size: 11px; font-weight: 600; letter-spacing: .11em;
  text-transform: uppercase; color: var(--text-4);
}
.kicker { margin-bottom: 10px; }
.kicker.is-course { color: var(--accent); }

/* ══ Top chrome ═══════════════════════════════════════════════════════ */

.nav {
  display: flex; align-items: center;
  height: calc(var(--nav-h) + var(--safe-t));
  padding-top: var(--safe-t);
  padding-left: calc(var(--pad-x) + var(--safe-l));
  padding-right: calc(var(--pad-x) + var(--safe-r));
  background: var(--chrome);
  box-shadow: inset 0 -1px 0 var(--edge);
  position: sticky; top: 0; z-index: 40;
}
:root[data-vp="desktop"] .nav { gap: 28px; }
:root[data-vp="mobile"]  .nav { gap: 9px; }

.nav-brand { display: flex; align-items: center; gap: 9px; }
:root[data-vp="desktop"] .nav-brand { margin-right: 6px; }
.nav-brand span { font-size: 15px; font-weight: 500; letter-spacing: -.01em; }

/* ── Desktop: links live in the bar, underlined when active ───────────── */

:root[data-vp="desktop"] .nav-links {
  display: flex; align-items: center; gap: 24px; height: var(--nav-h);
}
:root[data-vp="desktop"] .nav-links a {
  font-size: 13.5px; color: var(--text-2); height: var(--nav-h);
  display: flex; align-items: center; white-space: nowrap;
}
:root[data-vp="desktop"] .nav-links a i { display: none; }
:root[data-vp="desktop"] .nav-links a:hover { color: var(--text); }
:root[data-vp="desktop"] .nav-links a.is-active {
  color: var(--text); box-shadow: inset 0 -1.5px 0 var(--accent);
}

/* ── Mobile: links become the bottom tab bar ──────────────────────────── */

:root[data-vp="mobile"] .nav-links {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
  display: flex; justify-content: space-around;
  height: calc(var(--tabbar-h) + var(--safe-b));
  padding: 9px calc(4px + var(--safe-r)) var(--safe-b) calc(4px + var(--safe-l));
  background: var(--chrome);
  box-shadow: inset 0 1px 0 var(--edge);
  /* Frosted, so content scrolling under the home indicator stays legible. */
  backdrop-filter: saturate(140%) blur(12px);
  background: color-mix(in srgb, var(--chrome) 92%, transparent);
}
:root[data-vp="mobile"] .nav-links a {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  flex: 1; color: var(--text-2); font-size: 10px; letter-spacing: .01em;
  padding-top: 0;
}
:root[data-vp="mobile"] .nav-links a i { font-size: 19px; }
:root[data-vp="mobile"] .nav-links a.is-active { color: var(--accent); }

.nav-right { margin-left: auto; display: flex; align-items: center; }
:root[data-vp="desktop"] .nav-right { gap: 18px; }
:root[data-vp="mobile"]  .nav-right { gap: 16px; min-width: 0; }

/* Search: a real field on desktop, a single glyph that expands on mobile. */
.nav-search { position: relative; display: flex; align-items: center; gap: 7px; }
:root[data-vp="desktop"] .nav-search {
  width: 200px; height: 30px; padding: 0 10px;
  border-radius: var(--r-md); background: var(--inset);
  box-shadow: inset 0 0 0 1px var(--edge);
}
.nav-search > i { font-size: 13px; color: var(--text-3); flex: none; }
.nav-search input {
  border: 0; background: none; outline: none; width: 100%; font-size: 12.5px;
}
.nav-search input::placeholder { color: var(--text-3); }

:root[data-vp="mobile"] .nav-search > i { font-size: 17px; color: var(--text-2); }
/* Collapsed by default; the shell sets `is-open` when the glyph is tapped. */
:root[data-vp="mobile"] .nav-search input { display: none; }
:root[data-vp="mobile"] .nav-search.is-open {
  position: absolute; left: calc(12px + var(--safe-l)); right: calc(12px + var(--safe-r));
  top: calc(var(--safe-t) + 9px); height: 32px; padding: 0 10px; z-index: 5;
  border-radius: var(--r-md); background: var(--inset);
  box-shadow: inset 0 0 0 1px var(--line-strong);
}
:root[data-vp="mobile"] .nav-search.is-open input { display: block; font-size: 13.5px; }

/* Sync: "Synced 2m ago" spelled out on desktop, just the age on mobile. */
.sync-pill {
  display: flex; align-items: center; gap: 7px; white-space: nowrap;
  font-size: 12px; color: var(--text-2); min-width: 0;
}
.sync-pill span:not(.dot) { overflow: hidden; text-overflow: ellipsis; }
.sync-pill i { display: none; }
:root[data-vp="mobile"] .sync-pill { gap: 6px; font-size: 11.5px; color: var(--text-3); }

.dot { width: 5px; height: 5px; border-radius: 50%; background: var(--accent); flex: none; }
.dot.warn { background: var(--warn); } .dot.bad { background: var(--danger); }
.dot.pulse { animation: pulse 1.4s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .35; } }

.avatar {
  width: 27px; height: 27px; border-radius: 50%; background: var(--accent-ink);
  display: grid; place-items: center; font-size: 11px; font-weight: 500;
  color: #cfe0ec; flex: none;
}
.icon-btn { color: var(--text-2); font-size: 16px; display: grid; place-items: center; }
.icon-btn:hover { color: var(--text); }
/* The phone bar has no room for a sign-out glyph or an avatar -- Settings ›
   Account owns signing out. The gear stays: it is the only way in to Settings
   on a phone, since Settings is not one of the five tabs. */
:root[data-vp="mobile"] .nav .is-signout,
:root[data-vp="mobile"] .nav .avatar { display: none; }
:root[data-vp="mobile"] .nav .is-settings { font-size: 18px; }
.icon-btn.is-active { color: var(--accent); }

/* ══ Page scaffold ════════════════════════════════════════════════════ */

.page {
  padding:
    40px
    calc(var(--pad-x) + var(--safe-r))
    calc(48px + var(--tabbar-h) + var(--safe-b))
    calc(var(--pad-x) + var(--safe-l));
  max-width: 1244px; margin: 0 auto;
}
:root[data-vp="mobile"] .page { padding-top: 22px; }

/* Headline block: on desktop a second column sits beside it (the 14-day
   strip, the filter tabs, the score). On mobile that column drops under. */
.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 32px; margin-bottom: 26px;
}
.page-head > :first-child { min-width: 0; }
.page-head-aside { flex: none; padding-bottom: 2px; }
.page-head h2 { font-size: 32px; letter-spacing: -.025em; line-height: 1.15; }

:root[data-vp="mobile"] .page-head {
  flex-direction: column; align-items: stretch; gap: 0; margin-bottom: 22px;
}
:root[data-vp="mobile"] .page-head h2 { font-size: 24px; line-height: 1.2; }
:root[data-vp="mobile"] .page-head-aside { padding-bottom: 0; margin-top: 20px; }

.section-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 12px; }
.section-head .hint { font-size: 12px; font-weight: 400; letter-spacing: 0;
  text-transform: none; color: var(--text-3); }
:root[data-vp="mobile"] .section-head .hint { font-size: 11.5px; }

.back-link {
  display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px;
  color: var(--text-2); margin-bottom: 22px; padding: 0;
}
.back-link:hover { color: var(--text); }
.back-link i { font-size: 15px; }
:root[data-vp="mobile"] .back-link { gap: 7px; margin-bottom: 16px; }

/* ══ Tabs: the design's underlined text row, used for filters ═════════ */

.seg { display: flex; align-items: baseline; gap: 20px; }
.seg button {
  font-size: 13px; color: var(--text-3); padding: 0 0 5px; white-space: nowrap;
}
.seg button:hover { color: var(--text-2); }
.seg button.is-active {
  color: var(--accent); font-weight: 500; box-shadow: inset 0 -1.5px 0 var(--accent);
}
.seg-label { font-size: 11px; font-weight: 600; letter-spacing: .11em;
  text-transform: uppercase; color: var(--text-4); }

/* A full-bleed underlined row, the way Assignments and Course home use it. */
.tabrow {
  display: flex; gap: 24px; border-bottom: 1px solid var(--line); margin-bottom: 24px;
}
.tabrow button { padding-bottom: 10px; }
:root[data-vp="mobile"] .tabrow {
  gap: 18px; margin-left: calc(-1 * var(--pad-x)); margin-right: calc(-1 * var(--pad-x));
  padding: 0 var(--pad-x) 0; margin-bottom: 18px;
  overflow-x: auto; scrollbar-width: none;
}
:root[data-vp="mobile"] .tabrow::-webkit-scrollbar { display: none; }
:root[data-vp="mobile"] .tabrow button { padding-bottom: 9px; }

/* Boxed segmented control, for the few places that need a real widget
   (density, urgency window) rather than a filter row. */
.seg.is-boxed {
  display: inline-flex; gap: 0; border-radius: var(--r-md); overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--line-strong);
}
.seg.is-boxed button {
  padding: 7px 13px; font-size: 12.5px; color: var(--text-3);
  border-left: 1px solid var(--line-strong); box-shadow: none;
}
.seg.is-boxed button:first-child { border-left: 0; }
.seg.is-boxed button.is-active {
  color: var(--accent); font-weight: 400; box-shadow: inset 0 0 0 1px var(--accent);
}

/* ══ Course cards ═════════════════════════════════════════════════════ */

.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.grid-3 > *, .stat-grid > *, .conn-grid > *, .settings-wrap > * { min-width: 0; }
:root[data-vp="mobile"] .grid-3 { display: flex; flex-direction: column; gap: 12px; }

.course-card {
  display: flex; flex-direction: column; text-align: left;
  background: var(--surface); border: 1px solid var(--line-card);
  border-radius: var(--r-lg); padding: 18px 20px 16px;
  transition: border-color .15s ease;
}
.course-card:hover { border-color: rgba(126, 166, 196, .45); }
:root[data-vp="mobile"] .course-card { padding: 15px 16px 14px; }

.cc-code {
  letter-spacing: .08em; color: var(--accent); margin-bottom: 7px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cc-name {
  font-size: 17px; font-weight: 400; letter-spacing: -.015em; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
:root[data-vp="desktop"] .cc-name { min-height: 42px; }

/* The rule under the title, then the next deadline, then the footer. */
.cc-rule { height: 1px; background: var(--line); margin: 16px 0 14px; }
:root[data-vp="mobile"] .cc-rule { margin: 13px 0 12px; }

.cc-next {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  margin-bottom: 18px;
}
:root[data-vp="mobile"] .cc-next { margin-bottom: 0; }
.cc-next > div:first-child { min-width: 0; }
.cc-next-title { font-size: 13.5px; line-height: 1.35; color: var(--text-1); }
.cc-next.is-critical .cc-next-title { color: var(--accent-soft); }
.cc-next-due { font-size: 12px; color: var(--text-3); margin-top: 4px; }
.cc-rel {
  flex: none; font-size: 12.5px; font-variant-numeric: tabular-nums;
  color: var(--text-3); padding-top: 1px;
}
.cc-next.is-critical .cc-rel { color: var(--accent-soft); }

.cc-foot {
  margin-top: auto; display: flex; align-items: flex-end;
  justify-content: space-between; gap: 12px;
}
:root[data-vp="mobile"] .cc-foot { margin-top: 15px; align-items: center; }
.cc-score {
  font-size: 26px; font-weight: 400; letter-spacing: -.025em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
:root[data-vp="mobile"] .cc-score { font-size: 24px; }
.cc-label { letter-spacing: .09em; color: var(--text-3); margin-top: 7px; }
/* On the phone the score and its label sit on one baseline. */
:root[data-vp="mobile"] .cc-foot > div:first-child {
  display: flex; align-items: baseline; gap: 8px;
}
:root[data-vp="mobile"] .cc-label { margin-top: 0; }
.cc-progress { text-align: right; }
.cc-progress .m {
  font-size: 12px; font-variant-numeric: tabular-nums;
  color: var(--text-3); margin-bottom: 7px;
}
:root[data-vp="mobile"] .cc-progress .m { font-size: 11.5px; margin-bottom: 6px; }
/* A 2px rule, not a rounded pill: the canvas draws progress as a hairline. */
.hairline { width: 72px; height: 2px; background: rgba(233, 233, 237, .14); }
.hairline > i { display: block; height: 2px; background: var(--accent); }

/* ══ The 14-day strip ═════════════════════════════════════════════════ */

.runway { margin-bottom: 0; }
.runway-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 9px;
}
.runway-head .m { font-size: 11.5px; color: var(--text-3); }
.runway-bars { display: flex; align-items: flex-end; gap: 5px; height: 56px; }
:root[data-vp="mobile"] .runway-bars {
  justify-content: space-between; gap: 0; height: 48px;
}
.runway-bars .col {
  position: relative; width: 16px; padding-bottom: 18px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
}
:root[data-vp="mobile"] .runway-bars .col { width: 18px; padding-bottom: 16px; }
.runway-bars .col > i { display: block; width: 100%; background: var(--accent-deep); }
.runway-bars .col.is-empty > i { background: rgba(233, 233, 237, .12); }
.runway-bars .col > span {
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  white-space: nowrap; font-size: 9.5px; color: var(--text-4);
}
.runway-bars .col.is-today > span { color: var(--accent-soft); }

/* ══ Rows and bands ═══════════════════════════════════════════════════ */

.list { display: flex; flex-direction: column; }
.row {
  display: flex; align-items: center; gap: 16px; padding: 14px 0;
  border-top: 1px solid var(--line); text-align: left; width: 100%;
}
.row:hover { background: rgba(233, 233, 237, .03); }
.row-main { flex: 1; min-width: 0; }
.row-title {
  font-size: 14.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.row-sub { font-size: 12px; color: var(--text-3); margin-top: 3px; }
.row-right { text-align: right; flex: none; }

.tag {
  display: inline-flex; align-items: center; font-size: 11.5px; font-weight: 500;
  padding: 3px 9px; border-radius: var(--r-sm); white-space: nowrap;
}
.tag-accent { background: var(--accent-ink); color: #cfe0ec; }
.tag-neutral { background: var(--edge-2); color: var(--text); }
.tag-danger { background: #4a2b2b; color: #ecc; }
.tag-ok { background: #2b4a34; color: #cec; }
.tag-outline { border: 1px solid var(--accent-deep); color: #cfe0ec; }
.pill-solid {
  font-size: 11.5px; font-weight: 500; color: var(--on-accent);
  background: var(--accent-soft); padding: 3px 9px;
  border-radius: var(--r-sm); white-space: nowrap;
}
.pill-outline {
  font-size: 11.5px; font-weight: 500; color: #cfe0ec; border: 1px solid var(--accent-deep);
  padding: 2px 8px; border-radius: var(--r-sm); white-space: nowrap;
}

/* The fixed identifier column. On the phone it moves above the title, where
   a 118px gutter would leave the title nothing to occupy. */
.course-chip {
  letter-spacing: .08em; color: var(--text-3); flex: none; width: 118px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.35;
}
/* On the phone the identifier moves inside the title column -- the views
   build it there, because a 118px gutter beside a wrapping title leaves the
   title about four characters. `is-inline` is that placement. */
.course-chip.is-inline { width: auto; display: block; margin-bottom: 4px; }
:root[data-vp="mobile"] .row { align-items: flex-start; gap: 12px; padding: 13px 0; }
:root[data-vp="mobile"] .row .row-title { white-space: normal; line-height: 1.35; }
:root[data-vp="mobile"] .row .row-right { margin-top: 14px; }

/* Long-overdue work is kept but visibly demoted. */
.row.is-stale { opacity: .52; }
.row.is-stale:hover { opacity: .8; }

/* A revealed non-work row. Visibly a different kind of thing from the list
   it was spliced into, so "show" reads as widening the view rather than as
   the work list having grown. */
.row.is-quiet { opacity: .55; }
.row.is-quiet:hover { opacity: .85; }
.row.is-quiet .row-title { font-weight: 400; color: var(--text-2); }

/* The one line that says the list is filtered. */
.list-note {
  display: flex; align-items: baseline; gap: 8px;
  padding: 16px 0 0; font-size: 12px; color: var(--text-3);
  border-top: 1px solid var(--line); margin-top: 8px;
}

.list-divider {
  display: flex; align-items: center; gap: 10px; margin: 24px 0 0;
  color: var(--text-4);
}
.list-divider::after {
  content: ''; order: 5; flex: 1; height: 1px;
  background: linear-gradient(to right, var(--edge), transparent);
}
.list-divider .n {
  font-size: 12px; font-weight: 400; letter-spacing: 0; text-transform: none;
  font-variant-numeric: tabular-nums; color: var(--text-3);
}
.list-divider button { order: 6; }

/* ══ Panels and stats ═════════════════════════════════════════════════ */

.panel {
  background: var(--surface); border: 1px solid var(--line-card);
  border-radius: var(--r-lg); padding: 18px 20px 20px; margin-bottom: 16px;
}
:root[data-vp="mobile"] .panel { padding: 15px 16px 16px; margin-bottom: 14px; }
.panel-title { margin-bottom: 13px; color: var(--text-3); }

.stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin-bottom: 16px; }
:root[data-vp="mobile"] .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-bottom: 24px; }
.stat {
  background: var(--surface); border: 1px solid var(--line-card);
  border-radius: var(--r-lg); padding: 16px 18px 17px;
}
:root[data-vp="mobile"] .stat { padding: 13px 14px 14px; }
.stat .t { letter-spacing: .09em; color: var(--text-3); margin-bottom: 12px; }
.stat .v { display: flex; align-items: baseline; gap: 7px; }
.stat .v b {
  font-size: 26px; font-weight: 400; letter-spacing: -.025em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
:root[data-vp="mobile"] .stat .v b { font-size: 24px; }
.stat .v span { font-size: 12px; color: var(--text-3); }
.stat .n { font-size: 12px; color: var(--text-3); margin-top: 9px; }

.bar { height: 2px; background: rgba(233, 233, 237, .14); margin-top: 10px; }
.bar > i { display: block; height: 2px; background: var(--accent); }

.notice {
  display: flex; align-items: center; gap: 16px; padding: 15px 20px;
  background: var(--surface); border: 1px solid var(--line-card);
  border-radius: var(--r-lg); font-size: 13px; color: var(--text-2);
  margin-bottom: 26px;
}
.notice.is-next { border-color: rgba(126, 166, 196, .45); }
.notice.bad { border-color: #5a3a3a; }
.notice .spacer { flex: 1; }
.notice button:not(.btn) { color: var(--accent); font-size: 12.5px; }
:root[data-vp="mobile"] .notice {
  flex-direction: column; align-items: stretch; gap: 9px;
  padding: 14px 16px; margin-bottom: 24px;
}

/* ══ Buttons and forms ════════════════════════════════════════════════ */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 13px; font-weight: 500; height: 32px; padding: 0 13px;
  border-radius: var(--r-md); border: 1px solid transparent; white-space: nowrap;
}
.btn-primary { color: var(--accent); border-color: var(--accent); }
.btn-primary:hover { background: rgba(126, 166, 196, .12); }
.btn-solid {
  background: var(--accent); color: var(--on-accent); font-weight: 500;
  height: 40px; font-size: 14px;
}
.btn-solid:hover { background: var(--accent-soft); }
.btn-ghost { color: var(--text-2); box-shadow: inset 0 0 0 1px var(--line-strong); }
.btn-ghost:hover { color: var(--text); background: rgba(233, 233, 237, .05); }
.btn-bare { color: var(--text-2); box-shadow: none; padding: 0 4px; }
.btn-bare:hover { color: var(--text); background: none; }
.btn-danger { color: var(--danger); border-color: rgba(217, 141, 141, .4); }
.btn-danger:hover { background: rgba(217, 141, 141, .1); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
:root[data-vp="mobile"] .btn-solid { height: 42px; }

.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; color: var(--text-2); margin-bottom: 6px; }
.input {
  width: 100%; height: 36px; padding: 0 11px; font-size: 13.5px;
  background: var(--inset); color: var(--text); caret-color: var(--accent);
  border: 0; box-shadow: inset 0 0 0 1px var(--line-strong);
  border-radius: var(--r-md); outline: none;
}
.input::placeholder { color: var(--text-3); }
.input:hover { box-shadow: inset 0 0 0 1px rgba(233, 233, 237, .22); }
.input:focus { box-shadow: inset 0 0 0 1px var(--accent); }
textarea.input { height: auto; min-height: 110px; padding: 9px 11px; line-height: 1.5; resize: vertical; }
:root[data-vp="mobile"] .input { height: 42px; }
:root[data-vp="mobile"] textarea.input { height: auto; }

.dropzone {
  width: 100%; padding: 22px; text-align: center; color: var(--text-2);
  background: var(--inset); border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
}
.dropzone .s { font-size: 11.5px; color: var(--text-3); margin-top: 4px; }

.setting-row {
  display: flex; align-items: flex-start; gap: 32px; padding: 18px 0;
  border-top: 1px solid var(--line);
}
.setting-copy { flex: 1; min-width: 0; }
.setting-copy .t { font-size: 14.5px; margin-bottom: 4px; }
.setting-copy .d { font-size: 12.5px; line-height: 1.55; color: var(--text-3); }
.setting-ctl { flex: none; }
/* At phone width a fixed control beside flexible copy leaves the copy at
   zero, so the control drops onto its own full-width line. */
:root[data-vp="mobile"] .setting-row {
  flex-direction: column; align-items: stretch; gap: 0; padding: 16px 0;
}
:root[data-vp="mobile"] .setting-copy .d { margin-bottom: 12px; }
:root[data-vp="mobile"] .setting-ctl { width: 100%; }
:root[data-vp="mobile"] .setting-ctl .input,
:root[data-vp="mobile"] .setting-ctl select { width: 100%; }
:root[data-vp="mobile"] .setting-ctl .seg.is-boxed { display: flex; }
:root[data-vp="mobile"] .setting-ctl .seg.is-boxed button { flex: 1; text-align: center; }

.switch {
  width: 40px; height: 23px; border-radius: 12px; background: var(--edge-2);
  position: relative; transition: background .16s ease; flex: none;
}
.switch > i {
  position: absolute; top: 3px; left: 3px; width: 17px; height: 17px;
  border-radius: 50%; background: var(--text-3);
  transition: transform .16s ease, background .16s ease;
}
.switch.on { background: var(--accent-deep); }
.switch.on > i { transform: translateX(17px); background: #eaf2f8; }

.radio-list { display: flex; flex-direction: column; gap: 9px; }
.radio { display: flex; align-items: center; gap: 9px; font-size: 13.5px; cursor: pointer; }
.radio .dotm { width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid var(--line-strong); flex: none; }
.radio.on .dotm { border-color: var(--accent); background: var(--accent); box-shadow: inset 0 0 0 4px var(--chrome); }

/* ══ Settings layout ══════════════════════════════════════════════════ */

/* Desktop keeps the nine panes as a standing index beside the body. Mobile
   has no room for a 190px gutter, so the same list becomes the scrolling
   tab row the canvas shows. */
.settings-wrap { display: flex; gap: 44px; align-items: flex-start; }
.settings-side { width: 190px; flex: none; position: sticky; top: calc(var(--nav-h) + var(--safe-t) + 40px); }
.settings-side .t { margin-bottom: 14px; }
.settings-side button {
  display: block; width: 100%; text-align: left; padding: 7px 0;
  font-size: 13.5px; color: var(--text-2);
}
.settings-side button:hover { color: var(--text); }
.settings-side button.is-active { color: var(--accent); }
.settings-body { flex: 1; min-width: 0; max-width: 660px; }
.settings-body h2 { font-size: 26px; letter-spacing: -.022em; margin-bottom: 8px; }
.settings-body > p {
  font-size: 13.5px; line-height: 1.6; color: var(--text-2);
  margin: 0 0 26px; max-width: 56ch;
}

:root[data-vp="mobile"] .settings-wrap { flex-direction: column; gap: 0; }
:root[data-vp="mobile"] .settings-side {
  width: 100%; position: static; display: flex; gap: 18px;
  margin: 0 calc(-1 * var(--pad-x)) 18px; padding: 0 var(--pad-x) 0;
  border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
:root[data-vp="mobile"] .settings-side::-webkit-scrollbar { display: none; }
:root[data-vp="mobile"] .settings-side .t { display: none; }
:root[data-vp="mobile"] .settings-side button {
  width: auto; white-space: nowrap; font-size: 13px; padding: 0 0 9px;
  color: var(--text-3);
}
:root[data-vp="mobile"] .settings-side button.is-active {
  box-shadow: inset 0 -1.5px 0 var(--accent); font-weight: 500;
}
:root[data-vp="mobile"] .settings-body { max-width: none; }
:root[data-vp="mobile"] .settings-body h2 { font-size: 22px; }
:root[data-vp="mobile"] .settings-body > p { margin-bottom: 22px; }

.cust-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 26px; align-items: start;
}
.cust-grid > * { min-width: 0; }
:root[data-vp="mobile"] .cust-grid { grid-template-columns: 1fr; gap: 20px; }

/* Compact density tightens the rhythm everywhere, not just the preview. */
:root[data-density="compact"] .course-card { padding: 13px 15px 12px; }
:root[data-density="compact"] .row { padding: 10px 0; }
:root[data-density="compact"] .panel { padding: 14px 16px 15px; }
:root[data-density="compact"] .page { padding-top: 26px; }
:root[data-density="compact"] .grid-3 { gap: 12px; }

/* ══ Two-column detail layouts ════════════════════════════════════════ */

/* Assignment: brief and rubric left, submit right — as the canvas lays it
   out. The phone puts them in reading order down one column. */
.detail-grid {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: 20px; align-items: start;
}
.detail-grid > * { min-width: 0; }
:root[data-vp="mobile"] .detail-grid { display: block; }

/* Course home: two module columns on desktop, stacked on the phone. */
.module-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.module-grid > * { min-width: 0; }
:root[data-vp="mobile"] .module-grid { display: block; }
.module-block { margin-bottom: 0; }
:root[data-vp="mobile"] .module-block { margin-bottom: 20px; }
.module-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; margin-bottom: 12px;
}
.module-head .t { font-size: 14.5px; font-weight: 500; }
.module-head .s { font-size: 12px; color: var(--text-3); margin-top: 3px; }
:root[data-vp="mobile"] .module-head { gap: 12px; margin-bottom: 10px; }
:root[data-vp="mobile"] .module-head .t { font-size: 14px; }

/* Assignments: the workload chart beside its course filter. */
.work-grid { display: flex; gap: 16px; align-items: stretch; margin-bottom: 28px; }
.work-grid > :first-child { flex: 1; min-width: 0; }
.work-grid > :last-child { flex: none; width: 240px; }
.work-grid .panel { margin: 0; height: 100%; }
:root[data-vp="mobile"] .work-grid {
  flex-direction: column; gap: 0; margin-bottom: 22px;
}
:root[data-vp="mobile"] .work-grid > :last-child { width: 100%; }

.workload { display: flex; align-items: flex-end; gap: 10px; height: 92px; }
:root[data-vp="mobile"] .workload { justify-content: space-between; gap: 0; height: 76px; }
.workload .col {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 9px;
  justify-content: flex-end;
}
:root[data-vp="mobile"] .workload .col { flex: none; width: 38px; gap: 8px; }
.workload .col > i { display: block; width: 100%; max-width: 46px; background: var(--accent-deep); }
:root[data-vp="mobile"] .workload .col > i { max-width: 30px; }
.workload .col.is-today > i { background: var(--accent); }
.workload .col.is-empty > i { background: rgba(233, 233, 237, .12); }
.workload .col > span { font-size: 11px; color: var(--text-3); }
.workload .col.is-today > span { color: var(--accent-soft); }
:root[data-vp="mobile"] .workload .col > span { font-size: 10px; }

/* ══ Connection screen ════════════════════════════════════════════════ */

.conn-grid { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 20px; align-items: start; }
:root[data-vp="mobile"] .conn-grid { grid-template-columns: 1fr; }
.kv { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--line); font-size: 13px; }
.kv:first-child { border-top: 0; }
.kv .k { width: 118px; flex: none; color: var(--text-3); font-size: 12px; }
.kv .v { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kv .v.mono { font-family: ui-monospace, Menlo, monospace; font-size: 12px; }
.kv button { font-size: 12px; color: var(--accent); flex: none; }
:root[data-vp="mobile"] .kv { flex-wrap: wrap; row-gap: 2px; }
:root[data-vp="mobile"] .kv .k { width: 100%; }
:root[data-vp="mobile"] .kv .v { flex-basis: 100%; white-space: normal; }

.capture-window { background: var(--inset); border-radius: var(--r-lg); box-shadow: inset 0 0 0 1px var(--edge); overflow: hidden; }
.capture-bar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: #14161f; border-bottom: 1px solid var(--line); }
.capture-bar .lights { display: flex; gap: 5px; }
.capture-bar .lights span { width: 9px; height: 9px; border-radius: 50%; background: var(--edge-2); }
.capture-bar .url { font-size: 11.5px; color: var(--text-3); font-family: ui-monospace, Menlo, monospace; flex: 1; }
.capture-body { padding: 18px; display: flex; gap: 12px; align-items: flex-start; font-size: 13px; }
.capture-log { padding: 0 18px 16px; font-size: 12px; color: var(--text-3); }
.capture-log div { padding: 3px 0; }
.spin { animation: spin 1.1s linear infinite; display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }

.fail-row { display: flex; gap: 12px; padding: 11px 0; border-top: 1px solid var(--line); font-size: 12.5px; }
.code {
  font-family: ui-monospace, Menlo, monospace; font-size: 11px; font-weight: 600;
  padding: 2px 7px; border-radius: 4px; flex: none; height: fit-content;
}
.code.c401 { background: #4a3a2b; color: #ecd9c0; }
.code.c429 { background: #2b3a4a; color: #c0d9ec; }
.code.cERR { background: #4a2b2b; color: #ecc0c0; }

.q-item { padding: 12px 0; border-top: 1px solid var(--line); }
.q-head { display: flex; align-items: center; gap: 8px; font-size: 12px; margin-bottom: 4px; }
.q-head .p { font-family: ui-monospace, Menlo, monospace; color: var(--text-2); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-label { font-size: 13px; }
.q-note { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }

/* ══ Auth ═════════════════════════════════════════════════════════════ */

/* Desktop centres a 400px card on the ground; the phone drops the card and
   sets the form directly on the page, as screen 2i does. */
.auth-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.auth-card {
  width: min(400px, 100%); background: var(--surface);
  border: 1px solid var(--line-card); border-radius: 12px;
  padding: 32px 32px 28px; box-shadow: 0 20px 50px rgba(0, 0, 0, .5);
}
.auth-card .brand { display: flex; align-items: center; gap: 10px; margin-bottom: 26px; }
.auth-card .brand span { font-size: 17px; font-weight: 500; letter-spacing: -.01em; }
.auth-card h1 { font-size: 22px; letter-spacing: -.022em; margin-bottom: 8px; }
.auth-card .sub { font-size: 13.5px; line-height: 1.55; color: var(--text-2); margin-bottom: 24px; }

:root[data-vp="mobile"] .auth-wrap {
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 28px calc(var(--safe-b) + 24px);
}
:root[data-vp="mobile"] .auth-card {
  width: 100%; background: none; border: 0; box-shadow: none; padding: 0;
}
:root[data-vp="mobile"] .auth-card .brand { margin-bottom: 34px; }
:root[data-vp="mobile"] .auth-card h1 { font-size: 24px; letter-spacing: -.025em; }
:root[data-vp="mobile"] .auth-card .sub { margin-bottom: 28px; }

.auth-err {
  font-size: 12.5px; color: #eab; background: rgba(217, 141, 141, .1);
  border: 1px solid rgba(217, 141, 141, .3); border-radius: var(--r-md);
  padding: 9px 12px; margin-bottom: 14px;
}
.auth-or {
  display: flex; align-items: center; gap: 12px;
  margin: 20px 0 16px; color: var(--text-3); font-size: 11.5px;
}
.auth-or::before, .auth-or::after { content: ''; flex: 1; height: 1px; background: var(--edge); }
#passkey-signin { gap: 9px; width: 100%; height: 40px; }
#passkey-signin i { font-size: 17px; }
:root[data-vp="mobile"] #passkey-signin { height: 44px; font-size: 14px; }

.code-input {
  letter-spacing: .5em; font-size: 20px; text-align: center; height: 48px;
  font-family: ui-monospace, Menlo, monospace;
}
.qr { display: block; margin: 0 auto 14px; border-radius: 8px; background: #fff; padding: 8px; }
.secret-box {
  font-family: ui-monospace, Menlo, monospace; font-size: 12.5px; word-break: break-all;
  background: var(--inset); padding: 10px 12px; border-radius: var(--r-md);
  box-shadow: inset 0 0 0 1px var(--line); margin-bottom: 16px; text-align: center;
}
.recovery-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px;
  font-family: ui-monospace, Menlo, monospace; font-size: 13px;
  background: var(--inset); padding: 14px; border-radius: var(--r-md); margin-bottom: 16px;
}
:root[data-vp="mobile"] .recovery-grid { grid-template-columns: 1fr; }

.passkey-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.passkey-row .meta { flex: 1; min-width: 0; }
.passkey-row .name { font-size: 14px; }
.passkey-row .sub { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }

/* ══ Grade protection ═════════════════════════════════════════════════ */

.headroom-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 8px; }
:root[data-vp="mobile"] .headroom-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.headroom {
  background: var(--inset); border-radius: var(--r-md); padding: 13px 14px;
  box-shadow: inset 0 0 0 1px var(--line-card);
}
.headroom .k { font-size: 10px; letter-spacing: .09em; color: var(--accent); }
.headroom .v {
  font-size: 21px; font-weight: 400; letter-spacing: -.02em; margin-top: 5px;
  font-variant-numeric: tabular-nums;
}
.headroom .n { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }
.headroom.tight { box-shadow: inset 0 0 0 1px rgba(217, 141, 141, .5); }
.headroom.tight .n { color: var(--danger); }
.headroom.ok { box-shadow: inset 0 0 0 1px rgba(217, 192, 141, .4); }

/* ══ Grade impact ═════════════════════════════════════════════════════ */

.impact-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
:root[data-vp="mobile"] .impact-grid { gap: 6px; }
.impact-cell {
  background: var(--inset); border-radius: var(--r-md); padding: 11px 12px;
  box-shadow: inset 0 0 0 1px var(--line);
}
:root[data-vp="mobile"] .impact-cell { padding: 9px 7px; text-align: center; }
.impact-cell .k { font-size: 10.5px; color: var(--text-3); white-space: nowrap; }
.impact-cell .v { font-size: 15px; margin-top: 5px; font-variant-numeric: tabular-nums; }
.impact-cell .d { font-size: 10.5px; margin-top: 3px; font-variant-numeric: tabular-nums; color: var(--text-3); }
:root[data-vp="mobile"] .impact-cell .k { font-size: 10px; }
:root[data-vp="mobile"] .impact-cell .v { font-size: 13.5px; }
:root[data-vp="mobile"] .impact-cell .d { font-size: 10px; }
.impact-cell.up .d { color: var(--ok); }
.impact-cell.down .d { color: var(--danger); }

/* ══ Search results ═══════════════════════════════════════════════════ */

.search-pop {
  position: absolute; top: calc(100% + 6px); right: 0; width: 380px; max-width: 90vw;
  background: var(--surface); border-radius: var(--r-lg); overflow: hidden;
  box-shadow: 0 0 0 1px var(--edge), 0 18px 44px rgba(0, 0, 0, .55); z-index: 60;
  max-height: 60vh; overflow-y: auto;
}
:root[data-vp="mobile"] .search-pop { width: calc(100vw - 24px); right: 0; left: auto; max-height: 55vh; }
.search-item {
  display: flex; align-items: center; gap: 11px; padding: 11px 14px;
  width: 100%; text-align: left; border-top: 1px solid var(--line);
}
.search-item:first-child { border-top: 0; }
.search-item:hover, .search-item.is-cursor { background: rgba(233, 233, 237, .06); }
.search-item .t { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-item .s { font-size: 11px; color: var(--text-3); margin-top: 2px; }
.search-empty { padding: 20px; text-align: center; font-size: 13px; color: var(--text-3); }

/* ══ Bulk selection ═══════════════════════════════════════════════════ */

.bulk-bar {
  position: sticky; z-index: 45;
  bottom: calc(var(--tabbar-h) + var(--safe-b) + 10px);
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; margin-top: 16px;
  background: var(--surface); border-radius: var(--r-lg);
  box-shadow: 0 0 0 1px var(--accent-deep), 0 -8px 24px rgba(0, 0, 0, .4);
}
.bulk-bar > span { white-space: nowrap; font-variant-numeric: tabular-nums; }
:root[data-vp="mobile"] .bulk-bar { flex-wrap: wrap; row-gap: 8px; }
:root[data-vp="mobile"] .bulk-bar .btn { flex: 1 1 auto; }
/* The checkbox is not the point of the row -- the assignment is. It appears
   on hover, on keyboard focus, and whenever anything is already selected, so
   sweeping up stays possible without every row leading with a box.
   `:focus-within` is what keeps it reachable by tab rather than mouse-only. */
.row-check {
  width: 20px; height: 20px; flex: none; border-radius: var(--r-sm);
  border: 1px solid rgba(233, 233, 237, .16);
  display: grid; place-items: center; color: transparent; font-size: 11px;
  opacity: 0; transition: opacity .12s ease;
}
.row:hover .row-check,
.row:focus-within .row-check,
.row-check:focus-visible,
.row-check.on,
.list.is-selecting .row-check { opacity: 1; }
/* A pointer-less device has no hover, so there the box is simply always there. */
@media (hover: none) {
  .row-check { opacity: 1; }
}
.row-check.on { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
:root[data-vp="mobile"] .row .row-check { margin-top: 18px; }

/* ══ Noise cleanup ════════════════════════════════════════════════════ */

.noise-banner { font-size: 12px; line-height: 1.5; color: var(--text-3); }
.noise-banner .t { margin-bottom: 12px; }
.noise-banner .t b { color: var(--text-2); font-weight: 400; }

/* ══ Offline ══════════════════════════════════════════════════════════ */

.offline-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 9px calc(var(--pad-x) + var(--safe-r)) 9px calc(var(--pad-x) + var(--safe-l));
  background: #3a2f22; color: #e8d6bd; font-size: 12.5px;
  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .3);
  position: sticky; top: calc(var(--nav-h) + var(--safe-t)); z-index: 39;
}
.offline-bar i { font-size: 15px; }
.offline-bar .btn { color: #f0dfc6; box-shadow: none; }

/* ══ Misc ═════════════════════════════════════════════════════════════ */

.empty { padding: 48px 0; color: var(--text-3); font-size: 13.5px; }
.empty i { font-size: 26px; display: block; margin-bottom: 14px; color: var(--text-4); }
.empty .t {
  font-size: 19px; font-weight: 400; letter-spacing: -.02em;
  color: var(--text); margin-bottom: 8px;
}
.empty p { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--text-2); max-width: 44ch; }
.empty .btn { margin-top: 18px; height: 36px; }

/* Skeletons are flat blocks of the inset colour, as screen 2j draws them —
   a moving sheen over half the screen reads as activity that is not there. */
.skeleton { background: var(--inset); border-radius: 4px; }

.prose { font-size: 14px; line-height: 1.7; color: var(--text-1); max-width: 64ch; }
.prose :where(h1, h2, h3) { color: var(--text); margin: 18px 0 8px; font-size: 17px; font-weight: 400; }
.prose a { text-decoration: underline; }
.prose img { max-width: 100%; border-radius: var(--r-sm); }
.prose ul, .prose ol { padding-left: 20px; }
.prose table { border-collapse: collapse; width: 100%; font-size: 13px; }
.prose td, .prose th { border: 1px solid var(--line); padding: 6px 9px; }
.prose :first-child { margin-top: 0; }

.toast-host {
  position: fixed; z-index: 90; display: flex; flex-direction: column; gap: 9px;
  right: calc(20px + var(--safe-r));
  bottom: calc(20px + var(--tabbar-h) + var(--safe-b));
}
:root[data-vp="mobile"] .toast-host { left: calc(16px + var(--safe-l)); }
.toast {
  background: var(--surface); box-shadow: 0 0 0 1px var(--edge), 0 10px 30px rgba(0, 0, 0, .5);
  border-radius: var(--r-lg); padding: 12px 16px; font-size: 13px; max-width: 340px;
  animation: rise .18s ease;
}
.toast.bad { box-shadow: 0 0 0 1px #5a3a3a, 0 10px 30px rgba(0, 0, 0, .5); }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(15, 16, 24, .72);
  display: grid; place-items: center; padding: 22px; z-index: 80;
}
.modal {
  width: min(460px, 100%); background: var(--surface); border-radius: 12px; padding: 24px;
  box-shadow: 0 0 0 1px var(--edge), 0 20px 50px rgba(0, 0, 0, .6);
}
.modal h3 { font-size: 20px; letter-spacing: -.022em; margin-bottom: 8px; }
.modal p { font-size: 13.5px; line-height: 1.6; color: var(--text-2); margin: 0 0 20px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 9px; }

/* ══ Touch targets ═══════════════════════════════════════════════════════
   Several controls are deliberately small — a 20px checkbox, a 2px progress
   rule. Rather than inflate them visually, each grows an invisible hit area
   so a finger lands reliably. The element needs a positioning context for
   the pseudo-element to anchor to. */

@media (pointer: coarse), (max-width: 860px) {
  .row-check, .switch, .icon-btn,
  .kv button, .list-divider button, [data-hex] { position: relative; }
  .row-check::after, .switch::after, .icon-btn::after,
  .kv button::after, .list-divider button::after, [data-hex]::after {
    content: ''; position: absolute; top: 50%; left: 50%;
    width: max(100%, 44px); height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
  /* The row itself is the primary target, so its checkbox must not swallow
     the whole row's tap area. */
  .row-check::after { width: max(100%, 40px); height: max(100%, 40px); }

  /* Bare text buttons inside panels (Test connection, Reveal, Copy) are laid
     out as inline text and end up around 21px tall. Give them a real box. */
  .panel button:not(.btn):not(.switch):not(.row-check),
  .notice button:not(.btn) {
    position: relative; min-height: 34px; padding: 6px 8px; border-radius: var(--r-sm);
  }
  .panel button:not(.btn):not(.switch)::after,
  .notice button:not(.btn)::after {
    content: ''; position: absolute; top: 50%; left: 50%;
    width: max(100%, 44px); height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
}
