/* ══════════════════════════════════════════════════════════════
   PPG — styled to the Google design language, the same system
   Capra runs (cariara.com).

   Three rules carried over from Capra, and they are the whole brief:

   1. One palette. Capra dropped its dark mode because two palettes
      meant every surface had to be proven twice. PPG follows: a
      single light ramp, no [data-theme] fork, no toggle.
   2. White canvas. Surfaces are white with #DADCE0 hairlines; large
      groups may sit on the #F8F9FA panel tint. Tint or hairline,
      never both on one box.
   3. The Google four are visible, in order blue, red, yellow, green:
      card seams, section headings, chips, charts (the Cariara
      standard, tools/web/CARIARA_STYLE.md, settled in the last
      block of this file). Anything set as type uses the darkened
      text-safe variant, because #9AD61A on white is unreadable.
   ══════════════════════════════════════════════════════════════ */

:root {
  /* ── ground and surfaces ──
     Two planes, not four. The canvas is warm; everything lifted off it is
     plain white. --surface-2/-3 are quiet greys for insets and wells, not
     another elevation step. */
  --ground:     #FFFFFF;
  --surface-1:  #FFFFFF;
  --surface-2:  #F8F9FA;
  --surface-3:  #F8F9FA;

  --bg-base:      var(--ground);
  --bg-app:       var(--surface-1);
  --bg-surface:   var(--surface-1);
  --bg-elevated:  var(--surface-2);
  --bg-raised:    var(--surface-3);
  --bg-overlay:   rgba(33,34,38,.5);

  /* Google's grey hairlines. Solid hex, not alpha: there is one ground now,
     so a fixed value is correct on every surface. */
  --border:        #E8EAED;   /* hairline: cards, dividers */
  --control:       #DADCE0;   /* inputs, chips, buttons */
  --border-strong: #DADCE0;
  --border-hover:  #DADCE0;
  --hairline:      #E8EAED;
  --inset-top:     transparent;
  --panel:         #F8F9FA;
  --panel-blue:    #EEF3FE;
  --title:         #212226;

  --text-primary:   #212226;
  --text-secondary: #5F6368;
  --text-muted:     #686D72;
  --text-dimmed:    #686D72;
  --text-disabled:  #9AA0A6;

  /* ── The four hues: Waymo Blue, Sky, Lime and Mint ──
     The names are the old Google slots (blue, red, yellow, green), kept so
     every rule that reads them takes the Waymo hue in that slot: red is Sky.
     The raw hues are for fills and rules. The -text variants are darkened to
     clear 4.5:1 on the canvas, and are the only ones allowed on type. Red
     itself is only --err / --danger: an error or a failing test. */
  --g-blue:        #0077FF;
  --g-red:         #5AA2FF;
  --g-yellow:      #9AD61A;
  --g-green:       #00C896;
  --g-blue-text:   #0062D6;
  --g-red-text:    #2B83EC;
  --g-yellow-text: #5E8C0A;
  --g-green-text:  #00866B;
  --g-ink:         #212226;
  /* Red is kept for one meaning only: an error or a failing test. */
  --err:           #EA4335;
  --err-text:      #C5221F;
  --err-t:         #FCE8E6;

  --accent:         #0062D6;
  --accent-hover:   #0052B4;
  --accent-pressed: #0052B4;
  --accent-text:    #0062D6;
  --accent-subtle:  rgba(0, 119, 255,.12);
  --accent-line:    rgba(0, 119, 255,.45);
    --accent-ink:     #FFFFFF;

  --success: #00866B;
  --warning: #5E8C0A;
  --danger:  #C5221F;
  --danger-fill: #C5221F;
  --success-bg: rgba(0, 200, 150,.14);
  --warning-bg: rgba(154, 214, 26,.22);
  --danger-bg:  rgba(234,67,53,.12);
  --sky-bg:     rgba(90, 162, 255,.14);
  --info-bg:    rgba(0, 119, 255,.12);
  /* Matching hairlines for the washes, so a status chip is a wash, its
     text colour and a line in the same hue. */
  --blue-line:   rgba(0, 119, 255,.45);
  --red-line:    rgba(234,67,53,.45);
  --sky-line:    rgba(90, 162, 255,.45);
  --yellow-line: rgba(154, 214, 26,.6);
  --green-line:  rgba(0, 200, 150,.45);

  /* Difficulty is the one place the four-colour set earns its keep: three
     tiers, three hues, read at a glance down the rail. */
  --easy:   #00866B;
  --medium: #5E8C0A;
  --hard:   #2B83EC;

  --rail-head:      #0062D6;
  --rail-head-mark: rgba(0, 98, 214,.9);
  --rail-head-line: rgba(0, 98, 214,.16);

  /* Text colour on a filled --success chip. */
  --lum-bg: #FFFFFF;

  /* ── syntax ──
     A light code ramp built from Google's four plus one purple, so the editor
     belongs to the same palette as the chrome around it. */
  --syn-keyword: #2B83EC;
  --syn-string:  #00866B;
  --syn-number:  #5E8C0A;
  --syn-comment: #5F6368;
  --syn-def:     #0062D6;
  --syn-builtin: #0052B4;
  --syn-operator:#5F6368;

  /* ── type ── Roboto and Roboto Mono, Google's own pairing. */
  --font-sans: 'Roboto', system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-mono: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;

  /* Google's 4px-stepped scale, line-heights on the same grid. */
  --fs-body-s:     12px;  --lh-body-s:     16px;
  --fs-body-m:     14px;  --lh-body-m:     20px;
  --fs-heading-xs: 14px;  --lh-heading-xs: 18px;
  --fs-heading-s:  16px;  --lh-heading-s:  20px;
  --fs-heading-m:  18px;  --lh-heading-m:  22px;
  --fs-heading-l:  20px;  --lh-heading-l:  24px;
  --fs-heading-xl: 24px;  --lh-heading-xl: 30px;
  --fs-display-l:  34px;  --lh-display-l:  40px;

  --radius-card:     0;
  --radius-card-sm:  0;
  --radius-chip:    9999px;
  --radius-badge:    0;
  --radius-input:    0;

  /* Material elevation: a tight contact shadow plus a wider ambient one, both
     in Google grey rather than neutral black. */
  --shadow-xs: 0 1px 2px rgba(60,64,67,.30);
  --shadow-sm: 0 1px 2px rgba(60,64,67,.30), 0 1px 3px 1px rgba(60,64,67,.15);
  --shadow-md: 0 1px 2px rgba(60,64,67,.24), 0 2px 6px 2px rgba(60,64,67,.12);
  --shadow-lg: 0 1px 3px rgba(60,64,67,.24), 0 4px 12px 3px rgba(60,64,67,.14);
  --shadow-focus: 0 0 0 2px #0062D6;

  /* Google Cloud's own two card elevations, kept under their own names so a
     card can ask for the GCP step rather than the generic one. */
  --gcp-elevation-1: 0 1px 2px rgba(60,64,67,.30), 0 1px 3px 1px rgba(60,64,67,.15);
  --gcp-elevation-2: 0 1px 2px rgba(60,64,67,.30), 0 2px 6px 2px rgba(60,64,67,.15);
  --gcp-card-radius: 0;
  --gcp-measure: 1072px;
  --gcp-gutter: 24px;

  --ease: cubic-bezier(.4,0,.2,1);   /* Material standard easing */
  --dur: 140ms;

    /* PPG's own row under the Cariara header (the sub-header). */
  --topbar-h: 56px;
  --rail: 268px;
  /* A length, not a track function, so the grid can wrap it in minmax(0, …)
     and shrink it when the window is too narrow to honour it. */
  --probw: clamp(340px, 40vw, 680px);
  /* The work pane's floor. Stacked, the editor needs about this much before
     code starts wrapping; side by side it also has to hold the console, so
     the side-by-side breakpoint raises it. */
  --workmin: 420px;

  /* The rule that divides Capra's sections: one smooth Waymo gradient. */
  --spectrum: linear-gradient(90deg, #0077FF, #5AA2FF 40%, #00C896 75%, #9AD61A);

  color-scheme: light;
}

* { box-sizing: border-box; }
/* An author `display` beats the UA stylesheet, so a flex button carrying the
   `hidden` attribute would still paint. This keeps `hidden` meaning hidden. */
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
  margin: 0;
  color: var(--text-primary);
  font: var(--fs-body-m)/var(--lh-body-m) var(--font-sans);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  letter-spacing: 0;
  /* Google's canvas is a flat warm off-white and nothing else. The tinted
     pools that used to sit here were doing the depth work; on this system
     that job belongs to hairlines on a white canvas. */
  background: var(--bg-base);
}
button { font: inherit; color: inherit; }
:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: 0; }
::selection { background: var(--accent-subtle); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 6px; border: 2px solid var(--bg-base); }
::-webkit-scrollbar-thumb:hover { background: var(--border-hover); }

/* ── top bar ─────────────────────────────────────────────── */
/* Google app bars are opaque. The frosted-glass panel that used to sit here
   belongs to a different design language; here the bar is plain white on the
   warm canvas, and the four-colour rule along its base does the brand work. */
.topbar {
  height: 56px; flex: 0 0 56px;
  display: flex; align-items: center; gap: 18px; padding: 0 16px;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
  position: relative; z-index: 20;
}
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -3px; height: 3px;
  background: var(--spectrum);
}
.brand { display: flex; align-items: center; gap: 9px; }
.brand-mark { color: var(--accent); }
/* Google wordmarks are set light and wide, not bold and tight. */
.brand-name {
  font-weight: 500; letter-spacing: -.01em; font-size: var(--fs-heading-l);
  color: var(--g-ink);
}
.brand-sub { color: var(--text-dimmed); font-size: var(--fs-body-s); }

.pg-tabs { display: flex; gap: 4px; margin-left: 6px; }
.pg-tab {
  padding: 5px 13px; border-radius: var(--radius-chip);
  border: 1px solid transparent; background: transparent;
  color: var(--text-secondary); cursor: pointer;
  font-size: var(--fs-body-m); display: flex; align-items: center; gap: 6px;
  transition: background .12s, color .12s, border-color .12s;
}
.pg-tab:hover { background: var(--bg-elevated); color: var(--text-primary); }
/* A selected Material chip is a tinted fill and a colour change — the outline
   as well would be saying the same thing twice. */
.pg-tab.is-on {
  background: var(--accent-subtle); color: var(--accent-text);
  border-color: transparent; font-weight: 500;
}
.pg-tab[disabled] { opacity: .45; cursor: not-allowed; }
.pg-tab .soon {
  font-size: 10px; background: var(--bg-elevated); border: 1px solid var(--border);
  padding: 1px 5px; border-radius: 0; color: var(--text-dimmed);
  text-transform: uppercase; letter-spacing: .06em;
}

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.runtime-status { display: flex; align-items: center; }
.runtime-status .dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--text-dimmed);
  box-shadow: 0 0 0 3px transparent;
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* Visible only to assistive technology — the dot alone conveys nothing to a
   screen reader. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.runtime-status[data-state="boot"]  .dot { background: var(--g-yellow); animation: pulse 1.1s infinite; }
.runtime-status[data-state="ready"] .dot { background: var(--g-green); }
.runtime-status[data-state="busy"]  .dot { background: var(--g-blue); animation: pulse .7s infinite; }
.runtime-status[data-state="error"] .dot { background: var(--err); }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .25 } }

/* ── icons ───────────────────────────────────────────────── */
.ico { display: block; flex: 0 0 auto; }
.brand-mark { display: flex; align-items: center; color: var(--accent); }
.p-item .stat, .case .mark, .sol-caret { display: flex; align-items: center; justify-content: center; }

/* ── buttons ─────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--border); background: var(--bg-elevated); color: var(--text-primary);
  padding: 6px 13px; border-radius: 0; cursor: pointer;
  font-size: var(--fs-body-m); font-weight: 500; white-space: nowrap;
  transition: background .12s, border-color .12s, box-shadow .12s;
}
.btn:hover { background: var(--surface-1); border-color: var(--border-hover); box-shadow: var(--shadow-xs); }
.btn:active { box-shadow: none; }
.btn:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
.btn-sm { padding: 4px 10px; font-size: var(--fs-body-s); font-weight: 500; }
.btn-icon { padding: 6px; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-secondary); font-weight: 400; }
.btn-ghost:hover { background: var(--bg-elevated); color: var(--text-primary); border-color: transparent; }
/* Material's filled button is one flat colour carried by elevation. The
   gradient and inset highlight it used to wear were dark-UI devices; on white
   they read as a bevel. */
