@font-face {
  font-family: "Pretendard Variable";
  src: url("/static/fonts/PretendardVariable.woff2") format("woff2");
  font-weight: 45 920;
  font-display: swap;
}

:root {
  /* Difficulty is one axis between two poles (2026-10-20): easy green ↔ hard red; medium is literally their mix
     (in oklch, so the midpoint is a clear amber instead of the muddy brown an sRGB mix gives). */
  --easy: #1E9E4A;
  --hard: #D2453B;
  --medium: color-mix(in oklch, var(--easy), var(--hard));
  /* Question types: categorical, kept away from the difficulty green–amber–red range. */
  --kind-choice: #2F6FDB;
  --kind-text_entry: #7B5CC4;
  --kind-other: #5C6F82;
  --surface: #FFFFFF;
  --surface-canvas: #ECEEF0;
  --surface-sunken: #F1F3F5;
  --border: #D5DAE0;
  --border-subtle: #E6E9ED;
  --border-control: #7F8892;
  --text: #1B2126;
  --text-secondary: #4A5560;
  --text-muted: #5C666F;
  --text-disabled: #8A939C;
  /* User avatar icon (2026-10-20): lighter than --text-muted, still 3:1 on white for an icon control. */
  --avatar: #8A939C;
  --primary: #1B6340;
  --primary-hover: #14502F;
  --primary-active: #0F3F25;
  --primary-text: #16583A;
  --primary-soft: #E8F0EB;
  --danger: #B02318;
  --danger-soft: #FBEAE7;
  --warn: #7A4E00;
  --warn-soft: #FCF1DC;
  --info: #16548F;
  --info-soft: #E6EEF8;
  /* PDF export pair (2026-09-11): student = light orange, teacher = lighter orange; text is --text (contrast >= 8.5:1) */
  --export: #F6C08A;
  --export-hover: #F2AE68;
  --export-soft: #FCE6CF;
  --export-soft-hover: #F9D8B3;
  --fs-100: 12px;
  --fs-200: 13px;
  --fs-300: 14px;
  --fs-400: 17px;
  --fs-500: 21px;
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --r-sm: 4px;
  --r-md: 6px;
  --shadow-drag: 0 6px 16px rgb(20 26 32 / 16%);
  --shadow-dialog: 0 24px 64px rgb(20 26 32 / 28%);
}

* {
  box-sizing: border-box;
}

[hidden] {
  display: none !important;
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

html,
body {
  margin: 0;
  color: var(--text);
  background: var(--surface-canvas);
  font-family: "Pretendard Variable", Pretendard, "Noto Sans KR", system-ui, sans-serif;
  font-size: var(--fs-300);
  font-weight: 400;
  line-height: 1.571429;
  font-synthesis: none;
}

body {
  min-width: 320px;
  overflow: hidden;
}

button,
input,
select {
  font: inherit;
}

input[type="search"] {
  cursor: text;
}

button {
  height: 32px;
  padding: 0 var(--sp-3);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: var(--fs-200);
  font-weight: 500;
  line-height: 1.384615;
  white-space: nowrap;
}

button:hover {
  background: var(--surface-sunken);
}

button:active {
  border-color: var(--border);
}

button.primary-button {
  color: var(--surface);
  background: var(--primary);
  border: 0;
  font-weight: 600;
}

button.primary-button:hover {
  background: var(--primary-hover);
}

button.primary-button:active {
  background: var(--primary-active);
}

/* PDF export buttons, right of the worksheet heading. Orange keeps them apart from primary green.
   Declared before the shared button:disabled rule so that rule still wins when disabled. */
button.export-button {
  color: var(--text);
  border: 0;
  font-weight: 600;
}

button.export-student { background: var(--export); }
button.export-student:hover { background: var(--export-hover); }
button.export-answer { background: var(--export-soft); }
button.export-answer:hover { background: var(--export-soft-hover); }

button:disabled,
button.primary-button:disabled {
  color: var(--text-disabled);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  cursor: default;
}

.app-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 48px;
  padding: 0 var(--sp-4);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.app-logo { margin: 0; line-height: 0; }
/* 2026-10-20: "Contents Bank (Question)" wordmark in Zilla Slab (static/brand/SOURCE.md). Small phones step down one size. */
.app-logo img { display: block; width: 253px; height: 30px; }
@media (max-width: 380px) {
  .app-logo img { width: auto; height: 28px; }
}
/* Screen language links (2026-10-16): plain links, current one in primary.
   2026-10-20: moved to the right end of the bar (Español · English · 한국어); they also pick the item language. */
/* 2026-10-20 (later): the links live in the user panel (person icon, top right) as segmented buttons. */
.user-menu-button {
  margin-left: auto;
  padding: 2px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--avatar);
  line-height: 0;
  cursor: pointer;
}
.user-menu-button:hover { color: var(--text-secondary); }
.user-menu-button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.user-panel {
  inset: auto;
  top: 52px;
  right: var(--sp-4);
  margin: 0;
  width: 280px;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-dialog);
}
.user-card { display: flex; gap: var(--sp-3); align-items: center; color: var(--avatar); }
.user-card p { margin: 0; }
.user-name { color: var(--text); font-weight: 600; font-size: var(--fs-300); }
.user-meta { color: var(--text-secondary); font-size: var(--fs-200); }
.ui-lang { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border-subtle); }
.ui-lang-label { margin: 0 0 var(--sp-2); color: var(--text-muted); font-size: var(--fs-100); }
.ui-lang-options { display: flex; gap: var(--sp-2); }
.ui-lang a,
.time-zone button {
  flex: 1;
  padding: var(--sp-2) 0;
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-200);
  line-height: inherit;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}
.ui-lang a:hover,
.time-zone button:hover { background: var(--surface-sunken); }
.ui-lang a[aria-current="true"],
.time-zone button[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); font-weight: 600; }

.workspace {
  display: grid;
  grid-template-columns: minmax(280px, 35fr) var(--sp-4) minmax(560px, 65fr);
  height: calc(100vh - 48px);
  padding: var(--sp-4);
  overflow: hidden;
}

.pane-resizer {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  cursor: col-resize;
  touch-action: none;
  border-radius: var(--r-sm);
}
.pane-resizer::after {
  content: "";
  width: var(--sp-1);
  height: var(--sp-6);
  border-radius: var(--r-sm);
  background: var(--border-control);
}
.pane-resizer:hover, .pane-resizer:focus-visible { background: var(--surface-sunken); }
.pane-resizer:focus-visible { outline-offset: -2px; }
body.resizing-panes { cursor: col-resize; user-select: none; }
body.resizing-panes .preview-pages { pointer-events: none; }

/* Page vs. issues horizontal divider. Same handle and the same hover/focus rules as the
   side .pane-resizer, laid on its side. */
.issue-divider {
  display: flex;
  flex: 0 0 var(--sp-5);
  align-items: center;
  gap: var(--sp-1);
  margin: 0 var(--sp-4);
}
.issue-divider[hidden] { display: none; }
.issue-resizer {
  display: flex;
  flex: 1;
  align-self: stretch;
  align-items: center;
  justify-content: center;
  min-width: 0;
  cursor: row-resize;
  touch-action: none;
  border-radius: var(--r-sm);
}
.issue-resizer::after {
  content: "";
  width: var(--sp-6);
  height: var(--sp-1);
  border-radius: var(--r-sm);
  background: var(--border-control);
}
.issue-resizer:hover, .issue-resizer:focus-visible { background: var(--surface-sunken); }
.issue-resizer:focus-visible { outline-offset: -2px; }
/* One-step grow/shrink. A §7 quiet icon, 24x24; the arrow is drawn with CSS borders
   (no Unicode shape glyphs). */
.issue-step {
  position: relative;
  width: 24px;
  min-width: 24px;
  height: 24px;
  padding: 0;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
}
.issue-step::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  border-top: 2px solid currentColor;
  border-left: 2px solid currentColor;
}
.issue-step-up::before { transform: translate(-50%, -25%) rotate(45deg); }
.issue-step-down::before { transform: translate(-50%, -75%) rotate(-135deg); }
.issue-step:hover:not(:disabled) { background: var(--surface-sunken); }
.issue-step:disabled { color: var(--text-disabled); background: transparent; border: 0; }
/* Worksheet header ↕ page divider (panel-height.js, 2026-10-20). Same look as .issue-resizer.
   The header block (title, settings, notes) gives up height to the page; what no longer fits scrolls. */
.worksheet-top {
  flex: none;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
}
.panel-height-resizer {
  display: flex;
  flex: 0 0 var(--sp-4);
  align-items: center;
  justify-content: center;
  cursor: row-resize;
  touch-action: none;
}
.panel-height-resizer::after {
  content: "";
  width: var(--sp-6);
  height: var(--sp-1);
  border-radius: var(--r-sm);
  background: var(--border-control);
}
.panel-height-resizer:hover, .panel-height-resizer:focus-visible { background: var(--surface-sunken); }
.panel-height-resizer:focus-visible { outline-offset: -2px; }
body.resizing-height { cursor: row-resize; user-select: none; }
body.resizing-height .preview-pages { pointer-events: none; }
body.resizing-issues { cursor: row-resize; user-select: none; }
body.resizing-issues .preview-pages { pointer-events: none; }

