:root {
  --bg: #0f1115; --panel: #151922; --border: #262b36; --text: #e6e9ef; --muted: #8b93a3;
  --accent: #4f8cff; --green: #5fd38d; --red: #ff5f5f; --yellow: #f0b34c; --blue: #9ecbff;
  /* Surfaces that are not --panel: a control's face, its hover, the "this one is selected"
     blue, and the recessed background a toolbar or an input sits on. */
  --control: #1c212c; --hover: #242a37; --selected: #1b2a44; --bg-deep: #12151c;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
/* Two-tier chrome over one workspace: the app bar and the mode switch never change, the
   toolbar under them belongs entirely to the mode you are in, and the file list is shared by
   all three modes because the files are. */
body {
  background: var(--bg); color: var(--text); font-family: var(--font); font-size: 13px;
  display: grid; height: 100vh; overflow: hidden;
  grid-template-columns: var(--side-w, 220px) 5px minmax(0, 1fr);
  grid-template-rows: 42px 40px minmax(0, 1fr);
  grid-template-areas:
    "top  top    top"
    "bar  bar    bar"
    "side vsplit main";
}
/* The file list folds away; the screens keep the whole window width either way. */
body.side-collapsed { grid-template-columns: 0 0 minmax(0, 1fr); }
body.side-collapsed .sidebar, body.side-collapsed > #vsplitter { display: none; }
body.resizing { cursor: col-resize; user-select: none; }
body.resizing.row { cursor: row-resize; }

/* ---------- modes ---------- */
.stage { grid-area: main; min-width: 0; min-height: 0; display: flex; }
.screen { flex: 1; min-width: 0; min-height: 0; display: none; }
body[data-mode="sim"]   .screen[data-screen="sim"],
body[data-mode="build"] .screen[data-screen="build"],
body[data-mode="prog"]  .screen[data-screen="prog"] { display: grid; }

/* Simulate keeps the editor-over-waves split it always had. */
.screen[data-screen="sim"] { grid-template-rows: minmax(0, 1fr) 6px var(--bottom-h, 52vh); }
/* Maximized: the editor row collapses so the waves fill the screen. */
body.bottom-max .screen[data-screen="sim"] { grid-template-rows: 0 6px minmax(0, 1fr); }

/* The mode switch, in the app bar. Each stage's state rides on its icon as a pip, so a
   student looking at the waves still sees that the build failed. */
.modes { display: flex; align-items: stretch; align-self: stretch; margin-left: 4px; }
.mode-btn { display: flex; align-items: center; gap: 8px; padding: 0 14px; border: none; border-radius: 0;
  background: transparent; color: var(--muted); font-weight: 600; white-space: nowrap;
  border-bottom: 2px solid transparent; }
.mode-btn:hover { background: var(--control); color: var(--text); }
.mode-btn[aria-selected="true"] { background: var(--selected); color: #fff; border-bottom-color: var(--accent); }
.mode-btn .ico { width: 17px; height: 17px; display: block; }
.mode-btn .ico-wrap { position: relative; display: flex; }
.mode-btn .pip { position: absolute; right: -4px; top: -3px; width: 8px; height: 8px; border-radius: 50%;
  background: #39404e; border: 2px solid var(--panel); }
.mode-btn[aria-selected="true"] .pip { border-color: var(--selected); }
.mode-btn .pip.ok { background: var(--green); }
.mode-btn .pip.err { background: var(--red); }
.mode-btn .pip.warn { background: var(--yellow); }
.mode-btn .pip.busy { background: var(--accent); }

/* ---------- the contextual toolbar ---------- */
.toolbar { grid-area: bar; display: flex; align-items: center; padding: 0 12px;
  background: var(--bg-deep); border-bottom: 1px solid var(--border); min-width: 0; }
.mode-bar { display: none; flex: 1; align-items: center; gap: 10px; min-width: 0; }
body[data-mode="sim"]   .mode-bar[data-for="sim"],
body[data-mode="build"] .mode-bar[data-for="build"],
body[data-mode="prog"]  .mode-bar[data-for="prog"] { display: flex; }
.bar-sep { flex: none; width: 1px; height: 18px; background: var(--border); margin: 0 3px; }
.mode-bar .top-select { flex: none; }
.mode-bar .status { max-width: 46ch; }
/* One shape for all three primary actions: switching mode must not move or resize the button
   you are about to press. */
.act { display: inline-flex; align-items: center; justify-content: center; gap: 7px; flex: none;
  min-width: 152px; height: 28px; padding: 0 14px; }
.act .ico { width: 15px; height: 15px; }
/* One key, drawn the same wherever a key is shown. */
kbd, .kbd { display: inline-block; font-family: var(--mono); font-size: 11px; line-height: 16px;
  color: var(--text); border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 4px;
  padding: 0 5px; background: var(--control); white-space: nowrap; }
button, select, input[type=search] {
  font: inherit; color: var(--text); background: var(--control); border: 1px solid var(--border);
  border-radius: 5px; padding: 4px 10px; cursor: pointer;
}
button:hover, select:hover { background-color: var(--hover); }
button.primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
button.primary:hover { background: #3f7bef; }
button:disabled { opacity: .55; cursor: default; }
/* One focus ring for everything a keyboard can reach. :focus-visible, so a mouse click does
   not leave a ring behind, and outline rather than border so nothing moves by a pixel. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 4px; }
/* The native caret is a few pixels of system chrome that all but vanishes on this background,
   and the pin table is a column of forty of them. Draw one that can be seen and aimed at. */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 24px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%238b93a3' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 7px center;
  background-size: 10px 6px;
}
select:hover, select:focus { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23e6e9ef' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>"); }
select:disabled { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%235c6473' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>"); }
/* Firefox still paints its own arrow behind ours unless the text colour is forced. */
@-moz-document url-prefix() { select { text-indent: 0.01px; text-overflow: ''; } }
a { color: var(--blue); }

.topbar { grid-area: top; display: flex; align-items: center; gap: 10px; padding: 0 12px; border-bottom: 1px solid var(--border); background: var(--panel); }
/* The bar is a single non-wrapping row; the brand is the one thing allowed to give way,
   otherwise a narrow laptop pushes the sign-out button off the right edge. */
.brand { font-weight: 700; font-size: 14px; margin-right: 8px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.brand span { font-weight: 400; color: var(--muted); }
.top-select, .menu { display: flex; align-items: center; gap: 6px; color: var(--muted); min-width: 0; }
/* Let the two dropdowns give way before the buttons past them do, on a narrow window. */
.top-select select, .menu select { min-width: 0; text-overflow: ellipsis; }
.spacer { flex: 1; }
.status { color: var(--muted); font-family: var(--mono); font-size: 12px; max-width: 40ch; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.status.ok { color: var(--green); } .status.err { color: var(--red); }
.status.warn { color: var(--yellow); } .status.busy { color: var(--accent); }
.help { color: var(--muted); text-decoration: none; }
.icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 24px;
  padding: 0; color: var(--muted); background: transparent; border-color: transparent; font-size: 14px; line-height: 18px; }
.icon-btn .ico { width: 16px; height: 16px; display: block; }
.icon-btn:hover { color: var(--text); background: var(--hover); border-color: var(--border); }
.icon-btn[aria-pressed="true"] { color: var(--text); background: var(--selected); border-color: var(--accent); }
.user-box { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--muted); font-size: 12px; border-left: 1px solid var(--border); padding-left: 10px; }

/* The app bar is one row that must not wrap: a wrapped "Download .zip" grows the bar and
   pushes the whole layout down. Labels stay on one line and the mode switch drops its text on
   a narrow window, which buys back the width the three stage names take. */
.topbar button, .topbar .help, .topbar .user-box, .mode-btn { white-space: nowrap; }
@media (max-width: 1150px) {
  .mode-btn { padding: 0 11px; gap: 0; font-size: 0; }
  .mode-btn .ico { width: 18px; height: 18px; }
  .brand span { display: none; }
}
@media (max-width: 900px) {
  .topbar .help { display: none; }
}

.sidebar { grid-area: side; background: var(--panel); display: flex; flex-direction: column; min-height: 0; min-width: 0; overflow: hidden; }
/* The uppercase 11px label that heads a sidebar, a pane, a dialog field or a section. */
.sidebar-head, .pane-head, .build-section h3, .dialog-field span, .shortcut-group h3,
.settings-section h4 {
  font-weight: 600; color: var(--muted); text-transform: uppercase; font-size: 11px; letter-spacing: .05em;
}
.sidebar-head { display: flex; align-items: center; justify-content: space-between; padding: 8px 10px; }
.sidebar-head button { padding: 0 8px; line-height: 20px; }
.file-list { list-style: none; margin: 0; padding: 0; overflow: auto; flex: 1; }
.file-list li { display: flex; align-items: center; padding: 0 10px; height: 26px; cursor: pointer; font-family: var(--mono); font-size: 12px; gap: 6px; }
.file-list li:hover { background: var(--control); }
.file-list li.active { background: var(--selected); color: #fff; }
.file-list li .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-list li .err-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--red); }
.file-list li .kind { font-size: 9px; letter-spacing: .04em; text-transform: uppercase; padding: 1px 4px; border-radius: 3px; border: 1px solid var(--border); color: var(--muted); }
.file-list li .actions { display: flex; gap: 2px; visibility: hidden; }
.file-list li:hover .actions { visibility: visible; }
.file-list li .actions button { display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 18px; padding: 0; background: transparent; border-color: transparent; color: var(--muted); }
.file-list li .actions .ico { width: 13px; height: 13px; display: block; }
.file-list li .actions button:hover { color: var(--text); border-color: var(--border); }
.sidebar-foot { padding: 8px 10px; color: var(--muted); font-size: 11px; border-top: 1px solid var(--border); }

/* Inside the Simulate screen, not the body grid; a flex column so the vim bar can sit under
   Monaco, which lays itself out automatically and follows the row that leaves it. */
.editor-area { min-height: 0; min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
#editor { flex: 1; min-height: 0; width: 100%; }
.vim-status { flex: 0 0 auto; padding: 2px 10px; border-top: 1px solid var(--border); background: var(--panel); color: var(--muted); font-family: var(--mono); font-size: 12px; line-height: 18px; white-space: nowrap; }
.vim-status[hidden] { display: none; }
/* Mode indicator, then the command line, then notifications — each its own span. */
.vim-status > span + span { margin-left: 12px; }
/* monaco-vim renders its `:` command line as a bare input; make it belong to the dark theme. */
.vim-status input { background: transparent; border: 0; outline: 0; color: var(--text); font: inherit; width: 60%; padding: 0; }
.vim-status .vim-notification { color: var(--red); }

.splitter { background: var(--border); cursor: row-resize; }
.splitter:hover, .splitter.dragging { background: var(--accent); }
.vsplitter { background: var(--border); cursor: col-resize; }
/* Only the file-list splitter sits in the body grid; the Build screen reuses the look. */
#vsplitter { grid-area: vsplit; }
.vsplitter:hover, .vsplitter.dragging { background: var(--accent); }

.bottom { display: flex; flex-direction: column; min-height: 0; background: var(--panel); }
.tabs { display: flex; align-items: center; border-bottom: 1px solid var(--border); padding: 0 6px; gap: 2px; height: 30px; }
.tab { background: transparent; border: none; border-bottom: 2px solid transparent; border-radius: 0; color: var(--muted); padding: 5px 12px; }
.tab.active { color: var(--text); border-bottom-color: var(--accent); }
.tab .badge { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: 8px; font-size: 10px; font-weight: 700; line-height: 15px; background: var(--muted); color: #0f1115; }
.tab .badge.err { background: var(--red); color: #fff; }
.tab .badge.warn { background: var(--yellow); color: #12151b; }
.tab .badge[hidden] { display: none; }
.tab-link { font-size: 12px; margin-right: 10px; }
.tab-btn { font-size: 12px; padding: 2px 8px; margin-right: 8px; }
.panel { display: none; flex: 1; min-height: 0; }
.panel.active { display: block; }
.transcript { overflow: auto; padding: 8px 12px; font-family: var(--mono); font-size: 12px; line-height: 1.5; white-space: pre-wrap; }
.transcript .line { display: block; }
.transcript .pass { color: var(--green); }
.transcript .fail { color: var(--red); }
.transcript .warn { color: var(--yellow); }
.transcript .info { color: var(--muted); }
.transcript .head { color: var(--blue); font-weight: 600; margin-top: 6px; }
.transcript .loc { cursor: pointer; text-decoration: underline dotted; }
.muted { color: var(--muted); }
#waves.active { display: flex; }

/* wave viewer */
.wave-viewer { width: 100%; height: 100%; min-height: 0; }
.panel:not(.active) { display: none !important; }
.wave-tree { width: 220px; border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
.wave-tree-head { padding: 6px; border-bottom: 1px solid var(--border); }
.wave-filter { width: 100%; padding: 3px 8px; }
.wave-tree-body { overflow: auto; flex: 1; font-family: var(--mono); font-size: 12px; padding: 4px 0; }
.tree-scope-head { display: flex; align-items: center; gap: 4px; padding: 0 6px; height: 22px; cursor: pointer; color: var(--yellow); }
.tree-scope-head:hover { background: var(--control); }
.tree-caret { width: 12px; color: var(--muted); }
.tree-scope-name { flex: 1; }
.tree-add-all { visibility: hidden; padding: 0 5px; height: 18px; font-size: 10px; line-height: 16px; }
.tree-scope-head:hover .tree-add-all { visibility: visible; }
.tree-var { display: flex; align-items: center; gap: 6px; padding: 0 6px; height: 22px; cursor: pointer; white-space: nowrap; }
.tree-var:hover { background: var(--control); }
.tree-var input { margin: 0; }
.tree-size { color: var(--muted); font-size: 10px; }
.wave-main { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; position: relative; }
.wave-toolbar { display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-bottom: 1px solid var(--border); font-size: 12px; }
.wave-toolbar button { padding: 1px 8px; }
.wave-cursor-readout { font-family: var(--mono); color: var(--yellow); margin-left: 8px; }
.wave-hint { flex: 1; min-width: 0; margin-left: auto; color: var(--muted); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wave-export { position: relative; display: flex; margin-left: 8px; }
.wave-export > button { padding: 1px 8px; }
.wave-export > button.primary { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.wave-export > button.caret { border-top-left-radius: 0; border-bottom-left-radius: 0; margin-left: -1px; padding: 1px 6px; }
.wave-export-menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; width: 270px; padding: 10px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.45); display: flex; flex-direction: column; gap: 8px; }
.wave-export-menu[hidden] { display: none; }
.wave-export-menu label { display: flex; align-items: center; justify-content: space-between; gap: 8px; color: var(--muted); }
.wave-export-menu label.check { justify-content: flex-start; }
.wave-export-menu select { flex: 1; max-width: 160px; }
.wave-export-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 2px; }
.wave-names { display: flex; align-items: center; gap: 4px; color: var(--muted); margin-left: 4px; }
.wave-names select { padding: 1px 22px 1px 6px; font-size: 11px; }

/* Right-click menu over the waves: radix, label style, reorder, cursor. */
.wave-menu { position: absolute; z-index: 20; background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 4px 0; min-width: 180px; box-shadow: 0 8px 24px rgba(0,0,0,.5); font-size: 12px; }
.wave-menu[hidden] { display: none; }
.menu-item { position: relative; padding: 5px 24px 5px 22px; cursor: pointer; white-space: nowrap; }
.menu-item:hover { background: #2a3140; }
.menu-item.checked::before { content: "\2713"; position: absolute; left: 8px; color: var(--green); }
.menu-item.has-sub::after { content: "\25B8"; position: absolute; right: 8px; color: var(--muted); }
.menu-sub { display: none; position: absolute; left: 100%; top: -5px; background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 4px 0; min-width: 190px; box-shadow: 0 8px 24px rgba(0,0,0,.5); }
.menu-item.has-sub:hover > .menu-sub { display: block; }
.wave-menu.flip-sub .menu-sub { left: auto; right: 100%; }
.menu-sep { height: 1px; background: var(--border); margin: 4px 0; }

.wave-canvas-wrap { flex: 1; min-height: 0; position: relative; }
.wave-canvas-wrap canvas { display: block; outline: none; }
/* The canvas takes keyboard focus and owns a dozen keys, so it has to show it. */
.wave-canvas-wrap canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.wave-empty { position: absolute; left: 240px; right: 20px; top: 50%; transform: translateY(-50%); text-align: center; color: var(--muted); pointer-events: none; }

/* First-run disclosure: what this tool records, and the two things a student can switch off. */
.consent {
  position: fixed; z-index: 30; left: 50%; bottom: 18px; transform: translateX(-50%);
  width: min(560px, calc(100vw - 32px));
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 16px 18px; box-shadow: 0 12px 32px rgba(0,0,0,.55);
}
.consent[hidden] { display: none; }
.consent-title { font-weight: 700; font-size: 14px; margin-bottom: 8px; }
.consent p { margin: 0 0 12px; color: var(--muted); line-height: 1.5; }
.consent strong { color: var(--text); font-weight: 600; }
.consent-opt { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 12px; color: var(--muted); line-height: 1.5; cursor: pointer; }
.consent-opt[hidden] { display: none; }
.consent-opt input { flex: none; margin: 3px 0 0; cursor: pointer; }
.consent-foot { font-size: 11px; margin-bottom: 0; }
.consent-actions { display: flex; justify-content: flex-end; margin-top: 14px; }

.modal { position: fixed; inset: 0; background: rgba(0,0,0,.5); display: flex; align-items: center; justify-content: center; z-index: 40; }
.modal[hidden] { display: none; }
.modal-box { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 18px; min-width: 320px; max-width: 480px; box-shadow: 0 16px 40px rgba(0,0,0,.55); }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }

/* Settings: the preferences that belong to the person rather than to a file or a run. */
.settings-box { width: min(440px, calc(100vw - 32px)); max-width: none; }
.settings-box h3 { margin: 0 0 14px; font-size: 14px; font-weight: 700; }
.settings-section + .settings-section { margin-top: 16px; }
.settings-section h4 { margin: 0 0 8px; }
.settings-opt { display: flex; align-items: flex-start; gap: 9px; color: var(--muted); line-height: 1.5; cursor: pointer; }
.settings-opt + .settings-opt { margin-top: 12px; }
.settings-opt input { flex: none; margin: 3px 0 0; cursor: pointer; }
.settings-opt strong { display: block; color: var(--text); font-weight: 600; }
/* While a setting is being applied — vim mode is a download — the row says so rather than
   pretending the click has already taken effect. */
.settings-opt:has(input:disabled) { opacity: .6; cursor: progress; }
/* ---------- the app's own alert / confirm / prompt ---------- */
.dialog-box { width: min(440px, calc(100vw - 32px)); }
.dialog-title { font-weight: 700; font-size: 14px; margin-bottom: 8px; }
.dialog-body { color: var(--muted); line-height: 1.55; }
.dialog-field { display: flex; flex-direction: column; gap: 5px; margin-top: 14px; }
.dialog-input { width: 100%; padding: 7px 10px; font-family: var(--mono); font-size: 13px;
  color: var(--text); background: var(--bg-deep); border: 1px solid var(--border); border-radius: 5px; }
.dialog-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgba(79,140,255,.25); }
.dialog-hint { margin-top: 6px; color: var(--muted); font-size: 11px; line-height: 1.5; }
/* Inline, so a bad value keeps the dialog and the text the student typed. */
.dialog-error { margin-top: 8px; color: var(--red); font-size: 12px; line-height: 1.5; }
.dialog-error[hidden] { display: none; }
button.danger { background: var(--red); border-color: var(--red); color: #fff; }
button.danger:hover { background: #e94b4b; }

/* The shortcuts window: two columns of tables, so the whole list fits without scrolling. */
.dialog-wide { width: min(820px, calc(100vw - 32px)); max-width: none; }
.dialog-content { margin-top: 12px; max-height: min(66vh, 620px); overflow: auto; }
/* A grid rather than CSS columns: a group is a cell, so nothing flows across the fold. */
.shortcut-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 6px 30px; align-items: start; }
.shortcut-group { margin-bottom: 14px; }
.shortcut-group h3 { margin: 0 0 6px; }
.shortcut-note { margin: 0 0 6px; color: var(--muted); font-size: 11px; line-height: 1.5; }
.shortcut-table { border-collapse: collapse; width: 100%; font-size: 12px; }
.shortcut-table td { padding: 3px 0; vertical-align: baseline; }
.shortcut-keys { white-space: nowrap; padding-right: 12px !important; width: 1%; }

/* A menu hanging off the button that opened it, for a question with two or three answers. */
.pop-menu { position: fixed; z-index: 45; min-width: 240px; padding: 5px; background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,.6);
  display: flex; flex-direction: column; gap: 2px; }
.pop-item { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%;
  padding: 6px 9px; text-align: left; background: transparent; border: none; border-radius: 5px; }
.pop-item:hover, .pop-item:focus { background: var(--selected); outline: none; }
.pop-item small { color: var(--muted); font-size: 11px; }

/* ---------- Build screen ---------- */
/* Pins on the left at full window height — the table is the reason this stage wanted a screen
   of its own — with results over the log on the right. */
.screen[data-screen="build"] { grid-template-columns: var(--pin-w, 520px) 5px minmax(0, 1fr); }
.pane { display: flex; flex-direction: column; min-height: 0; min-width: 0; background: var(--panel); }
.pane-head { flex: none; display: flex; align-items: center; gap: 8px; min-height: 30px; padding: 4px 10px;
  border-bottom: 1px solid var(--border); }
.pane-head .spacer { flex: 1; }
.pane-head button { padding: 2px 8px; font-size: 12px; font-weight: 400; text-transform: none; letter-spacing: 0; }
.pane-body { flex: 1; min-height: 0; overflow: auto; padding: 10px 12px 20px; }
.build-right { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
#pinPane { border-right: 1px solid var(--border); }
/* Results take what they need and no more, so a short build does not leave the log in a slot. */
#resultsPane { flex: 0 0 auto; max-height: 55%; border-bottom: 1px solid var(--border); }
#logPane { flex: 1; }
.build-section { margin-bottom: 18px; }
.build-section:last-child { margin-bottom: 0; }
.build-section h3 { margin: 0 0 8px; }
.section-note { font-size: 11px; color: var(--muted); font-weight: 400; text-transform: none; letter-spacing: 0; }

/* ---------- Program screen ---------- */
.screen[data-screen="prog"] { overflow: auto; }
.prog-screen { padding: 28px 24px 40px; display: flex; justify-content: center; }
.prog-col { width: min(680px, 100%); display: flex; flex-direction: column; gap: 14px; }
.card { border: 1px solid var(--border); border-radius: 8px; background: var(--panel); padding: 16px 18px; }
.card h2 { margin: 0 0 10px; font-size: 15px; }
.card p { margin: 0 0 8px; line-height: 1.6; }
.card p:last-child { margin-bottom: 0; }
.stat-row { display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 12px; }
.stat-row:last-of-type { border-bottom: none; }
.stat-row .k { color: var(--muted); white-space: nowrap; }
.stat-row .v { font-family: var(--mono); text-align: right; min-width: 0; overflow-wrap: anywhere; }
.build-warning, .build-error { border: 1px solid var(--yellow); border-left-width: 3px; border-radius: 4px;
  padding: 7px 10px; margin-bottom: 10px; color: var(--yellow); font-size: 12px; line-height: 1.5; }
/* Same block, for something that failed rather than something to look at twice. */
.build-error { border-color: var(--red); color: var(--red); }
.notice-dismiss { float: right; margin-left: 10px; }
.ok-text { color: var(--green); }
.warn-text { color: var(--yellow); }
.fail-text { color: var(--red); }
.inline-check { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px; color: var(--muted); font-size: 12px; }
.link-btn { background: transparent; border: none; color: var(--blue); text-decoration: underline dotted; padding: 0 4px; font-size: 11px; }

/* pin table */
.pin-table { border-collapse: collapse; width: 100%; max-width: 840px; font-size: 12px; }
/* The pane scrolls a bus of forty bits past the header, so the header comes along. */
.pin-table th { position: sticky; top: -10px; z-index: 1; text-align: left; color: var(--muted);
  font-weight: 600; font-size: 11px; padding: 6px 8px; background: var(--panel);
  border-bottom: 1px solid var(--border); }
.pin-table td { padding: 3px 8px; border-bottom: 1px solid #1b1f28; vertical-align: middle; }
.pin-table tbody tr:hover td { background: #191e28; }
.pin-table td.port { font-family: var(--mono); }
.pin-table td.dir, .pin-table td.width { color: var(--muted); font-size: 11px; }
.pin-table tr.bit-row td.port { padding-left: 26px; color: var(--muted); }
/* A port name and its expander belong on one line; wrapping them misaligns the row. */
.pin-table td.port, .pin-table tr.bus-row td:first-child { white-space: nowrap; }
.pin-table tr.conflict td { background: rgba(255, 95, 95, .12); }
.pin-table tr.problem td { background: rgba(240, 179, 76, .12); }
.pin-table tr.bus-row td { border-bottom: none; }
/* The expander is how a 25-bit bus becomes 25 assignable pins, so it is a button that looks
   like one rather than a grey glyph the size of the text beside it. */
.bus-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; padding: 0; margin-right: 2px;
  border: 1px solid var(--border); border-radius: 4px;
  background: var(--control); color: var(--text); line-height: 0;
  transition: transform .12s ease, background-color .12s ease, border-color .12s ease;
}
.bus-toggle svg { display: block; }
.bus-toggle:hover { background: #2f3746; border-color: var(--accent); color: #fff; }
.bus-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.bus-toggle.open { transform: rotate(90deg); }
.bus-name { cursor: pointer; }
.bus-name:hover { color: #fff; text-decoration: underline dotted; }
.bus-summary { color: var(--muted); font-size: 11px; }
.bus-pullups { color: var(--muted); font-size: 11px; }
.pin-select { width: 100%; min-width: 190px; max-width: 270px; padding: 3px 24px 3px 8px;
  font-family: var(--mono); font-size: 12px; }
/* An unassigned row is the default state of forty rows at once: it should recede, so the pins
   that are assigned are the ones that catch the eye. */
.pin-select.is-unassigned { color: var(--muted); }
.pullup-select { min-width: 104px; padding: 3px 22px 3px 8px; font-size: 11px; }
.pullup-select.is-off { color: var(--muted); }
.pin-table td.pull { white-space: nowrap; }
.pin-conflict { color: var(--red); font-size: 12px; margin-top: 6px; }

/* results */
.util-table { border-collapse: collapse; font-size: 12px; max-width: 620px; width: 100%; }
.util-table td { padding: 2px 8px 2px 0; }
.util-label { color: var(--muted); white-space: nowrap; }
.util-bar { width: 100%; }
.util-bar span { display: block; height: 8px; background: var(--accent); border-radius: 4px; min-width: 2px; }
.util-bar span.hot { background: var(--red); }
.util-num, .util-pct { font-family: var(--mono); text-align: right; white-space: nowrap; }
.util-pct { color: var(--muted); width: 46px; }
.timing-line { font-family: var(--mono); font-size: 12px; margin-top: 6px; }
.shims-used { margin-top: 8px; font-size: 12px; color: var(--muted); }
.shim-list { margin-top: 14px; }
.card strong { color: var(--text); font-weight: 600; }
.shims-used code, .shim-table code { font-family: var(--mono); color: var(--blue); background: var(--control); padding: 0 4px; border-radius: 3px; }
.shim-table { border-collapse: collapse; font-size: 12px; margin-top: 6px; }
.shim-table th { text-align: left; color: var(--muted); font-weight: 600; font-size: 11px; padding: 3px 12px 3px 0; }
.shim-table td { padding: 2px 12px 2px 0; vertical-align: top; }
.shim-doc { color: var(--muted); max-width: 60ch; }

/* program */
.terminal-help { margin-top: 8px; color: var(--muted); font-size: 12px; }
.terminal-help pre { font-family: var(--mono); background: var(--control); border: 1px solid var(--border); border-radius: 4px; padding: 7px 10px; overflow-x: auto; margin: 6px 0 0; color: var(--text); }
#buildLog { flex: 1; min-height: 0; }

/* programming modal */
.prog-modal .modal-box { width: min(440px, calc(100vw - 32px)); max-width: none; }
.prog-modal h3 { margin: 0 0 12px; font-size: 14px; }
.prog-steps { list-style: none; margin: 0 0 12px; padding: 0; font-size: 12px; }
.prog-steps li { padding: 3px 0; color: var(--muted); }
.prog-steps li .mark { display: inline-block; width: 16px; }
.prog-steps li.active { color: var(--text); }
.prog-steps li.done { color: var(--green); }
.prog-steps li.failed { color: var(--red); }
.prog-steps li .detail { color: var(--muted); font-size: 11px; }
.prog-bar { height: 6px; background: var(--control); border-radius: 3px; overflow: hidden; }
.prog-bar span { display: block; height: 100%; width: 0; background: var(--accent); transition: width .15s linear; }
.prog-message { margin-top: 12px; font-size: 12px; line-height: 1.5; }
.prog-message p { margin: 6px 0; }
.prog-message pre { font-family: var(--mono); background: var(--control); border: 1px solid var(--border); border-radius: 4px; padding: 6px 8px; overflow-x: auto; white-space: pre-wrap; word-break: break-all; }