.btn-primary {
  background: var(--accent); border-color: transparent; color: var(--accent-ink);
  box-shadow: var(--shadow-xs);
}
.btn-primary:hover { background: var(--accent-hover); box-shadow: var(--shadow-sm); }
.btn-primary:active { box-shadow: var(--shadow-xs); }
/* Material's outlined button: the accent is the border and the label only. */
.btn-secondary { border-color: var(--border-strong); color: var(--accent-text); background: var(--surface-1); }
.btn-secondary:hover { background: var(--accent-subtle); border-color: var(--accent); }
.btn-danger { background: var(--danger); border-color: transparent; color: #fff; box-shadow: var(--shadow-xs); }
.btn-danger:hover { background: var(--err-text); }

/* ── layout ──────────────────────────────────────────────── */
.layout {
  height: calc(100vh / var(--pz, 1) - var(--cariara-chrome, 0px) - var(--topbar-h, 56px));
  display: grid;
  /* Every fixed track is wrapped in minmax(0, …) and the work column carries a
     real minimum. A dragged width is a preference, not a guarantee: sized as
     bare lengths, --rail and --probw were rigid, so on a narrower window they
     took their full width off the top and the editor and console were pushed
     off the right edge with no way to reach them. Now the two reading columns
     give way together and the work pane keeps its floor. */
  grid-template-columns:
    minmax(0, var(--rail)) 5px
    minmax(0, var(--probw)) 5px
    minmax(var(--workmin), 1.1fr);
}
.layout.rail-hidden {
  grid-template-columns: 0 0 minmax(0, var(--probw)) 5px minmax(var(--workmin), 1.1fr);
}
.rail-grip, .col-grip { background: transparent; cursor: col-resize; position: relative; }
.rail-grip::after, .col-grip::after {
  content: ""; position: absolute; inset: 0 2px; background: var(--border); transition: background .15s;
}
.rail-grip:hover::after, .col-grip:hover::after,
.dragging .rail-grip::after, .dragging .col-grip::after { background: var(--accent); }
.row-grip { height: 5px; cursor: row-resize; position: relative; flex: 0 0 auto; }
.row-grip::after { content: ""; position: absolute; inset: 2px 0; background: var(--border); transition: background .15s; }
.row-grip:hover::after { background: var(--accent); }
body.dragging { user-select: none; cursor: col-resize; }

/* ── rail ────────────────────────────────────────────────── */
.rail { background: var(--bg-surface); border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; }
.rail-head {
  padding: 12px; border-bottom: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 10px;
  background: var(--bg-elevated);
}

/* Progress summary: one ring for the whole catalogue, three meters for the split. */
.rail-stats { display: flex; align-items: center; gap: 12px; }
.ring {
  --pct: 0;
  position: relative; flex: 0 0 46px; width: 46px; height: 46px; border-radius: 50%;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--border) 0);
  display: grid; place-items: center;
}
.ring::after {
  content: ''; position: absolute; inset: 4px; border-radius: 50%;
  background: var(--bg-surface);
}
.ring-n {
  position: relative; z-index: 1; font: 500 13px/1 var(--font-mono);
  color: var(--text-primary); letter-spacing: -.02em;
}
.ring-n i { font-style: normal; font-size: 8.5px; color: var(--text-dimmed); margin-left: 1px; }
.rail-stats-b { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.rail-stats-h { margin: 0; font-size: 11.5px; color: var(--text-dimmed); }
.rail-stats-h b { color: var(--text-primary); font-size: 13px; font-family: var(--font-mono); }
.tiers { display: flex; flex-direction: column; gap: 3px; }
.tier { display: flex; align-items: center; gap: 6px; }
.tier-l { font: 500 9px/1 var(--font-mono); width: 7px; flex: none; }
.tier-bar {
  flex: 1; height: 3px; border-radius: 0; background: var(--border); overflow: hidden;
}
.tier-bar i { display: block; height: 100%; border-radius: 0; transition: width .35s var(--ease); }
.d-Easy-bg { background: var(--easy); }
.d-Medium-bg { background: var(--medium); }
.d-Hard-bg { background: var(--hard); }
.tier-n {
  font: 9.5px/1 var(--font-mono); color: var(--text-dimmed);
  width: 34px; text-align: right; flex: none; font-variant-numeric: tabular-nums;
}

/* Search with its own affordance rather than a bare box. */
.rail-search { position: relative; display: flex; align-items: center; }
.rail-search-i {
  position: absolute; left: 9px; display: flex; color: var(--text-dimmed); pointer-events: none;
}
.search {
  width: 100%; padding: 7px 34px 7px 29px; border-radius: 0;
  border: 1px solid var(--border); background: var(--bg-base); color: var(--text-primary);
  font: var(--fs-body-m)/1.4 var(--font-sans); outline: none;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.search::placeholder { color: var(--text-dimmed); }
.search:focus { border-color: var(--accent); box-shadow: var(--shadow-focus); }
.search::-webkit-search-cancel-button { -webkit-appearance: none; }
.rail-kbd {
  position: absolute; right: 8px; padding: 1px 5px; border-radius: 4px;
  border: 1px solid var(--border-strong); background: var(--bg-elevated);
  font: 10px/1.5 var(--font-mono); color: var(--text-dimmed); pointer-events: none;
}
.search:focus ~ .rail-kbd { opacity: 0; }

/* Segmented controls read as one object; loose chips read as four. */
.seg {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px;
  padding: 2px; border-radius: var(--radius-input);
  background: var(--bg-base); border: 1px solid var(--border);
}
.seg-b {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  padding: 4px 6px; border: none; border-radius: 6px; cursor: pointer;
  background: transparent; color: var(--text-dimmed);
  font: 500 11px/1.4 var(--font-sans); white-space: nowrap;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.seg-b:hover { color: var(--text-primary); background: var(--bg-elevated); }
.seg-b.is-on {
  background: var(--surface-1); color: var(--accent-text); font-weight: 500;
  box-shadow: var(--shadow-xs);
}
.seg-quiet .seg-b { font-size: 10.5px; padding: 3px 6px; }
.seg .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }
.seg-b .dot.d-Easy { background: var(--easy); }
.seg-b .dot.d-Medium { background: var(--medium); }
.seg-b .dot.d-Hard { background: var(--hard); }

.topic-pill {
  display: flex; align-items: center; gap: 6px; margin-top: 8px;
  padding: 4px 4px 4px 10px; border-radius: var(--radius-chip);
  background: var(--accent-subtle); border: 1px solid var(--accent);
  color: var(--accent-text); font-size: var(--fs-body-s); font-weight: 500;
}
.topic-pill-t { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topic-pill-x {
  display: flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: 0 0 20px; padding: 0;
  border: none; border-radius: var(--radius-chip);
  background: transparent; color: inherit; cursor: pointer; opacity: .75;
}
.topic-pill-x:hover { background: var(--bg-elevated); opacity: 1; }

.tp-head-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }

.rail-list { flex: 1; overflow-y: auto; padding: 6px 6px 14px; scrollbar-width: thin; }
.rail-sec { display: flex; flex-direction: column; }

/* Group headers stay put while their rows scroll under them. */
.rail-group {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 9px 9px 7px; margin-top: 6px; cursor: pointer;
  border: none; border-bottom: 1px solid var(--rail-head-line);
  border-radius: 0;
  background: var(--bg-surface); color: var(--rail-head);
  font: 500 10.5px/1.4 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  text-align: left; transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.rail-group::before {
  content: ''; width: 3px; height: 11px; border-radius: 0; flex: none;
  background: var(--rail-head-mark);
}
.rail-group:hover { background: var(--bg-elevated); }
.rail-sec.is-shut .rail-group { border-bottom-color: transparent; }
.rail-group-x {
  display: flex; flex: none; transform: rotate(90deg);
  color: var(--rail-head-mark); opacity: .8;
  transition: transform var(--dur) var(--ease);
}
.rail-sec.is-shut .rail-group-x { transform: rotate(0deg); }
.rail-group-t {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.rail-meter {
  flex: 1 1 26px; min-width: 18px; height: 3px; border-radius: 0;
  background: var(--border); overflow: hidden;
}
.rail-meter-f {
  display: block; height: 100%; border-radius: 0; background: var(--accent);
  transition: width .35s var(--ease);
}
.rail-meter-f.is-done { background: var(--success); }
.rail-group-n {
  flex: none; color: var(--text-dimmed); letter-spacing: 0; font-size: 10px;
  font-variant-numeric: tabular-nums;
}
.rail-group-n.is-done { color: var(--success); }

.rail-rows { display: flex; flex-direction: column; gap: 1px; }
.rail-sec.is-shut .rail-rows { display: none; }

.p-item {
  display: flex; align-items: center; gap: 9px; padding: 7px 10px;
  border-radius: 0; cursor: pointer; border: 1px solid transparent;
  outline: none; position: relative;
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.p-item:hover { background: var(--bg-elevated); }
.p-item:focus-visible { background: var(--bg-elevated); box-shadow: var(--shadow-focus); }
.p-item.is-on {
  background: var(--accent-subtle); border-color: var(--accent-line);
  box-shadow: inset 2px 0 0 var(--accent);
}
.p-item .stat { width: 14px; flex: 0 0 14px; color: var(--text-dimmed); display: flex; }
.p-item.solved .stat { color: var(--success); }
.p-item .p-name {
  flex: 1; font-size: var(--fs-body-m); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--text-secondary); min-width: 0;
}
.p-item.is-on .p-name, .p-item:hover .p-name, .p-item:focus-visible .p-name { color: var(--text-primary); }
.p-item.solved .p-name { color: var(--text-dimmed); }
.p-num {
  flex: none; font: 9.5px/1.5 var(--font-mono); color: var(--text-dimmed);
  padding: 1px 4px; border-radius: 0; background: var(--bg-base);
  border: 1px solid var(--border); opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.p-item:hover .p-num, .p-item.is-on .p-num { opacity: 1; }
.p-item .p-diff {
  flex: none; font-size: 10.5px; font-weight: 500; font-family: var(--font-mono); width: 9px;
}
.d-Easy { color: var(--easy); } .d-Medium { color: var(--medium); } .d-Hard { color: var(--hard); }

.rail-none {
  display: flex; flex-direction: column; align-items: flex-start; gap: 9px;
  padding: 22px 14px; color: var(--text-dimmed); font-size: var(--fs-body-m);
}
.rail-none p { margin: 0; }
.rail-none b { color: var(--text-primary); }

.rail-foot {
  padding: 9px 12px; border-top: 1px solid var(--border); display: flex; align-items: center;
  justify-content: space-between; font-size: 11.5px; color: var(--text-dimmed); font-family: var(--font-mono);
}

/* ── panes ───────────────────────────────────────────────── */
.pane { display: flex; flex-direction: column; overflow: hidden; background: var(--bg-base); }
.pane-problem { background: var(--bg-surface); }
.pane-head {
  height: 40px; flex: 0 0 40px; display: flex; align-items: center; gap: 8px; padding: 0 12px;
  border-bottom: 1px solid var(--border); background: var(--bg-surface);
}
.spacer { flex: 1; }
.tabbar { display: flex; gap: 2px; height: 100%; align-items: center; }
.tab {
  background: transparent; border: none; border-bottom: 2px solid transparent;
  color: var(--text-dimmed); padding: 0 12px; height: 100%; cursor: pointer;
  font-size: var(--fs-body-m); transition: color .12s;
  /* A Material tab label is one line. In a narrow console pane "Test Results"
     was wrapping and pushing the underline off the text. */
  white-space: nowrap;
}
.tab:hover { color: var(--text-primary); }
.tab.is-on { color: var(--accent-text); border-bottom-color: var(--accent); font-weight: 500; }
.tabbar.sm .tab { font-size: var(--fs-body-s); padding: 0 10px; }
.pane-body { flex: 1; overflow-y: auto; position: relative; }
.panel { display: none; padding: 22px 26px 60px; max-width: 820px; }
.panel.is-on { display: block; }

/* ── problem document ────────────────────────────────────── */
.panel { display: none; padding: 0 0 64px; max-width: none; }
.panel.is-on { display: block; }
.panel > .prose, .panel > .block,
.panel > .empty, .panel > .sol-gate { padding-inline: 26px; }
/* Text fills its pane: a line-length cap left a blank band beside it. */

.prob-head {
  padding: 22px 26px 16px; border-bottom: 1px solid var(--border);
  margin-bottom: 20px; background: var(--bg-surface);
}
/* One row: title, then its badges, then the solved state at the far end. The
   badges wrap under the title only when the pane is too narrow to hold them. */
.prob-head-row { display: flex; align-items: center; gap: 8px 14px; flex-wrap: wrap; }
.prob-title {
  font-size: var(--fs-heading-xl); line-height: var(--lh-heading-xl);
  font-weight: 400; margin: 0; flex: 0 1 auto; min-width: 0; letter-spacing: -.01em;
  color: var(--g-ink);
}
.prob-state {
  display: flex; align-items: center; gap: 6px; flex: 0 0 auto; margin-left: auto;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 4px 10px; border-radius: var(--radius-chip);
  border: 1px solid var(--border); color: var(--text-dimmed); background: var(--bg-base);
}
.prob-state.is-solved {
  color: var(--success); border-color: var(--border);
  background: var(--success-bg);
}
.prob-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.badge {
  padding: 3px 10px; border-radius: var(--radius-chip); font-size: 11px; font-weight: 700;
  border: 1px solid var(--border); background: var(--bg-elevated); color: var(--text-secondary);
  letter-spacing: .02em;
}
.badge.d-Easy { color: var(--easy); border-color: var(--border); }
.badge.d-Medium { color: var(--medium); border-color: var(--border); }
.badge.d-Hard { color: var(--hard); border-color: var(--border); }
.badge.src { color: var(--accent-text); border-color: var(--border); background: var(--accent-subtle); }

.block { margin-top: 26px; }
.block-h {
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-dimmed); margin: 0 0 10px; font-weight: 500; font-family: var(--font-mono);
}

/* Examples are one list, so they live in one card separated by rules. */
.ex-card {
  border: 1px solid var(--border); border-radius: 0; overflow: hidden;
  background: var(--bg-elevated); box-shadow: var(--shadow-sm), inset 0 1px 0 var(--inset-top);
}
.ex-row { display: flex; gap: 12px; padding: 12px 14px; }
.ex-row + .ex-row { border-top: 1px solid var(--hairline); }
.ex-n {
  flex: 0 0 20px; height: 20px; border-radius: 50%; background: var(--bg-elevated);
  color: var(--text-secondary); font: 500 10px/20px var(--font-mono); text-align: center;
}
.ex-kv { display: grid; grid-template-columns: 58px 1fr; gap: 3px 10px; margin: 0; flex: 1; min-width: 0; }
.ex-kv dt { color: var(--text-dimmed); font: 11px/1.6 var(--font-mono); }
.ex-kv dd { margin: 0; color: var(--text-primary); font: 12.5px/1.6 var(--font-mono); white-space: pre-wrap; word-break: break-word; }
.ex-kv dd.ex-note { color: var(--text-secondary); font: var(--fs-body-m)/1.55 var(--font-sans); }

.constraints { display: flex; flex-wrap: wrap; gap: 6px; }
.constraints code {
  font-family: var(--font-mono); font-size: 12px; background: var(--bg-base);
  border: 1px solid var(--border); color: var(--text-secondary);
  padding: 4px 9px; border-radius: 0;
}

.hintbox {
  border: 1px solid var(--border); border-radius: 0;
  margin: 0 0 6px; background: var(--bg-base); overflow: hidden;
}
.hintbox summary {
  padding: 9px 13px; cursor: pointer; font-size: var(--fs-body-m); color: var(--text-secondary);
  user-select: none; display: flex; align-items: center; gap: 8px; font-weight: 500;
  list-style: none;
}
.hintbox summary::-webkit-details-marker { display: none; }
.hintbox summary .ico { color: var(--text-dimmed); transition: transform .18s; }
.hintbox[open] summary .ico { transform: rotate(90deg); }
.hintbox[open] summary { border-bottom: 1px solid var(--border); color: var(--text-primary); }
.hintbox .hint-b { padding: 12px 14px; color: var(--text-secondary); font-size: var(--fs-body-m); }
.hintbox .hint-b p:last-child { margin-bottom: 0; }

/* ── prose ───────────────────────────────────────────────── */
.prose { color: var(--text-primary); font-size: var(--fs-heading-s); line-height: 1.65; }
.prose p { margin: 0 0 12px; }
.prose p:last-child { margin-bottom: 0; }
.prose ul, .prose ol { margin: 0 0 12px; padding-left: 22px; }
.prose li { margin: 5px 0; }
.prose li::marker { color: var(--text-dimmed); }
.prose code {
  font-family: var(--font-mono); font-size: 12.5px; background: var(--bg-elevated);
  padding: 1.5px 5px; border-radius: 0; border: 1px solid var(--border);
  color: var(--accent-text);
}
.prose pre {
  background: var(--bg-base); border: 1px solid var(--border); border-radius: 0;
  padding: 12px 14px; overflow-x: auto; margin: 0 0 14px;
}
.prose pre code { background: none; border: none; padding: 0; color: var(--text-primary); font-size: 12.5px; line-height: 1.7; display: block; }
.prose strong { color: var(--text-primary); font-weight: 700; }
.prose table { border-collapse: collapse; width: 100%; margin: 0 0 14px; font-size: var(--fs-body-m); }
.prose th, .prose td { border: 1px solid var(--border); padding: 7px 10px; text-align: left; }
.prose th { background: var(--bg-elevated); color: var(--text-secondary); font-size: var(--fs-body-s); }
.prose blockquote { margin: 0 0 14px; padding: 2px 0 2px 14px; border-left: 2px solid var(--border-hover); color: var(--text-secondary); }

/* ── solutions: the gate that stands in front of them ─────── */
/* Centred and unhurried on purpose: this screen asks the learner to stop and
   decide, so it reads as a pause rather than as content withheld. */
.sol-gate {
  margin: 0 auto; padding: 56px 0 40px; text-align: center;
}
.sol-gate-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; margin-bottom: 18px; border-radius: 50%;
  background: var(--bg-elevated); border: 1px solid var(--border); color: var(--text-dimmed);
}
.sol-gate-h {
  font-size: var(--fs-heading-m); line-height: var(--lh-heading-m);
  font-weight: 700; color: var(--text-primary); margin: 0 0 12px;
}
.sol-gate-p {
  font-size: var(--fs-body-m); line-height: 1.6; color: var(--text-secondary); margin: 0 0 12px;
}
.sol-gate .btn { margin-top: 12px; }
.sol-gate-n {
  margin: 14px 0 0; font-size: var(--fs-body-s); color: var(--text-dimmed);
}

/* ── solutions: one card, a switcher header, one panel at a time ──
   The switcher is the card's header rather than a floating strip: an even
   grid of numbered cells, one row on a desktop pane. It stays pinned while
   the approach scrolls, so its background is fully opaque; a translucent
   one let the heading underneath read through the chips. */
.sol-card {
  margin: 20px 26px 0; background: var(--surface-1);
  border: 1px solid var(--border); border-radius: 0;
  box-shadow: var(--shadow-sm); overflow: clip;
  container-type: inline-size;
}
/* The approach tabs: one line of compact tabs in the pinned .sol-nav, each
   the approach's short name and its time. The full name is the panel title. */
.sol-switch { display: flex; gap: 6px; }
.sol-pill {
  flex: none; display: inline-flex; align-items: center; gap: 6px; height: 28px;
  padding: 0 10px 0 4px; border: 1px solid var(--control); border-radius: 14px;
  background: var(--surface-1); color: var(--text-secondary); cursor: pointer;
  font: 500 12.5px/1 var(--font-sans); white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s;
}
.sol-pill:hover { background: var(--bg-elevated); color: var(--text-primary); }
.sol-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.sol-pill-n {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  background: var(--bg-elevated); border: 1px solid var(--border);
  font: 500 10.5px/18px var(--font-mono); text-align: center; color: var(--text-secondary);
}
.sol-pill-cx { font: 400 11px/1 var(--font-mono); color: var(--text-dimmed); }
@container (max-width: 560px) {
  .sol-panel { padding: 18px 16px 20px; }
}

.sol-panel { display: none; padding: 22px 24px 24px; }
/* The variant challenge (review-masters-plan §18): locked approaches, a claim's solver and code. */
.sol-pill.is-locked .sol-pill-t { display: inline-flex; align-items: center; gap: 6px; color: var(--text-dimmed); }
.sol-panel.is-locked .sol-title { display: inline-flex; align-items: center; gap: 8px; color: var(--text-secondary); }
.sol-locked-act { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.sol-claim { margin: 14px 0 6px; }
.sol-claim-by { display: flex; align-items: center; gap: 6px; margin: 12px 0 8px; font-size: 13.5px; color: var(--text-secondary); }
.sol-claim-by b { font-weight: 600; color: var(--text-primary); }
.sol-claim-by.is-private { font-size: 13px; color: var(--text-dimmed); }
.sol-claim-code { margin: 0; padding: 12px 14px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-elevated);
  font: 400 13px/1.55 var(--font-mono); overflow-x: auto; white-space: pre; }
.phd-ver-first { display: inline-flex; align-items: center; gap: 5px; margin-left: 10px; font-size: 12.5px; color: var(--text-secondary); }
.uc-chip.has-first span::after { content: ''; display: inline-block; width: 6px; height: 6px; margin-left: 6px; border-radius: 50%; background: var(--g-yellow); vertical-align: middle; }
.rm-verdict.is-claim { margin-top: 6px; }
.sol-panel.is-on { display: block; }
.sol-head { margin-bottom: 16px; }
.sol-title { font-size: var(--fs-heading-m); line-height: var(--lh-heading-m); font-weight: 700; margin: 0 0 10px; }
.metrics { display: flex; gap: 8px; flex-wrap: wrap; }
.metric {
  display: flex; align-items: baseline; gap: 7px; padding: 5px 11px;
  border: 1px solid var(--border); border-radius: 0; background: var(--bg-base);
}
.metric span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--text-dimmed); }
.metric b { font-family: var(--font-mono); font-size: 12.5px; color: var(--accent-text); font-weight: 500; }
.metric.is-best {
  color: var(--success); border-color: var(--border);
  background: var(--success-bg);
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
}
.sol-why { margin-bottom: 16px; }
.sol-extra + .sol-why { margin-top: 16px; }
.sol-actions { display: flex; gap: 8px; margin-top: 14px; }

/* ── editor ──────────────────────────────────────────────── */
.editor-wrap { flex: 1 1 auto; min-height: 80px; overflow: hidden; position: relative; }
.CodeMirror {
  height: 100%; font-family: var(--font-mono); font-size: 13.5px; line-height: 1.65;
  background: var(--bg-app); color: var(--text-primary);
}
.CodeMirror-gutters { background: var(--bg-app); border-right: 1px solid var(--border); }
.CodeMirror-linenumber { color: var(--text-dimmed); }
.CodeMirror-cursor { border-left: 2px solid var(--accent); }
.CodeMirror-selected { background: var(--accent-subtle) !important; }
.CodeMirror-activeline-background { background: var(--surface-2); }
.CodeMirror-matchingbracket { color: var(--accent) !important; border-bottom: 1px solid var(--accent); }

/* Syntax skin — one theme, both modes, driven by the tokens above. */
.cm-s-cariara .cm-keyword,
.cm-hl .cm-keyword   { color: var(--syn-keyword); font-weight: 500; }
.cm-s-cariara .cm-string,
.cm-hl .cm-string    { color: var(--syn-string); }
.cm-s-cariara .cm-string-2,
.cm-hl .cm-string-2  { color: var(--syn-string); }
.cm-s-cariara .cm-number,
.cm-hl .cm-number    { color: var(--syn-number); }
.cm-s-cariara .cm-comment,
.cm-hl .cm-comment   { color: var(--syn-comment); font-style: italic; }
.cm-s-cariara .cm-def,
.cm-hl .cm-def       { color: var(--syn-def); }
.cm-s-cariara .cm-variable,
.cm-hl .cm-variable  { color: var(--text-primary); }
.cm-s-cariara .cm-variable-2,
.cm-hl .cm-variable-2{ color: var(--text-primary); }
.cm-s-cariara .cm-builtin,
.cm-hl .cm-builtin   { color: var(--syn-builtin); }
.cm-s-cariara .cm-operator,
.cm-hl .cm-operator  { color: var(--syn-operator); }
.cm-s-cariara .cm-property,
.cm-hl .cm-property  { color: var(--text-primary); }
.cm-s-cariara .cm-meta,
.cm-hl .cm-meta      { color: var(--text-dimmed); }
.cm-hl {
  background: var(--bg-base); border: 1px solid var(--border); border-radius: 0;
  padding: 12px 14px; overflow-x: auto; margin: 0; font-family: var(--font-mono);
  font-size: 12.5px; line-height: 1.7; color: var(--text-primary);
}
.cm-hl code { font-family: inherit; }

/* ── console ─────────────────────────────────────────────── */
.console { flex: 0 0 38%; min-height: 90px; display: flex; flex-direction: column; background: var(--bg-surface); border-top: 1px solid var(--border); }
.console-head { height: 36px; flex: 0 0 36px; display: flex; align-items: center; padding: 0 8px; border-bottom: 1px solid var(--border); }
.timing {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-dimmed);
  margin-right: 8px; white-space: nowrap;
}
.console-body { flex: 1; overflow: auto; position: relative; }
.out {
  display: none; padding: 11px 13px; margin: 0; font-family: var(--font-mono);
  font-size: 12.5px; line-height: 1.65; white-space: pre-wrap; word-break: break-word; min-height: 100%;
}
.out.is-on { display: block; }
/* The console is preformatted text; the results pane is markup. Left as
   pre-wrap, every newline and indent in the results template rendered as
   real whitespace and pushed the cards apart. */
#out-results { white-space: normal; padding: 12px; }
#out-mine { white-space: normal; padding: 12px; font-family: var(--font-sans); }
#out-stdin { padding: 0; }
.stdin {
  width: 100%; height: 100%; min-height: 120px; border: none; outline: none; resize: none;
  padding: 11px 13px; background: transparent; color: var(--text-primary);
  font: 12.5px/1.65 var(--font-mono);
}
.stdin::placeholder { color: var(--text-dimmed); }
.empty { color: var(--text-dimmed); font-family: var(--font-sans); font-style: italic; }
.err { color: var(--danger); }
.sys { color: var(--text-dimmed); }

/* ── results: verdict first, failures next, passes folded away ── */
.verdict {
  padding: 12px 14px; border-radius: 0; margin-bottom: 12px;
  border: 1px solid var(--border); background: var(--bg-base); font-family: var(--font-sans);
}
.verdict.is-pass {
  border-color: var(--border);
  background: var(--success-bg);
}
.verdict.is-fail {
  border-color: var(--border);
  background: var(--danger-bg);
}
.verdict-main { font-size: var(--fs-heading-s); font-weight: 700; line-height: 1.3; }
.verdict.is-pass .verdict-main { color: var(--success); }
.verdict.is-fail .verdict-main { color: var(--danger); }
.verdict-sub { font-size: var(--fs-body-s); color: var(--text-secondary); margin-top: 2px; }
.verdict-bar {
  height: 3px; border-radius: 0; background: var(--surface-3);
  margin-top: 10px; overflow: hidden;
}
.verdict-bar span { display: block; height: 100%; border-radius: 0; background: var(--success); transition: width .25s; }

.case-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.case { border: 1px solid var(--border); border-radius: 0; overflow: hidden; background: var(--bg-base); }
.case-h {
  display: flex; align-items: center; gap: 9px; padding: 9px 12px; cursor: pointer;
  font-family: var(--font-sans); font-size: var(--fs-body-m);
}
.case-h:hover { background: var(--bg-elevated); }
.mark { width: 13px; flex: 0 0 13px; display: flex; align-items: center; justify-content: center; }
.mark.ok { color: var(--success); }
.mark.no { color: var(--danger); }
.case-name { flex: 1; color: var(--text-primary); font-weight: 500; }
.case-tier {
  font-size: 9.5px; text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
  padding: 2px 6px; border-radius: 0;
  color: var(--warning); background: var(--warning-bg);
}
.case-ms { font-family: var(--font-mono); font-size: 11px; color: var(--text-dimmed); }
.case-b { display: none; padding: 12px; border-top: 1px solid var(--border); background: var(--bg-surface); }
.case.is-open .case-b { display: block; }
.kv { display: grid; grid-template-columns: 74px 1fr; gap: 5px 12px; margin: 0; }
.kv dt { color: var(--text-dimmed); font: 10.5px/1.7 var(--font-mono); text-transform: uppercase; letter-spacing: .06em; }
.kv dd { margin: 0; white-space: pre-wrap; word-break: break-word; font: 12.5px/1.7 var(--font-mono); color: var(--text-secondary); }
.kv dd.want { color: var(--success); }
.kv dd.got { color: var(--danger); }
.case-out { margin-top: 10px; }
.case-out span {
  font: 10.5px/1.7 var(--font-mono); text-transform: uppercase; letter-spacing: .06em; color: var(--text-dimmed);
}
.case-out pre, .trace {
  margin: 4px 0 0; padding: 10px 12px; border-radius: 0;
  background: var(--bg-base); border: 1px solid var(--border);
  font: 12px/1.65 var(--font-mono); white-space: pre-wrap; word-break: break-word;
  color: var(--text-secondary); overflow-x: auto;
}
.trace { color: var(--danger); }

/* Passing cases are reassurance, not reading material. */
.tier-note {
  margin: 10px 0 0; padding: 9px 12px; border-radius: 0;
  border: 1px solid var(--border); background: var(--bg-surface);
  color: var(--text-secondary); font-size: var(--fs-body-s); line-height: 1.55;
}

.passed-strip { border: 1px solid var(--border); border-radius: 0; overflow: hidden; background: var(--bg-base); }
.passed-h {
  padding: 7px 12px; background: var(--bg-elevated); color: var(--text-secondary);
  font: 500 10.5px/1.6 var(--font-mono); text-transform: uppercase; letter-spacing: .08em;
}
.passed-row { display: flex; align-items: center; gap: 9px; padding: 5px 12px; }
.passed-row + .passed-row { border-top: 1px solid var(--hairline); }
.passed-name { flex: 1; font-size: var(--fs-body-s); color: var(--text-secondary); }
.passed-ms { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-dimmed); }

/* ── notes ───────────────────────────────────────────────── */
.notes-box {
  width: 100%; min-height: 340px; resize: vertical; padding: 13px 14px;
  border: 1px solid var(--border); border-radius: 0;
  background: var(--bg-base); color: var(--text-primary);
  font: 13px/1.7 var(--font-mono); outline: none;
}
.notes-box:focus { border-color: var(--accent); box-shadow: var(--shadow-focus); }
.notes-box::placeholder { color: var(--text-dimmed); }

/* ── boot veil ───────────────────────────────────────────── */
.boot-veil {
  position: fixed; inset: 0; background: rgba(255,255,255,.92); display: grid; place-items: center; z-index: 50; transition: opacity .3s;
}
.boot-veil.gone { opacity: 0; pointer-events: none; }
.boot-card { text-align: center; max-width: 420px; padding: 28px; }
.boot-card h2 { margin: 16px 0 8px; font-size: var(--fs-heading-m); font-weight: 700; }
.boot-card p { margin: 0; color: var(--text-dimmed); font-size: var(--fs-body-m); }
.boot-spin {
  width: 34px; height: 34px; margin: 0 auto; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--accent); animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg) } }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ── responsive ──────────────────────────────────────────── */
@media (max-width: 1100px) {
  .layout { grid-template-columns: 1fr; grid-template-rows: auto; overflow-y: auto; height: auto; }
  .rail-grip, .col-grip { display: none; }
  /* The rail used to be display:none from here down, which left a narrow window
     with no way to reach the catalogue, the search box or the filter chips at
     all. It becomes a normal block above the panes instead. */
  .rail { border-right: 0; border-bottom: 1px solid var(--border); max-height: 44vh; }
  .pane { height: auto; }
  .pane-work { height: 78vh; }
  .brand-sub { display: none; }
  .panel { padding: 18px 16px 48px; }
}

@media (max-width: 760px) {
  /* Brand + three labelled tabs + status do not fit; the whole page was pushed
     ~100px wider than the screen. The tab icons carry the meaning on their own. */
  .topbar { gap: 10px; padding: 0 10px; }
  .brand-name { display: none; }
  .mode-tabs { margin-left: 0; }
  .mode-tab { padding: 5px 9px; gap: 0; }
  .mode-tab span { display: none; }
  .editor-head { flex-wrap: wrap; height: auto; padding-block: 6px; row-gap: 6px; }
  .rmv-head { padding: 18px 16px 14px; }
  .rmv-graph { padding: 18px 12px 28px; }
}