.search-panel,
.worksheet-panel {
  display: flex;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.worksheet-panel { container-type: inline-size; }

.panel-heading {
  display: flex;
  flex: 0 0 44px;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  height: 44px;
  padding: 0 var(--sp-4);
  border-bottom: 1px solid var(--border-subtle);
}

.panel-heading h2,
.dialog-heading h2 {
  margin: 0;
  font-size: var(--fs-400);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.411765;
}

.worksheet-heading-lead,
.worksheet-heading-status,
.export-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.worksheet-heading { gap: var(--sp-2); }

.worksheet-heading-lead {
  flex: 1 1 auto;
  gap: var(--sp-2);
}

.worksheet-heading-lead h2,
.worksheet-heading-status {
  flex: 0 0 auto;
  white-space: nowrap;
}

.worksheet-heading-status { gap: var(--sp-1); }

.worksheet-heading .export-actions,
.worksheet-heading .worksheet-actions {
  flex-wrap: nowrap;
  gap: var(--sp-1);
}

.worksheet-heading button {
  height: 28px;
  padding-inline: var(--sp-2);
  font-size: var(--fs-100);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.result-count,
.worksheet-status,
.preview-state {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-200);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1.384615;
}

.filters {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3) var(--sp-4);
  margin: 0;
  padding: var(--sp-4);
  border-bottom: 1px solid var(--border-subtle);
}

.filters label,
.worksheet-settings label {
  display: grid;
  gap: var(--sp-1);
  min-width: 0;
  color: var(--text-secondary);
  font-size: var(--fs-200);
  font-weight: 600;
  line-height: 1.384615;
}

.filters select,
.filters input[type="search"],
.worksheet-settings input[type="text"],
.worksheet-settings select {
  width: 100%;
  min-width: 0;
  height: 32px;
  padding: 0 var(--sp-2);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  font-size: var(--fs-300);
  font-weight: 400;
  line-height: 1.571429;
}

.filters .search-input {
  grid-column: span 2;
}

.filters .assemble-field {
  display: flex;
  align-items: end;
  align-self: end;
  min-width: 0;
}

.filters .assemble-field button {
  width: 100%;
}

.filters label.toggle,
.worksheet-settings label.toggle {
  display: flex;
  align-items: center;
  align-self: end;
  gap: var(--sp-2);
  min-height: 32px;
  color: var(--text);
  font-weight: 400;
}

.toggle input {
  width: var(--sp-4);
  height: var(--sp-4);
  margin: 0;
  accent-color: var(--primary);
}

.error-message {
  margin: var(--sp-3) var(--sp-4) 0;
  padding: var(--sp-2) var(--sp-3);
  color: var(--danger);
  background: var(--danger-soft);
  border-radius: var(--r-sm);
  font-size: var(--fs-200);
  line-height: 1.384615;
}

.table-wrap {
  flex: 1;
  min-height: 0;
  margin: var(--sp-4) var(--sp-4) 0;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.table-wrap table,
.worksheet-list-wrap table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
  font-size: var(--fs-200);
  line-height: 1.384615;
}

.table-wrap thead tr,
.worksheet-list-wrap thead tr,
.table-wrap th,
.worksheet-list-wrap th {
  height: 32px;
}

.table-wrap th,
.worksheet-list-wrap th {
  position: sticky;
  z-index: 1;
  top: 0;
  padding: 0 var(--sp-3);
  color: var(--text-secondary);
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
}

.table-wrap tbody tr,
.worksheet-list-wrap tbody tr,
.table-wrap td,
.worksheet-list-wrap td {
  height: 36px;
}

.table-wrap tbody tr,
.worksheet-list-wrap tbody tr {
  background: var(--surface);
  transition: background .12s ease;
}

.table-wrap tbody tr + tr td,
.worksheet-list-wrap tbody tr + tr td {
  border-top: 1px solid var(--border-subtle);
}

.table-wrap tbody tr:hover,
.worksheet-list-wrap tbody tr:hover {
  background: var(--surface-sunken);
}

.table-wrap tbody tr.added,
.table-wrap tbody tr.added:hover {
  background: var(--primary-soft);
}

.table-wrap tbody tr.unprintable {
  background: var(--surface);
}

.table-wrap tbody tr.unprintable .title-cell {
  color: var(--text-muted);
}

.table-wrap tbody tr:focus-visible,
.worksheet-list-wrap tbody tr:focus-visible {
  outline-offset: -2px;
}

.table-wrap td,
.worksheet-list-wrap td {
  max-width: 0;
  padding: 0 var(--sp-3);
  overflow: hidden;
  color: var(--text);
  font-weight: 400;
  text-overflow: ellipsis;
  vertical-align: middle;
  white-space: nowrap;
}

.search-panel th:nth-child(1),
.search-panel td:nth-child(1) {
  width: 32px;
  padding-right: 0;
  padding-left: 0;
  text-align: center;
}

.search-panel th:nth-child(2),
.search-panel td:nth-child(2) {
  width: 36px;
  padding-right: var(--sp-2);
  padding-left: 0;
  text-align: right;
}

.search-panel th:nth-child(4),
.search-panel td:nth-child(4) {
  width: 72px;
}

.search-panel th:nth-child(5),
.search-panel td:nth-child(5) {
  width: 76px; /* difficulty badge (쉬움 · 보통 · 어려움), 2026-10-20; was the grade label */
}

/* English and Spanish words are longer than the Korean column labels and grade values
   ("Agregar", "Opción múltiple", "Secundaria 1"); widen only those columns so the Korean table is unchanged. */
html:not([lang="ko"]) .search-panel th:nth-child(1),
html:not([lang="ko"]) .search-panel td:nth-child(1) {
  width: 56px;
}

html:not([lang="ko"]) .search-panel th:nth-child(4),
html:not([lang="ko"]) .search-panel td:nth-child(4) {
  width: 96px;
  white-space: normal; /* "Multiple choice" may take two lines rather than squeeze the title (2026-10-20) */
}

html:not([lang="ko"]) .search-panel th:nth-child(5),
html:not([lang="ko"]) .search-panel td:nth-child(5) {
  width: 80px;
  padding-right: var(--sp-1);
  padding-left: var(--sp-1);
}

.select-cell input {
  width: var(--sp-4);
  height: var(--sp-4);
  margin: 0;
  accent-color: var(--primary);
  vertical-align: middle;
}

.select-cell .table-replace {
  width: auto;
  min-width: 0;
  height: var(--sp-6);
  margin-left: var(--sp-1);
  padding: 0 var(--sp-1);
  font-size: var(--fs-100);
}

.search-panel:has(#replacement-mode:not([hidden])) th:nth-child(1),
.search-panel:has(#replacement-mode:not([hidden])) td:nth-child(1) {
  width: calc(var(--sp-6) * 2 + var(--sp-5) - var(--sp-1));
}

.number-cell,
#page-position,
#worksheet-list-dialog td:nth-child(2),
#worksheet-list-dialog td:nth-child(3) {
  font-variant-numeric: tabular-nums;
}

.title-cell {
  font-weight: 500;
}

.title-cell-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.title-cell .cell-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.title-cell .status-tag {
  flex: 0 0 auto;
}

.empty-message {
  margin: 0;
  padding: var(--sp-6);
  color: var(--text-muted);
  font-size: var(--fs-200);
  line-height: 1.384615;
  text-align: center;
}

.pagination {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  padding: 0 var(--sp-4) var(--sp-4);
}

.pagination span {
  min-width: calc(var(--sp-6) + var(--sp-6));
  color: var(--text-secondary);
  font-size: var(--fs-200);
  font-variant-numeric: tabular-nums;
  line-height: 1.384615;
  text-align: center;
}

.worksheet-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.worksheet-command-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
}

.preview-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--sp-2);
  min-width: 0;
}

.worksheet-command-bar > .preview-state {
  justify-self: end;
  white-space: nowrap;
}

.worksheet-guard {
  margin: 0 var(--sp-4) var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  color: var(--warn);
  background: var(--warn-soft);
  border-radius: var(--r-sm);
  font-size: var(--fs-200);
  line-height: 1.384615;
}

.assemble-note {
  margin: 0 var(--sp-4) var(--sp-4);
  color: var(--text-muted);
  font-size: var(--fs-200);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1.384615;
}

.worksheet-settings {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
}

.worksheet-settings label {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  white-space: nowrap;
}

.worksheet-settings select {
  width: auto;
  min-width: calc(var(--sp-6) * 2);
  font-size: var(--fs-200);
}

.worksheet-settings label.toggle {
  align-self: center;
}

.worksheet-canvas {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  border-top: 1px solid var(--border-subtle);
}

.kind-badge,
.reconverted-badge,
.status-tag {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-100);
  font-weight: 500;
  line-height: 1.333333;
  white-space: nowrap;
}

.kind-badge {
  color: var(--text-secondary);
  background: var(--surface-sunken);
}

/* Difficulty on candidate cards (2026-10-20): easy green, medium blue, hard amber. Not red — hard is not an error. */
.difficulty-badge {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-100);
  font-weight: 600;
  line-height: 1.333333;
  white-space: nowrap;
  color: var(--text-secondary);
  background: var(--surface-sunken);
}
.difficulty-1 { color: color-mix(in srgb, var(--easy) 78%, black); background: color-mix(in srgb, var(--easy) 12%, white); }
.difficulty-3 { color: color-mix(in srgb, var(--medium) 78%, black); background: color-mix(in srgb, var(--medium) 12%, white); }
.difficulty-5 { color: color-mix(in srgb, var(--hard) 78%, black); background: color-mix(in srgb, var(--hard) 12%, white); }

.reconverted-badge {
  color: var(--info);
  background: var(--info-soft);
}

.canvas-item-meta .reconverted-badge,
.warning-title .reconverted-badge {
  margin-left: var(--sp-1);
}

.status-danger {
  color: var(--danger);
  background: var(--danger-soft);
}

.close-button {
  width: 24px;
  height: 24px;
  padding: 0;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
  line-height: 1;
}

.close-button:hover {
  color: var(--danger);
  background: var(--danger-soft);
}

.review-tag {
  color: var(--text-secondary);
  background: var(--surface-sunken);
}

.review-tag.review-needed {
  color: var(--warn);
  background: var(--warn-soft);
}

.review-tag.review-checked {
  color: var(--info);
  background: var(--info-soft);
}

.read-value {
  margin: 0;
  padding: var(--sp-2) 0;
  white-space: pre-wrap;
  border-bottom: 1px solid var(--border-subtle);
}

/* Structured answer controls (ticket 20). They were built by the item editing modal until
   ticket 34 removed it; the edit layer carries the same five controls under `inline-edit-*`
   names, so these rules moved with them. Wording lives in `vocab.py`. */
.inline-edit-answer-field {
  display: grid;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

.inline-edit-answer-heading {
  color: var(--text-secondary);
  font-size: var(--fs-200);
  font-weight: 600;
  line-height: 1.384615;
}

.inline-edit-answer-field select,
.inline-edit-answer-field input[type="text"] {
  width: 100%;
  height: 32px;
  padding: 0 var(--sp-2);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  font-size: var(--fs-300);
  font-weight: 400;
}

.inline-edit-choice-list,
.inline-edit-text-answer {
  display: grid;
  gap: var(--sp-2);
}

.inline-edit-choice-list label,
.inline-edit-text-answer-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.inline-edit-choice-list input {
  width: var(--sp-4);
  height: var(--sp-4);
  margin: 0;
  accent-color: var(--primary);
}

.inline-edit-text-answer-row input {
  flex: 1;
  min-width: 0;
}

.edit-answer-unsupported,
.edit-answer-limit,
.inline-edit-grid-hint {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-200);
  line-height: 1.384615;
}

.inline-edit-match-list {
  display: grid;
  gap: var(--sp-2);
}

.inline-edit-match-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(calc(var(--sp-6) * 4), 1fr);
  align-items: center;
  gap: var(--sp-2);
}

.inline-edit-match-left {
  overflow: hidden;
  color: var(--text-secondary);
  font-size: var(--fs-200);
  line-height: 1.384615;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inline-edit-match-row select {
  min-width: 0;
  width: 100%;
}

.inline-edit-calc-grid-answer {
  display: grid;
  gap: var(--sp-2);
  justify-items: start;
}

.inline-edit-calc-grid {
  display: grid;
  grid-template-columns: repeat(var(--edit-grid-cols, 1), var(--sp-6));
  grid-auto-rows: var(--sp-6);
  gap: var(--sp-1);
  width: max-content;
}

.inline-edit-grid-cell {
  display: grid;
  width: var(--sp-6);
  height: var(--sp-6);
  place-items: center;
  font-size: var(--fs-300);
  font-variant-numeric: tabular-nums;
}

.inline-edit-answer-field .inline-edit-grid-input {
  width: var(--sp-6);
  padding: 0 var(--sp-1);
  text-align: center;
}

.inline-edit-grid-answer-row {
  border-top: 1px solid var(--text);
}

.inline-edit-grid-dividend-start {
  border-top: 1px solid var(--text);
  border-left: 1px solid var(--text);
}

.inline-edit-fraction-answer,
.inline-edit-fraction-widget {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.inline-edit-fraction-answer {
  flex-wrap: wrap;
}

.inline-edit-fraction-stack {
  display: grid;
  gap: 0;
}

.inline-edit-answer-field .inline-edit-fraction-input {
  width: var(--sp-6);
  padding: 0 var(--sp-1);
  text-align: center;
}

.inline-edit-answer-field .inline-edit-fraction-numerator {
  border-bottom: 1px solid var(--text);
}

.inline-edit-answer-field .inline-edit-fraction-value {
  width: calc(var(--sp-6) * 3);
  text-align: left;
}

.inline-edit-fraction-affix,
.inline-edit-fraction-static {
  color: var(--text-secondary);
  font-size: var(--fs-300);
  line-height: 1.571429;
}

.preview-state,
.preview-zoom-control {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--text-secondary);
}

.preview-zoom-control {
  font-size: var(--fs-200);
  font-weight: 600;
  line-height: 1.384615;
}

/* Page size (2026-10-20): − slider + value Fit. Ctrl/Cmd + wheel over the pages does the same. */
.preview-zoom-control { gap: var(--sp-1); }
.preview-zoom-control label { margin-right: var(--sp-1); }
#preview-zoom {
  width: 112px;
  height: 32px;
  margin: 0;
  accent-color: var(--primary);
  cursor: pointer;
}
.preview-zoom-control .zoom-step {
  width: 28px;
  min-width: 28px;
  height: 28px;
  padding: 0;
  font-size: var(--fs-300);
  line-height: 1;
}
#preview-zoom-value {
  min-width: 40px;
  color: var(--text);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
#preview-zoom-fit {
  height: 28px;
  padding: 0 var(--sp-2);
  font-size: var(--fs-200);
  font-weight: 400;
}
#preview-zoom-fit[aria-pressed="true"] {
  background: var(--surface-sunken);
  border-color: var(--text-secondary);
}

#preview-status.busy::before {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: var(--sp-2);
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: var(--r-md);
  animation: preview-spin .7s linear infinite;
  content: "";
}

@keyframes preview-spin {
  to {
    transform: rotate(360deg);
  }
}

#preview-slow {
  color: var(--warn);
  font-size: var(--fs-100);
  font-weight: 500;
  line-height: 1.333333;
}

.pdf-preview {
  position: relative;
  display: flex;
  flex: 1;
  min-height: 0;
  margin: var(--sp-3) var(--sp-4) var(--sp-4);
}