/* ── mode switch ─────────────────────────────────────────── */
.mode-tabs { display: flex; gap: 3px; margin-left: 6px; padding: 3px; border-radius: var(--radius-chip); background: var(--bg-elevated); }
.mode-tab {
  display: flex; align-items: center; gap: 7px; padding: 5px 14px;
  border: none; border-radius: var(--radius-chip); background: transparent;
  color: var(--text-secondary); cursor: pointer; font-size: var(--fs-body-m); font-weight: 500;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.mode-tab:hover { color: var(--text-primary); }
.mode-tab.is-on { background: var(--bg-base); color: var(--accent-text); box-shadow: var(--shadow-xs); }

/* ── playground view ─────────────────────────────────────── */
/* SQL view: a full-height host for the capra SQL playground, which lays
   itself out to fill it (panes, splitters, its own scroll areas). */

/* ── guides: a nav of guides beside the one open, full width ── */
.sqlv-state { margin: auto; color: var(--text-secondary); font-size: var(--fs-body-m); }
.gdv {
  height: calc(100vh / var(--pz, 1) - var(--cariara-chrome, 0px) - var(--topbar-h, 56px));
  display: grid; grid-template-columns: 220px minmax(0, 1fr); background: var(--bg-surface);
}
.gdv[hidden] { display: none; }
.gd-nav {
  overflow-y: auto; padding: 16px 10px 24px; border-right: 1px solid var(--border);
  background: var(--surface-1); display: flex; flex-direction: column; gap: 2px;
}
.gd-nav-h {
  font: 600 11px/1 var(--font-sans); color: var(--text-dimmed); text-transform: uppercase;
  letter-spacing: .04em; padding: 14px 10px 6px;
}
.gd-nav-h:first-child { padding-top: 0; }
.gd-nav-i {
  text-align: left; padding: 7px 10px; border: 0; border-radius: 0; cursor: pointer;
  background: transparent; color: var(--text-secondary); font: 500 13px/1.3 var(--font-sans);
}
.gd-nav-i:hover { background: var(--surface-2); color: var(--text-primary); }
.gd-nav-i.is-on { background: var(--accent-subtle); color: var(--accent-text); }
.gd-body { overflow-y: auto; padding: 24px clamp(16px, 3vw, 40px) 48px; display: grid; gap: 16px; align-content: start; }
.gd-head { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.gd-head h1 { margin: 0; font: 400 var(--fs-heading-xl)/var(--lh-heading-xl) var(--font-sans); color: var(--g-ink); }
.gd-head p { flex-basis: 100%; margin: 0; color: var(--text-secondary); }
.gd-grid { display: grid; gap: 12px; }
.gd-grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.gd-grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.gd-grid-4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.gd-card {
  --tone: var(--g-blue); border: 1px solid var(--border); border-top: 2px solid var(--tone);
  border-radius: 0; padding: 14px 16px; background: var(--surface-1); min-width: 0;
}
.gd-card[data-tone="red"] { --tone: var(--g-red); }
.gd-card[data-tone="yellow"] { --tone: var(--g-yellow); }
.gd-card[data-tone="green"] { --tone: var(--g-green); }
.gd-h { margin: 0 0 10px; font: 600 14px/1.3 var(--font-sans); color: var(--text-primary); }
.gd-p { margin: 0 0 12px; color: var(--text-secondary); }
.gd-list { margin: 0; padding-left: 18px; display: grid; gap: 6px; color: var(--text-primary); }
.gd-list.is-num { list-style: decimal; }
.gd-list.is-cols { columns: 2 280px; column-gap: 32px; display: block; }
.gd-list.is-cols li { break-inside: avoid; margin-bottom: 6px; }
.gd-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.gd-chips-k { font: 600 12px/1 var(--font-sans); color: var(--text-secondary); margin-right: 4px; }
.gd-chip {
  padding: 4px 10px; border-radius: 12px; border: 1px solid var(--control);
  background: var(--surface-1); font: 500 12px/1.3 var(--font-sans); color: var(--text-primary);
}
.gd-tier { text-align: left; }
.gd-tier-n { font: 500 28px/1 var(--font-sans); color: var(--tone); }
.gd-tier-l { font: 600 13px/1.4 var(--font-sans); margin-top: 4px; }
.gd-tier p { margin: 6px 0 0; color: var(--text-secondary); font-size: 13px; }
.gd-phase { border: 1px solid var(--border); border-radius: 0; padding: 12px; display: grid; gap: 6px; align-content: start; }
.gd-phase p { margin: 0; color: var(--text-secondary); font-size: 13px; }
.gd-phase-w { font: 600 11px/1 var(--font-sans); color: var(--text-dimmed); text-transform: uppercase; letter-spacing: .04em; }
.gd-phase-n { font: 600 14px/1.3 var(--font-sans); }
.gd-phase-p { font: 500 12px/1 var(--font-mono); color: var(--g-blue-text); }
.gd-table { width: 100%; border-collapse: collapse; }
.gd-table th, .gd-table td { text-align: left; padding: 6px 0; border-bottom: 1px solid var(--hairline); font-size: 13px; }
.gd-table th { font-weight: 500; color: var(--text-secondary); width: 40%; }
.gd-note { margin: 8px 0 0; font-size: 12px; color: var(--text-dimmed); }
.gd-qs { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.gd-q { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.gd-q-t {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 0; border: 0; background: none;
  color: var(--accent-text); font: 500 13px/1.3 var(--font-sans); cursor: pointer; text-decoration: none; text-align: left;
}
.gd-q-t:hover { text-decoration: underline; }
.gd-q-t .ico { color: var(--text-secondary); }
.gd-ext { font-size: 11px; color: var(--text-dimmed); margin-left: 4px; }
.gd-faq + .gd-faq { margin-top: 6px; }
.gd-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.gd-checks label { display: flex; gap: 8px; align-items: flex-start; cursor: pointer; font-size: 13px; }
.gd-checks input { margin-top: 3px; accent-color: var(--accent); }
.gd-checks input:checked + span { color: var(--text-dimmed); text-decoration: line-through; }
.gd-inline .hint-b { display: grid; gap: 10px; justify-items: start; }
@media (max-width: 760px) {
  .gdv { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .gd-nav { flex-direction: row; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--border); padding: 8px; }
  .gd-nav-h { display: none; }
  .gd-nav-i { flex: none; white-space: nowrap; }
}

/* DevOps: a page, not a workspace, so it scrolls inside the view (the body
   does not scroll in this app). */

.pgv { height: calc(100vh / var(--pz, 1) - var(--cariara-chrome, 0px) - var(--topbar-h, 56px)); display: flex; flex-direction: column; background: var(--bg-base); }
.pgv-bar {
  height: 46px; flex: 0 0 46px; display: flex; align-items: center; gap: 8px;
  padding: 0 14px; border-bottom: 1px solid var(--border); background: var(--bg-surface);
}
.lang-tabs {
  display: flex; gap: 4px; min-width: 0; flex: 0 1 auto;
  overflow-x: auto; scrollbar-width: none; padding: 2px 0;
}
.lang-tabs::-webkit-scrollbar { display: none; }
.lang-tab { flex: 0 0 auto; white-space: nowrap; }
/* Eight languages do not fit beside the run buttons on a laptop pane: the
   row scrolls sideways and the buttons never shrink off the edge. */
.pgv-bar > .btn { flex: 0 0 auto; }
.lang-tab {
  display: flex; align-items: center; gap: 7px; padding: 5px 13px;
  border: 1px solid var(--border); border-radius: var(--radius-chip);
  background: var(--bg-base); color: var(--text-secondary); cursor: pointer;
  font-size: var(--fs-body-m); font-weight: 500;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.lang-tab:hover { border-color: var(--border-hover); color: var(--text-primary); }
.lang-tab.is-on { background: var(--accent-subtle); border-color: var(--accent); color: var(--text-primary); }
.pgv-editor { flex: 1 1 auto; min-height: 120px; overflow: hidden; }
.pgv-console { flex: 0 0 38%; min-height: 120px; display: flex; flex-direction: column; background: var(--bg-surface); border-top: 1px solid var(--border); }
.pgv-console .console-body { flex: 1; overflow: auto; }
.sh-note {
  padding: 10px 13px; margin: 0 0 10px; border-radius: 0;
  border: 1px solid var(--border); border-left: 2px solid var(--accent);
  background: var(--bg-base); color: var(--text-secondary);
  font: var(--fs-body-s)/1.6 var(--font-sans); white-space: normal;
}
.sh-note b { color: var(--text-primary); font-weight: 500; }

/* ── richer solution sections ────────────────────────────── */
.sol-extra {
  margin-top: 18px; padding: 14px 16px; border-radius: 0;
  background: var(--bg-elevated); border: 1px solid var(--border);
}
.sol-extra.is-warn { border-left: 2px solid var(--warning); }
.extra-h {
  margin: 0 0 10px; font: 500 10.5px/1.4 var(--font-mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-dimmed);
}
.sol-extra.is-warn .extra-h { color: var(--warning); }
.sol-extra .prose { font-size: var(--fs-body-m); }
.sol-extra .prose table { margin-bottom: 0; font-size: 12.5px; }
.sol-extra .prose th { font-family: var(--font-mono); font-size: 11px; }
.sol-extra .prose td { font-family: var(--font-mono); font-size: 12px; }
.pitfalls { margin: 0; padding-left: 18px; }
.pitfalls li { margin: 7px 0; font-size: var(--fs-body-m); color: var(--text-secondary); line-height: 1.6; }
.when-to-use {
  margin: 16px 0 0; padding: 11px 14px; border-radius: 0;
  background: var(--accent-subtle); border: 1px solid var(--accent-line);
  font-size: var(--fs-body-m); color: var(--text-primary); line-height: 1.6;
}
.when-to-use span {
  display: block; font: 500 10.5px/1.4 var(--font-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent-text); margin-bottom: 5px;
}

/* ── execution visualiser ────────────────────────────────── */
.viz-empty { padding: 16px; color: var(--text-dimmed); font-family: var(--font-sans); font-style: italic; }
.viz-empty.err { color: var(--danger); font-style: normal; }
.viz-bar {
  display: flex; align-items: center; gap: 12px; padding: 9px 12px;
  border-bottom: 1px solid var(--border); background: var(--bg-elevated);
}
.viz-count { font: 600 11.5px/1 var(--font-mono); color: var(--text-secondary); min-width: 92px; }
.viz-controls { display: flex; gap: 4px; margin-inline: auto; }
.viz-btn {
  width: 30px; height: 26px; border-radius: 0; cursor: pointer;
  border: 1px solid var(--border); background: var(--bg-base); color: var(--text-secondary);
  font-size: 11px; display: grid; place-items: center; transition: all var(--dur) var(--ease);
}
.viz-btn:hover { border-color: var(--border-hover); color: var(--text-primary); }
.viz-btn.is-play { background: var(--accent); border-color: transparent; color: var(--accent-ink); }
.viz-speeds { display: flex; gap: 2px; }
.viz-speed {
  padding: 4px 9px; border-radius: 0; cursor: pointer; border: 1px solid transparent;
  background: transparent; color: var(--text-dimmed); font: 600 11px/1 var(--font-mono);
}
.viz-speed.is-on { background: var(--accent-subtle); border-color: var(--accent-line); color: var(--accent-text); }
.viz-scrub { width: calc(100% - 24px); margin: 10px 12px 4px; accent-color: var(--accent); }
.viz-io {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 12px 10px; border-bottom: 1px solid var(--border);
  font: 11.5px/1.6 var(--font-mono); color: var(--text-dimmed);
}
.viz-io code {
  background: var(--bg-base); border: 1px solid var(--border); color: var(--text-primary);
  padding: 2px 7px; border-radius: 0; font-size: 11.5px;
}
.viz-vars { display: flex; flex-direction: column; gap: 5px; padding: 12px; }
.viz-var {
  display: grid; grid-template-columns: 110px 1fr; gap: 12px; align-items: baseline;
  padding: 7px 11px; border-radius: 0;
  background: var(--bg-base); border: 1px solid var(--border);
}
.viz-name { font: 600 11px/1.5 var(--font-mono); color: var(--accent-text); }
.viz-val { font: 12.5px/1.5 var(--font-mono); color: var(--text-primary); word-break: break-all; }
.viz-note { margin: 0; padding: 0 12px 12px; font-size: 11.5px; color: var(--text-dimmed); }

/* ── roadmap ─────────────────────────────────────────────── */
.rmv { height: calc(100vh / var(--pz, 1) - var(--cariara-chrome, 0px) - var(--topbar-h, 56px)); display: flex; flex-direction: column; overflow: hidden; }
.rmv-head { padding: 24px 26px 18px; border-bottom: 1px solid var(--border); background: var(--bg-surface); }
.rmv-head h1 { margin: 0 0 4px; font-size: var(--fs-heading-xl); font-weight: 400; color: var(--g-ink); }
.rmv-head p { margin: 0 0 14px; color: var(--text-secondary); font-size: var(--fs-body-m); }
.rmv-overall { display: flex; align-items: center; gap: 12px; max-width: 560px; }
.rmv-bar { flex: 1; height: 5px; border-radius: 0; background: var(--bg-raised); overflow: hidden; }
.rmv-bar span { display: block; height: 100%; background: var(--success); border-radius: 0; transition: width .3s var(--ease); }
.rmv-count { font: 11.5px/1 var(--font-mono); color: var(--text-dimmed); white-space: nowrap; }
.rmv-body { flex: 1; display: flex; overflow: hidden; }
.rmv-graph {
  flex: 1; overflow-y: auto; padding: 26px 20px 34px; position: relative;
  display: flex; flex-direction: column; gap: 34px; align-items: stretch;
}
.rmv-tier { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; row-gap: 34px; }
.rmv-node {
  position: relative; z-index: 1; min-width: 170px; flex: 0 1 190px; max-width: 240px;
  text-align: left; cursor: pointer;
  padding: 12px 14px 14px; border-radius: 0;
  border: 1px solid var(--border); background: var(--bg-elevated);
  box-shadow: var(--shadow-xs), inset 0 1px 0 var(--inset-top);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.rmv-node:hover:not([disabled]) { border-color: var(--accent); transform: translateY(-1px); }
.rmv-node[disabled] { opacity: .45; cursor: not-allowed; }
.rmv-node.is-done { border-color: var(--border); }
.rmv-label { display: block; font-size: var(--fs-body-m); font-weight: 500; color: var(--text-primary); }
.rmv-meta { display: block; margin-top: 3px; font: 11px/1.4 var(--font-mono); color: var(--text-dimmed); }
.rmv-track { display: block; margin-top: 9px; height: 3px; border-radius: 0; background: var(--bg-base); overflow: hidden; }
.rmv-track span { display: block; height: 100%; background: var(--accent); border-radius: 0; }
.rmv-node.is-done .rmv-track span { background: var(--success); }

.rmv-panel {
  width: 380px; flex: 0 0 380px; overflow-y: auto; padding: 22px;
  border-left: 1px solid var(--border); background: var(--bg-surface);
}
.tp-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 20px; }
.tp-head h2 { margin: 0; font-size: var(--fs-heading-m); font-weight: 700; }
.tp-head p { margin: 3px 0 0; font: 11.5px/1.5 var(--font-mono); color: var(--text-dimmed); }
.tp-head-actions .btn { margin-left: 0; }
.tp-block { margin-bottom: 22px; }
.tp-prereqs { display: flex; flex-direction: column; gap: 7px; }
.tp-prereq {
  padding: 10px 12px; border-radius: 0;
  border: 1px solid var(--border); background: var(--bg-base);
}
.tp-prereq-n { display: block; font-size: var(--fs-body-m); font-weight: 500; color: var(--accent-text); }
.tp-prereq-w { display: block; margin-top: 3px; font-size: var(--fs-body-s); color: var(--text-secondary); line-height: 1.55; }
.tp-list { display: flex; flex-direction: column; gap: 3px; }
.tp-row {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; cursor: pointer;
  padding: 8px 10px; border-radius: 0; border: 1px solid transparent; background: transparent;
}
.tp-row:hover { background: var(--bg-elevated); }
.tp-mark { display: flex; color: var(--text-dimmed); }
.tp-row.is-solved .tp-mark { color: var(--success); }
.tp-name { flex: 1; font-size: var(--fs-body-m); color: var(--text-secondary); }
.tp-row:hover .tp-name { color: var(--text-primary); }
.tp-diff { font: 500 10px/1 var(--font-mono); text-transform: uppercase; letter-spacing: .04em; }
@media (max-width: 1000px) { .rmv-panel { display: none; } }

/* ── visualiser: drawn state ─────────────────────────────── */
.viz-var { display: grid; grid-template-columns: 96px 1fr; gap: 12px; align-items: start;
  padding: 9px 11px; border-radius: 0;
  background: var(--bg-base); border: 1px solid var(--border); }
.viz-var.is-scalar { align-items: center; }
.viz-body { min-width: 0; }
.viz-scalar { font: 600 13px/1.4 var(--font-mono); color: var(--text-primary); }
.viz-none { font: italic 12px/1.4 var(--font-sans); color: var(--text-dimmed); }
.viz-repr { font: 12px/1.5 var(--font-mono); color: var(--text-secondary); word-break: break-all; }

.cells { display: flex; flex-wrap: wrap; gap: 4px; }
.cell {
  position: relative; min-width: 38px; padding: 5px 7px 3px; text-align: center;
  border-radius: 0; border: 1px solid var(--border); background: var(--bg-elevated);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.cell-v { display: block; font: 600 12.5px/1.3 var(--font-mono); color: var(--text-primary); }
.cell-i { display: block; font: 9.5px/1.3 var(--font-mono); color: var(--text-dimmed); }
.cell.is-marked { border-color: var(--accent); background: var(--accent-subtle); }
.cell-p {
  display: block; margin-top: 2px; font: 500 9.5px/1.2 var(--font-mono);
  color: var(--accent-text); letter-spacing: .04em;
}
.cell.is-more { display: grid; place-items: center; color: var(--text-dimmed); font: 11px var(--font-mono); }

.pairs { display: flex; flex-wrap: wrap; gap: 4px; }
.pair {
  display: inline-flex; align-items: center; gap: 3px; padding: 4px 8px;
  border-radius: 0; border: 1px solid var(--border);
  background: var(--bg-elevated); font: 12px/1.3 var(--font-mono); color: var(--text-primary);
}
.pair b { color: var(--accent-text); font-weight: 700; }
.pair i { color: var(--text-dimmed); font-style: normal; }
.pair.is-more { color: var(--text-dimmed); }
.pair.is-marked { border-color: var(--accent); background: var(--accent-subtle); }
.pair-p {
  margin-left: 4px; padding-left: 5px; border-left: 1px solid var(--border);
  font: 500 9.5px/1.2 var(--font-mono); color: var(--accent-text);
  font-style: normal; letter-spacing: .04em;
}

/* ── spoon-fed solution sections ─────────────────────────── */
/* The editor while it is showing a published approach rather than the learner's
   own answer: a tint and a muted cursor, so read-only is visible before a
   keystroke goes nowhere. */
.editor-wrap.is-solution { background: var(--info-bg); }
.editor-wrap.is-solution .CodeMirror-cursor { display: none !important; }
.sol-actions .sol-note {
  font-size: var(--fs-body-s); color: var(--text-dimmed); line-height: 1.55;
}

.prereq-warn {
  margin: 0 0 10px; font-size: var(--fs-body-s); color: var(--text-dimmed); font-style: italic;
}
.sol-extra.is-idea { border-left: 2px solid var(--accent); background: var(--accent-subtle); }
.sol-extra.is-idea .extra-h { color: var(--accent-text); }
.algo { margin: 0; padding-left: 20px; counter-reset: none; }
.algo li { margin: 8px 0; font-size: var(--fs-body-m); color: var(--text-secondary); line-height: 1.65; }
.algo li::marker { color: var(--accent-text); font-weight: 500; font-family: var(--font-mono); }
.sol-figure {
  margin: 18px 0 0; padding: 16px; border-radius: 0;
  border: 1px solid var(--border); background: var(--bg-base); overflow-x: auto;
}
.sol-figure svg { display: block; max-width: 100%; height: auto; margin: 0 auto; }
.sol-figure figcaption {
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--hairline);
  font-size: var(--fs-body-s); color: var(--text-dimmed); line-height: 1.6; text-align: center;
}

/* ── roadmap edges ───────────────────────────────────────── */
.rmv-graph { position: relative; }
.rmv-edges { position: absolute; inset: 0; pointer-events: none; z-index: 0; overflow: visible; }
.rmv-tier { position: relative; z-index: 1; }
.verdict.is-idle {
  border-color: var(--border);
  background: var(--warning-bg);
}
.verdict.is-idle .verdict-main { color: var(--warning); }

/* ── Input (stdin) tab ───────────────────────────────────── */
#out-stdin { display: none; flex-direction: column; gap: 10px; padding: 12px 14px; overflow: auto; }
#out-stdin.is-on { display: flex; }
/* ── custom-input dialog ─────────────────────────────────── */
.inputdlg {
  border: none; padding: 0; background: transparent; color: inherit;
  max-width: min(560px, calc(100vw / var(--pz, 1) - 32px)); width: 100%;
}
.inputdlg::backdrop { background: var(--bg-overlay); }
.inputdlg-card {
  display: flex; flex-direction: column; gap: 14px; padding: 18px 20px 16px;
  border: 1px solid var(--border); border-radius: 0;
  background: var(--bg-surface); box-shadow: var(--shadow-md);
}
.inputdlg-head { display: flex; align-items: center; gap: 12px; }
.inputdlg-head h2 { margin: 0; font-size: var(--fs-heading-s); font-weight: 700; }
.inputdlg-head .btn { margin-left: auto; }
.inputdlg-box {
  width: 100%; min-height: 116px; resize: vertical; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 0;
  background: var(--bg-base); color: var(--text-primary);
  font: 12.5px/1.6 var(--font-mono);
}
.inputdlg-box:focus { outline: none; border-color: var(--accent); }
.inputdlg-box::placeholder { color: var(--text-dimmed); }
.inputdlg-foot { display: flex; align-items: center; gap: 8px; }
.inputdlg-foot .spacer { flex: 1; }
.inputdlg-lead { margin: 0 0 8px; font-size: 12px; color: var(--text-secondary); }
.inputdlg-lead code { font: 11.5px var(--font-mono); color: var(--accent-text); }
.inputdlg-lines { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; }
.inputdlg-lines li { font-size: 12px; color: var(--text-secondary); }
.inputdlg-lines code {
  font: 11.5px var(--font-mono); color: var(--accent-text);
  background: var(--bg-elevated); border-radius: 0; padding: 1px 5px;
}
.inputdlg-lines span { margin-left: 7px; color: var(--text-dimmed); }
.inputdlg-off { margin: 0; font-size: 12px; color: var(--text-dimmed); }

.stdin-spec { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.stdin-lead { margin: 0; font-size: 12px; color: var(--text-secondary); }
.stdin-lead code { font: 11.5px var(--font-mono); color: var(--accent-text); }
.stdin-lines { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; }
.stdin-lines li { font-size: 12px; color: var(--text-secondary); }
.stdin-lines code {
  font: 600 11.5px var(--font-mono); color: var(--text-primary);
  padding: 1px 5px; border-radius: 0;
  background: var(--bg-elevated); border: 1px solid var(--border);
}
.stdin-lines span { margin-left: 7px; color: var(--text-dimmed); }
.stdin-off { margin: 0; font-size: 12px; color: var(--text-dimmed); }
.stdin:disabled { opacity: .5; cursor: not-allowed; }

.sol-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sol-loaded {
  margin-right: auto; font-size: 11.5px; color: var(--text-dimmed);
  display: inline-flex; align-items: center; gap: 6px;
}
.sol-loaded::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); flex: none;
}

/* ── "Watch it run": the step player, inside the solution ─── */
.sol-viz { display: flex; flex-direction: column; gap: 8px; }
.viz-lead { margin: 0; font-size: var(--fs-body-s); color: var(--text-dimmed); }
.viz-host { min-height: 64px; }
.viz.is-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px; border-radius: 0;
  border: 1px solid var(--border); background: var(--bg-base);
}
.viz.is-card .viz-bar { margin: 0; }

/* The source, with the running line marked — the card is self-contained. */
.viz-code {
  list-style: none; margin: 0; padding: 8px 0; max-height: 232px; overflow: auto;
  border-radius: 0; border: 1px solid var(--border);
  background: var(--bg-surface); counter-reset: none;
}
.viz-code li {
  display: flex; gap: 10px; padding: 1px 10px 1px 0;
  border-left: 2px solid transparent;
  font: 12px/1.65 var(--font-mono);
}
.viz-code .viz-ln {
  flex: 0 0 30px; text-align: right; color: var(--text-dimmed);
  font-size: 10.5px; user-select: none; padding-top: 1px;
}
.viz-code code { color: var(--text-secondary); white-space: pre; }
.viz-code li.is-now {
  border-left-color: var(--accent); background: var(--accent-subtle);
}
.viz-code li.is-now code { color: var(--text-primary); }
.viz-code li.is-now .viz-ln { color: var(--accent-text); font-weight: 700; }

.stdin-actions { display: flex; gap: 6px; flex-wrap: wrap; }

/* ══════════════════════════════════════════════════════════════
   Landing — what the root URL shows.

   The app used to open straight into the first problem, which gave a new
   visitor an editor and no explanation, and gave a returning one no way back
   to an overview. This is the front door: what PPG is, what it contains, and
   the one action worth taking. It sits above the workspace rather than
   replacing it, so opening a problem is a reveal, not a page load.
   ══════════════════════════════════════════════════════════════ */

.landing {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  padding: 32px 20px;
  background: var(--bg-base);
  overflow-y: auto;
}
.landing[hidden] { display: none; }

.landing-inner {
  width: 100%; max-width: 760px;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}

.landing-mark {
  display: flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; margin-bottom: 22px;
  border-radius: 0;
  background: var(--accent-subtle);
  border: 1px solid var(--accent-line);
  color: var(--accent);
}

.landing h1 {
  margin: 0;
  font-size: clamp(28px, 5.2vw, 42px);
  line-height: 1.12;
  letter-spacing: -.02em;
  font-weight: 400;
  color: var(--g-ink);
}
.landing h1 em {
  font-style: normal;
  color: var(--accent-text);
}

.landing-lede {
  margin: 14px 0 0;
  font-size: clamp(14px, 2.2vw, 16px);
  line-height: 1.6;
  color: var(--text-secondary);
}

.landing-stats {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 10px; margin: 26px 0 0;
}
.landing-stat {
  display: flex; align-items: baseline; gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-chip);
  background: var(--bg-elevated);
}
.landing-stat b {
  font-family: var(--font-mono);
  font-size: var(--fs-heading-xs);
  color: var(--text-primary);
}
.landing-stat span {
  font-size: var(--fs-body-s);
  color: var(--text-dimmed);
  letter-spacing: .2px;
}

.landing-actions {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 10px; margin: 30px 0 0;
}
.landing-actions .btn { padding: 10px 20px; font-size: var(--fs-heading-xs); }

.landing-note {
  margin: 18px 0 0;
  font-size: var(--fs-body-s);
  color: var(--text-dimmed);
}

/* Three plain statements of what the thing does, not feature marketing. */
.landing-points {
  display: grid; gap: 12px; margin: 38px 0 0; width: 100%;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  text-align: left;
}
.landing-point {
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--bg-surface);
}
.landing-point h3 {
  margin: 0 0 6px;
  font-size: var(--fs-heading-xs);
  font-weight: 500;
  color: var(--text-primary);
}
.landing-point p {
  margin: 0;
  font-size: var(--fs-body-s);
  line-height: 1.55;
  color: var(--text-muted);
}

.landing-resume {
  margin: 26px 0 0; padding-top: 22px;
  border-top: 1px solid var(--hairline);
  width: 100%;
}
.landing-resume-label {
  font-size: var(--fs-body-s);
  color: var(--text-dimmed);
  letter-spacing: .3px; text-transform: uppercase;
}
.landing-resume-list {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 8px; margin-top: 12px;
}
.landing-resume-list button {
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-chip);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  font: 500 var(--fs-body-s)/1 var(--font-sans);
  cursor: pointer;
}
.landing-resume-list button:hover {
  border-color: var(--border-hover);
  color: var(--text-primary);
}