.preview-pages {
  flex: 1;
  width: 100%;
  min-height: 0;
  padding: var(--sp-2);
  overflow: auto;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.preview-page {
  position: relative;
  margin: 0 auto var(--sp-2);
  overflow: hidden;
  background: var(--surface);
}

.preview-page:last-child {
  margin-bottom: 0;
}

.preview-page-image {
  display: block;
  width: 100%;
  height: auto;
}

.item-hit {
  position: absolute;
  height: auto;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 0;
}

.item-hit:hover,
.item-hit:active,
.item-hit:focus-visible {
  background: transparent;
}

.item-hit:hover {
  border-color: var(--border-control);
}

.item-hit[aria-pressed="true"] {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

.worksheet-title-hit,
.worksheet-title-editor {
  position: absolute;
  z-index: 2;
  text-align: center;
}

.worksheet-title-hit {
  height: auto;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 0;
  cursor: text;
}

.worksheet-title-hit:hover,
.worksheet-title-hit:active,
.worksheet-title-hit:focus-visible {
  background: transparent;
}

.worksheet-title-hit:hover {
  border-color: var(--border-control);
}

.worksheet-title-hit:disabled {
  color: transparent;
  background: transparent;
  border-color: transparent;
  cursor: default;
}

.worksheet-title-hit.pending {
  color: var(--text);
  background: var(--surface);
  border-color: transparent;
  font-weight: 600;
}

.worksheet-title-editor {
  z-index: 4;
  min-width: 0;
  padding: 0 var(--sp-2);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  font-weight: 600;
}

/* T23 common canvas-action surface. */
.canvas-item-tools {
  position: absolute;
  right: var(--sp-1);
  left: var(--sp-1);
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1);
  max-width: calc(100% - var(--sp-2));
  padding: var(--sp-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  transform: translateY(-100%);
}

.canvas-item-tools.canvas-tools-below {
  transform: translateY(var(--sp-1));
}

.canvas-item-tools.canvas-tools-pass-through {
  pointer-events: none;
}

/* T28-FIX1 F7: no grow. Growing stretched whatever landed on the last wrapped
   line to the full toolbar width, which turned the trailing control into a
   321px target next to 41px ones. */
.canvas-item-tools button {
  flex: 0 1 auto;
  min-width: 0;
  height: var(--sp-6);
  padding: var(--sp-1) var(--sp-2);
  white-space: normal;
}

/* Restore specificity over `.canvas-item-tools button`: the handle keeps the
   `flex: 0 0 auto` the drag region asks for, so it never shrinks. */
.canvas-item-tools .canvas-drag-handle {
  flex: 0 0 auto;
}

/* The selection close control is an icon-sized square at the end of the button run. */
.canvas-item-tools .canvas-close {
  flex: 0 0 var(--sp-6);
  width: var(--sp-6);
  padding: 0;
}

.canvas-item-meta {
  flex: 1 0 100%;
  min-width: 0;
  overflow: hidden;
  color: var(--text-secondary);
  font-size: var(--fs-100);
  line-height: 1.333333;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.canvas-action-status {
  position: absolute;
  width: var(--sp-1);
  height: var(--sp-1);
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.replacement-mode {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin: var(--sp-3) var(--sp-4) 0;
  padding: var(--sp-2) var(--sp-3);
  color: var(--text-secondary);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}

.replacement-mode strong {
  min-width: 0;
  font-size: var(--fs-200);
  line-height: 1.384615;
}

.replacement-mode button {
  flex: 0 0 auto;
}

/* T25 canvas drag owner region begins. */
.canvas-drag-handle {
  flex: 0 0 auto;
  cursor: grab;
  touch-action: none;
}

.canvas-drag-handle:active {
  cursor: grabbing;
}

.canvas-item-tools.canvas-tools-dragging {
  pointer-events: none;
}

.canvas-drop-marker {
  position: absolute;
  z-index: 4;
  height: var(--sp-1);
  background: var(--primary-soft);
  border: 1px dashed var(--primary);
  border-radius: var(--r-sm);
  pointer-events: none;
}

.canvas-drop-label {
  position: absolute;
  top: var(--sp-2);
  left: 0;
  padding: var(--sp-1) var(--sp-2);
  color: var(--text);
  font-size: var(--fs-100);
  font-weight: 500;
  line-height: 1.333333;
  white-space: nowrap;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}

.canvas-drop-label.canvas-drop-label-above {
  top: auto;
  bottom: var(--sp-2);
}
/* T25 canvas drag owner region ends. */
/* T26 canvas issue-policy owner region begins. */
.issue-panel {
  flex: 0 1 40%;
  min-height: 0;
  max-height: 40%;
  /* The top border belongs to .issue-divider: never draw the line and its spacing twice. */
  margin: 0 var(--sp-4) var(--sp-4);
  padding-top: var(--sp-1);
  overflow: auto;
}

.issue-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
}

.issue-head h3 {
  margin: 0;
  font-size: var(--fs-300);
  font-weight: 600;
  line-height: 1.571429;
}

#issue-counts {
  margin: 0;
  overflow: hidden;
  color: var(--text-muted);
  font-size: var(--fs-100);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1.333333;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#issue-note {
  margin: var(--sp-2) 0 0;
  padding: var(--sp-2) var(--sp-3);
  color: var(--warn);
  background: var(--warn-soft);
  border-radius: var(--r-sm);
  font-size: var(--fs-100);
  font-weight: 400;
  line-height: 1.333333;
}

#issue-details {
  margin-top: var(--sp-2);
}

/* The base .warning rule sits after this region, so raise specificity with li. */
li.warning {
  grid-template-columns: var(--sp-2) auto minmax(0, 1fr) auto minmax(0, 1fr) auto;
}

li.warning-off-page {
  grid-template-columns: var(--sp-2) auto minmax(0, 1fr) auto minmax(0, 1fr) auto auto;
  height: 36px;
}

.warning-unknown::before {
  background: var(--danger);
}

.warning-target,
.warning-output {
  white-space: nowrap;
}

.warning-title {
  overflow: hidden;
  color: var(--text-secondary);
  font-weight: 400;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.warning-output {
  height: 18px;
  padding: 0 var(--sp-2);
  color: var(--text-secondary);
  background: var(--surface-sunken);
  border-radius: var(--r-sm);
  font-size: var(--fs-100);
  font-weight: 500;
  line-height: 18px;
}

.warning-actions {
  display: flex;
  gap: var(--sp-1);
}

.warning-actions button {
  padding: 0 var(--sp-2);
}

.warning-actions .issue-remove:hover {
  color: var(--danger);
  background: var(--danger-soft);
}

#issue-recovery {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border-subtle);
}

#issue-recovery h4 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-200);
  font-weight: 600;
  line-height: 1.384615;
}

#issue-recovery-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.issue-recovery-item {
  display: grid;
  height: 36px;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  color: var(--text);
  background: var(--surface);
  border-bottom: 1px solid var(--border-subtle);
  cursor: pointer;
  font-size: var(--fs-100);
  line-height: 1.333333;
}

.issue-recovery-item:hover {
  background: var(--surface-sunken);
}

#issue-undo {
  margin-top: var(--sp-2);
}
/* T26 canvas issue-policy owner region ends. */

#preview-empty {
  display: grid;
  flex: 1;
  place-items: center;
  margin: 0;
  padding: var(--sp-3);
  color: var(--text-muted);
  background: var(--surface-sunken);
  border: 1px dashed var(--border);
  border-radius: var(--r-md);
  font-size: var(--fs-200);
  line-height: 1.384615;
  text-align: center;
}
/* Pencil above the words (2026-10-20): the pair is one centered block, not two rows splitting the height.
   Same light gray as the avatar, a step lighter than the words. */
#preview-empty { align-content: center; gap: var(--sp-3); }
.preview-empty-icon { color: var(--avatar); }

/* Export buttons moved to the heading (2026-09-11); only #rejected-note remains here, so height is 0 at rest. */
.download-actions {
  margin: 0 var(--sp-4);
}

#rejected-note,
#last-export {
  margin: 0;
  font-size: var(--fs-100);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  line-height: 1.333333;
}

#rejected-note {
  margin-bottom: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  color: var(--danger);
  background: var(--danger-soft);
  border-radius: var(--r-sm);
}

#last-export {
  color: var(--text-muted);
  text-align: right;
}

#warning-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.warning {
  display: grid;
  grid-template-columns: var(--sp-2) auto auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  height: 28px;
  color: var(--text);
  background: var(--surface);
  border-bottom: 1px solid var(--border-subtle);
  cursor: pointer;
  font-size: var(--fs-100);
  line-height: 1.333333;
}

.warning:hover {
  background: var(--surface-sunken);
}

.warning::before {
  width: 6px;
  height: 6px;
  border-radius: var(--r-md);
  content: "";
  justify-self: center;
}

.warning-rejected::before,
.warning-item::before {
  background: var(--danger);
}

.warning-image::before,
.warning-math::before {
  background: var(--warn);
}

.warning-columns::before,
.warning-moved::before {
  background: var(--info);
}

.warning strong,
.warning-label {
  font-weight: 600;
  white-space: nowrap;
}

.warning-message {
  overflow: hidden;
  color: var(--text-muted);
  font-weight: 400;
  text-overflow: ellipsis;
  white-space: nowrap;
}

dialog {
  width: min(880px, calc(100vw - 96px));
  max-height: calc(100vh - 96px);
  padding: 0;
  color: var(--text);
  background: var(--surface);
  border: 0;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-dialog);
}

dialog::backdrop {
  background: rgb(20 26 32 / 45%);
}

.dialog-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  height: 48px;
  padding: 0 var(--sp-5);
  border-bottom: 1px solid var(--border);
}

.dialog-heading form {
  margin: 0;
}

.preview-mount,
.worksheet-list-wrap {
  max-height: calc(100vh - 48px - 96px);
  padding: var(--sp-5);
  overflow: auto;
}

.preview-fallback {
  display: grid;
  place-items: center;
  margin: 0;
  padding: var(--sp-6);
  color: var(--text-muted);
  background: var(--surface-sunken);
  border: 1px dashed var(--border);
  border-radius: var(--r-md);
  font-size: var(--fs-200);
  line-height: 1.384615;
}

.worksheet-list-wrap table {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

#worksheet-list-dialog tbody tr {
  cursor: pointer;
}

.review-dialog-body {
  padding: var(--sp-5);
}

#review-dialog-items {
  margin: 0 0 var(--sp-4);
  padding-left: var(--sp-5);
  font-variant-numeric: tabular-nums;
}

.review-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
}

/* Stack complete panels when their usable minimum widths no longer fit. */
.mobile-tabs {
  display: none;
  position: sticky;
  top: 0;
  z-index: 5;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.mobile-tabs button {
  flex: 1;
  height: 36px;
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-200);
  cursor: pointer;
}
.mobile-tabs button[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); font-weight: 600; }
.mobile-tab-count {
  display: inline-block;
  min-width: 20px;
  margin-left: var(--sp-1);
  padding: 0 6px;
  border-radius: 10px;
  background: var(--surface-sunken);
  font-size: var(--fs-100);
}

.workspace.panes-stacked {
  display: flex;
  flex-direction: column;
  height: auto;
  min-height: calc(100vh - 48px);
  gap: var(--sp-4);
  overflow: visible;
}
.workspace.panes-stacked .pane-resizer { display: none; }
.workspace.panes-stacked .search-panel { height: 640px; flex: none; }
.workspace.panes-stacked .worksheet-panel { height: 720px; flex: none; }

@media (max-width: 959px) {
  body { overflow: auto; }
  .workspace {
    display: flex;
    flex-direction: column;
    height: auto;
    min-height: calc(100vh - 48px);
    gap: var(--sp-4);
    overflow: visible;
  }
  .pane-resizer { display: none; }
  .search-panel { height: 640px; flex: none; }
  .worksheet-panel { height: 720px; flex: none; }
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* One panel at a time (2026-10-20); .mobile-tabs switches. The visible one fills the screen. */
  .mobile-tabs { display: flex; }
  .workspace[data-mobile-panel="search"] .worksheet-panel,
  .workspace[data-mobile-panel="worksheet"] .search-panel { display: none; }
  .workspace .search-panel, .workspace .worksheet-panel { height: max(520px, calc(100dvh - 48px - 52px - 2 * var(--sp-4))); }
  .table-wrap { overflow: auto; }
  .table-wrap table { min-width: 440px; }
}

/* Compact panes keep controls usable while the divider moves. */
.search-panel { container-type: inline-size; }
@container (max-width: 440px) {
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@container (max-width: 720px) {
  .worksheet-heading {
    flex-basis: auto;
    flex-wrap: wrap;
    height: auto;
    min-height: 44px;
    padding-block: var(--sp-2);
  }

  .worksheet-heading-lead {
    flex-wrap: wrap;
    width: 100%;
  }

  .worksheet-heading-status {
    width: 100%;
    justify-content: flex-end;
  }

  .worksheet-command-bar { grid-template-columns: minmax(0, 1fr); }
}

.worksheet-heading .worksheet-actions button {
  padding-inline: var(--sp-1);
  white-space: nowrap;
}

.candidate-heading-actions,
.candidate-view-toggle,
.candidate-metadata,
.candidate-actions {
  display: flex;
  align-items: center;
}

.candidate-heading-actions {
  gap: var(--sp-2);
}

.candidate-view-toggle {
  gap: var(--sp-1);
}

.candidate-view-toggle button[aria-pressed="true"] {
  background: var(--surface-sunken);
  border-color: var(--text-secondary);
}

.candidate-cards {
  flex: 1;
  min-height: 0;
  margin: var(--sp-4) var(--sp-4) 0;
  overflow: auto;
}

/* Image left, details right (2026-10-20). Thumbnails are wide strips (~910×175), so a narrow stacked card
   shrank the question ~5×; one card per row (two on a very wide panel) gives the image most of the width. */
.candidate-card-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 520px), 1fr));
  gap: var(--sp-3);
}

.candidate-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(96px, 26%, 160px);
  grid-template-rows: auto 1fr;
  grid-template-areas: "thumb details" "thumb actions";
  min-width: 0;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.candidate-card > .candidate-thumbnail { grid-area: thumb; border-right: 1px solid var(--border-subtle); }
.candidate-card > .candidate-details { grid-area: details; border-top: 0; }
.candidate-card > .candidate-actions { grid-area: actions; align-content: end; grid-template-columns: 1fr; }

.candidate-card.added {
  background: var(--primary-soft);
}

.candidate-thumbnail {
  display: grid;
  min-height: calc(var(--sp-6) * 4);
  place-items: center start;
  overflow: hidden;
  background: #fff;
}

/* Trimmed to its content in candidates.js; shown at up to natural size (never blown up), top part only if tall. */
.candidate-thumbnail { padding: var(--sp-2); max-height: 280px; align-items: start; }
.candidate-thumbnail img {
  display: block;
  max-width: 100%;
  height: auto;
}

.thumbnail-failure {
  padding: var(--sp-3);
  color: var(--warn);
  font-size: var(--fs-200);
  line-height: 1.384615;
  text-align: center;
}

.thumbnail-failure p {
  margin: 0 0 var(--sp-2);
}

.candidate-details {
  padding: var(--sp-3);
  border-top: 1px solid var(--border-subtle);
}

.candidate-details h3 {
  margin: 0;
  overflow: hidden;
  font-size: var(--fs-300);
  font-weight: 600;
  line-height: 1.571429;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Badges wrap (2026-10-20): difficulty + type + "already added" do not fit one line on narrow cards. */
.candidate-metadata {
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-2);
  margin-top: var(--sp-2);
  color: var(--text-muted);
  font-size: var(--fs-100);
  line-height: 1.333333;
  white-space: nowrap;
}

.candidate-used {
  color: var(--primary-text);
  font-weight: 600;
}

/* Side by side when they fit, stacked on narrow cards — "Reemplazar" must not be cut (2026-10-20). */
.candidate-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: var(--sp-2);
  padding: 0 var(--sp-3) var(--sp-3);
}

.candidate-actions button {
  min-width: 0;
  height: 32px;
  padding: 0 var(--sp-2);
  overflow: hidden;
  font-size: var(--fs-200);
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* T31 inline editor owner region begins (.inline-editor*). */
/* The edit layer is a direct child of `.preview-page`, a sibling of `.item-hit` and
   `.canvas-item-tools`. Its box is the printed column: left/top/width come from the
   response coordinates (0004 CONTRACT C5) and are set inline by `inline-editor.js`. */
.inline-editor {
  position: absolute;
  z-index: 3;
  display: flex;
  flex-direction: column;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--primary);
}

/* The page clips whatever hangs below it, so the box is capped in `inline-editor.js` and the
   editing surface takes the squeeze — the toolbar, the answer row and the apply/cancel row
   stay on screen for a long item (34). */
.inline-editor-rejected {
  border-color: var(--danger);
}

/* The surface prints in the same family Typst uses, so a line wraps here where it wraps on
   paper. Size and line height are `body_size` / `line_pitch` times the zoom scale. */
.inline-editor-surface {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  font-family: "NanumGothic Print", "Pretendard", system-ui, sans-serif;
  color: var(--text);
}

.inline-editor-surface-content:focus-visible {
  outline: none;
}

.inline-editor-paragraph {
  margin: 0;
}

.inline-editor-paragraph[data-align="center"] {
  text-align: center;
}

.inline-editor-paragraph[data-align="right"] {
  text-align: right;
}

.inline-editor-choice,
.inline-editor-match-option {
  display: flex;
  gap: var(--sp-1);
}

.inline-editor-choice-label {
  flex: none;
  user-select: none;
}

/* Match options. The two printed columns are one editable list here — the pairing is
   answered on the bottom row, the wording is edited in place like a choice option. */
.inline-editor-match {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
}

.inline-editor-match-option {
  flex: 0 1 auto;
}

.inline-editor-table {
  width: 100%;
  border-collapse: collapse;
}

.inline-editor-cell {
  padding: 0 var(--sp-1);
  border: 1px solid var(--border);
}

/* Read-only stand-ins: block image, unsupported interaction, source passage. */
.inline-editor-image-block,
.inline-editor-opaque,
.inline-editor-stimulus {
  min-height: var(--sp-5);
  background: var(--surface-sunken);
  border: 1px dashed var(--border-control);
  user-select: none;
}

/* Sealed inline runs: selectable and deletable, never editable. */
.inline-editor-math,
.inline-editor-run-image,
.inline-editor-blank,
.inline-editor-box,
.inline-editor-linebreak {
  display: inline-block;
  user-select: none;
}

.inline-editor-math {
  cursor: pointer;
  border-bottom: 1px dotted var(--primary);
}

.inline-editor-run-image {
  width: var(--sp-5);
  height: var(--sp-4);
  background: var(--surface-sunken);
  border: 1px solid var(--border-control);
}

.inline-editor-box {
  min-width: var(--sp-5);
  height: var(--sp-4);
  border: 1px solid var(--text);
}

.inline-editor-linebreak {
  color: var(--text-disabled);
}

.inline-editor-highlight {
  border-radius: var(--r-sm);
}

.ProseMirror-selectednode {
  outline: 2px solid var(--primary);
}

/* Toolbar sits 28px above the box; when the box starts near the top of the page it flips
   below, the same rule `.canvas-tools-below` uses for the item toolbar. */
/* The bar floats fully clear of the box: `bottom: 100%` pins its underside to the box top,
   whatever the bar's own height is. A fixed negative `top` used a guessed height and covered
   the first printed line (independent review M1). */
/* Ticket 36: one icon row like Word's font ribbon. `nowrap` is the shape — the row of glyph
   buttons is narrower than a printed column, so it no longer wraps to a second line. */
.inline-editor-toolbar {
  position: absolute;
  left: 0;
  bottom: 100%;
  display: flex;
  flex-wrap: nowrap;
  gap: 2px;
  align-items: center;
  margin-bottom: var(--sp-1);
  padding: 2px;
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  white-space: nowrap;
}

.inline-editor-toolbar-below {
  top: 100%;
  bottom: auto;
  margin-top: var(--sp-1);
  margin-bottom: 0;
}

/* Icon button, the 24px fixed size DESIGN §2 allows. The glyph carries the meaning; the
   Korean wording lives in `title` / `aria-label` only. */
.inline-editor-tool {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: var(--sp-5);
  height: var(--sp-5);
  padding: 0;
  font-size: var(--fs-200);
  line-height: 1;
}