/* ── the signed-in chip in the topbar ── */
.user-chip {
  display: flex; align-items: center; gap: 8px;
  padding: 3px 4px 3px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-chip);
  background: var(--bg-elevated);
}
.user-chip[hidden] { display: none; }
.user-chip .user-name {
  font-size: var(--fs-body-s);
  color: var(--text-secondary);
  max-width: 160px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.user-chip img, .user-chip .user-initial {
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-subtle);
  color: var(--accent-text);
  font-size: var(--fs-body-s); font-weight: 700;
  object-fit: cover;
}

@media (max-width: 620px) {
  .landing-points { grid-template-columns: 1fr; }
  .user-chip .user-name { display: none; }
}

/* ── language switch ──
   Practice and Roadmap each exist per language; this says which one you are
   looking at. It sits beside the mode tabs rather than inside the rail because
   it applies to the roadmap too, where there is no rail. */
.lang-switch {
  display: flex; align-items: center; gap: 2px;
  padding: 2px; border-radius: var(--radius-chip);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
}
.lang-switch[hidden] { display: none; }
.lang-pill {
  padding: 4px 12px; border: 0; border-radius: var(--radius-chip);
  background: transparent; color: var(--text-dimmed);
  font: 600 var(--fs-body-s)/1 var(--font-sans);
  cursor: pointer; white-space: nowrap;
}
.lang-pill:hover { color: var(--text-primary); }
.lang-pill.is-on {
  background: var(--bg-raised);
  color: var(--text-primary);
  box-shadow: var(--shadow-xs);
}

@media (max-width: 720px) {
  .lang-switch { display: none; }
}

/* ══════════════════════════════════════════════════════════════
   Work split — editor and output.

   Stacked, the output pane spends a wide screen's worth of horizontal room
   showing short lines, and pushes the editor into a letterbox. Side by side,
   the problem, the answer and the result are all in view at once, which is
   the arrangement the work actually wants. Narrow screens keep the stack,
   where a second column would leave neither pane usable.
   ══════════════════════════════════════════════════════════════ */

.work-split {
  flex: 1; min-height: 0; min-width: 0;
  display: flex; flex-direction: column;
}
.work-split > .editor-wrap { flex: 1; min-height: 0; min-width: 0; }
.work-split > .console     { min-height: 0; min-width: 0; }

@media (min-width: 1400px) {
  /* Editor floor + grip + console floor. Below this the split is stacked and
     --workmin's smaller value applies. */
  .layout { --workmin: 620px; }
  .work-split { flex-direction: row; }
  /* The editor keeps a floor and the console gives way. A console width
     saved from a wide window used to take nearly all of a 620px work column
     and leave the editor ~120px, so code wrapped a word per line. */
  .work-split > .editor-wrap { min-width: min(360px, 55%); }

  /* Height is the stacked layout's business; side by side, the console owns
     a width instead and must not inherit a pixel height from a past drag. */
  .work-split > .console {
    /* Shrinkable, and capped: a console dragged wide on a large monitor used
       to keep that exact width on a smaller one and leave the editor a sliver. */
    flex: 0 1 var(--consolew, 38%);
    min-width: 220px; max-width: 62%;
    height: auto !important;
    border-left: 1px solid var(--border);
    border-top: 0;
  }

  .work-split > .row-grip {
    width: 5px; height: auto;
    flex: 0 0 5px;
    cursor: col-resize;
  }
  .work-split > .row-grip::after { inset: 0 2px; }
}

/* ── reachable controls ──
   The editor's actions are the most-used controls on the page, and they sat
   flush against the window edge where a maximised window clips them and a
   pointer has to travel the full width. They now keep a margin, never shrink,
   and meet a comfortable target height. */
.editor-head { padding-right: 16px; gap: 6px; flex-wrap: nowrap; }
.editor-head .spacer { min-width: 0; }
.editor-head .btn { flex: 0 0 auto; min-height: 30px; }

/* Anything that responds to a click says so on hover and under the keyboard. */
.mode-tab, .lang-pill, .seg-b, .tab, .btn {
  min-height: 28px;
  -webkit-tap-highlight-color: transparent;
}
.mode-tab:focus-visible, .lang-pill:focus-visible, .seg-b:focus-visible,
.tab:focus-visible, .btn:focus-visible, .p-item:focus-visible {
  outline: none; box-shadow: var(--shadow-focus);
}
.p-item { cursor: pointer; }

@media (pointer: coarse) {
  .mode-tab, .lang-pill, .seg-b, .tab, .btn { min-height: 36px; }
}

/* ── the playground's own split ──
   The scratchpad had the same stacked arrangement as Practice and wants the
   same fix: code on the left, what it printed on the right. */
.pgv-split {
  flex: 1; min-height: 0; min-width: 0;
  display: flex; flex-direction: column;
}

@media (min-width: 1400px) {
  .pgv-split { flex-direction: row; }

  .pgv-split > .pgv-editor { flex: 1 1 auto; min-width: min(360px, 55%); min-height: 0; }

  .pgv-split > .pgv-console {
    flex: 0 1 var(--pgconsolew, 38%);
    height: auto !important;
    min-height: 0; min-width: 0;
    border-left: 1px solid var(--border);
    border-top: 0;
  }

  .pgv-split > .row-grip {
    width: 5px; height: auto;
    flex: 0 0 5px;
    cursor: col-resize;
  }
  .pgv-split > .row-grip::after { inset: 0 2px; }
}

/* ══════════════════════════════════════════════════════════════
   THE GOOGLE LAYER

   Everything above is the app's own structure carrying Google's
   tokens. This is the part that makes it read as Google rather
   than merely as light: the search field, the navigation rail, the
   card elevation, the state layers, and the four-colour bar that
   doubles as the progress indicator.

   It is appended rather than woven in so the conversion stays
   reviewable — every rule here is a deliberate override, and the
   structure it overrides is still legible above.
   ══════════════════════════════════════════════════════════════ */

/* ── 1. the shell keeps its content ────────────────────────────
   The stacked breakpoint set `.layout { height: auto }` while `body`
   stayed `overflow: hidden`, so everything below the fold became
   unreachable — the page looked cut off. A grid item also defaults to
   `min-width: auto`, which stops a pane shrinking below its content and
   pushes the rest off-screen. Both are fixed here.

   `scrollbar-gutter: stable` is the load-time flicker: a scrollbar
   appearing after the problem list renders used to resize every pane. */
html { scrollbar-gutter: stable; }

.layout > *, .pane, .pane-body, .rail, .rail-list,
.work-split, .pgv, .pgv-split, .rmv, .rmv-body {
  min-width: 0; min-height: 0;
}
.pane { min-width: 0; }
.panel { max-width: 100%; }

@media (max-width: 1100px) {
  /* Below this width the app stops being a three-pane workspace and becomes
     a scrolling page. The document has to be able to scroll for that to work. */
  html, body { height: auto; min-height: 100%; overflow: visible; }
  body { overflow-x: hidden; }
  .layout { height: auto; overflow: visible; }
  .pane, .pane-work { overflow: visible; }
  .pane-body { overflow: visible; }
  .boot-veil { position: fixed; }

  /* The rail capped at 44vh spent all of it on the stats, the search and two
     filter rows, leaving about one visible problem. The head keeps its natural
     height and the list gets a scroller of its own underneath. */
  .rail { max-height: none; }
  .rail-list { max-height: min(340px, 46vh); overflow-y: auto; }
}

/* ── 2. the search field ───────────────────────────────────────
   Google's search box: a filled grey pill with no border, which lifts to
   white on an elevation when focused rather than growing a coloured ring. */
.rail-search { isolation: isolate; }
.search {
  padding: 9px 36px 9px 38px;
  border: 1px solid transparent;
  border-radius: var(--radius-chip);
  background: var(--surface-3);
  font-size: var(--fs-body-m);
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.search:hover { background: var(--surface-2); box-shadow: var(--shadow-xs); }
.search:focus {
  background: var(--surface-1);
  border-color: transparent;
  box-shadow: var(--shadow-sm);
}
.rail-search-i { left: 13px; transition: color var(--dur) var(--ease); }
.rail-search:focus-within .rail-search-i { color: var(--accent); }
.rail-kbd {
  right: 10px; border: none; background: transparent;
  font-family: var(--font-mono); color: var(--text-dimmed);
  transition: opacity var(--dur) var(--ease);
}

/* ── 3. the navigation rail ────────────────────────────────────
   Gmail and Drive mark the selected item with a full pill in the accent
   tint, not an inset bar and a border. The pill is the whole affordance:
   it is why the list reads as navigation rather than as a table. */
.rail-list { padding-inline: 6px; }
.p-item {
  border: none; border-radius: var(--radius-chip);
  padding: 8px 12px; gap: 10px;
}
.p-item::before {
  /* Material's state layer: one translucent plane that carries hover and
     press, so the resting background never has to change. */
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: currentColor; opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.p-item:hover { background: transparent; }
.p-item:hover::before { opacity: .06; }
.p-item:active::before { opacity: .10; }
.p-item.is-on {
  background: var(--accent-subtle);
  border-color: transparent;
  box-shadow: none;
}
.p-item.is-on .p-name { color: var(--accent-text); font-weight: 500; }
.p-item.is-on .stat { color: var(--accent); }
.p-item.is-on::before { opacity: 0; }
.p-item.solved .stat { color: var(--g-green); }

/* The difficulty letter reads as a Material assist chip, not bare type. */
.p-item .p-diff {
  width: auto; min-width: 18px; height: 18px;
  display: grid; place-items: center;
  font-family: var(--font-sans); font-size: 10px; font-weight: 500;
  border-radius: 0;
}
.p-item .p-diff.d-Easy   { color: var(--g-green-text);  background: var(--success-bg); }
.p-item .p-diff.d-Medium { color: var(--g-yellow-text); background: var(--warning-bg); }
.p-item .p-diff.d-Hard   { color: var(--g-red-text);    background: var(--sky-bg); }

/* Group headings are Material overlines: small, spaced, and quiet. */
.rail-group-h, .rail-group-title {
  font-family: var(--font-sans); letter-spacing: .08em;
}

/* ── 4. the app bar ────────────────────────────────────────────
   The mode switch is a Material segmented button; the avatar is the
   circular account button Google puts at the end of every app bar. */
.mode-tabs { background: var(--surface-3); padding: 4px; }
.mode-tab { padding: 6px 16px; }
.mode-tab.is-on {
  background: var(--surface-1); color: var(--accent-text);
  box-shadow: var(--shadow-xs); font-weight: 500;
}
.mode-tab .ico { opacity: .9; }

.user-chip { border: none; background: transparent; padding: 0 0 0 8px; gap: 10px; }
.user-chip .user-initial {
  width: 32px; height: 32px;
  background: var(--accent); color: #fff;
  font-weight: 500; font-size: var(--fs-body-m);
  box-shadow: var(--shadow-xs);
}
.user-chip .user-name { color: var(--text-secondary); font-size: var(--fs-body-m); }

/* The brand mark carries the four colours; the wordmark stays ink. */
.brand-mark { color: inherit; }
.brand-svg { display: block; }

/* ── 5. cards ──────────────────────────────────────────────────
   Material's card: white, 8px, resting on elevation 1 and lifting to
   elevation 2 on hover. A border and a shadow together is one signal
   too many, so the border goes. */
.landing-point, .block, .case, .sol-panel, .boot-card {
  border-radius: 0;
}
.landing-point {
  border: none; background: var(--surface-1);
  box-shadow: var(--gcp-elevation-1, var(--shadow-sm));
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.landing-point:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.landing-point h3 { font-weight: 500; color: var(--g-ink); }

.landing-stat {
  border-radius: var(--radius-chip);
  background: var(--surface-1);
  border: 1px solid var(--border);
}
.landing-stat b { font-family: var(--font-mono); }

/* ── 6. state layers on every control ──────────────────────────
   Material presses do not move the element; they darken it. The 1px
   translate the buttons used to take now belongs to the shadow. */
.btn { position: relative; overflow: hidden; }
.btn::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: currentColor; opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.btn:hover::after  { opacity: .08; }
.btn:active::after { opacity: .14; }
.btn-primary::after, .btn-danger::after { background: #fff; }
.btn:disabled::after { opacity: 0; }

.tab, .seg-b, .mode-tab { position: relative; }

/* ── 7. the four-colour bar as the progress indicator ──────────
   The rule under the app bar is already Google's four colours. While
   Python is booting or a run is in flight it becomes Material's
   indeterminate linear progress — the same object doing both jobs,
   rather than a spinner appearing from nowhere. */
.topbar::after {
  background: var(--spectrum);
  transform-origin: 0 50%;
}
body.is-booting .topbar::after,
body.is-running .topbar::after {
  animation: g-sweep 1.6s var(--ease) infinite;
}
@keyframes g-sweep {
  0%   { clip-path: inset(0 100% 0 0); }
  45%  { clip-path: inset(0 0 0 0); }
  55%  { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(0 0 0 100%); }
}

/* The boot veil gets the same bar instead of a grey spinner. */
.boot-veil { backdrop-filter: none; background: rgba(255,255,255,.94); }
.boot-card h2 { font-weight: 400; color: var(--g-ink); font-size: var(--fs-heading-l); }
.boot-spin {
  width: 220px; height: 4px; border: none; border-radius: var(--radius-chip);
  background: var(--surface-3); overflow: hidden; position: relative;
  animation: none;
}
.boot-spin::after {
  content: ""; position: absolute; inset: 0;
  background: var(--spectrum);
  animation: g-sweep 1.6s var(--ease) infinite;
}

/* ── 8. the problem document ───────────────────────────────────
   Google sets long-form text in regular weight on a constrained measure.
   Headings differ from body by size and colour, not by boldness. */

.prose h2, .prose h3, .sol-title, .tp-head h2, .inputdlg-head h2 {
  font-weight: 500; color: var(--g-ink); letter-spacing: -.005em;
}
.prose strong { font-weight: 500; color: var(--g-ink); }
/* Inline code is a Material assist chip, sized to sit on the text baseline. */
.prose code, .prob-head code {
  font-family: var(--font-mono); font-size: .875em;
  background: var(--surface-3); color: var(--g-blue-text);
  padding: .1em .4em; border-radius: 0;
}

/* Eyebrow labels — Material overline. */
.block-label, .rail-group-h, .metric-k, .case-tag {
  font-weight: 500; letter-spacing: .1em;
}

/* ── 9. motion ─────────────────────────────────────────────────
   Material's standard easing on everything that moves, and a fade-through
   when a panel is swapped so the change is legible rather than abrupt. */
.panel.is-on, .out.is-on, .sol-panel.is-on {
  animation: g-fade-through 180ms var(--ease) both;
}
@keyframes g-fade-through {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* The reduced-motion block above already disables all of this. */

/* ── 10. the roadmap as a Material card grid ───────────────────
   The tier nodes were grey panels with an inset highlight — a raised-surface
   trick from the dark palette. On white they become plain Material cards:
   white, elevation 1, lifting to elevation 2 under the pointer. */
.rmv-node {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 0;
  box-shadow: var(--gcp-elevation-1);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.rmv-node:hover:not([disabled]) {
  box-shadow: var(--gcp-elevation-2);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}
.rmv-node[disabled] { box-shadow: none; opacity: .5; }
.rmv-node.is-done { border-color: var(--border); }
.rmv-node.is-done .rmv-track span { background: var(--g-green); }
.rmv-label { font-weight: 500; color: var(--g-ink); }
.rmv-track { background: var(--surface-3); height: 4px; border-radius: var(--radius-chip); }
.rmv-track span { border-radius: var(--radius-chip); transition: width .3s var(--ease); }

/* The overall meter takes the full four-colour rule once it is complete —
   a small reward that uses the brand rather than inventing a new colour. */
.rmv-bar { background: var(--surface-3); height: 6px; border-radius: var(--radius-chip); }
.rmv-bar span { background: var(--accent); border-radius: var(--radius-chip); }
.rmv-overall.is-complete .rmv-bar span { background: var(--spectrum); }

.rmv-panel { background: var(--surface-1); }
.tp-prereq {
  background: var(--surface-1); border-radius: 0;
  box-shadow: var(--shadow-xs); border-color: transparent;
}
.tp-row { border-radius: var(--radius-chip); border: none; }
.tp-row:hover { background: var(--accent-subtle); }
.tp-row.is-solved .tp-mark { color: var(--g-green); }
.tp-diff { font-family: var(--font-sans); font-weight: 500; letter-spacing: .06em; }

/* ── 11. verdicts in Google's four ─────────────────────────────
   A pass is green, a failure is red, both in the text-safe variants so the
   label clears contrast on its own tinted panel. The verdict banner becomes
   a Material surface: a white card with a coloured left edge, rather than a
   wash with a matching outline. */
.verdict {
  background: var(--surface-1); border: none; border-radius: 0;
  box-shadow: var(--shadow-xs); border-left: 2px solid var(--border-strong);
}
.verdict.is-pass { background: var(--success-bg); border-left-color: var(--g-green); }
.verdict.is-fail { background: var(--danger-bg); border-left-color: var(--err); }
.verdict.is-idle { border-left-color: var(--g-yellow); }
.verdict-main { font-weight: 500; }
.verdict.is-pass .verdict-main { color: var(--g-green-text); }
.verdict.is-fail .verdict-main { color: var(--err-text); }
.verdict.is-idle .verdict-main { color: var(--g-yellow-text); }
.verdict-bar { background: var(--surface-3); border-radius: var(--radius-chip); }
.verdict-bar span { border-radius: var(--radius-chip); background: var(--g-green); }
.verdict.is-fail .verdict-bar span { background: var(--err); }

.case { border-radius: 0; border-color: var(--border); background: var(--surface-1); }
.case .mark.ok { color: var(--g-green); }
.case .mark.no { color: var(--err); }

/* ── 12. the console strip under pressure ──────────────────────
   The console pane is resizable, so its header has to survive being dragged
   narrow. The tabs and the button keep their size; the timing readout is the
   one thing that may shrink, and it truncates rather than pushing the Clear
   button out of reach. */
.console-head { gap: 6px; min-width: 0; }
.console-head .tabbar, .console-head .btn { flex: 0 0 auto; }
.console-head .timing {
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
}

/* ── 13. the landing ───────────────────────────────────────────
   The landing covers the app bar, so it carries the four-colour rule itself.
   Without it the front door is the one surface with no brand on it. */
.landing::before {
  content: ""; position: fixed; top: 0; left: 0; right: 0; height: 3px;
  background: var(--spectrum); z-index: 1;
}
.landing-mark {
  background: var(--surface-1);
  border: 1px solid var(--border);
  box-shadow: var(--gcp-elevation-1);
  width: 64px; height: 64px;
  border-radius: 0;
}
.landing-note { color: var(--text-dimmed); }
.landing-resume-label { letter-spacing: .1em; font-weight: 500; }
.landing-resume-list button {
  border-radius: var(--radius-chip); border-color: var(--border);
  background: var(--surface-1); transition: box-shadow var(--dur) var(--ease);
}
.landing-resume-list button:hover { box-shadow: var(--shadow-xs); background: var(--accent-subtle); }

/* ══════════════════════════════════════════════════════════════
   THE FOUR COLOURS

   Google does not spend its palette on one logo and then go grey. It
   runs the four across a page in sequence — the process strip, the
   card rules, the section labels — so the set reads as a system
   rather than as an accent.

   The rule followed here: the sequence is always blue → red → yellow
   → green, in that order, and it keys off position, never off
   meaning. A section is not blue because it is important; it is blue
   because it is first. Anything that does carry meaning (difficulty,
   a pass, a failure) keeps the colour that means it.

   Everything set as type uses the darkened -text variant. #9AD61A at
   11px on white is unreadable, and that is the one mistake this
   palette invites.
   ══════════════════════════════════════════════════════════════ */

/* ── rail: the topic sections run the sequence ─────────────────
   Nineteen topics down a scrolling list is exactly where a repeating
   four-colour cycle earns its place: it gives the eye a position. */
.rail-sec:nth-of-type(4n+1) { --sec: var(--g-blue);   --sec-text: var(--g-blue-text); }
.rail-sec:nth-of-type(4n+2) { --sec: var(--g-red);    --sec-text: var(--g-red-text); }
.rail-sec:nth-of-type(4n+3) { --sec: var(--g-yellow); --sec-text: var(--g-yellow-text); }
.rail-sec:nth-of-type(4n+4) { --sec: var(--g-green);  --sec-text: var(--g-green-text); }

.rail-group { color: var(--sec-text, var(--g-blue-text)); border-bottom-color: var(--border); }
.rail-group::before { background: var(--sec, var(--g-blue)); width: 4px; height: 13px; }
.rail-group-x { color: var(--sec, var(--g-blue)); }
.rail-meter-f { background: var(--sec, var(--g-blue)); }
.rail-meter-f.is-done { background: var(--g-green); }
.rail-group-n.is-done { color: var(--g-green-text); }

/* ── the problem document: section labels run the sequence ─────
   Examples, Constraints, Stuck? — three labels down one page, each
   with its own colour and a bar to hang it on. */
.block:nth-of-type(4n+1) { --sec: var(--g-blue);   --sec-text: var(--g-blue-text); }
.block:nth-of-type(4n+2) { --sec: var(--g-red);    --sec-text: var(--g-red-text); }
.block:nth-of-type(4n+3) { --sec: var(--g-yellow); --sec-text: var(--g-yellow-text); }
.block:nth-of-type(4n+4) { --sec: var(--g-green);  --sec-text: var(--g-green-text); }

.block-h {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-sans); font-weight: 500; font-size: 11px;
  color: var(--sec-text, var(--g-blue-text));
}
.block-h::before {
  content: ""; width: 14px; height: 3px; border-radius: 0; flex: none;
  background: var(--sec, var(--g-blue));
}

/* The examples card takes its section's colour as a top rule — Google's
   card-with-a-coloured-edge, the shape the whole GCP catalogue uses. */
.ex-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-top: 2px solid var(--sec, var(--g-blue));
  border-radius: 0;
  box-shadow: var(--gcp-elevation-1);
}
.ex-n { color: var(--sec-text, var(--g-blue-text)); font-weight: 500; }

/* Constraints are chips, and a row of chips is the clearest place in the
   app to show the four running in order. */
.constraints code {
  border-radius: var(--radius-chip);
  padding: 4px 12px; border: 1px solid transparent;
  font-family: var(--font-mono); font-size: var(--fs-body-s);
}
.constraints code:nth-child(4n+1) { color: var(--g-blue-text);   background: var(--info-bg);  border-color: var(--border); }
.constraints code:nth-child(4n+2) { color: var(--g-red-text);    background: var(--sky-bg);   border-color: var(--border); }
.constraints code:nth-child(4n+3) { color: var(--g-yellow-text); background: var(--warning-bg);   border-color: var(--border); }
.constraints code:nth-child(4n+4) { color: var(--g-green-text);  background: var(--success-bg);   border-color: var(--border); }

/* Hints are the one nudge before the answer; yellow is Google's "careful,
   you are about to be told something" colour. */
.hintbox {
  border-radius: 0;
  border-left: 2px solid var(--g-yellow);
  background: var(--surface-1);
  box-shadow: var(--shadow-xs);
}
.hintbox summary { color: var(--text-primary); font-weight: 500; }
.hintbox summary .ico { color: var(--text-secondary); }

/* ── the app bar: each mode keeps a colour ─────────────────────
   Google's own products are colour-coded — Docs blue, Sheets green,
   Slides yellow. The three modes follow the same idea. */
.mode-tab[data-mode="practice"]   { --sec: var(--g-blue);   --sec-text: var(--g-blue-text); }
.mode-tab[data-mode="playground"] { --sec: var(--g-green);  --sec-text: var(--g-green-text); }
.mode-tab[data-mode="roadmap"]    { --sec: var(--g-yellow); --sec-text: var(--g-yellow-text); }
.mode-tab .ico { color: var(--sec); opacity: 1; }
.mode-tab.is-on { color: var(--sec-text); }
.mode-tab.is-on::after {
  content: ""; position: absolute; left: 16px; right: 16px; bottom: 3px; height: 2px;
  border-radius: 0; background: var(--sec);
}

/* ── footers ───────────────────────────────────────────────────
   The rail's footer and the landing both close on the same rule the
   app bar opens with, so the page is bracketed by the brand. */
.rail-foot { position: relative; background: var(--surface-1); }
.rail-foot::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--spectrum);
}

/* ── the landing's three cards ─────────────────────────────────
   Capra's process strip: one colour per column, carried by a top rule
   and the heading, with the body text left neutral. */
.landing-points > .landing-point:nth-child(4n+1) { --sec: var(--g-blue);   --sec-text: var(--g-blue-text); }
.landing-points > .landing-point:nth-child(4n+2) { --sec: var(--g-red);    --sec-text: var(--g-red-text); }
.landing-points > .landing-point:nth-child(4n+3) { --sec: var(--g-yellow); --sec-text: var(--g-yellow-text); }
.landing-points > .landing-point:nth-child(4n+4) { --sec: var(--g-green);  --sec-text: var(--g-green-text); }
.landing-point {
  border-top: 2px solid var(--sec);
  border-radius: 0;
}
.landing-point h3 { color: var(--sec-text); }

/* The three stats take the first three of the sequence. */
.landing-stats > .landing-stat:nth-child(4n+1) b { color: var(--g-blue-text); }
.landing-stats > .landing-stat:nth-child(4n+2) b { color: var(--g-red-text); }
.landing-stats > .landing-stat:nth-child(4n+3) b { color: var(--g-yellow-text); }
.landing-stats > .landing-stat:nth-child(4n+4) b { color: var(--g-green-text); }

/* The roadmap's own colour cycle lives with the stages, further down. */
.rmv-track span { background: var(--sec, var(--accent)); }

/* ── the solution switcher ─────────────────────────────────────
   Several approaches to one problem is another sequence, so it runs
   the same four. */
.sol-pill:nth-of-type(4n+1) { --sec: var(--g-blue);   --sec-text: var(--g-blue-text); }
.sol-pill:nth-of-type(4n+2) { --sec: var(--g-red);    --sec-text: var(--g-red-text); }
.sol-pill:nth-of-type(4n+3) { --sec: var(--g-yellow); --sec-text: var(--g-yellow-text); }
.sol-pill:nth-of-type(4n+4) { --sec: var(--g-green);  --sec-text: var(--g-green-text); }
.sol-pill.is-on {
  color: var(--text-primary); border-color: var(--sec);
  background: var(--surface-1); box-shadow: inset 0 0 0 1px var(--sec);
}
.sol-pill.is-on .sol-pill-n { background: var(--sec-text); border-color: var(--sec-text); color: #fff; }
.sol-pill.is-on .sol-pill-cx { color: var(--sec-text); }

/* ══════════════════════════════════════════════════════════════
   THE ROADMAP, GOOGLYFIED

   The graph was a grid of grey boxes with a hairline bar. What makes
   Google's own progress pages read the way they do is not the colour
   on its own — it is the three things underneath it: a figure set
   large and light, a status mark you can scan a column of without
   reading, and stages that announce themselves.
   ══════════════════════════════════════════════════════════════ */

/* ── the header: figures first ─────────────────────────────── */
.rmv-head { padding: 28px 32px 22px; }
.rmv-head h1 { font-size: var(--fs-display-l); line-height: var(--lh-display-l); letter-spacing: -.02em; }
.rmv-overall { display: block; max-width: none; }

.rmv-tiles { display: flex; gap: 40px; margin: 20px 0 18px; }
.rmv-tile b {
  display: block; font-family: var(--font-mono); font-weight: 400;
  font-size: 34px; line-height: 1.1; letter-spacing: -.02em;
}
.rmv-tile span {
  display: block; margin-top: 2px;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-muted); font-weight: 500;
}
/* The three figures take the first three of the sequence. */
.rmv-tiles > .rmv-tile:nth-child(1) b { color: var(--g-blue-text); }
.rmv-tiles > .rmv-tile:nth-child(2) b { color: var(--g-red-text); }
.rmv-tiles > .rmv-tile:nth-child(3) b { color: var(--g-green-text); }

.rmv-meter { display: flex; align-items: center; gap: 14px; max-width: 620px; }
.rmv-bar { flex: 1; height: 8px; }
/* Empty, the track shows the four colours at low opacity — the path you have
   not walked yet. The fill covers them in accent blue as you go, and the whole
   bar turns to the full spectrum once it is done. */
.rmv-bar { background: var(--surface-3); position: relative; }
.rmv-bar::before {
  content: ""; position: absolute; inset: 0; background: var(--spectrum); opacity: .18;
}
.rmv-bar span { position: relative; z-index: 1; background: var(--accent); }
.rmv-overall.is-complete .rmv-bar span { background: var(--spectrum); }
.rmv-count { color: var(--text-muted); }

/* ── stages ─────────────────────────────────────────────────── */
.rmv-graph { gap: 0; padding: 22px 28px 40px; }
.rmv-stage { display: flex; flex-direction: column; gap: 14px; padding-bottom: 30px; }
.rmv-stage:nth-of-type(4n+1) { --sec: var(--g-blue);   --sec-text: var(--g-blue-text);   --sec-bg: var(--info-bg); }
.rmv-stage:nth-of-type(4n+2) { --sec: var(--g-red);    --sec-text: var(--g-red-text);    --sec-bg: var(--sky-bg); }
.rmv-stage:nth-of-type(4n+3) { --sec: var(--g-yellow); --sec-text: var(--g-yellow-text); --sec-bg: var(--warning-bg); }
.rmv-stage:nth-of-type(4n+4) { --sec: var(--g-green);  --sec-text: var(--g-green-text);  --sec-bg: var(--success-bg); }

.rmv-stage-h {
  display: flex; align-items: center; gap: 12px;
  position: relative; z-index: 2;
}
.rmv-stage-n {
  font-family: var(--font-mono); font-size: 28px; font-weight: 400;
  line-height: 1; letter-spacing: -.03em;
  color: var(--sec); opacity: .38;
}
.rmv-stage-l {
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  font-weight: 500; color: var(--sec-text);
}
.rmv-stage-rule { flex: 1; height: 2px; border-radius: 0; background: var(--sec); opacity: .2; }
.rmv-stage-c {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-dimmed);
  white-space: nowrap;
}

/* ── the node cards ─────────────────────────────────────────── */
.rmv-tier { row-gap: 16px; }
.rmv-node {
  display: flex; flex-direction: column; gap: 0;
  padding: 14px 16px 16px;
  flex: 0 1 216px; max-width: 260px; min-width: 190px;
  border: 1px solid var(--border);
  border-top: 2px solid var(--sec, var(--g-blue));
  background: var(--surface-1);
  box-shadow: var(--gcp-elevation-1);
}
.rmv-node-h { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
/* The status mark: a filled circle in the stage colour, the way Google Cloud
   fronts every service card. */
.rmv-ico {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; flex: none;
  background: var(--sec-bg, var(--info-bg));
  color: var(--sec-text, var(--g-blue-text));
}
.rmv-pct {
  font-family: var(--font-mono); font-size: 13px;
  color: var(--sec-text, var(--g-blue-text)); font-weight: 500;
}
.rmv-label { font-size: var(--fs-heading-s); line-height: 1.25; }
.rmv-meta { margin-top: 4px; font-family: var(--font-sans); font-size: var(--fs-body-s); color: var(--text-muted); }
.rmv-track { margin-top: 12px; height: 4px; }

/* Done: the card commits to green, mark and all. */
.rmv-node.is-done { --sec: var(--g-green); --sec-text: var(--g-green-text); border-top-color: var(--g-green); }
.rmv-node.is-done .rmv-ico { background: var(--g-green); color: #fff; }
/* Nothing to do yet: the card stands down rather than shouting a colour. */
.rmv-node.is-empty { --sec: var(--border-strong); --sec-text: var(--text-dimmed); }
.rmv-node.is-empty .rmv-ico { background: var(--surface-3); color: var(--text-dimmed); }
.rmv-node.is-empty .rmv-pct { display: none; }

/* Edges in Google's hairline grey, behind the cards. */
.rmv-edges path { stroke: var(--border-strong); }

@media (max-width: 760px) {
  .rmv-tiles { gap: 24px; }
  .rmv-tile b { font-size: 26px; }
  .rmv-head { padding: 20px 16px 16px; }
}

/* ── 14. the app bar under pressure ────────────────────────────
   Brand, three labelled modes, the language switch, the runtime dot, a full
   name, an avatar and Sign out do not fit in 820px. The bar had no rule for
   that width — the labels only dropped at 760 — so it simply ran off the
   side. Everything that can give way now does, in the order it should. */
.topbar { min-width: 0; }
.topbar-right { min-width: 0; }
.user-chip { min-width: 0; }
.user-chip .user-name { max-width: 140px; }

@media (max-width: 1240px) {
  /* The avatar already identifies the account; the name is the first thing
     that can go. */
  .user-chip .user-name { display: none; }
}
@media (max-width: 1040px) {
  /* Next to give way are the mode labels. The icons are distinct and each
     keeps its own colour, and the buttons keep their accessible names, so
     nothing is lost but the width. Sign out stays: hiding it would leave no
     way to sign out at all. */
  .topbar { gap: 12px; }
  .mode-tab { padding: 6px 11px; gap: 0; }
  .mode-tab span { display: none; }
  .mode-tab.is-on::after { left: 8px; right: 8px; }
}

/* ══════════════════════════════════════════════════════════════
   TODAY

   Google's own progress surfaces lead with a figure, not a chart:
   the number large and light, what it counts small underneath. The
   page is one column on the GCP measure, sectioned by a heading and
   a rule, and every card is a target.
   ══════════════════════════════════════════════════════════════ */

/* ── streak ──────────────────────────────────────────────────
   The number says how long; the bars say what shape it is in. */

/* ── the daily goal ──────────────────────────────────────── */

/* ── sections ────────────────────────────────────────────── */

/* ── a card ──────────────────────────────────────────────── */

/* The left edge says which of the three reasons this card is here for. */

/* ── coverage ────────────────────────────────────────────── */

/* ── the rail's new marks ─────────────────────────────────── */
.p-tag {
  flex: none; display: grid; place-items: center;
  font-family: var(--font-sans); font-size: 9.5px; font-weight: 500;
  height: 16px; min-width: 16px; padding: 0 4px;
  border-radius: 0;
}
.p-tag.b75 { color: var(--g-blue-text); background: var(--info-bg); }
.p-tag.due { color: var(--g-red-text);  background: var(--sky-bg); }
/* Due is additive: the solved check stays exactly as it was. */
.p-item.is-due .p-name { color: var(--text-primary); }

.seg-n {
  margin-left: 5px; font-family: var(--font-mono); font-size: 9.5px;
  padding: 0 4px; border-radius: var(--radius-badge);
  background: var(--sky-bg); color: var(--g-red-text);
}
.seg-n[hidden] { display: none; }

/* ── the snackbar ─────────────────────────────────────────── */
.toast {
  position: fixed; right: 20px; bottom: 20px; z-index: 60; pointer-events: none;
  display: flex; align-items: center; gap: 8px; max-width: 340px;
  padding: 11px 16px; border-radius: 0;
  color: #fff; font: 500 var(--fs-body-m)/1.4 var(--font-sans);
  box-shadow: var(--shadow-lg);
  opacity: 0; transform: translateY(8px);
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}
.toast.is-in { opacity: 1; transform: none; }

/* ══════════════════════════════════════════════════════════════
   COMMAND PALETTE

   Google's pattern: a sheet near the top of the window, a single
   field, and results that are all one keystroke away. It is a
   <dialog>, so the backdrop, the focus trap and Escape are the
   browser's job rather than ours.
   ══════════════════════════════════════════════════════════════ */

/* The UA hides a closed <dialog> with `display: none`, and an author
   `display` outranks it — the same trap this sheet already documents for
   [hidden] up at the top. Declaring `display: flex` unconditionally left the
   palette painted over every page while closed: not modal, no backdrop, an
   empty list, and Escape doing nothing because there was nothing open to
   close. The flex box only applies once the dialog is actually open. */
.cmdk {
  display: none;
  width: min(620px, calc(100vw / var(--pz, 1) - 32px));
  max-height: min(520px, calc(100vh / var(--pz, 1) - 140px));
  margin: 84px auto auto;
  padding: 0; border: none;
  border-radius: 0;
  background: var(--surface-1);
  box-shadow: var(--shadow-xl, var(--shadow-lg));
  overflow: hidden;
  color: var(--text-primary);
}
.cmdk[open] { display: flex; flex-direction: column; }
.cmdk::backdrop { background: var(--bg-overlay); }
.cmdk[open] { animation: cmdk-in 140ms var(--ease) both; }
@keyframes cmdk-in {
  from { opacity: 0; transform: translateY(-6px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.cmdk-in {
  display: flex; align-items: center; gap: 12px;
  padding: 0 16px; height: 56px; flex: none;
  border-bottom: 1px solid var(--border);
}
.cmdk-i { display: flex; color: var(--text-muted); flex: none; }
.cmdk-in input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font: var(--fs-heading-s)/1.4 var(--font-sans); color: var(--text-primary);
}
.cmdk-in input::placeholder { color: var(--text-dimmed); }
/* It looks like a key cap and behaves like a button, because it is one. */
.cmdk-esc {
  flex: none; font: 10px/1.6 var(--font-mono); color: var(--text-muted);
  border: 1px solid var(--border-strong); border-radius: 0;
  padding: 3px 8px; background: var(--surface-1); cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.cmdk-esc:hover { background: var(--surface-3); color: var(--text-primary); }
.cmdk-esc:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

.cmdk-list { flex: 1; overflow-y: auto; padding: 6px; min-height: 0; }
.cmdk-none { margin: 0; padding: 22px 12px; color: var(--text-muted); font-size: var(--fs-body-m); }

.cmdk-row {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 9px 10px; border: none; background: transparent; cursor: pointer;
  border-radius: 0; text-align: left;
}
.cmdk-row.is-sel { background: var(--accent-subtle); }
.cmdk-kind {
  flex: none; width: 22px; height: 22px; border-radius: 0;
  display: grid; place-items: center;
  font: 500 10px/1 var(--font-sans);
  background: var(--surface-3); color: var(--text-muted);
}
/* A problem's marker carries its difficulty; a view's is just a chevron. */
.cmdk-row .cmdk-kind.k-problem { background: var(--info-bg); color: var(--g-blue-text); }
.cmdk-row .cmdk-kind.k-view    { background: var(--success-bg);  color: var(--g-green-text); }
.cmdk-row .cmdk-kind.k-lang,
.cmdk-row .cmdk-kind.k-action  { background: var(--warning-bg);  color: var(--g-yellow-text); }

.cmdk-l {
  flex: 1; min-width: 0; font-size: var(--fs-body-m); color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cmdk-row.is-sel .cmdk-l { color: var(--accent-text); font-weight: 500; }
.cmdk-b {
  flex: none; font: 500 9.5px/1 var(--font-sans); letter-spacing: .05em;
  text-transform: uppercase; padding: 3px 7px; border-radius: var(--radius-chip);
}
.cmdk-b.ok  { color: var(--g-green-text); background: var(--success-bg); }
.cmdk-b.due { color: var(--g-red-text);   background: var(--sky-bg); }
.cmdk-h {
  flex: none; max-width: 34%; font-size: var(--fs-body-s); color: var(--text-dimmed);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.cmdk-foot {
  flex: none; display: flex; gap: 16px; padding: 9px 16px;
  border-top: 1px solid var(--border); background: var(--surface-2);
  font-size: var(--fs-body-s); color: var(--text-dimmed);
}
.cmdk-foot span { display: flex; align-items: center; gap: 5px; }
.cmdk-foot kbd {
  font: 10px/1.6 var(--font-mono);
  border: 1px solid var(--border-strong); border-radius: var(--radius-badge);
  padding: 0 5px; background: var(--surface-1);
}

@media (max-width: 620px) {
  .cmdk { margin-top: 40px; }
  .cmdk-h { display: none; }
}

/* ── signal badges on the problem header ──────────────────────
   How widely a question is asked is the single most useful thing to know
   before spending forty minutes on it, and it was sitting in the dataset
   unread. It belongs next to the difficulty, not buried in a panel. */
.badge.b75 { color: var(--g-blue-text); background: var(--info-bg); border-color: var(--border); }
.badge.freq,
.badge.due {
  display: inline-flex; align-items: center; gap: 5px;
}
.badge.freq { color: var(--g-green-text); background: var(--success-bg); border-color: var(--border); }
.badge.due  { color: var(--g-red-text);   background: var(--sky-bg);  border-color: var(--border); }
.badge.freq .ico, .badge.due .ico { opacity: .85; }

/* Solved and due at once: the check keeps its meaning, the ring is added. */
.prob-state.is-solved.is-due {
  color: var(--g-red-text);
  background: var(--sky-bg);
  border-color: var(--border);
}

/* ══════════════════════════════════════════════════════════════
   VISUAL EXPLANATION

   Two figures, with different jobs and different rules.

   The example figure sits on the Problem tab and draws the
   question: the input as cells, the answer marked on it. It shows
   what, never how, so the solution gate is untouched.

   The trace player sits behind that gate and draws the method,
   one real step at a time, and now says what each step did.
   ══════════════════════════════════════════════════════════════ */

.fig-host { margin: 0 0 14px; }
.fig {
  margin: 0; padding: 16px 18px 14px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-top: 2px solid var(--sec, var(--g-blue));
  border-radius: 0;
  box-shadow: var(--gcp-elevation-1);
}

.fig-cap {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.fig-t {
  font-family: var(--font-mono); font-size: var(--fs-body-m);
  color: var(--sec-text, var(--g-blue-text)); font-weight: 500;
}
.fig-arg {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: var(--fs-body-s);
  color: var(--text-secondary);
  background: var(--surface-3); padding: 3px 9px; border-radius: var(--radius-chip);
}
.fig-arg b { color: var(--text-muted); font-weight: 500; }
.fig-play {
  margin-left: auto; flex: none;
  width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--border-strong); background: var(--surface-1);
  color: var(--text-muted); cursor: pointer; font-size: 10px; line-height: 1;
  display: grid; place-items: center;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.fig-play:hover { background: var(--accent-subtle); color: var(--accent-text); border-color: var(--accent); }
.fig-play:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

/* ── the cells ──
   Each lands in turn rather than the row appearing whole: the stagger is what
   makes the sequence read as a sequence. */
.fig-row { display: flex; gap: 6px; flex-wrap: wrap; align-items: flex-end; }
.fig-cell {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  min-width: 44px; padding: 9px 10px 6px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--surface-2);
  opacity: 0; transform: translateY(6px) scale(.96);
  transition: opacity .22s var(--ease), transform .22s var(--ease),
              background .22s var(--ease), border-color .22s var(--ease),
              box-shadow .22s var(--ease);
}
.fig-cell.is-in { opacity: 1; transform: none; }
.fig-cell.is-mark {
  background: var(--success-bg);
  border-color: var(--g-green);
  transform: translateY(-3px);
}
.fig-v {
  font-family: var(--font-mono); font-size: var(--fs-heading-s);
  color: var(--text-primary); line-height: 1.2;
}
.fig-cell.is-mark .fig-v { color: var(--g-green-text); font-weight: 500; }
.fig-i {
  font-family: var(--font-mono); font-size: 9.5px; color: var(--text-dimmed);
}
.fig-cell.is-mark .fig-i { color: var(--g-green-text); }

.fig-out {
  display: flex; align-items: center; gap: 10px; margin-top: 14px;
  opacity: 0; transform: translateY(4px);
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.fig-out.is-in { opacity: 1; transform: none; }
.fig-arrow {
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 500; color: var(--text-muted);
}
.fig-res {
  font-family: var(--font-mono); font-size: var(--fs-body-m); font-weight: 500;
  color: var(--g-green-text); background: var(--success-bg);
  padding: 4px 12px; border-radius: var(--radius-chip);
}
.fig-note {
  margin: 12px 0 0; font-size: var(--fs-body-s); color: var(--text-muted);
  line-height: 1.6;
}

/* ── the trace player's narration ──
   One line naming what the step did, so the grid below is confirmation
   rather than homework. */
.viz-say {
  margin: 10px 0 0; padding: 9px 12px;
  background: var(--surface-2); border-left: 2px solid var(--g-blue);
  border-radius: 0;
  font-size: var(--fs-body-m); color: var(--text-secondary);
  min-height: 38px; display: flex; align-items: center;
}
.viz-say b { color: var(--g-blue-text); font-weight: 500; font-family: var(--font-mono); }
.viz-say code {
  font-family: var(--font-mono); font-size: .92em;
  background: var(--surface-3); color: var(--text-primary);
  padding: 1px 6px; border-radius: 0;
}
.viz-say em { color: var(--text-dimmed); font-style: normal; }

.viz-loop { font-size: 13px; }
.viz-loop.is-on { color: var(--accent-text); background: var(--accent-subtle); }

/* A value that changed this step announces itself rather than just being
   different from a frame you are no longer looking at. */
.viz-var.is-changed { animation: viz-pop .32s var(--ease); }
@keyframes viz-pop {
  0%   { background: var(--warning-bg); }
  100% { background: transparent; }
}

@media (max-width: 760px) {
  .fig { padding: 13px 14px 12px; }
  .fig-cell { min-width: 38px; padding: 7px 8px 5px; }
}

/* A linked list is the same row of cells with the arrows made explicit. */
.fig-row.is-nodes .fig-cell + .fig-cell { margin-left: 16px; position: relative; }
.fig-row.is-nodes .fig-cell + .fig-cell::before {
  content: "→"; position: absolute; left: -16px; top: 50%;
  transform: translate(-50%, -50%);
  color: var(--text-dimmed); font-size: 13px; line-height: 1;
}
.fig-row.is-nodes .fig-i { display: none; }

/* A span answer is contiguous, so it reads as one block rather than as
   separate marked cells. */
.fig-cell.is-mark + .fig-cell.is-mark { border-left-color: transparent; }
.fig-arg i { font-style: normal; color: var(--text-dimmed); }

/* ── a matrix ──
   Rows and columns, drawn as a grid rather than a wrapped row, so the shape
   of the problem is the shape on screen. */
.fig-row.is-grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(34px, 44px));
  gap: 4px; width: max-content; max-width: 100%;
}
.fig-row.is-grid .fig-cell { min-width: 0; padding: 9px 4px; }
.fig-row.is-grid .fig-v { font-size: var(--fs-body-m); }

/* ── a timeline ──
   Intervals on a shared axis. Overlap becomes something you see instead of
   something you compute from a table of pairs. */
.fig-tl { display: flex; flex-direction: column; gap: 5px; }
.tl-set { display: flex; flex-direction: column; gap: 5px; }
.tl-row { position: relative; height: 26px; }
.tl-row::before {
  content: ""; position: absolute; inset: 50% 0 auto; height: 1px;
  background: var(--border); transform: translateY(-50%);
}
.tl-bar {
  position: absolute; top: 0; height: 26px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-chip);
  background: var(--info-bg);
  border: 1px solid var(--g-blue);
  opacity: 0; transform: scaleX(.4); transform-origin: left center;
  transition: opacity .25s var(--ease), transform .25s var(--ease),
              background .25s var(--ease), border-color .25s var(--ease);
}
.tl-bar.is-in { opacity: 1; transform: none; }
.tl-bar.is-mark {
  background: var(--success-bg);
  border-color: var(--g-green);
}
.tl-bar.is-out {
  background: var(--success-bg);
  border-color: var(--g-green);
}
.tl-lab {
  font-family: var(--font-mono); font-size: 10.5px; color: var(--text-primary);
  white-space: nowrap; padding: 0 6px;
}
.tl-bar.is-out .tl-lab { color: var(--g-green-text); }
.tl-sep {
  display: flex; align-items: center; gap: 8px; margin: 3px 0;
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-dimmed); font-weight: 500;
}
.tl-sep::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.tl-axis {
  display: flex; justify-content: space-between; margin-top: 2px;
  font-family: var(--font-mono); font-size: 10px; color: var(--text-dimmed);
}

/* Before and after, for the matrix problems whose answer is the same grid
   changed. The chip is hidden in that case — it would only repeat the grid. */
.fig-pair { display: flex; flex-direction: column; gap: 4px; }
.fig-becomes {
  display: flex; align-items: center; gap: 8px; margin: 8px 0 4px;
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-dimmed); font-weight: 500;
}
.fig-becomes::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.fig-cell.is-outcell {
  background: var(--success-bg);
  border-color: var(--border);
}
.fig-cell.is-outcell .fig-v { color: var(--g-green-text); }

/* ══════════════════════════════════════════════════════════════
   THE PLAYER, IN MOTION

   The panel is reconciled rather than redrawn, so elements survive
   from one step to the next and can actually transition. These are
   the rules that spend that: a pointer travels, a new cell or map
   entry arrives, and a changed value is marked where it changed.
   ══════════════════════════════════════════════════════════════ */

/* The row reserves space beneath itself for the pointer layer, which is
   positioned over it rather than flowing inside the cells. */
.cells { position: relative; padding-bottom: 18px; }
.ptrs { position: absolute; left: 0; top: 100%; height: 0; width: 100%; pointer-events: none; }
.ptr {
  position: absolute; top: 2px; left: 0; white-space: nowrap;
  font: 500 9.5px/1.2 var(--font-mono); letter-spacing: .04em;
  color: var(--accent-text);
  padding: 1px 5px; border-radius: var(--radius-chip);
  background: var(--accent-subtle);
  /* The whole point: an index change becomes a movement. */
  transition: transform .3s var(--ease), opacity .18s var(--ease);
}
.ptr.is-enter { opacity: 0; }
/* A caret joining the marker to the cell it points at. */
.ptr::before {
  content: ""; position: absolute; left: 50%; top: -4px;
  border: 2px solid transparent; border-bottom-color: var(--accent);
  transform: translateX(-50%);
}

/* Cells and map entries fade in where they appear instead of the row
   jumping to a new length. */
.cell, .pair {
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
              opacity .22s var(--ease), transform .22s var(--ease);
}
.cell.is-enter, .pair.is-enter, .viz-var.is-enter {
  opacity: 0; transform: translateY(4px) scale(.96);
}
.viz-var { transition: opacity .2s var(--ease), transform .2s var(--ease); }

/* The changed-value pulse now lands on the element that changed — the cell
   or the entry — rather than washing the whole variable block. */
.cell.is-changed, .pair.is-changed, .viz-scalar.is-changed {
  animation: viz-pop .34s var(--ease);
}
.viz-scalar.is-changed { border-radius: 0; }

/* Reconciled markup: the key, arrow and value are their own elements now. */
.pair-k { color: var(--accent-text); font-weight: 500; }
.pair-arrow { color: var(--text-dimmed); font-style: normal; }
.pair-p:empty { display: none; }

/* ── my cases ────────────────────────────────────────────────
   Cases of your own under the console's third tab. One card per case:
   a numbered head you can name, a field per argument labelled with the
   parameter it fills, an optional expected value, and the result the
   last run produced underneath. The left edge carries the state. */
.mc-count {
  display: inline-block; min-width: 16px; padding: 0 5px; margin-left: 4px;
  border-radius: var(--radius-chip); background: var(--bg-elevated);
  font: 600 10.5px/16px var(--font-mono); color: var(--text-secondary); text-align: center;
}
.mc-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--border);
}
.mc-lead { flex: 1 1 260px; margin: 0; font-size: var(--fs-body-s); color: var(--text-dimmed); line-height: 1.5; }
.mc-lead code { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-secondary); }
.mc-sum { font: 12px/1.4 var(--font-mono); color: var(--text-secondary); }
.mc-list { display: flex; flex-direction: column; gap: 8px; }
.mc-case {
  border: 1px solid var(--border); border-left: 2px solid var(--border);
  border-radius: 0; background: var(--surface-1);
}
.mc-case.is-pass { border-left-color: var(--success); }
.mc-case.is-fail, .mc-case.is-err { border-left-color: var(--danger); }
.mc-case.is-ran { border-left-color: var(--accent); }
.mc-head { display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 10px; border-bottom: 1px solid var(--border); }
.mc-n {
  flex: 0 0 20px; height: 20px; border-radius: 50%; background: var(--bg-elevated);
  font: 500 10.5px/20px var(--font-mono); text-align: center; color: var(--text-secondary);
}
.mc-name {
  flex: 1; min-width: 0; border: 0; background: transparent; padding: 4px 6px; border-radius: 0;
  font: 500 var(--fs-body-m)/1.3 var(--font-sans); color: var(--text-primary);
}
.mc-name:focus { outline: none; background: var(--bg-elevated); }
.mc-state { font: 11px/1 var(--font-mono); color: var(--text-dimmed); white-space: nowrap; }
.mc-case.is-pass .mc-state { color: var(--success); }
.mc-case.is-fail .mc-state, .mc-case.is-err .mc-state { color: var(--danger); }
.mc-case.is-ran .mc-state { color: var(--accent-text); }
.mc-fields { display: grid; gap: 6px; padding: 10px; }
.mc-field { display: grid; grid-template-columns: minmax(64px, max-content) minmax(0, 1fr); gap: 10px; align-items: start; }
.mc-field > span {
  padding-top: 7px; font: 11px/1.3 var(--font-mono); color: var(--text-dimmed); white-space: nowrap;
}
.mc-field > span em { font-style: normal; opacity: .75; }
.mc-field textarea {
  width: 100%; box-sizing: border-box; resize: none; overflow: hidden; min-height: 30px;
  padding: 6px 8px; border: 1px solid var(--border); border-radius: 0; background: var(--bg-base);
  font: 12.5px/1.5 var(--font-mono); color: var(--text-primary);
}
.mc-field textarea:focus { outline: none; border-color: var(--accent); background: var(--surface-1); }
.mc-field.is-want textarea { border-style: dashed; }
.mc-result { padding: 10px 12px; border-top: 1px solid var(--border); background: var(--bg-surface); }
.mc-empty { padding: 18px 4px; font-size: var(--fs-body-s); color: var(--text-secondary); line-height: 1.6; }
.mc-empty p { margin: 0 0 6px; }
.mc-empty p:first-child { color: var(--text-primary); font-weight: 500; }
.mc-empty .btn { margin-top: 8px; }
.mc-icon {
  flex: 0 0 28px; height: 28px; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 50%; background: transparent; color: var(--text-dimmed); cursor: pointer;
}
.mc-icon:hover { background: var(--bg-elevated); color: var(--text-primary); }
.mc-icon[data-act="del"]:hover { color: var(--danger); }
.mc-icon:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* The console can be a narrow column beside the editor. Below ~440px the
   labels move above their fields and the bar stacks, instead of every
   field being crushed to a few characters. */
#out-mine { container-type: inline-size; }
@container (max-width: 440px) {
  .mc-field { grid-template-columns: minmax(0, 1fr); gap: 3px; }
  .mc-field > span { padding-top: 0; }
  .mc-head { flex-wrap: wrap; }
  .mc-state { order: 5; flex-basis: 100%; padding: 2px 0 2px 26px; }
  .mc-bar .btn { flex: 1 1 auto; justify-content: center; }
}

/* ── playground test cases ───────────────────────────────────
   Same card as My cases, holding stdin and the expected stdout side by
   side. A failed case shows the two as a line-numbered diff with the
   differing lines tinted, so the first wrong line is found by eye. */
#pgout-cases { white-space: normal; padding: 12px; font-family: var(--font-sans); container-type: inline-size; }
.pc-io { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; padding: 10px; }
.pc-box { display: grid; gap: 4px; }
.pc-box > span { font: 11px/1.3 var(--font-mono); color: var(--text-dimmed); }
.pc-box > span em { font-style: normal; opacity: .75; }
.pc-box textarea {
  width: 100%; box-sizing: border-box; resize: vertical; min-height: 64px;
  padding: 6px 8px; border: 1px solid var(--border); border-radius: 0; background: var(--bg-base);
  font: 12.5px/1.5 var(--font-mono); color: var(--text-primary);
}
.pc-box textarea:focus { outline: none; border-color: var(--accent); background: var(--surface-1); }
.pc-box.is-want textarea { border-style: dashed; }
.mc-case.is-running { border-left-color: var(--g-yellow, var(--warning)); }
.mc-case.is-running .mc-state { color: var(--g-yellow-text, var(--warning)); }
.pc-diff { width: 100%; border-collapse: collapse; font: 12px/1.55 var(--font-mono); table-layout: fixed; }
.pc-diff th {
  text-align: left; font: 10.5px/1.6 var(--font-mono); text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dimmed); padding: 0 8px 4px; border-bottom: 1px solid var(--border);
}
.pc-diff th:first-child, .pc-diff .pc-ln { width: 28px; }
.pc-diff td { padding: 1px 8px; vertical-align: top; white-space: pre-wrap; word-break: break-word; color: var(--text-secondary); }
.pc-diff .pc-ln { color: var(--text-dimmed); text-align: right; padding-right: 6px; }
.pc-diff tr.is-diff td { background: var(--danger-bg); }
.pc-diff tr.is-diff td:last-child { color: var(--danger); }
.pc-none { color: var(--text-dimmed); font-style: italic; }
@container (max-width: 520px) {
  .pc-io { grid-template-columns: minmax(0, 1fr); }
}