.inline-editor-tool[aria-pressed="true"] {
  background: var(--primary-soft);
  border-color: var(--primary);
}

.inline-editor-bold {
  font-weight: 600;
}

.inline-editor-italic {
  font-style: italic;
}

.inline-editor-underline {
  text-decoration: underline;
}

.inline-editor-toolbar-sep {
  flex: 0 0 auto;
  align-self: stretch;
  width: 1px;
  margin: 0 2px;
  background: var(--border-subtle);
}

/* Split button: the left half applies the remembered colour, the right arrow opens the
   palette. The palette is positioned against this group, hence `relative`. */
.inline-editor-split {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
}

.inline-editor-split-main {
  flex-direction: column;
}

.inline-editor-split-glyph {
  font-size: var(--fs-100);
  line-height: 1;
}

.inline-editor-split-bar {
  width: var(--sp-3);
  height: var(--sp-1);
}

.inline-editor-split-arrow {
  width: var(--sp-3);
  font-size: var(--fs-100);
}

.inline-editor-tool-icon {
  width: var(--sp-3);
  height: var(--sp-3);
}

.inline-editor-palette {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1;
  display: flex;
  gap: 2px;
  align-items: center;
  margin-top: 2px;
  padding: var(--sp-1);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
}

.inline-editor-palette[hidden] {
  display: none;
}

.inline-editor-swatch,
.inline-editor-swatch-clear {
  width: var(--sp-4);
  height: var(--sp-4);
  padding: 0;
  font-size: var(--fs-100);
}

.inline-editor-swatch {
  border: 1px solid var(--border-control);
}

.inline-editor-overflow {
  display: flex;
  gap: var(--sp-2);
  align-items: center;
  padding: var(--sp-1);
  color: var(--danger);
  background: var(--danger-soft);
  font-size: var(--fs-100);
}

.inline-editor-notice {
  margin: 0;
  padding: var(--sp-1);
  color: var(--warn);
  background: var(--warn-soft);
  font-size: var(--fs-100);
}

/* Bottom row: answers and the explanation, collapsed until asked for. */
.inline-editor-bottom,
.inline-editor-actions,
.inline-editor-confirm {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: center;
  padding: var(--sp-1);
  border-top: 1px solid var(--border-subtle);
  font-family: "Pretendard", system-ui, sans-serif;
  font-size: var(--fs-100);
  line-height: normal;
}

.inline-editor-bottom-panel {
  flex-basis: 100%;
}

/* The explanation is the `feedback` area of the same ProseMirror document, so it cannot be
   moved into the panel element; it opens and closes with the same class instead, and takes its
   heading from an inherited custom property the layer sets from UI_TEXT (writing an attribute
   onto ProseMirror's own DOM would loop against its mutation observer). */
.inline-editor-feedback {
  padding: var(--sp-1);
  border-top: 1px dashed var(--border-subtle);
}

.inline-editor:not(.inline-editor-bottom-open) .inline-editor-feedback {
  display: none;
}

.inline-editor-feedback::before {
  content: var(--inline-editor-feedback-label, "");
  display: block;
  color: var(--text-muted);
  font-family: "Pretendard", system-ui, sans-serif;
  font-size: var(--fs-100);
  line-height: normal;
}

.inline-editor-confirm {
  color: var(--danger);
  background: var(--danger-soft);
}

/* T34: the stored copy cannot be read, so the layer is the notice and the one recovery the
   removed modal used to hold. No editing surface, no toolbar. */
.inline-editor-conflict {
  border-color: var(--danger);
}

.inline-editor-conflict .inline-editor-notice {
  color: var(--danger);
  background: var(--danger-soft);
}
/* T31 inline editor owner region ends. */
/* T32 math editor owner region begins (.math-editor*). */
/* The popover floats over the editing layer next to the formula it edits. It casts no
   shadow, because the design invariant allows exactly one shadow declaration in this file
   (tests/test_16_design.py); a border and the sunken surface separate it from the page. */
.math-editor {
  position: absolute;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: max-content;
  max-width: 420px;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r-md);
}

.math-editor-field {
  min-width: 260px;
  min-height: 40px;
  padding: var(--sp-2);
  font-size: var(--fs-400);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}

.math-editor-keypad {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.math-editor-keypad-row {
  display: flex;
  gap: var(--sp-1);
}

.math-editor-key {
  width: 36px;
  height: 32px;
  padding: 0;
  font-size: var(--fs-300);
  color: var(--text);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
}

.math-editor-key:hover {
  background: var(--primary-soft);
  border-color: var(--primary);
}

.math-editor-message {
  margin: 0;
  font-size: var(--fs-200);
  color: var(--danger);
}

.math-editor-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
}

.math-editor-confirm {
  color: var(--surface);
  background: var(--primary);
  border: 1px solid var(--primary);
}

.math-editor-confirm:disabled {
  color: var(--text-disabled);
  background: var(--surface-sunken);
  border-color: var(--border);
  cursor: default;
}

.math-editor-cancel {
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-control);
}
/* T32 math editor owner region ends. */
/* T33 print font owner region begins (@font-face "NanumGothic Print"). */
/* Regular and Bold faces of fonts/NanumGothic.ttc, the file Typst prints with,
   converted to woff2 without subsetting (provenance and SHA in fonts/SOURCE.md).
   Only the inline editor layer uses this family; the app UI keeps Pretendard.
   font-display: block, because a fallback face would wrap lines differently. */