/* ── use-case labs ───────────────────────────────────────────
   A picker of lab cards, a strip that says which lab you are in, the
   brief as its own console tab, and the lab's tests as a compact list at
   the top of Test cases: one row per test with its tier, the failing ones
   opening onto the input and an Expected / Got diff. */
.pgv-labs-btn { flex: 0 0 auto; }
.pgv-labs-btn.is-on { background: var(--accent-subtle); border-color: var(--accent); }

.labdlg { border: 0; padding: 0; background: transparent; width: min(980px, calc(100vw / var(--pz, 1) - 32px)); max-height: calc(100vh / var(--pz, 1) - 48px); }
.labdlg::backdrop { background: var(--bg-overlay); }
.labdlg-card {
  background: var(--surface-1); border-radius: 0; box-shadow: var(--shadow-md, var(--shadow-sm));
  padding: 20px 22px 22px; display: flex; flex-direction: column; gap: 16px; max-height: calc(100vh / var(--pz, 1) - 48px); box-sizing: border-box;
}
.labdlg-head { display: flex; align-items: flex-start; gap: 16px; }
.labdlg-head > div { flex: 1; }
.labdlg-head h2 { margin: 0 0 4px; font-size: var(--fs-heading-m, 20px); font-weight: 600; }
.labdlg-head p { margin: 0; color: var(--text-secondary); font-size: var(--fs-body-m); }
.labdlg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; overflow-y: auto; padding: 2px; }
.lab-card {
  display: flex; flex-direction: column; gap: 8px; text-align: left; cursor: pointer;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 0;
  background: var(--surface-1); color: inherit; font: inherit;
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.lab-card:hover { box-shadow: var(--shadow-sm); border-color: var(--border-hover); transform: translateY(-1px); }
.lab-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lab-card.is-on { border-color: var(--accent); background: var(--accent-subtle); }
.lab-card-top { display: flex; align-items: center; justify-content: space-between; }
.lab-card-n { font: 11px/1 var(--font-mono); color: var(--text-dimmed); }
.lab-card-title { font-size: var(--fs-body-l, 15px); font-weight: 600; color: var(--text-primary); }
.lab-card-sum { font-size: var(--fs-body-s); color: var(--text-secondary); line-height: 1.5; }
.lab-card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: auto; }
.lab-card-tags span { font: 10.5px/1.6 var(--font-mono); color: var(--text-dimmed); background: var(--bg-elevated); border-radius: 0; padding: 0 6px; }
.lab-diff { font: 700 10.5px/20px var(--font-sans); padding: 0 8px; border-radius: 0; text-transform: uppercase; letter-spacing: .04em; }
.lab-diff.is-green  { color: var(--g-green-text);  background: var(--success-bg); }
.lab-diff.is-yellow { color: var(--g-yellow-text); background: var(--warning-bg); }
.lab-diff.is-red    { color: var(--g-red-text);    background: var(--sky-bg); }

.lab-strip {
  flex: 0 0 auto; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 14px; border-bottom: 1px solid var(--border);
  background: var(--info-bg);
}
.lab-strip[hidden] { display: none; }
.lab-tag {
  font: 500 10px/18px var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: #fff; background: var(--g-blue-text); border-radius: 0; padding: 0 6px;
}
.lab-strip-title { font-weight: 600; color: var(--text-primary); }
.lab-strip-meta { font-size: var(--fs-body-s); color: var(--text-secondary); }


.lab-tests { margin-bottom: 18px; }
.lab-tests-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.lab-tests-head h3, .lab-own-h { margin: 0; font-size: var(--fs-body-m); font-weight: 600; color: var(--text-primary); }
.lab-own-h { margin: 4px 0 10px; padding-top: 14px; border-top: 1px solid var(--border); }
.lab-tiers { display: flex; gap: 6px; flex-wrap: wrap; }
.lab-tier { font: 11px/20px var(--font-mono); padding: 0 8px; border-radius: 0; background: var(--bg-elevated); color: var(--text-secondary); }
.lab-tier.is-ok { color: var(--g-green-text); background: var(--success-bg); }
.lab-tier.is-no { color: var(--err-text); background: var(--danger-bg); }
.lab-tests .verdict { margin-bottom: 10px; }
.lab-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: 0; overflow: hidden; background: var(--surface-1); }
.lab-row + .lab-row { border-top: 1px solid var(--border); }
.lab-row-h {
  width: 100%; display: flex; align-items: center; gap: 10px; padding: 7px 12px;
  border: 0; background: transparent; font: inherit; color: inherit; text-align: left; cursor: default;
}
.lab-row.is-fail .lab-row-h, .lab-row.is-err .lab-row-h { cursor: pointer; }
.lab-row.is-fail .lab-row-h:hover, .lab-row.is-err .lab-row-h:hover { background: var(--bg-elevated); }
.lab-mark { flex: 0 0 14px; display: grid; place-items: center; }
.lab-row.is-pass .lab-mark { color: var(--g-green-text); }
.lab-row.is-fail .lab-mark, .lab-row.is-err .lab-mark { color: var(--err-text); }
.lab-row.is-wait .lab-mark::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--g-yellow); }
.lab-row-name { flex: 1; min-width: 0; font-size: var(--fs-body-s); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lab-row.is-idle .lab-row-name { color: var(--text-secondary); }
.lab-tier-chip { font: 10px/16px var(--font-mono); padding: 0 6px; border-radius: 4px; text-transform: uppercase; letter-spacing: .04em; }
.lab-tier-chip.is-sample { color: var(--g-blue-text);   background: var(--info-bg); }
.lab-tier-chip.is-edge   { color: var(--g-yellow-text); background: var(--warning-bg); }
.lab-tier-chip.is-random { color: var(--g-green-text);  background: var(--success-bg); }
.lab-tier-chip.is-stress { color: var(--g-red-text);    background: var(--sky-bg); }
.lab-row-ms { flex: 0 0 64px; text-align: right; font: 11px/1 var(--font-mono); color: var(--text-dimmed); }
.lab-row-b { padding: 4px 12px 12px 36px; display: grid; gap: 10px; background: var(--bg-surface); }
.lab-io { display: grid; gap: 4px; }
.lab-io > span { font: 10.5px/1.6 var(--font-mono); text-transform: uppercase; letter-spacing: .06em; color: var(--text-dimmed); }
.lab-io pre { margin: 0; padding: 8px 10px; border: 1px solid var(--border); border-radius: 0; background: var(--bg-base); font: 12px/1.5 var(--font-mono); white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow: auto; }
.lab-io .btn { justify-self: start; }
@container (max-width: 440px) {
  .lab-row-ms { display: none; }
  .lab-row-b { padding-left: 12px; }
}

/* ── capra's Problems and Codepad tabs ───────────────────────
   In capra's Playground, Problems and Codepad are two tabs of the page,
   each a frame of this app. The Codepad frame drops the mode tabs and the
   practice language switch; the Problems frame drops the scratchpad's tab,
   which is Codepad out there. */
.tab-codepad #modeTabs,
.tab-codepad #langSwitch { display: none !important; }
/* With its tabs gone the Codepad frame's bar held only the logo, a second
   row under the page's own tab strip. The logo now sits in that strip, so
   the bar goes and the views take the full frame height. */
.tab-codepad { --topbar-h: 0px; }
.tab-codepad .topbar { display: none !important; }
.tab-problems #modeTabs .mode-tab[data-mode="playground"] { display: none; }

#pgExplain.is-on { background: var(--accent-subtle); border-color: var(--accent); color: var(--accent-text); }

/* ── explain ─────────────────────────────────────────────── */
#pgout-explain { white-space: normal; font-family: var(--font-sans); padding: 14px 16px 24px; }
.ex-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.ex-line { flex: 0 0 auto; font: 500 10.5px/1.6 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--g-blue-text); }
.ex-head code { font: 12.5px/1.5 var(--font-mono); color: var(--text-primary); white-space: pre-wrap; word-break: break-word; }
.ex-what { margin: 0 0 14px; font-size: var(--fs-body-l, 15px); line-height: 1.55; color: var(--text-primary); }
.ex-sec { margin: 0 0 14px; }
.ex-sec > span { display: block; margin-bottom: 6px; font: 10.5px/1.6 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--text-dimmed); }
.ex-sec p { margin: 0; font-size: var(--fs-body-m); color: var(--text-secondary); line-height: 1.6; }
.ex-how { display: grid; grid-template-columns: minmax(0, max-content) minmax(0, 1fr); gap: 6px 12px; margin: 0; }
.ex-how dt code { font: 12px/1.5 var(--font-mono); background: var(--bg-elevated); border-radius: 0; padding: 1px 6px; color: var(--text-primary); white-space: pre-wrap; word-break: break-word; }
.ex-how dd { margin: 0; font-size: var(--fs-body-s); color: var(--text-secondary); line-height: 1.55; }
.ex-trace { margin: 0; padding: 8px 10px; border-radius: 0; background: var(--bg-base); border: 1px solid var(--border); font: 12px/1.55 var(--font-mono); white-space: pre-wrap; }
.ex-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.ex-tags span { font-size: 12px; padding: 2px 10px; border-radius: 0; color: var(--g-blue-text); background: var(--info-bg); }
.ex-empty { color: var(--text-dimmed); font-size: var(--fs-body-s); }
.ex-empty.is-err { color: var(--danger); }
.ex-buy { margin-top: 10px; align-self: flex-start; }
@container (max-width: 420px) { .ex-how { grid-template-columns: minmax(0, 1fr); } }

/* ── language groups ─────────────────────────────────────────
   Platform (application languages) and DevOps (Bash, Docker, Terraform)
   as a two-option toggle in front of the language row; only the chosen
   group's languages are listed after it. */
.lang-groups {
  flex: 0 0 auto; display: inline-flex; padding: 2px; gap: 2px;
  border-radius: var(--radius-chip); background: var(--bg-elevated);
}
.lang-group {
  border: 0; background: transparent; cursor: pointer; white-space: nowrap;
  padding: 4px 12px; border-radius: var(--radius-chip);
  font: 600 12px/1.4 var(--font-sans); letter-spacing: .02em; color: var(--text-secondary);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.lang-group:hover { color: var(--text-primary); }
.lang-group.is-on { background: var(--surface-1); color: var(--g-blue-text); box-shadow: var(--shadow-xs, 0 1px 2px rgba(60, 64, 67, .2)); }
.lang-group:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lang-sep { flex: 0 0 1px; align-self: stretch; margin: 4px 4px; background: var(--border); }
.lang-tabs { align-items: center; }

/* ── the playground bar: one cluster ─────────────────────────
   Labs, the language groups and languages, then Run, then the editor
   tools, packed from the left. The language row gives way (it scrolls)
   before anything else does, so Run and the tools never leave the screen. */
.pgv-bar { gap: 6px; }
.pgv-bar > .lang-tabs { flex: 0 1 auto; }
.pgv-sep { flex: 0 0 1px; align-self: stretch; margin: 10px 4px; background: var(--border); }
.pgv-run { flex: 0 0 auto; gap: 6px; padding-inline: 14px 16px; }
.pgv-tools { flex: 0 0 auto; display: flex; align-items: center; gap: 2px; }
@media (max-width: 900px) {
  .pgv-tools #pgReset, .pgv-tools #pgClear { display: none; }
}

/* ── the code side and the brief ──────────────────────────────
   The action strip sits over the code it acts on. A lab adds its brief as
   the left pane (statement | code, as in Problems) and stacks the editor
   over the output; the scratchpad is the code side alone. */
.pgv-body { flex: 1; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
.pgv-work { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.pgv-actions {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px; min-height: 52px;
  padding: 7px 14px; border-bottom: 1px solid var(--border); background: var(--bg-surface);
  container-type: inline-size;
}
.pgv-actions > .btn, .pgv-actions > .pgv-tools { flex: 0 0 auto; }
.pgv-actions .spacer { flex: 1; }
#pgRunTests[hidden] { display: none; }
@container (max-width: 560px) { .pgv-tools #pgReset, .pgv-tools #pgClear { display: none; } }
@container (max-width: 420px) { .pgv-tools #pgCopy, .pgv-tools #pgExplain { display: none; } }

.pgv-brief { flex: 0 0 38%; min-width: 0; min-height: 0; display: flex; flex-direction: column; background: var(--bg-surface); border-bottom: 1px solid var(--border); }
.pgv-brief[hidden], .pgv-brief-grip[hidden] { display: none; }
.pgv-brief-head { flex: 0 0 auto; padding: 16px 22px 14px; border-bottom: 1px solid var(--border); display: grid; gap: 10px; }
.pgv-brief-top { display: flex; align-items: center; gap: 8px; }
.pgv-brief-top .spacer { flex: 1; }
.pgv-brief-body { flex: 1 1 auto; min-height: 0; overflow: auto; white-space: normal; font-family: var(--font-sans); padding: 16px 22px 40px; }
.lab-brief-title { margin: 0; font: 800 clamp(24px, 2.2vw, 30px)/1.1 'Plus Jakarta Sans', var(--font-sans); letter-spacing: -.03em; color: var(--text-primary); }
.lab-brief-tiers { display: flex; flex-wrap: wrap; gap: 6px; }
.lab-brief-tiers .lab-tier-chip { font-size: 11px; line-height: 22px; padding: 0 9px; border-radius: 8px; }
.lab-brief-tag { font: 500 11px/22px var(--font-mono); padding: 0 9px; border-radius: 0; background: var(--bg-elevated); color: var(--text-secondary); }
.pgv-brief-body pre { border-radius: 0; }
.pgv-brief-body h3 { font: 700 15px/1.3 'Plus Jakarta Sans', var(--font-sans); margin: 22px 0 8px; }

/* A lab stacks the editor over the output at every width. */
.pgv.is-lab .pgv-split { flex-direction: column !important; }
.pgv.is-lab .pgv-split > .pgv-editor { min-width: 0; }
.pgv.is-lab .pgv-split > .pgv-console { flex: 0 1 var(--pgconsoleh, 40%); border-left: 0; border-top: 1px solid var(--border); }
.pgv.is-lab .pgv-split > .row-grip { width: auto; height: 5px; flex: 0 0 5px; cursor: row-resize; }
.pgv.is-lab .pgv-split > .row-grip::after { inset: 2px 0; }
.pgv-brief-grip::after { inset: 0 2px; }

@media (min-width: 1000px) {
  .pgv.is-lab .pgv-body { flex-direction: row; }
  .pgv.is-lab .pgv-brief { border-bottom: 0; border-right: 1px solid var(--border); max-width: 60%; }
  .pgv-brief-grip { width: 5px; flex: 0 0 5px; cursor: col-resize; }
}
@media (max-width: 999px) {
  .pgv.is-lab .pgv-brief { flex-basis: 40%; }
  .pgv-brief-grip { height: 5px; flex: 0 0 5px; cursor: row-resize; }
  .pgv-brief-grip::after { inset: 2px 0; }
}

/* ── Gen-Z controls: chunky, tactile, a solid under-edge that presses ── */
.pgv-bar { height: 58px; flex-basis: 58px; gap: 8px; }
.pgv-bar .lang-tab, .pgv-bar .lang-group, .pgv-labs-btn { min-height: 38px; border-radius: 0; font-weight: 600; }
.pgv-bar .lang-tab { border-width: 1px; box-shadow: none; transition: transform .08s, box-shadow .08s, background-color .15s, border-color .15s; }
.pgv-bar .lang-tab:active { transform: translateY(2px); box-shadow: 0 0 0 var(--border); }
.pgv-bar .lang-tab.is-on { background: var(--info-bg); border-color: var(--g-blue-text); color: var(--g-blue-text); box-shadow: none; }
.pgv-labs-btn { padding-inline: 16px; font: 700 14px/1 'Plus Jakarta Sans', var(--font-sans); box-shadow: none; }
.pgv-labs-btn.is-on { background: var(--g-blue-text); border-color: var(--g-blue-text); color: #fff; box-shadow: none; }
.pgv-actions .pgv-run, .pgv-actions .pgv-tests, .pgv-actions #pgStop {
  min-height: 38px; border-radius: 0; padding-inline: 18px; font: 700 14px/1 'Plus Jakarta Sans', var(--font-sans);
  transition: transform .08s, box-shadow .08s, background-color .15s;
}
.pgv-actions .pgv-run { box-shadow: none; }
.pgv-actions .pgv-tests { border: 1px solid var(--g-blue-text); background: var(--surface-1); color: var(--g-blue-text); box-shadow: none; }
.pgv-actions .pgv-run:active, .pgv-actions .pgv-tests:active { transform: translateY(3px); box-shadow: none; }
.pgv-tools .btn { min-height: 34px; border-radius: 0; font-weight: 600; }
.pgv-console .console-head .tab { font-weight: 600; }
.pgv-bar > .lang-tabs { flex: 0 1 auto; }
@media (max-width: 1100px) {
  .pgv-tools #pgReset, .pgv-tools #pgClear { display: none; }
}
@media (max-width: 760px) {
  .pgv-tools #pgCopy, .pgv-tools #pgExplain { display: none; }
  .pgv-actions { flex-wrap: wrap; }
}

/* ── use cases ────────────────────────────────────────────────
   A row of chips under the problem's title: the problem as written, then
   each variant of it. The one on screen is filled; solved ones carry a
   tick. The variant's one-line summary sits under the row. */
/* A tinted blue panel with a blue rule down its left edge, so the variants
   are the second thing the eye lands on after the title. */
.uc-bar {
  margin-top: 16px; padding: 12px 14px 14px;
  border: 1px solid var(--border);
  border-left: 2px solid var(--g-blue);
  border-radius: 0;
  background: var(--info-bg);
}
.uc-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.uc-label {
  display: inline-flex; align-items: center; gap: 6px;
  font: 600 14px/20px var(--font-sans); color: var(--g-blue-text);
}
.uc-count {
  min-width: 22px; height: 20px; padding: 0 7px; border-radius: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font: 700 12px/1 var(--font-sans); color: #fff; background: var(--g-blue);
}
.uc-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.uc-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-chip); background: var(--bg-surface);
  font: 500 13px/1.4 var(--font-sans); color: var(--text-primary);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.uc-chip:hover { border-color: var(--g-blue); background: var(--info-bg); }
.uc-chip.is-on { border-color: var(--g-blue); background: var(--g-blue); color: #fff; }
.uc-chip .ico { color: var(--g-green-text); }
.uc-chip.is-on .ico { color: #fff; }
.uc-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.uc-sum { margin: 10px 0 0; font-size: var(--fs-body-m); color: var(--text-primary); }
/* The Solutions tab's navigation: use cases on one line, approaches on the
   next, pinned together on an opaque band so both stay one click away while a
   solution scrolls. A line that runs out of room scrolls sideways. */
.sol-nav {
  position: sticky; top: 0; z-index: 6;
  display: grid; gap: 6px; padding: 10px 24px;
  background: var(--bg-surface); border-bottom: 1px solid var(--hairline);
  /* Under the page zoom a sticky band can land a fraction of a pixel low and
     let the text scrolling under it show above; this paints over that seam. */
  box-shadow: 0 -6px 0 var(--bg-surface);
}
.sol-nav-row { display: flex; align-items: center; gap: 10px; min-width: 0; }
.sol-nav-label {
  flex: none; width: 64px;
  font: 600 11px/1 var(--font-sans); color: var(--text-dimmed);
  text-transform: uppercase; letter-spacing: .04em;
}
.sol-nav-items, .sol-nav .sol-switch {
  display: flex; gap: 6px; min-width: 0; overflow-x: auto; scrollbar-width: none;
}
.sol-nav-items::-webkit-scrollbar, .sol-nav .sol-switch::-webkit-scrollbar { display: none; }
.sol-nav .uc-chip { flex: none; height: 28px; padding: 0 10px; font-size: 12.5px; white-space: nowrap; }
.sol-nav + .sol-card, .sol-nav + .empty { margin-top: 12px; }

/* Prev / next through the problem list, at the right of the pane's tabs. */
.prob-nav { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; }
.prob-nav-b {
  width: 28px; height: 28px; border-radius: 0; border: 1px solid var(--control);
  background: var(--surface-1); color: var(--text-secondary); cursor: pointer;
  font: 500 17px/1 var(--font-sans);
}
.prob-nav-b:hover:not(:disabled) { background: var(--surface-2); color: var(--text-primary); }
.prob-nav-b:disabled { opacity: .4; cursor: default; }
.prob-nav-pos { font: 400 12px/1 var(--font-sans); color: var(--text-dimmed); white-space: nowrap; padding: 0 4px; }
.prob-nav-pos b { color: var(--text-primary); font-weight: 600; }

/* The editor's language: Python in the browser, the rest on the code runner. */
.edit-langs {
  flex: none; height: 28px; padding: 0 26px 0 10px; border: 1px solid var(--control); border-radius: 0;
  background: var(--surface-1) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%235F6368' stroke-width='1.5'/%3E%3C/svg%3E") no-repeat right 9px center;
  appearance: none; color: var(--text-primary); font: 500 12.5px/1 var(--font-sans); cursor: pointer;
}
.edit-langs:hover { border-color: var(--border-hover); }
.edit-langs[hidden] { display: none; }
/* Why a test case exists, under its name. */
.case-why { margin: 0 0 8px; font-size: 12px; color: var(--text-secondary); }

/* The follow-up question an interviewer asks next. */
.followup { border-left: 2px solid var(--g-yellow); padding-left: 12px; }

/* An approach's code: its languages as tabs, and Copy. */
.sol-code { margin: 16px 0; border: 1px solid var(--border); border-radius: 0; overflow: hidden; }
.sol-code-bar {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
}
.sol-code-langs { display: flex; gap: 2px; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.sol-lang {
  flex: none; height: 26px; padding: 0 10px; border: 0; border-radius: 0; cursor: pointer;
  background: transparent; color: var(--text-secondary); font: 500 12px/1 var(--font-sans);
}
.sol-lang:hover { background: var(--surface-1); color: var(--text-primary); }
.sol-lang.is-on { background: var(--surface-1); color: var(--accent-text); box-shadow: var(--shadow-xs); }
.sol-code-one { font: 500 12px/1 var(--font-sans); color: var(--text-secondary); padding: 0 4px; }
.sol-copy {
  margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 5px;
  height: 26px; padding: 0 10px; border: 1px solid var(--control); border-radius: 0; cursor: pointer;
  background: var(--surface-1); color: var(--text-secondary); font: 500 12px/1 var(--font-sans);
}
.sol-copy:hover { color: var(--text-primary); }
.sol-code .cm-hl { border: 0; border-radius: 0; }

/* Key points: the few lines worth saying out loud. */
.keypoints { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.keypoints li { display: flex; gap: 8px; align-items: flex-start; }
.keypoints .ico { color: var(--g-green-text); flex: none; margin-top: 3px; }

/* ── lab picker: filters and search ──────────────────────────── */
.labdlg-tools { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.labdlg-filters { display: inline-flex; gap: 2px; padding: 2px; border-radius: var(--radius-chip); background: var(--bg-elevated); }
.lab-filter {
  border: 0; background: transparent; cursor: pointer; padding: 5px 12px; border-radius: var(--radius-chip);
  font: 600 12.5px/1.3 var(--font-sans); color: var(--text-secondary);
}
.lab-filter span { font: 500 11px/1 var(--font-mono); color: var(--text-dimmed); margin-left: 3px; }
.lab-filter.is-on { background: var(--surface-1); color: var(--g-blue-text); box-shadow: var(--shadow-xs, 0 1px 2px rgba(60,64,67,.2)); }
.lab-filter:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.labdlg-search {
  flex: 1 1 220px; min-width: 0; padding: 8px 14px; border: 1px solid transparent; border-radius: var(--radius-chip);
  background: var(--surface-3, var(--bg-elevated)); font: 14px/1.3 var(--font-sans); color: var(--text-primary);
}
.labdlg-search:focus { outline: none; background: var(--surface-1); border-color: var(--accent); }
.lab-card.is-passed { border-color: var(--border); }
.lab-card-passed { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--g-green-text); }

/* ══════════════════════════════════════════════════════════════
   CARIARA GOOGLE SPEC — the same idiom as cariara.com/tools.
   Last in the file on purpose: it settles every component the
   passes above left in an earlier style. Colours only from the
   palette in :root; the four hues are accents, never large fills.
   ══════════════════════════════════════════════════════════════ */

/* ── top app bar: 64px, white, hairline; product icon + name ── */
.topbar {
  height: 64px; flex: 0 0 64px; gap: 24px; padding: 0 16px;
  background: var(--surface-1); border-bottom: 1px solid var(--border);
}
.brand { gap: 8px; flex: 0 0 auto; }
.brand-icon { display: block; width: 32px; height: 32px; flex: none; }
.brand-name {
  font: 400 22px/28px var(--font-sans); color: var(--text-secondary);
  letter-spacing: 0; white-space: nowrap;
}
/* The rule under the bar is only a progress indicator now: invisible at
   rest, Material's indeterminate blue bar while Python boots or a run is in
   flight. */
.topbar::after { background: var(--g-blue); bottom: -1px; height: 3px; opacity: 0; }
body.is-booting .topbar::after,
body.is-running .topbar::after { opacity: 1; }

/* ── mode tabs: Google tabs, blue label and 3px indicator ── */
.mode-tabs {
  align-self: stretch; height: 100%; gap: 0; margin-left: 0; padding: 0;
  border-radius: 0; background: transparent;
}
.mode-tabs .mode-tab { --sec: var(--text-secondary); --sec-text: var(--accent); }
.mode-tab {
  height: 100%; padding: 0 16px; gap: 8px; border-radius: 0;
  background: transparent; color: var(--text-secondary); box-shadow: none;
  font: 500 14px/20px var(--font-sans);
}
.mode-tab .ico { color: var(--text-secondary); opacity: 1; }
.mode-tab:hover { background: var(--surface-3); color: var(--text-primary); }
.mode-tab.is-on, .mode-tab.is-on:hover {
  background: transparent; color: var(--accent); box-shadow: none; font-weight: 500;
}
.mode-tab.is-on .ico { color: var(--accent); }
.mode-tab.is-on::after {
  left: 0; right: 0; bottom: 0; height: 3px; border-radius: 0;
  background: var(--accent);
}

/* ── language switch in the bar: filter chips ── */
.lang-switch { gap: 8px; padding: 0; border: 0; border-radius: 0; background: transparent; }
.lang-pill {
  height: 32px; padding: 0 12px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-1); color: var(--title); box-shadow: none;
  font: 500 14px/1 var(--font-sans);
}
.lang-pill:hover { background: var(--surface-3); color: var(--text-primary); }
.lang-pill.is-on { background: var(--accent-subtle); color: var(--accent-text); border-color: transparent; box-shadow: none; }

/* ── buttons: 4px radius, 36px, flat until hovered ── */
.btn::after { display: none; }
.btn {
  height: 36px; padding: 0 16px; gap: 8px; border-radius: 0;
  border: 1px solid var(--border); background: var(--surface-1); color: var(--accent);
  font: 500 14px/20px var(--font-sans); box-shadow: none;
}
.btn:hover { background: var(--surface-2); border-color: var(--border); box-shadow: none; }
.btn:active { background: var(--surface-3); }
.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; font-weight: 500; }
.btn-icon { width: 36px; padding: 0; justify-content: center; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--accent); font-weight: 500; }
.btn-ghost:hover { background: var(--surface-3); border-color: transparent; color: var(--accent-hover); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #FFFFFF; box-shadow: none; }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); box-shadow: var(--shadow-xs); }
.btn-primary:active { background: var(--accent-pressed); border-color: var(--accent-pressed); }
.btn-secondary { background: var(--surface-1); border-color: var(--border); color: var(--accent); }
.btn-secondary:hover { background: var(--surface-2); border-color: var(--border); }
.btn-danger { background: var(--danger-fill); border-color: var(--danger-fill); color: #FFFFFF; box-shadow: none; }
.btn-danger:hover { background: var(--danger); border-color: var(--danger); box-shadow: var(--shadow-xs); }
.btn:disabled, .btn:disabled:hover { opacity: 1; color: var(--text-disabled); background: var(--surface-2); border-color: var(--border); box-shadow: none; }
#pgExplain.is-on { background: var(--accent-subtle); border-color: transparent; color: var(--accent-text); }
.landing-actions .btn { height: 40px; padding: 0 24px; font-size: 14px; }

/* ── pane tabs: grey label, blue selected with a 3px indicator ── */
.tab {
  color: var(--text-secondary); font-weight: 500;
  border-bottom: 2px solid transparent; padding-top: 3px;
}
.tab:hover { color: var(--text-primary); background: var(--surface-2); }
.tab.is-on { color: var(--accent); border-bottom-color: var(--accent); }

/* ── filter chips: 32px, 8px radius, hairline; selected is tonal blue ── */
.seg { display: grid; gap: 4px; padding: 0; border: 0; border-radius: 0; background: transparent; }
.seg-b, .seg-quiet .seg-b {
  height: 32px; padding: 0 6px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-1); color: var(--title); box-shadow: none;
  font: 500 12px/1 var(--font-sans);
}
.seg-b:hover { background: var(--surface-3); color: var(--text-primary); }
.seg-b.is-on { background: var(--accent-subtle); color: var(--accent-text); border-color: transparent; box-shadow: none; }

.lang-tab {
  height: 32px; padding: 0 12px; border: 1px solid var(--border); border-radius: 0;
  background: var(--surface-1); color: var(--title); font: 500 14px/1 var(--font-sans);
}
.lang-tab:hover { background: var(--surface-3); border-color: var(--border); color: var(--text-primary); }
.lang-tab.is-on { background: var(--accent-subtle); border-color: transparent; color: var(--accent-text); }

.lang-groups, .labdlg-filters { gap: 4px; padding: 0; border-radius: 0; background: transparent; }
.lang-group, .lab-filter {
  height: 32px; padding: 0 12px; border: 1px solid var(--border); border-radius: 0;
  background: var(--surface-1); color: var(--title); box-shadow: none;
  font: 500 13px/1 var(--font-sans); letter-spacing: 0;
}
.lang-group:hover, .lab-filter:hover { background: var(--surface-3); color: var(--text-primary); }
.lang-group.is-on, .lab-filter.is-on {
  background: var(--accent-subtle); color: var(--accent-text); border-color: transparent; box-shadow: none;
}
.lab-filter span { color: inherit; }

.pg-tab { border-radius: 0; }
.pg-tab.is-on { background: var(--accent-subtle); color: var(--accent-text); }

/* Use cases: a pale-blue section with white chips in it. */
.uc-bar { background: var(--panel-blue); border: 0; border-radius: 0; }
.uc-count { background: var(--accent); color: #FFFFFF; }
.uc-chip {
  height: 32px; padding: 0 12px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-1); color: var(--title); font: 500 13px/1 var(--font-sans);
}
.uc-chip:hover { background: var(--surface-2); border-color: var(--border-hover); }
.uc-chip.is-on { background: var(--accent-subtle); border-color: var(--accent); color: var(--accent-text); }
.uc-chip.is-on .ico { color: var(--accent-text); }

/* ── the problem list as a Google side nav ── */
.rail-head { background: var(--surface-1); }
.rail-list { padding: 4px 8px 16px 0; }
.p-item { border-radius: 0 999px 999px 0; padding: 8px 12px 8px 16px; }
.p-item::before { display: none; }
.p-item:hover { background: var(--surface-3); }
.p-item.is-on, .p-item.is-on:hover { background: var(--accent-subtle); box-shadow: none; }
.p-item .p-name { color: var(--title); }
.p-item.is-on .p-name { color: var(--accent-text); }
.rail-group { font-family: var(--font-sans); font-weight: 500; }
.rail-foot { font-family: var(--font-sans); color: var(--text-secondary); }
.rail-foot::before { display: none; }

/* ── inputs: white, 4px, hairline; 2px blue on focus ── */
.search, .labdlg-search {
  height: 36px; border-radius: 0; border: 1px solid var(--border);
  background: var(--surface-1); color: var(--text-primary);
}
.search:hover, .labdlg-search:hover { border-color: var(--border-hover); }
.search:focus, .labdlg-search:focus, .notes-box:focus, .inputdlg-box:focus {
  outline: none; background: var(--surface-1);
  border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent);
}
.labdlg-search { padding: 0 12px; }
.notes-box, .inputdlg-box { border-radius: 0; background: var(--surface-1); }

/* ── cards: white, hairline, 8px, flat until hovered ── */
.ex-card, .sol-card { background: var(--surface-1); box-shadow: none; border-radius: 0; }
.landing-point {
  border: 1px solid var(--border); border-top: 2px solid var(--sec);
  border-radius: 0; box-shadow: none; transform: none;
}
.landing-point:hover, .rmv-node:hover:not([disabled]) {
  box-shadow: var(--gcp-elevation-1); transform: none;
}
.rmv-node, .fig { box-shadow: none; }
.verdict { box-shadow: none; }
.landing-stat { border-radius: 0; }
.landing::before { display: none; }
.landing-mark { box-shadow: none; }

/* Code blocks: light, #F8F9FA on a hairline. */
.prose pre, .cm-hl, .case-out pre, .trace, .lab-io pre, .ex-trace {
  background: var(--surface-2); border-color: var(--border);
}
.CodeMirror, .CodeMirror-gutters { background: var(--surface-1); }
.CodeMirror-linenumber { color: var(--text-disabled); }

/* Progress: the blue fill, green when complete. No multi-colour bars. */
.rmv-bar::before { display: none; }
.rmv-overall.is-complete .rmv-bar span { background: var(--g-green); }
.boot-spin { background: var(--surface-3); }
.boot-spin::after { background: var(--g-blue); }

/* ── headings: page 28/36 400, section 20/28 500 ── */
.prob-title, .rmv-head h1 {
  font-size: 28px; line-height: 36px; font-weight: 400; color: var(--g-ink); letter-spacing: 0;
}

.prose h2, .prose h3, .sol-title, .tp-head h2, .inputdlg-head h2 { color: var(--g-ink); }

/* Tables: grey 500 header on white, #E8EAED rows. */
.prose th { background: var(--surface-1); color: var(--text-secondary); font-weight: 500; }
.prose th, .prose td { border-color: var(--hairline); border-left: 0; border-right: 0; }
.prose tr:hover td { background: var(--surface-2); }

/* ══════════════════════════════════════════════════════════════
   CARIARA STANDARD — tools/web/CARIARA_STYLE.md

   Last on purpose. The Cariara header and footer are injected by
   tools/web/build.mjs (--cariara-header / --cariara-footer /
   --cariara-chrome, all 0 when PPG runs in a frame). PPG's own bar
   is the sub-header under it, and every full-height view is
   100vh less that chrome and the sub-header.
   ══════════════════════════════════════════════════════════════ */

/* ── 1. the sub-header ── */
.topbar {
  height: var(--topbar-h); flex: 0 0 var(--topbar-h) !important;
  gap: 20px; padding: 0 24px;
  background: #FFFFFF; border-bottom: 1px solid var(--hairline); box-shadow: none;
}
.brand { gap: 10px; }
.brand-icon { width: 28px; height: 28px; }
.brand-name { font: 500 18px/24px var(--font-sans); color: var(--g-ink); letter-spacing: 0; }
.topbar::after { bottom: -1px; height: 2px; }

/* Mode tabs: underline tabs, active blue with a 2px blue rule; each
   tab's icon takes one of the four in order. */
.mode-tab { padding: 0 14px; font: 500 14px/20px var(--font-sans); color: var(--text-secondary); }
.mode-tab:hover { background: transparent; color: var(--g-ink); }
.mode-tab.is-on, .mode-tab.is-on:hover { color: var(--accent-text); }
.mode-tab.is-on::after { height: 2px; border-radius: 0; background: var(--accent); }

/* Fixed layers sit between the Cariara header and footer, never under them. */
.landing, .boot-veil {
  inset: var(--cariara-header, 0px) 0 var(--cariara-footer, 0px) 0;
}
.toast { bottom: calc(var(--cariara-footer, 0px) + 20px); }

/* ── 2. controls ── */
::-webkit-scrollbar-thumb { background: var(--control); }

.btn {
  border-radius: 0; border-color: var(--control);
  background: #FFFFFF; color: var(--g-ink);
}
.btn:hover { background: #F8F9FA; border-color: var(--control); }
.btn-ghost, .btn-ghost:hover { border-color: transparent; }
.btn-ghost { background: transparent; color: var(--accent-text); }
.btn-ghost:hover { background: var(--accent-subtle); color: var(--accent-hover); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #FFFFFF; }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: #FFFFFF; }
.btn-secondary { background: #FFFFFF; border-color: var(--control); color: var(--g-ink); }
.btn-secondary:hover { background: #F8F9FA; border-color: var(--control); }
.btn-danger { background: var(--err-text); border-color: var(--err-text); color: #FFFFFF; }
.btn-danger:hover { background: var(--err-text); border-color: var(--err-text); box-shadow: 0 1px 3px rgba(60,64,67,.15); }
.btn:disabled, .btn:disabled:hover { color: var(--text-disabled); background: #F8F9FA; border-color: var(--control); }
/* The landing's single main action is a pill. */
.landing-actions .btn-primary { border-radius: 999px; }

.tab { font-size: 14px; font-weight: 500; border-bottom-width: 2px; padding-top: 2px; }
.tab:hover { background: transparent; color: var(--g-ink); }
.tab.is-on { color: var(--accent-text); border-bottom-color: var(--accent); }
.tabbar.sm .tab { font-size: 13px; }
.pane-head, .console-head { border-bottom-color: var(--hairline); }

.seg-b, .seg-quiet .seg-b, .lang-pill, .lang-tab, .lang-group, .lab-filter, .uc-chip {
  border-color: var(--control);
}
.seg-b.is-on, .lang-pill.is-on, .lang-tab.is-on, .lang-group.is-on, .lab-filter.is-on, .uc-chip.is-on {
  background: var(--accent-subtle); color: var(--accent-text); border-color: var(--blue-line);
}

.search, .labdlg-search, .notes-box, .inputdlg-box,
.mc-field textarea, .pc-box textarea {
  border-color: var(--control);
}
.search:focus, .labdlg-search:focus, .notes-box:focus, .inputdlg-box:focus, .mc-field textarea:focus, .pc-box textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent);
}

/* ── 3. the rail ──
   White, a right hairline; rows are 14px ink body, the open one a blue
   wash with blue text and a 3px blue bar on its left edge. Group
   headings (and their bars and meters) run blue, red, yellow, green. */
.rail { background: #FFFFFF; border-right: 1px solid var(--hairline); }
.rail-head { background: #FFFFFF; border-bottom: 1px solid var(--hairline); }
.rail-list { padding: 4px 8px 16px 0; }
.p-item { border-radius: 0; padding: 7px 12px 7px 16px; }
.p-item .p-name { font-size: 14px; color: var(--text-secondary); }
.p-item:hover { background: #F8F9FA; }
.p-item:hover .p-name { color: var(--g-ink); }
.p-item.is-on, .p-item.is-on:hover {
  background: var(--accent-subtle); box-shadow: inset 3px 0 0 var(--g-blue);
}
.p-item.is-on .p-name { color: var(--accent-text); font-weight: 500; }
.rail-group {
  font: 500 12px/16px var(--font-sans); letter-spacing: .06em;
  color: var(--sec-text, var(--g-blue-text)); border-bottom-color: var(--hairline);
}
.rail-group::before { background: var(--sec, var(--g-blue)); }
.rail-foot { border-top-color: var(--hairline); background: #FFFFFF; }
/* Charts take the bright fills. */
.ring { background: conic-gradient(var(--g-blue) calc(var(--pct) * 1%), var(--hairline) 0); }
.d-Easy-bg   { background: var(--g-green); }
.d-Medium-bg { background: var(--g-yellow); }
.d-Hard-bg   { background: var(--g-red); }
.tier-bar, .rail-meter { background: var(--hairline); }

/* ── 4. status: a wash, its text colour and a matching hairline ── */
.badge {
  padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 500;
  background: #F8F9FA; border: 1px solid var(--control); color: var(--text-secondary);
}
.badge.d-Easy,  .badge.freq          { color: var(--g-green-text);  background: var(--success-bg); border-color: var(--green-line); }
.badge.d-Medium                      { color: var(--g-yellow-text); background: var(--warning-bg); border-color: var(--yellow-line); }
.badge.d-Hard,  .badge.due           { color: var(--g-red-text);    background: var(--sky-bg);  border-color: var(--sky-line); }
.badge.src,     .badge.b75           { color: var(--g-blue-text);   background: var(--info-bg);    border-color: var(--blue-line); }
.prob-state { background: #F8F9FA; border-color: var(--control); color: var(--text-secondary); }
.prob-state.is-solved { color: var(--g-green-text); background: var(--success-bg); border-color: var(--green-line); }
.prob-state.is-solved.is-due { color: var(--g-red-text); background: var(--sky-bg); border-color: var(--sky-line); }
.lab-diff, .lab-tier, .lab-tier-chip, .cmdk-b { border: 1px solid transparent; }
.lab-diff.is-green, .lab-tier.is-ok, .lab-tier-chip.is-random, .cmdk-b.ok { border-color: var(--green-line); }
.lab-diff.is-yellow, .lab-tier-chip.is-edge { border-color: var(--yellow-line); }
.lab-diff.is-red, .lab-tier.is-no, .lab-tier-chip.is-stress, .cmdk-b.due { border-color: var(--sky-line); }
.lab-tier-chip.is-sample { border-color: var(--blue-line); }
.constraints code:nth-child(4n+1) { border-color: var(--blue-line); }
.constraints code:nth-child(4n+2) { border-color: var(--sky-line); }
.constraints code:nth-child(4n+3) { border-color: var(--yellow-line); }
.constraints code:nth-child(4n+4) { border-color: var(--green-line); }

.verdict { border: 1px solid var(--control); border-radius: 0; background: #FFFFFF; box-shadow: none; }
.verdict.is-pass { background: var(--success-bg); border-color: var(--green-line); }
.verdict.is-fail { background: var(--danger-bg);  border-color: var(--red-line); }
.verdict.is-idle { background: var(--warning-bg); border-color: var(--yellow-line); }

/* ── 5. tables ── */
.prose table {
  border: 1px solid var(--hairline); border-radius: 0;
  border-collapse: separate; border-spacing: 0; overflow: hidden;
}
.prose th, .prose td { border: 0; border-bottom: 1px solid var(--hairline); }
.prose th {
  background: #F8F9FA; color: var(--text-muted);
  font: 500 12px/16px var(--font-sans);
}
.prose tr:last-child td { border-bottom: 0; }
.prose td:first-child { color: var(--g-ink); font-weight: 500; }
.pc-diff th { background: #F8F9FA; font: 500 12px/16px var(--font-sans); color: var(--text-muted); text-transform: none; letter-spacing: 0; padding: 6px 8px; }

/* ── 6. cards: white, hairline, 10px, a 3px seam rotating
   blue → red → yellow → green across siblings. ── */
:is(.landing-stats, .landing-points, .labdlg-grid, .tp-prereqs) > :nth-child(4n+1), .block:nth-of-type(4n+1) {
  --seam: var(--g-blue); --seam-text: var(--g-blue-text); --seam-bg: var(--info-bg);
}
:is(.landing-stats, .landing-points, .labdlg-grid, .tp-prereqs) > :nth-child(4n+2), .block:nth-of-type(4n+2) {
  --seam: var(--g-red); --seam-text: var(--g-red-text); --seam-bg: var(--sky-bg);
}
:is(.landing-stats, .landing-points, .labdlg-grid, .tp-prereqs) > :nth-child(4n+3), .block:nth-of-type(4n+3) {
  --seam: var(--g-yellow); --seam-text: var(--g-yellow-text); --seam-bg: var(--warning-bg);
}
:is(.landing-stats, .landing-points, .labdlg-grid, .tp-prereqs) > :nth-child(4n+4), .block:nth-of-type(4n+4) {
  --seam: var(--g-green); --seam-text: var(--g-green-text); --seam-bg: var(--success-bg);
}

.landing-stat, .landing-point, .lab-card, .tp-prereq, .sol-card {
  background: #FFFFFF; box-shadow: none; transform: none;
  border: 1px solid var(--hairline); border-top: 2px solid var(--seam, var(--g-blue));
  border-radius: 0;
}
.rmv-node, .ex-card, .fig {
  border: 1px solid var(--hairline); border-top: 2px solid var(--sec, var(--g-blue));
  border-radius: 0; box-shadow: none;
}
.landing-point:hover, .lab-card:hover, .rmv-node:hover:not([disabled]) {
  border-color: var(--control); border-top-color: var(--seam, var(--sec, var(--g-blue)));
  box-shadow: 0 1px 3px rgba(60,64,67,.15); transform: none;
}
.lab-card.is-on { background: var(--accent-subtle); border-color: var(--blue-line); border-top-color: var(--seam, var(--g-blue)); }
.lab-card-title { font-size: 15px; font-weight: 500; color: var(--g-ink); }
.tp-prereq-n { color: var(--seam-text, var(--g-blue-text)); }
.case, .passed-strip, .mc-case, .lab-list, .viz.is-card, .sol-figure, .hintbox, .tier-note {
  border-color: var(--hairline);
}
.hintbox { border-left: 2px solid var(--g-yellow); }

/* ── 7. section headings: 16–20px / 500, colour by position ── */
.block-h {
  font: 500 16px/22px var(--font-sans); letter-spacing: 0; text-transform: none;
  color: var(--seam-text, var(--g-blue-text));
}
.block-h::before { width: 4px; height: 16px; background: var(--seam, var(--g-blue)); }
.ex-n { color: var(--seam-text, var(--g-blue-text)); background: var(--seam-bg, var(--info-bg)); }
.ex-card { border-top-color: var(--seam, var(--g-blue)); }
.fig { border-top-color: var(--seam, var(--sec, var(--g-blue))); }
.fig-t { color: var(--seam-text, var(--g-blue-text)); }

/* Solution sections run the sequence too; the pitfalls box keeps its
   yellow and the intuition its blue. */
.extra-h {
  font: 500 14px/20px var(--font-sans); letter-spacing: 0; text-transform: none;
}
.sol-panel .sol-extra:not(.is-warn):not(.is-idea):nth-of-type(4n+1) .extra-h { color: var(--g-blue-text); }
.sol-panel .sol-extra:not(.is-warn):not(.is-idea):nth-of-type(4n+2) .extra-h { color: var(--g-red-text); }
.sol-panel .sol-extra:not(.is-warn):not(.is-idea):nth-of-type(4n+3) .extra-h { color: var(--g-yellow-text); }
.sol-panel .sol-extra:not(.is-warn):not(.is-idea):nth-of-type(4n+4) .extra-h { color: var(--g-green-text); }
.sol-extra { background: #FFFFFF; border-color: var(--hairline); }
.sol-card { border-top-color: var(--g-blue); }

.rmv-stage-l { font: 500 16px/22px var(--font-sans); letter-spacing: 0; text-transform: none; }
.rmv-stage-n { opacity: 1; font-size: 20px; color: var(--sec); }

/* Icon tiles: the section's bright colour on its wash, 32px, radius 8px. */
.rmv-ico { width: 32px; height: 32px; border-radius: 0; }
.sol-gate-ico {
  width: 40px; height: 40px; border-radius: 0; border: 0;
  background: var(--info-bg); color: var(--g-blue);
}

/* ── 8. stats and charts ── */
.landing-stat b, .rmv-tile b { font-family: var(--font-sans); font-weight: 500; }
.rmv-tiles > .rmv-tile:nth-child(3) b { color: var(--g-yellow-text); }
.rmv-tiles > .rmv-tile:nth-child(4) b { color: var(--g-green-text); }
.rmv-bar, .rmv-track, .verdict-bar { background: var(--hairline); }
.rmv-bar span { background: var(--g-blue); }

/* ── 9. layout density: full width, compact intro bands ── */
.landing { display: block; padding: 0; background: #FFFFFF; }
.landing-inner {
  max-width: 1600px; margin: 0 auto; padding: 24px clamp(16px, 3vw, 52px) 40px;
  display: flex; flex-direction: column; align-items: stretch; gap: 24px; text-align: left;
}
.landing-band {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 20px;
  padding: 20px 24px 23px; border-radius: 0; background: var(--panel-blue);
}
.landing-mark {
  flex: none; width: 56px; height: 56px; margin: 0;
  background: #FFFFFF; border: 1px solid var(--hairline); border-radius: 0; box-shadow: none;
}
.landing-mark img { display: block; }
.landing-intro { flex: 1; min-width: 0; }
.landing h1 { font: 500 24px/32px var(--font-sans); letter-spacing: 0; color: var(--g-ink); }
.landing h1 em { color: var(--accent-text); }
.landing-lede { margin: 4px 0 0; font-size: 14px; line-height: 20px; color: var(--text-secondary); }
.landing-cta { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.landing-actions { margin: 0; justify-content: flex-end; gap: 8px; }
.landing-note { margin: 0; font-size: 12px; color: var(--text-muted); }

.landing-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px; margin: 0;
}
.landing-stat { flex-direction: column; align-items: flex-start; gap: 2px; padding: 16px 20px; }
.landing-stats > .landing-stat b { font-size: 28px; line-height: 34px; color: var(--seam-text); }
.landing-stat span { font-size: 12px; color: var(--text-muted); letter-spacing: 0; }

.landing-points { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin: 0; }
.landing-point { padding: 16px 20px 20px; }
.landing-point h3 { font: 500 16px/22px var(--font-sans); color: var(--seam-text); }
.landing-point p { font-size: 14px; line-height: 20px; color: var(--text-secondary); }

.landing-resume { margin: 0; padding: 0; border: 0; }
.landing-resume-label {
  font: 500 16px/22px var(--font-sans); letter-spacing: 0; text-transform: none;
  color: var(--g-blue-text);
}
.landing-resume-list { justify-content: flex-start; }
.landing-resume-list button { border-color: var(--control); border-radius: 0; height: 32px; }

.rmv-head {
  margin: 16px clamp(16px, 3vw, 52px) 0; padding: 20px 24px;
  border: 0; border-radius: 0; background: var(--panel-blue);
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 32px; align-items: center;
}
.rmv-head h1 { grid-column: 1; font: 500 24px/32px var(--font-sans); letter-spacing: 0; }
.rmv-head p { grid-column: 1; margin: 4px 0 0; }
.rmv-overall { grid-column: 2; grid-row: 1 / span 2; min-width: 320px; }
.rmv-tiles { margin: 0 0 10px; gap: 32px; }
.rmv-tile b { font-size: 28px; }
.rmv-meter { max-width: none; }
.rmv-graph { padding: 24px clamp(16px, 3vw, 52px) 40px; }

.labdlg-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.labdlg-head h2 { font-weight: 500; color: var(--g-ink); }
.sol-card { margin: 20px 24px 0; }
.panel > .prose, .panel > .block, .panel > .empty, .panel > .sol-gate { padding-inline: 24px; }
.prob-head { padding: 20px 24px 16px; border-bottom-color: var(--hairline); }

@media (max-width: 900px) {
  .landing-band { flex-wrap: wrap; }
  .landing-cta { align-items: flex-start; width: 100%; }
  .landing-actions { justify-content: flex-start; }
  .rmv-head { grid-template-columns: minmax(0, 1fr); }
  .rmv-overall { grid-column: 1; grid-row: auto; min-width: 0; margin-top: 14px; }
}



/* ── Gen-Z lab picker: bold titles, hard-offset lift in the lab's tone ── */
.labdlg-card { border-radius: 0; padding: 24px 26px 26px; }
.labdlg-head h2 { font: 800 30px/1.1 'Plus Jakarta Sans', var(--font-sans); letter-spacing: -.035em; }
.labdlg-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; padding: 4px 6px 6px 2px; }
.lab-card { --lab-tone: var(--g-blue-text); border: 1px solid var(--border); border-radius: 0; padding: 16px 18px; transition: transform .12s, box-shadow .12s, border-color .12s; }
.lab-card:has(.lab-diff.is-green) { --lab-tone: var(--g-green-text); }
.lab-card:has(.lab-diff.is-yellow) { --lab-tone: var(--g-yellow-text); }
.lab-card:has(.lab-diff.is-red) { --lab-tone: var(--g-red-text); }
.lab-card:hover { box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .3), 0 1px 3px 1px rgba(60, 64, 67, .15); border-color: var(--lab-tone); }
.lab-card-title { font: 800 17px/1.25 'Plus Jakarta Sans', var(--font-sans); letter-spacing: -.02em; }
.lab-card-tags span { border-radius: 0; padding: 1px 7px; }

/* Coding guide: topics nested under it, the topic map, and the richer topic
   sections (overview, diagram, patterns with templates, worked example). */
.gd-nav-sub { display: flex; flex-direction: column; gap: 2px; margin-left: 12px; padding-left: 4px; border-left: 1px solid var(--border); }
.gd-map { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; }
.gd-map-i { display: grid; gap: 4px; text-align: left; padding: 12px 14px; border: 1px solid var(--border); border-radius: 0; background: var(--surface-1); color: var(--text-primary); cursor: pointer; font: inherit; }
.gd-map-i:hover { border-color: var(--border-strong, var(--border)); box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .3), 0 1px 3px 1px rgba(60, 64, 67, .15); }
.gd-map-i b { font: 600 14px/1.3 var(--font-sans); }
.gd-map-d { font-size: 13px; line-height: 1.45; color: var(--text-secondary); }
.gd-map-n { font: 500 12px/1 var(--font-sans); color: var(--text-dimmed); }
.gd-map-n.is-done { color: var(--g-green-text, #00866B); }
.gd-sec { display: flex; align-items: center; gap: 8px; margin: 8px 0 0; font: 600 18px/1.3 var(--font-sans); color: var(--text-primary); }
.gd-pattern .gd-h { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.gd-cx { font: 500 12px/1 var(--font-mono); color: var(--text-secondary); padding: 3px 8px; border: 1px solid var(--border); border-radius: 999px; }
.gd-when { margin: 0 0 8px; color: var(--text-secondary); }
.gd-when b { color: var(--text-primary); font-weight: 600; margin-right: 4px; }
.gd-code { margin: 10px 0 0; padding: 12px 14px; border: 1px solid var(--border); background: var(--surface-2); overflow-x: auto; font: 500 12.5px/1.55 var(--font-mono); }
.gd-pchips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 10px; }
.gd-pchip { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px; background: transparent; color: var(--text-primary); font: 500 12.5px/1.2 var(--font-sans); cursor: pointer; }
.gd-pchip:hover { border-color: var(--accent, #0077FF); color: var(--accent-text, #0077FF); }
.gd-pchip.is-done { color: var(--g-green-text, #00866B); }
.gd-diagram { margin: 4px 0; overflow-x: auto; text-align: center; }
.gd-diagram svg { max-width: 100%; height: auto; }
.gd-card.gd-wide { grid-column: 1 / -1; }

/* A problem's address with this page on its own: one line to its console (app.js showMoved) */
.ppg-moved { position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%); z-index: 50; display: flex; align-items: center; gap: 12px; max-width: calc(100vw - 32px); padding: 10px 16px; border: 1px solid var(--border); border-radius: 999px; background: var(--bg-surface); color: var(--text-primary, inherit); font-size: 14px; }
.ppg-moved a { font-weight: 700; color: var(--accent-text); text-decoration: none; }
.ppg-moved a:hover { text-decoration: underline; }