@font-face {
  font-family: "NanumGothic Print";
  src: url("/static/fonts/NanumGothic-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: "NanumGothic Print";
  src: url("/static/fonts/NanumGothic-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: block;
}
/* T33 print font owner region ends. */

/* Language-stable worksheet header (2026-10-20). Every button and setting has a fixed width, so switching
   Español · English · 한국어 changes only the words; wrapping depends on the panel width alone.
   Widths fit the longest of the three languages; anything longer ellipsizes and keeps its title tooltip. */
.worksheet-heading-lead { flex: 0 0 auto; }
.worksheet-heading-lead h2 {
  width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.worksheet-heading .export-actions button,
.worksheet-heading .worksheet-actions button {
  flex: none;
  overflow: hidden;
  padding-inline: var(--sp-1);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.worksheet-heading .export-actions button { width: 108px; }
.worksheet-heading .worksheet-actions button { width: 68px; }
.worksheet-heading-status {
  flex: 1 1 0;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 0;
  min-width: 0;
}
.worksheet-heading-status > p {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.worksheet-settings,
.preview-controls { align-items: flex-end; gap: var(--sp-2) var(--sp-3); }
.worksheet-settings label,
.worksheet-settings label.setting-toggle {
  display: grid;
  grid-template-rows: auto 32px;
  gap: var(--sp-1);
  align-self: auto;
  width: 120px;
  min-width: 0;
  white-space: normal;
}
.setting-label {
  overflow: hidden;
  color: var(--text-secondary);
  font-size: var(--fs-100);
  font-weight: 600;
  line-height: 1.333333;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.worksheet-settings select { width: 100%; min-width: 0; }
.setting-check {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.setting-check input {
  width: var(--sp-4);
  height: var(--sp-4);
  margin: 0;
  accent-color: var(--primary);
}
.preview-zoom-control {
  display: grid;
  grid-template-rows: auto 32px;
  gap: var(--sp-1);
}
.preview-zoom-control label { margin-right: 0; }
.zoom-row {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}
#preview-zoom-fit {
  width: 64px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.worksheet-command-bar { align-items: end; }
.worksheet-command-bar { grid-template-columns: minmax(0, 1fr); }
.worksheet-status-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: 20px;
  margin: 0 var(--sp-4) var(--sp-2);
}
.worksheet-status-line .assemble-note { margin: 0; }
.worksheet-status-line .preview-state {
  flex: 0 1 auto;
  min-width: 0;
  margin-left: auto;
  white-space: nowrap;
}
#preview-status { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Search panel scales with its own width (2026-10-20). Four filters in one row when there is room,
   two when narrow, one when very narrow; 「시험지 생성」 is its own full-width row under them, never a
   fifth filter cell. Text steps down with the panel (cqi = 1% of the panel width) within legible bounds. */
.filters {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
}
.filters label { font-size: clamp(11px, 2.4cqi, 13px); }
.filters select { height: 32px; font-size: clamp(12px, 2.6cqi, 14px); }
.filters .assemble-field { grid-column: 1 / -1; }
.filters .assemble-field button {
  height: 34px;
  font-size: clamp(12px, 2.8cqi, 14px);
  white-space: nowrap;
}
.search-panel .panel-heading { gap: var(--sp-2); }
.search-panel .panel-heading h2 {
  min-width: 0;
  overflow: hidden;
  font-size: clamp(14px, 3.6cqi, 17px);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.search-panel .candidate-heading-actions { flex: none; }
.search-panel .result-count { font-size: clamp(11px, 2.4cqi, 13px); white-space: nowrap; }
.search-panel .candidate-view-toggle button {
  height: 28px;
  padding: 0 var(--sp-2);
  font-size: clamp(11px, 2.6cqi, 13px);
  white-space: nowrap;
}
@container (max-width: 600px) {
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (max-width: 300px) {
  .search-panel .result-count { display: none; }
}
@container (max-width: 200px) {
  .filters { grid-template-columns: minmax(0, 1fr); }
}
/* Short windows: the list keeps a usable height and the whole search panel scrolls instead. */
.search-panel { overflow-y: auto; }
.search-panel > .table-wrap,
.search-panel > .candidate-cards { flex-shrink: 0; min-height: 220px; flex-basis: 0; flex-grow: 1; }
.search-panel .pagination { flex-shrink: 0; }
#page-position { white-space: nowrap; font-size: clamp(11px, 2.6cqi, 13px); }
.search-panel .pagination button { white-space: nowrap; font-size: clamp(11px, 2.6cqi, 13px); }

/* Difficulty fills (stats bar). */
.difficulty-fill-1 { background: var(--easy); }
.difficulty-fill-3 { background: var(--medium); }
.difficulty-fill-5 { background: var(--hard); }
.difficulty-fill-none { background: var(--border-control); }


/* Phone-narrow search panel: side by side would make the image smaller than full width, so stack again. */
@container (max-width: 420px) {
  .candidate-card { grid-template-columns: minmax(0, 1fr); grid-template-areas: "thumb" "details" "actions"; }
  .candidate-card > .candidate-thumbnail { border-right: 0; border-bottom: 1px solid var(--border-subtle); }
  .candidate-card > .candidate-actions { grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); }
}

/* One PDF button opening a student/teacher menu (2026-10-20). Overrides the fixed 108px export width. */
.worksheet-heading .export-actions .export-menu-button {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  width: auto;
  padding-inline: var(--sp-3);
}
.export-menu {
  position: fixed;
  inset: auto;
  margin: 0;
  padding: var(--sp-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-dialog);
}
.export-menu:popover-open { display: grid; gap: var(--sp-2); }
.export-menu button { width: 180px; height: 36px; font-size: var(--fs-200); }

/* Preview dialog (2026-10-20): the upstream viewer's debug label and scorer-rubric notice are not for teachers;
   the viewer is a byte-identical copy, so they are hidden here. Item facts sit above the question instead. */
#preview-mount .qti-component-label,
#preview-mount .scorer-rubric-notice { display: none; }
.preview-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin: 0;
  padding: var(--sp-3) var(--sp-4) 0;
  font-size: var(--fs-200);
}
.preview-meta[hidden] { display: none; }
.preview-meta div { display: flex; gap: var(--sp-2); min-width: 0; }
.preview-meta dt { color: var(--text-muted); }
.preview-meta dd { margin: 0; color: var(--text); font-weight: 600; }
.candidate-card > .candidate-details .candidate-metadata { margin-top: 0; }

/* Card filters sit right above the cards; they narrow the list only, not generation. Same look as .filters. */
.filters.card-filters {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  padding: var(--sp-3) var(--sp-4) 0;
  border-bottom: 0;
}

/* Buttons keep their box; fit-text.js shrinks only the words that do not fit (2026-10-20), so no ellipsis. */
button { text-overflow: clip !important; }
.candidate-actions button { height: 28px; padding-inline: var(--sp-1); font-size: var(--fs-100); }
.candidate-card > .candidate-actions { gap: var(--sp-1); }

/* One row at any width (2026-10-20): title, PDF and the five actions never wrap. Buttons keep a share of the row
   and fit-text.js shrinks their words (and the title's) when the row gets narrow. */
.worksheet-heading-lead { flex: 1 1 auto; flex-wrap: nowrap !important; width: 100%; min-width: 0; }
.worksheet-heading-lead h2 { flex: 0 1 9em; width: auto; min-width: 0; text-overflow: clip; }
/* Buttons sit at the right edge, title at the left (2026-10-20): the free space goes before PDF, not after Save. */
.worksheet-heading .export-actions { flex: 0 1 auto; min-width: 0; margin-left: auto; }
.worksheet-heading .export-actions .export-menu-button { flex-shrink: 1; min-width: 0; padding-inline: var(--sp-2); }
.worksheet-heading .worksheet-actions { display: flex; flex: 0 1 auto; flex-wrap: nowrap; min-width: 0; }
/* width 68px, not auto: the group no longer grows, so its size comes from the buttons' own width — with auto the
   buttons collapsed to their words and fit-text.js shrank them. They still shrink (min-width 0) when the row is short. */
.worksheet-heading .worksheet-actions button { flex: 0 1 68px; width: 68px; min-width: 0; padding-inline: 2px; }

/* Phone / very narrow worksheet panel: one row cannot hold everything legibly, so the rows are deliberate —
   title + PDF + layout, then the five actions in one row. */
@container (max-width: 520px) {
  .worksheet-heading-lead { flex-wrap: wrap !important; row-gap: var(--sp-2); }
  .worksheet-heading-lead h2 { flex: 1 1 auto; }
  .worksheet-heading .worksheet-actions { flex: 1 1 100%; }
  .worksheet-heading .worksheet-actions button { flex: 1 1 0; }
}


/* ---- UX round 2 (2026-10-20): color means difficulty only, controls give room back to content. ---- */

/* Inline-label selects: the label sits inside the control's box ("학년  중1 ▾"), so there is no label row. */
.filters > label:not(.toggle) {
  display: flex;
  align-items: center;
  gap: 0;
  height: 34px;
  padding-left: var(--sp-3);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-muted);
  font-size: clamp(11px, 2.4cqi, 13px);
  font-weight: 500;
  white-space: nowrap;
}
.filters > label:not(.toggle):focus-within { outline: 2px solid var(--primary); outline-offset: -1px; }
.filters > label:not(.toggle) select {
  flex: 1 1 auto;
  height: 100%;
  border: 0;
  background-color: transparent;
  color: var(--text);
  font-weight: 600;
  outline: none;
}
.filters,
.filters.card-filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.filters.card-filters { padding-top: var(--sp-3); }

/* Generation: count stepper | difficulty presets on one row, total readout + nudge under it. */
.assemble-controls {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "count difficulty" "total total";
  grid-column: 1 / -1;
  gap: var(--sp-2) var(--sp-4);
  align-items: center;
}
.assemble-count { grid-area: count; }
.assemble-difficulty { grid-area: difficulty; }
.assemble-total { grid-area: total; }
.assemble-count,
.assemble-difficulty,
.assemble-total { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.field-label {
  flex: none;
  color: var(--text-secondary);
  font-size: clamp(11px, 2.4cqi, 13px);
  font-weight: 600;
  white-space: nowrap;
}
.stepper {
  display: inline-flex;
  flex: none;
  align-items: center;
  height: 34px;
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.stepper button {
  width: 32px;
  height: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font-size: 18px;
  line-height: 1;
}
.stepper button:hover:not(:disabled) { background: var(--surface-sunken); }
.stepper button:disabled { color: var(--text-muted); opacity: .45; }
.stepper output {
  min-width: 3ch;
  color: var(--text);
  font-size: var(--fs-300);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: center;
}
/* The item count is typable (2026-10-20): same look as the output, a focus ring only while editing. */
.stepper input {
  width: 3ch;
  height: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-300);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: center;
}
.stepper input:focus { outline: 2px solid var(--primary); outline-offset: -2px; }
.stepper-small { height: 28px; }
.stepper-small button { width: 28px; font-size: 16px; }
.stepper-small button + button { border-left: 1px solid var(--border-subtle); }
.segmented {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  height: 34px;
  padding: 2px;
  border-radius: var(--r-sm);
  background: var(--surface-sunken);
}
.segmented button {
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  padding: 0 var(--sp-1);
  border: 0;
  border-radius: calc(var(--r-sm) - 1px);
  background: transparent;
  color: var(--text-secondary);
  font-size: clamp(11px, 2.6cqi, 13px);
  font-weight: 500;
  white-space: nowrap;
}
.segmented button[aria-pressed="true"] {
  background: var(--surface);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 1px 2px rgb(0 0 0 / .12);
}
.assemble-total { justify-content: flex-end; }
.assemble-total .field-label { color: var(--text-muted); font-weight: 500; }
#target-difficulty-value {
  color: var(--text);
  font-size: clamp(11px, 2.6cqi, 13px);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}
@container (max-width: 360px) {
  .assemble-controls { grid-template-columns: minmax(0, 1fr); grid-template-areas: "count" "difficulty" "total"; }
}

/* Worksheet stats: one line in the worksheet panel — difficulty bar with counts inside, then plain text. */
.preview-controls { flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.worksheet-command-bar { padding-block: var(--sp-2); }
.worksheet-stats {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  min-width: 0;
  overflow: hidden;
  font-size: var(--fs-200);
  white-space: nowrap;
}
.stats-empty { color: var(--text-muted); }
.stats-stack {
  display: flex;
  flex: 0 1 280px;
  gap: 2px;
  min-width: 96px;
  height: 22px;
}
.stats-segment {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  overflow: hidden;
  border-radius: 3px;
  color: #fff;
  container-type: inline-size;
  font-size: var(--fs-100);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.stats-segment.difficulty-fill-none { color: var(--text); }
@container (max-width: 64px) { .stats-segment-word { display: none; } }
.stats-result { flex: none; color: var(--text); font-variant-numeric: tabular-nums; }
.stats-tally { min-width: 0; overflow: hidden; color: var(--text-secondary); text-overflow: ellipsis; }
.stats-tally + .stats-tally::before { content: "|"; margin-right: var(--sp-3); color: var(--border-control); }

/* Page size: − 100% + 맞춤, no slider (Ctrl-wheel still zooms). */
.preview-zoom-control { display: flex; flex: none; align-items: center; gap: var(--sp-1); }
.preview-zoom-control .zoom-row { display: flex; align-items: center; gap: var(--sp-1); }
#preview-zoom[hidden] { display: none; }
#preview-zoom-value { min-width: 42px; text-align: center; }

/* Layout menu: the four page settings, opened from the toolbar like PDF. */
.layout-menu-button {
  display: inline-flex;
  flex: 0 1 auto;
  align-items: center;
  gap: var(--sp-1);
  width: auto;
  min-width: 0;
  padding-inline: var(--sp-2);
}
.layout-menu {
  position: fixed;
  inset: auto;
  margin: 0;
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-dialog);
}
.layout-menu .worksheet-settings {
  display: grid;
  grid-template-columns: repeat(2, 160px);
  gap: var(--sp-3);
}
.layout-menu .worksheet-settings label { width: auto; flex: none; }
.export-actions { display: flex; gap: var(--sp-2); }

/* Question type is plain text on cards and in the worksheet list: color is kept for difficulty. */
.kind-badge { color: var(--text-secondary); background: transparent; padding-inline: 0; }
.worksheet-heading .export-actions .layout-menu-button { width: auto; justify-content: center; }
/* Page setup shares the squeeze with PDF on a short row (2026-10-20); before, flex: none left it all to PDF. */
.worksheet-heading .export-actions .layout-menu-button { flex-shrink: 1; min-width: 0; }
/* Narrow worksheet panel: the stats line gets its own row, page size goes under it. */
@container (max-width: 520px) {
  .preview-controls { flex-wrap: wrap; }
  .worksheet-stats { flex: 1 1 100%; flex-wrap: wrap; white-space: normal; }
  .stats-stack { flex: 1 1 100%; }
}
.kind-cell .kind-badge { height: auto; white-space: normal; line-height: 1.3; }


/* ---- UX round 3 (2026-10-20): two sections (new worksheet, question search), one control look. ---- */

/* The list is its own section: heading, count and Cards/Table sit right above the cards they control. */
/* Room to breathe (2026-10-20): 24px under the divider, 12px to the filters, then 16px to the cards. */
.search-panel .list-heading { flex: 0 0 auto; height: auto; padding: var(--sp-5) var(--sp-4) var(--sp-3); border-bottom: 0; }
.filters.card-filters { padding-top: 0; }

/* Count and difficulty sit on the same two columns as Subject and Grade, so every edge lines up. */
.assemble-controls {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-areas: "count difficulty" "total total";
  gap: var(--sp-1) var(--sp-3);
}

/* Count: the select's box and anatomy, label left, the number between two real buttons at the right edge. */
.assemble-count {
  height: 34px;
  padding: 0 var(--sp-1) 0 var(--sp-3);
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.assemble-count:focus-within { outline: 2px solid var(--primary); outline-offset: -1px; }
.assemble-count .field-label,
.assemble-total .field-label { color: var(--text-muted); font-weight: 500; }
.assemble-count .stepper { gap: 2px; height: 100%; margin-left: auto; border: 0; background: transparent; }
.assemble-count .stepper button {
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  background: var(--surface-sunken);
  font-size: 16px;
}
.assemble-count .stepper button:hover:not(:disabled) { background: var(--border-subtle); }
.assemble-count .stepper input { font-size: clamp(12px, 2.6cqi, 14px); }
.assemble-count .stepper input:focus { outline: 0; }

/* Difficulty: one flat outlined control, same height and border as the boxes; the pressed level looks like the
   pressed Cards/Table toggle (sunken + darker edge). The words name themselves, so the label is for screen readers
   only, and the caption under it says 「Average difficulty」. */
.assemble-difficulty .field-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.assemble-difficulty .segmented {
  height: 34px;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--border-control);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.assemble-difficulty .segmented button {
  border-radius: 0;
  font-size: clamp(12px, 2.6cqi, 14px);
}
.assemble-difficulty .segmented button + button { border-left: 1px solid var(--border-subtle); }
.assemble-difficulty .segmented button:hover:not([aria-pressed="true"]) { background: var(--surface-sunken); color: var(--text); }
.assemble-difficulty .segmented button[aria-pressed="true"] {
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--text-secondary);
}

/* The average is one caption line under the controls, left-aligned with them. Its ± 0.5 are the count's buttons,
   smaller: same sunken square, no box, so the line stays quiet. */
.assemble-total { justify-content: flex-start; min-height: 24px; }
.assemble-total .stepper { gap: 2px; height: 22px; border: 0; background: transparent; }
.assemble-total .stepper button {
  width: 22px;
  height: 22px;
  border-radius: var(--r-sm);
  background: var(--surface-sunken);
  font-size: 14px;
}
.assemble-total .stepper button + button { border-left: 0; }
.assemble-total .stepper button:hover:not(:disabled) { background: var(--border-subtle); }

/* Why 「Create worksheet」 is gray, in words under it (the tooltip alone was invisible). */
.assemble-hint {
  grid-column: 1 / -1;
  margin: calc(var(--sp-1) * -1) 0 0;
  color: var(--text-muted);
  font-size: clamp(11px, 2.4cqi, 12px);
  line-height: 1.4;
  text-align: center;
}
/* Stack only when a column is too narrow for the count box (~160px). */
@container (max-width: 360px) {
  .assemble-controls { grid-template-columns: minmax(0, 1fr); grid-template-areas: "count" "difficulty" "total"; }
}


/* ---- Edit focus mode (2026-10-20): while a question is edited, the rest of the worksheet steps back. ---- */

/* Every page and the canvas around them go dim; the question being edited is the one white card above. The veil
   takes the pointer, so a press on it is "outside the layer" (= apply, D9) and never selects another question. */
.preview-pages:has(.inline-editor) {
  background-image: linear-gradient(rgb(17 24 39 / .35), rgb(17 24 39 / .35));
  background-attachment: local;
}
.preview-pages:has(.inline-editor) .preview-page::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: rgb(17 24 39 / .35);
}
/* The selection strip (Edit · Replace · Delete · ×) says nothing new while editing; the card names the question. */
.preview-pages:has(.inline-editor) .canvas-item-tools { display: none; }

/* The card: raised, rounded, 12px wider than the printed column on each side. content-box keeps the text exactly
   as wide as the column, so lines still wrap where they wrap on paper. */
.inline-editor {
  box-sizing: content-box;
  /* 8px up: the printed first line's tops sit a little above body_y and peeked over the card's edge. */
  margin-top: calc(-1 * var(--sp-2));
  margin-left: calc(-1 * var(--sp-3) - 1px);
  padding: 0 var(--sp-3);
  border-radius: var(--r-md);
  box-shadow: 0 16px 40px rgb(0 0 0 / .28), 0 2px 8px rgb(0 0 0 / .12);
}
/* Every row but the text spans the card edge to edge. */
.inline-editor > :not(.inline-editor-surface) {
  margin-inline: calc(-1 * var(--sp-3));
  padding-inline: var(--sp-3);
}
.inline-editor-surface { padding-block: var(--sp-2); }

/* Head: which question, then the format bar, both inside the card — the bar no longer floats over the next
   question (it used to hang above the box, or below it near the top of a page). */
.inline-editor-title {
  padding-block: var(--sp-2) var(--sp-1);
  color: var(--text-secondary);
  font-family: "Pretendard", system-ui, sans-serif;
  font-size: var(--fs-200);
  font-weight: 600;
  line-height: normal;
}
.inline-editor .inline-editor-toolbar,
.inline-editor .inline-editor-toolbar-below {
  position: static;
  margin: 0 calc(-1 * var(--sp-3));
  padding: var(--sp-1) var(--sp-3) var(--sp-2);
  border: 0;
  border-bottom: 1px solid var(--border-subtle);
  border-radius: 0;
  /* Inside the card it cannot hang wider than the column any more: at a small zoom it takes a second line. */
  flex-wrap: wrap;
  row-gap: 2px;
}

/* Foot: answers row, then 「Mark as reviewed … Cancel · Apply」 with Apply the one green button. */
.inline-editor-bottom,
.inline-editor-actions { padding-block: var(--sp-2); }
/* The answer area of an interaction the editor cannot change (a written answer, say) showed as an empty dashed box.
   Only the view hides it: the node stays in the document, the structure lock (wsbStructureLock) rejects deleting
   it, and the printed page is unchanged. */
.inline-editor-opaque { display: none; }

.inline-editor-actions { justify-content: flex-end; }
.inline-editor-actions .inline-editor-review { margin-right: auto; }
.inline-editor-confirm { border-radius: 0 0 calc(var(--r-md) - 1px) calc(var(--r-md) - 1px); }
