/* Task 253kf: lock mobile zoom + horizontal pan (app-like surface). Taps,
   scrolling and form controls still work; pinch/double-tap zoom and sideways
   panning are blocked. */
html,
body {
  touch-action: manipulation;
  overflow-x: hidden;
  max-width: 100%;
}
body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  margin: 0;
  padding: 20px;
  background: #f6f7f9;
  color: #222;
}
.container {
  max-width: 1100px;
  margin: 0 auto;
  background: #fff;
  padding: 24px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}
header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  border-bottom: 1px solid #e1e4e8;
  padding-bottom: 16px;
  margin-bottom: 16px;
  min-width: 0;
}
/* Task 253kc: the right-hand account controls (Verify email / Users / Metrics /
   Log out) must stay on ONE horizontal line. 253jj added a button to a flex
   container whose labels were allowed to wrap (253fg), so each button shrank to
   one-word-per-line and the row read as a vertical stack. Keep the row nowrap
   and let it scroll horizontally when 360px cannot fit every control. */
#user-area {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}
#user-area .tab-btn {
  white-space: nowrap;
  word-break: normal;
  flex: 0 0 auto;
}
#user-area::-webkit-scrollbar { height: 4px; }
h1 { margin: 0; font-size: 1.6rem; }

/* Tabs */
#top-tabs, .sub-tabs {
  display: flex;
  gap: 4px;
  flex-wrap: wrap; /* Task 253fg: never spew tabs off the right edge on mobile. */
}
.tab-btn, .sub-tab-btn {
  padding: 8px 16px;
  border: 1px solid #d0d7de;
  background: #f6f8fa;
  cursor: pointer;
  border-radius: 6px 6px 0 0;
  white-space: normal;      /* Task 253fg: long button labels wrap, not overflow. */
  word-break: break-word;
  max-width: 100%;
}
.tab-btn.active, .sub-tab-btn.active {
  background: #fff;
  border-bottom-color: #fff;
  font-weight: 600;
}
.tab-panel { padding-top: 8px; }
.hidden { display: none !important; }

/* Toolbar */
.toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0;
  flex-wrap: wrap;
}
.session-title { font-weight: 600; font-size: 1.1rem; }

/* Task 253cf: search boxes in the Sessions and Study tabs. */
.search-input {
  flex: 1;
  min-width: 160px;
  max-width: 320px;
  padding: 8px 10px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  font-size: 0.95rem;
}

/* Cards / lists */
.session-card, .source-card, .deck-card, .upload-card, .card {
  border: 1px solid #d0d7de;
  border-radius: 8px;
  padding: 14px;
  margin: 10px 0;
  background: #fff;
}

/* Swipe-to-delete container for session cards */
.swipe-wrap {
  position: relative;
  overflow: hidden;
  border-radius: 8px;
  margin: 10px 0;
  touch-action: pan-y;
}
.swipe-actions {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 14px;
  background: #cf222e;
  border-radius: 8px;
}
.swipe-actions button {
  /* Task 253du: the revealed Delete action was see-through — make it solid.
     Task 253ef (REGRESSION guard): keep it fully opaque — no opacity < 1. */
  background: #fff;
  color: #cf222e;
  border: 1px solid #fff;
  border-radius: 6px;
  padding: 8px 16px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  opacity: 1;
}
.swipe-actions button:hover { background: rgba(255,255,255,0.85); }
.session-card {
  cursor: pointer;
  position: relative;
  z-index: 1;
  transition: transform 0.2s ease;
  margin: 0;
}
.session-card:hover { background: #f6f8fa; }
.session-card .meta, .source-card .meta, .deck-card .meta {
  display: block;
  color: #666;
  font-size: 0.9rem;
  margin-top: 4px;
}
.session-card.swiping { transition: none; }
.session-card.snapping { transition: transform 0.2s ease; }

/* Task 253du: suppress text selection while a swipe gesture is in progress. */
.session-card.swiping, .swipe-wrap .deck-card.swiping,
.swipe-wrap .deck-card.deck-importing.swiping {
  user-select: none;
  -webkit-user-select: none;
}

/* Prevent the actions layer from stealing pointer events during an active swipe. */
.swipe-wrap:has(.swiping) .swipe-actions {
  pointer-events: none;
}

/* Deck cards inside swipe containers use the same swipe behaviour as sessions. */
.swipe-wrap .deck-card {
  cursor: pointer;
  position: relative;
  z-index: 1;
  transition: transform 0.2s ease;
  margin: 0;
}
.swipe-wrap .deck-card.swiping { transition: none; }
.swipe-wrap .deck-card.snapping { transition: transform 0.2s ease; }
.source-card.status-accepted { border-left: 4px solid #2da44e; }
.source-card.status-preview { border-left: 4px solid #d29922; }
.source-card.status-rejected { border-left: 4px solid #cf222e; }
.source-card.status-pending { border-left: 4px solid #57606a; }
.source-card.status-pending.active { background: #f6f8fa; border-left-color: #0969da; }
.source-card .source-status-line { margin: 6px 0 4px; }
.plus-cards { color: #2da44e; font-weight: 600; margin-left: 8px; }
.source-card .meta .plus-cards { margin-left: 0; }
#layout-tree .plus-cards { font-size: 0.8rem; }

/* Task 253gn: a preview source card's discard action is a COMPACT inline link,
   not the oversized swipe-to-delete button. Preview cards show title + preview +
   Accept/Keep (253fs); this small Reject replaces the giant delete. */
.source-card .reject-source {
  font-size: 0.8rem;
  padding: 3px 8px;
  margin-left: auto;
  background: transparent;
  color: #cf222e;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
}
.source-card .reject-source:hover { background: #fff0f0; border-color: #ffb3b3; }

/* Task 253fs: reconstructed-text preview snippet on a preview-state source card.
   A preview source now shows its TITLE + a text preview + an Accept/Keep action
   instead of an empty box with only DELETE. */
.reconstructed-preview {
  margin: 6px 0 4px;
  padding: 8px 10px;
  background: #f6f8fa;
  border: 1px solid #e1e4e8;
  border-radius: 6px;
  font-size: 0.85rem;
  color: #444;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  max-height: 120px;
  overflow-y: auto;
}

/* Badges */
.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 12px;
  background: #eef1f4;
  font-size: 0.8rem;
  margin-left: 8px;
}

/* Layout */
.session-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 20px;
}
/* Task 253fq (verify fix): a grid item's default `min-width:auto` resolves to its
   min-content width, so #session-main (which holds the upload panels) sizes the
   track past the viewport on narrow screens. Allow grid children to shrink. */
.session-layout > * {
  min-width: 0;
}
#session-main {
  min-width: 0;
}
#session-sidebar {
  border-right: 1px solid #e1e4e8;
  padding-right: 16px;
}
#layout-tree .layout-chapter { margin: 6px 0; }
#layout-tree .layout-header { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
#layout-tree .layout-arrow { cursor: pointer; width: 18px; text-align: center; user-select: none; font-size: 1.1rem; }
#layout-tree .layout-toggle { cursor: pointer; }
/* Task 253fg: long layout titles wrap inside the flex row instead of pushing the
   delete × (margin-left:auto) off the right edge on narrow screens. */
#layout-tree .layout-title {
  font-weight: 600;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
#layout-tree .layout-lesson .layout-title { font-weight: 400; color: #444; }
/* Task 253nc: tighten the point header row so it sits close to its cards
   (was over-spaced — the header floated above its box list). */
#layout-tree .layout-point { display: flex; align-items: center; gap: 4px; margin: 0 0 0 20px; }
#layout-tree .layout-point .layout-title { color: #555; font-size: 0.95rem; font-weight: 400; }
#layout-tree .layout-children { margin-left: 18px; }
#layout-tree .layout-children.collapsed { display: none; }
#layout-tree .layout-cb { margin: 0 4px; }
#layout-tree .layout-lesson { margin: 4px 0; }
#layout-tree button.small { font-size: 0.75rem; padding: 2px 6px; }
#layout-tree .delete-node-btn {
  font-size: 0.85rem;
  padding: 0 4px;
  line-height: 1;
  color: #cf222e;
  background: transparent;
  border: none;
  margin-left: auto;
  flex-shrink: 0; /* Task 253fg: the × stays whole; the title shrinks instead. */
}
#layout-tree .delete-node-btn:hover { background: #ffebe9; border-radius: 4px; }
/* Task 253jz: draggable card boxes in the layout tree + the unmapped inbox. */
#layout-tree .layout-card-boxes,
.layout-inbox-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 4px 0 8px 20px;
  min-height: 12px;
  border-radius: 6px;
  padding: 2px;
}
/* Task 253nc: a point's card boxes sit directly under its header (no extra
   top gap) so the header and its cards read as one unit. */
#layout-tree .layout-children > .layout-card-boxes { margin-top: 0; }
#layout-tree .layout-card-boxes.drop-target,
.layout-inbox-list.drop-target {
  outline: 2px dashed #0969da;
  background: #eaf3ff;
}
.layout-card-box {
  border: 1px solid #d0d7de;
  border-left: 3px solid #0969da;
  background: #fff;
  border-radius: 6px;
  padding: 5px 7px;
  cursor: grab;
  font-size: 0.78rem;
  line-height: 1.3;
  overflow: hidden;
  /* Task 253lk: card interaction surfaces kill text selection + iOS callout so
     a hold/sweep gesture never selects text; editors stay selectable below.
     Native scroll is preserved (pan-y compromise) — sweep-select only engages
     within selection mode. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: pan-y;
}
/* Task 253lk: editors remain selectable even inside selection surfaces. */
input, textarea, [contenteditable="true"] {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}
.layout-card-box:hover { background: #f6f8fa; }
.layout-card-box:focus-visible { outline: 2px solid #0969da; outline-offset: 1px; }
.layout-card-box.dragging { opacity: 0.45; }
.layout-card-box.drop-target { border-top: 3px solid #0969da; }
/* Task 253mu: the chapter/lesson/point top+bottom drop-highlight BANDS are
   REMOVED (they caused vanish + wrong-parent bugs). Drop feedback is exactly two
   forms: the 2px insertion line (sibling) and the container fill + 'Into [name]'
   label (child) below. */
/* Task 253me: container body = child placement — a soft fill + 'Into [name]'
   label after the 250-350ms dwell; only the current valid target highlights. */
.drop-into {
  outline: 2px solid #0969da;
  background: #dbeafe;
}
.drop-into-label {
  display: none;
  position: absolute;
  top: -20px;
  left: 8px;
  padding: 1px 8px;
  border-radius: 4px;
  background: #0969da;
  color: #fff;
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  z-index: 6;
}
.drop-into-label.visible { display: block; }
.layout-card-box .card-box-q {
  font-weight: 600;
  color: #24292f;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: anywhere;
}
.layout-card-box .card-box-a {
  margin-top: 2px;
  color: #57606a;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: anywhere;
}
/* Task 253mj: source chip ('from <source>') + image indicator on session cards. */
.card-source-chip {
  display: inline-block;
  margin-top: 3px;
  padding: 0 6px;
  border-radius: 8px;
  background: #eef1f4;
  color: #57606a;
  font-size: 0.66rem;
  line-height: 1.5;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.card-has-image {
  font-size: 0.72rem;
  vertical-align: middle;
  color: #57606a;
}
/* Task 253mq: the image indicator is a REAL preview thumbnail (not an emoji). */
.card-has-image img {
  display: inline-block;
  width: 20px;
  height: 20px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid #d0d7de;
  vertical-align: middle;
  margin-left: 4px;
}
.layout-inbox { margin-top: 12px; border-top: 1px solid #e1e4e8; padding-top: 8px; }
.layout-inbox h4 { margin: 0 0 4px; }
.layout-inbox.empty .hint { display: none; }
.layout-inbox-list { margin-left: 0; min-height: 40px; background: #f6f8fa; }

/* Sub-panels */
.sub-panel { padding-top: 12px; }

/* Task 253nr: STICKY session navigation. The sub-tab bar (Sources / Upload /
   Decks / Review & export) stays visible while scrolling within a session, and a
   compact sticky generate footer keeps Generate layout / Generate deck reachable
   without scrolling back to the top. Mobile-first: `-webkit-sticky` for iOS
   Safari, solid background so content never bleeds through, z-index below the
   modals (100). */
#session-main .sub-tabs {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 30;
  background: #fff;
  padding: 8px 0;
  margin: 0 0 12px;
  border-bottom: 1px solid #e1e4e8;
}
.sticky-generate-bar {
  position: -webkit-sticky;
  position: sticky;
  bottom: 0;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  align-items: center;
  padding: 10px 0;
  margin-top: 12px;
  background: #fff;
  border-top: 1px solid #e1e4e8;
}
/* The sticky footer never overlaps the selection toolbar / drop-to-delete zone:
   those only appear in selection mode, and the footer is hidden then. */
.sticky-generate-bar.hidden { display: none; }

/* Upload */
.upload-card h4 { margin-top: 0; }
.upload-card label { display: block; margin: 8px 0; }
.upload-card select, .upload-card input[type="file"] { margin-top: 4px; }
.upload-method-panel { margin-top: 12px; }
.upload-method-panel textarea { width: 100%; max-width: 600px; }
#upload-result { white-space: pre-wrap; background: #f6f8fa; padding: 8px; border-radius: 6px; }

/* Preview */
#preview-text {
  width: 100%;
  font-family: monospace;
  font-size: 0.95rem;
  padding: 12px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
}
#preview-cutouts { margin-top: 12px; }
.cutout { padding: 8px; background: #f6f8fa; border-radius: 6px; margin: 6px 0; }
.cutout .label { font-weight: 600; }
.cutouts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 8px;
}
.cutout-thumb {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  margin-top: 6px;
  border: 1px solid #d0d7de;
}
.cutout-overlay-thumb {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  margin-top: 6px;
  border: 1px solid #e6a700;
}
.cutout-caption {
  color: #444;
  font-size: 0.9rem;
  margin-top: 4px;
}
.cutout-code {
  margin-top: 8px;
  font-size: 0.85rem;
}
.cutout-code pre {
  margin-top: 6px;
  max-height: 200px;
  overflow-y: auto;
}

/* Study */
#study-card {
  background: #f6f8fa;
  padding: 24px;
  border-radius: 6px;
  min-height: 160px;
  margin-bottom: 12px;
  cursor: pointer;
}
#study-card .front { font-size: 1.4rem; font-weight: 600; }
#study-card .back { margin-top: 16px; font-size: 1.2rem; color: #222; }
#study-buttons button { margin-right: 8px; }

/* Full-screen study overlay */
#study-overlay {
  position: fixed;
  inset: 0;
  background: #fff;
  z-index: 200;
  display: flex;
  flex-direction: column;
  padding: 24px;
  overflow-y: auto;
}
.study-overlay-content {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  flex: 1;
}
#study-overlay-card {
  background: #f6f8fa;
  padding: 40px;
  border-radius: 8px;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  margin: 16px 0;
  cursor: pointer;
}
#study-overlay-card .front { font-size: 2rem; font-weight: 600; }
#study-overlay-card .back { margin-top: 24px; font-size: 1.5rem; color: #222; }
#study-show-answer {
  padding: 14px 24px;
  font-size: 1.1rem;
  margin-bottom: 12px;
}
#study-overlay-buttons button { margin-right: 8px; }
#study-overlay-buttons.hidden { display: none; }
/* Task 253kb: Anki-style card images — shrink to FIT, preserve aspect ratio,
   never natural size. Centered, capped at 90vh so the answer stays reachable. */
.study-image { width: 100%; display: flex; justify-content: center; }
.study-image img,
#study-overlay-card img,
#study-card img {
  display: block;
  max-width: 100%;
  max-height: 90vh;
  width: auto;
  height: auto;
  object-fit: contain;
  margin: 8px auto;
}
/* Task 253kb: tap/click a card image → full-screen, zoomable viewer. */
.card-image-viewer {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: rgba(0, 0, 0, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  overflow: auto;
  cursor: zoom-out;
}
.card-image-viewer img {
  max-width: 100%;
  max-height: 95vh;
  width: auto;
  height: auto;
  object-fit: contain;
  background: #fff;
  border-radius: 4px;
  cursor: zoom-out;
}
.card-image-viewer-close {
  position: fixed;
  top: 10px;
  right: 14px;
  z-index: 401;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.9);
  color: #111;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
/* Task 253gz: the rating-scheme selector sits in the study toolbar. */
.study-scheme-selector {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: #555;
}
.study-scheme-selector select { max-width: 220px; }
.hint { color: #666; font-size: 0.9rem; }
.loading-status { color: #666; font-size: 0.9rem; margin-left: 8px; }
/* Task 253mw: generate-layout status line (error + Retry affordance). */
.generate-layout-status { color: #666; font-size: 0.9rem; margin: 6px 0; }
.generate-layout-status p { margin: 0 0 6px; }
.generate-layout-status button.secondary { margin-top: 2px; }
.field-error { color: #d32f2f; font-size: 0.85rem; margin-left: 8px; }
.import-deck-label { display: inline-block; }
.import-deck-label input[type="file"] { display: none; }
/* Task 253ev fix-loop (Blocker 2): pre-import preview panel. */
.import-preview {
  border: 1px solid #d0d7de;
  border-left: 4px solid #0969da;
  border-radius: 8px;
  padding: 10px 12px;
  margin: 10px 0;
  background: #f6f8fa;
  font-size: 0.9rem;
}
.import-preview-title { margin-bottom: 4px; }
.import-preview-meta { color: #555; font-size: 0.85rem; }
.import-preview-quality { margin-top: 6px; }
.import-preview-quality.ok { color: #1a7f37; }
.import-preview-ambiguous {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 6px;
  background: #fff8c5;
  border: 1px solid #d4a72c;
}
.import-preview-near-dup { margin-top: 8px; }
.import-preview-near-dup ul { margin: 4px 0 0 18px; padding: 0; }
.spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid #d0d7de;
  border-top-color: #0969da;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin-right: 6px;
  vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }
button:disabled, button.disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* Buttons */
button {
  padding: 8px 14px;
  cursor: pointer;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  background: #f6f8fa;
}
button:hover { background: #eef1f4; }
button.primary { background: #2da44e; color: #fff; border-color: #2da44e; }
button.primary:hover { background: #2c974b; }
button.danger { background: #cf222e; color: #fff; border-color: #cf222e; }
button.danger:hover { background: #b91c27; }
button.secondary { background: transparent; }

input[type="file"], input[type="text"], select, textarea {
  padding: 6px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  margin-right: 8px;
}
.choice-group { margin: 12px 0; }
.choice-group label { display: block; margin: 6px 0; }

pre {
  background: #f6f8fa;
  padding: 12px;
  border-radius: 6px;
  overflow-x: auto;
}

@media (max-width: 800px) {
  /* Task 253fq (verify fix): `1fr` == `minmax(auto, 1fr)`, whose `auto` min lets
     #session-main's min-content (native file input + padding) blow the track
     past the viewport. `minmax(0, 1fr)` lets the single column shrink to fit. */
  .session-layout { grid-template-columns: minmax(0, 1fr); }
  #session-sidebar { border-right: none; border-bottom: 1px solid #e1e4e8; padding-bottom: 16px; }
}

/* Modal */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}
.modal-content {
  background: #fff;
  padding: 20px;
  border-radius: 8px;
  max-width: 520px;
  width: 90%;
  box-shadow: 0 8px 24px rgba(0,0,0,0.15);
  /* Task 253je: a fixed overlay had no scroll path for tall content (the metrics
     modal's raw JSON ran off the viewport). Bound the modal and scroll it so the
     footer actions stay reachable. Modal-wide — all consumers benefit. */
  max-height: 85vh;
  overflow-y: auto;
}
.modal-content h3 { margin-top: 0; }
.overlap-list {
  background: #f6f8fa;
  padding: 12px;
  border-radius: 6px;
  max-height: 180px;
  overflow-y: auto;
  font-size: 0.9rem;
}
.overlap-list li { margin: 6px 0; }
#conflict-options label { display: block; margin: 8px 0; }
#conflict-options input { margin-right: 6px; }

/* Review popup */
.review-modal-content {
  max-width: 700px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Task 253fv: the tab panels scroll in one body while the action footer is a
   sticky footer that stays visible at the popup's bottom in ANY tab. */
.review-body {
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
}
.review-footer {
  flex-shrink: 0;
  position: sticky;
  bottom: 0;
  background: #fff;
  border-top: 1px solid #d0d7de;
  padding-top: 8px;
  margin-top: 8px;
}
#review-text { width: 100%; font-family: monospace; font-size: 0.95rem; padding: 12px; border: 1px solid #d0d7de; border-radius: 6px; }
#review-cutouts { margin-top: 12px; }
#review-resolution { margin-top: 12px; padding: 12px; background: #f6f8fa; border-radius: 6px; }
#review-resolution label { display: block; margin: 8px 0; }
#review-resolution input { margin-right: 6px; }
/* Task 253ft: forced review/confirm choices (Layout only vs Keep content). */
.review-forced-choices {
  margin-top: 12px;
  padding: 12px;
  background: #f6f8fa;
  border: 1px solid #d0d7de;
  border-radius: 6px;
}
.review-forced-choices .hint { margin-top: 0; }
.review-forced-choices .toolbar { margin-bottom: 0; }
/* Task 253gt: in-popup card-generation progress bar (accept → Keep content). */
.review-card-gen-progress {
  margin-top: 12px;
  padding: 12px;
  background: #f6f8fa;
  border: 1px solid #d0d7de;
  border-radius: 6px;
}
.review-card-gen-progress .review-card-gen-status {
  font-size: 0.85rem;
  color: #444;
  margin-bottom: 6px;
}
.review-card-gen-progress .toolbar { margin-top: 8px; margin-bottom: 0; }
.layout-state-badges { display: inline-flex; gap: 4px; margin-left: 6px; }
.layout-state-badges .badge { font-size: 0.75rem; padding: 1px 6px; }

/* Review tabs */
.review-tabs { display: flex; gap: 4px; margin: 12px 0; border-bottom: 1px solid #d0d7de; }
.review-tab-btn {
  padding: 8px 14px;
  border: 1px solid transparent;
  border-bottom: none;
  background: transparent;
  border-radius: 6px 6px 0 0;
  cursor: pointer;
}
.review-tab-btn.active {
  background: #fff;
  border-color: #d0d7de;
  font-weight: 600;
  margin-bottom: -1px;
}
.review-panel { margin-bottom: 12px; }

/* Transcription preview + uncertain-word highlighting */
.transcription-preview {
  white-space: pre-wrap;
  background: #f6f8fa;
  padding: 12px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  margin-top: 8px;
  min-height: 60px;
  max-height: 240px;
  overflow-y: auto;
  font-family: monospace;
  font-size: 0.95rem;
}
.uncertain {
  background: #fff8c5;
  padding: 1px 3px;
  border-radius: 4px;
  font-weight: 600;
}

/* Audit table */
.audit-table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 0.9rem; }
.audit-table th, .audit-table td {
  border: 1px solid #d0d7de;
  padding: 8px;
  text-align: left;
  vertical-align: top;
}
.audit-table th { background: #f6f8fa; }
.audit-answer {
  min-width: 120px;
  background: #fff;
  border: 1px dashed #d0d7de;
  border-radius: 4px;
  padding: 4px;
}
.audit-answer:focus { outline: 2px solid #0969da; background: #f6f8fa; }
.audit-gap {
  margin-top: 6px;
  padding: 6px;
  background: #fff8c5;
  border-radius: 4px;
  font-size: 0.85rem;
}

/* Coverage checklist + preview cards */
.coverage-checklist { margin: 8px 0; }
.coverage-checklist h4, .boundary-variants h4, .preview-cards h4 { margin: 12px 0 6px; }
.coverage-item {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  padding: 4px 0;
  border-bottom: 1px solid #eef1f4;
}
.coverage-item input { margin-top: 4px; }
.coverage-type {
  font-size: 0.75rem;
  text-transform: uppercase;
  background: #ddf4ff;
  color: #0969da;
  padding: 1px 5px;
  border-radius: 10px;
  margin-left: auto;
  white-space: nowrap;
}
.boundary-variants { margin: 12px 0; padding: 10px; background: #f6f8fa; border-radius: 6px; }
.variant-item { display: flex; align-items: flex-start; gap: 6px; margin: 6px 0; }
.variant-item input { margin-top: 3px; }
.preview-cards { margin-top: 12px; }
.preview-card {
  border: 1px solid #d0d7de;
  border-radius: 6px;
  padding: 10px;
  margin: 8px 0;
  background: #fff;
}
.preview-card .front { font-weight: 600; margin-bottom: 6px; }
.preview-card .back { color: #444; }
.preview-card .meta { font-size: 0.8rem; color: #666; margin-top: 4px; }

.deck-editor-content {
  max-width: 640px;
  max-height: 80vh;
  padding: 0;
  /* Task 253ba: header and footer stay stationary at the top/bottom; only the
     card list scrolls. Buttons are not sticky/floating and do not scroll away. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.deck-editor-header {
  background: #fff;
  padding: 20px 20px 0;
  flex-shrink: 0;
}
.deck-editor-header h3 { margin-top: 0; }
.deck-editor-body {
  padding: 0 20px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Task 253cm: iOS Safari does not scroll a fixed-position flex child without
     momentum scrolling + an explicit pan-y touch action. */
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
.deck-editor-footer {
  background: #fff;
  padding: 20px 20px 20px;
  flex-shrink: 0;
  border-top: 1px solid #e1e4e8;
}
.deck-editor-row {
  display: grid;
  /* Task 253mh: FRONT/BACK get a ~40% MINIMUM each so neither collapses to one
     character per line; the Delete button keeps its auto slot. */
  /* Task 253mr: the 40% minimums + a 72px Delete button overflowed the row on
     narrow phones. Allow the columns to shrink (text wraps via overflow-wrap)
     while keeping the Delete button's auto slot fixed and un-clipped. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 8px;
  align-items: start;
  margin: 8px 0;
  padding: 10px;
  background: #f6f8fa;
  border-radius: 6px;
  min-width: 0;
}
/* Task 253dm: rows are READ-ONLY summaries; clicking a row opens the front/back
   edit popup at #/study/deck/{id}/card/{cardId}. */
.deck-editor-row { cursor: pointer; }
/* Task 253mh: dragging a row must not select its text. */
.deck-editor-row {
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.deck-editor-row .row-front, .deck-editor-row .row-back {
  word-break: break-word;
  /* Task 253dw: the row content must NOT trap the wheel — the modal body is the
     only internal scroller, so rows grow and the body scrolls. */
  overflow: visible;
  min-height: 24px;
  font-size: 0.95rem;
  /* Task 253mr: let the front/back columns shrink so the Delete button always
     fits (never overflows the row on a narrow phone). */
  min-width: 0;
}
/* Task 253mh: bounded 3-line preview + ellipsis; full text stays editable in the
   popup editor (the row itself is read-only). */
.deck-editor-row .row-front-text,
.deck-editor-row .row-back-text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: normal;
  overflow-wrap: anywhere;
}
.deck-editor-row .row-label { display: block; font-size: 0.7rem; color: #888; text-transform: uppercase; }
.deck-editor-row.new-row { background: #fff8c5; }
/* Task 253kb: per-side image indicator (thumbnail + badge) in the edit-cards list. */
.row-image-badges { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; }
.card-row-image-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px 1px 2px;
  border: 1px solid #d0d7de;
  border-radius: 10px;
  background: #eef1f4;
  color: #57606a;
  font-size: 0.68rem;
  line-height: 1.4;
}
.card-row-image-badge img {
  width: 20px;
  height: 20px;
  object-fit: cover;
  border-radius: 8px;
  display: block;
}
/* Task 253eg: EVERY row (saved or new) shows the editable input-box affordance
   so users know all rows are clickable; new rows keep the yellow pending tint
   on the row background only. */
.deck-editor-row .row-front, .deck-editor-row .row-back {
  border: 1px solid #d0d7de;
  background: #fff;
  border-radius: 6px;
  padding: 6px;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.04);
}
/* Task 253ja: per-row failure annotation (shown only when a Save change fails). */
.deck-editor-row .row-error {
  grid-column: 1 / -1;
  color: #b42318;
  font-size: 0.8rem;
  font-weight: 600;
}
/* Task 253ja: per-side image upload status line + inline save summary. */
.card-edit-image-status {
  display: block;
  font-size: 0.8rem;
  color: #57606a;
  min-height: 1em;
  margin-top: 2px;
}
#deck-editor-save-status { color: #b42318; }

/* Front/back edit popup (Task 253dm). The popup fields scroll within the popup
   on all devices; the popup never traps the card-list scroll. */
.card-edit-popup-content {
  max-width: 560px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.card-edit-fields {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
.card-edit-fields textarea {
  width: 100%;
  min-height: 80px;
  resize: vertical;
  overflow-y: auto;
}
.card-edit-fields label { display: block; margin: 10px 0; font-weight: 600; }
.card-edit-footer { flex-shrink: 0; display: flex; gap: 8px; justify-content: flex-end; padding-top: 10px; }
/* Task 253ic: card image file-upload picker + preview thumbnail. */
.card-edit-image-file { display: block; margin-top: 4px; font-weight: 400; }
.card-edit-image-preview { display: block; max-width: 100%; max-height: 160px; margin-top: 6px; border: 1px solid #d0d7de; border-radius: 6px; }

/* Uniform per-card Delete button inside the deck editor (Task 253ar). */
.deck-delete-btn {
  width: 72px;
  min-height: 36px;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.2;
  background: #cf222e;
  color: #fff;
  border: 1px solid #cf222e;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
}
.deck-delete-btn:hover { background: #b91c27; border-color: #b91c27; }
.deck-delete-btn:active { background: #9e1b23; border-color: #9e1b23; }
.deck-delete-btn:focus-visible { outline: 2px solid #0969da; outline-offset: 2px; }

/* Language selector (Task 253bk): searchable filter above the dropdown. */
.language-filter {
  display: block;
  width: 100%;
  margin: 4px 0;
  padding: 6px 8px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  font-size: 0.9rem;
}
.new-textbook-dialog select,
.session-language-control select {
  max-height: 220px;
  overflow-y: auto;
}

/* ── Create-textbook dialog (Task 253et) ──────────────────────────────────── */
/* Every field owns its label; "Language:" sits ABOVE its own control instead of
   wrapping to the right of the title input. */
.new-textbook-dialog .create-field-row { margin: 10px 0; }
/* Task 253jw: the session-type <select> must never overflow its box on mobile
   (the long option label used to push past the dialog edge, IMG_9469). */
.new-textbook-dialog .create-session-mode-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-width: 0;
}
.new-textbook-dialog .new-session-mode {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  text-overflow: ellipsis;
}
.new-textbook-dialog .freeform-options { margin: 8px 0; }
.new-textbook-dialog .source-type-picker label { margin: 6px 0; }
.new-textbook-dialog .freeform-source-picker .field-label { margin-top: 8px; }
.new-textbook-dialog .field-label {
  display: block;
  font-weight: 600;
  margin-bottom: 4px;
}
.new-textbook-dialog .new-session-title {
  display: block;
  width: 100%;
  box-sizing: border-box;
}
/* ONE searchable real dropdown: the text input is the control, the list floats
   over the page and scrolls (never a separate search bar above a <select>). */
.language-combobox { position: relative; }
.language-combobox .language-filter { margin: 0; box-sizing: border-box; }
.language-selected-label {
  display: block;
  margin-top: 4px;
  font-weight: 600;
  color: #0969da;
}
.language-suggestions {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 2px);
  z-index: 30;
  max-height: 220px;
  overflow-y: auto;
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: #fff;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
.language-suggestion {
  padding: 8px 10px;
  cursor: pointer;
  font-size: 0.95rem;
}
.language-suggestion.active,
.language-suggestion:hover { background: #eaf3ff; }
.new-textbook-dialog .detect-title-status,
.new-textbook-dialog .detect-language-status {
  display: block;
  margin-top: 4px;
  font-size: 0.85rem;
  color: #57606a;
}
/* Task 253fd: the chosen filename must never overflow the dialog on narrow
   (mobile) screens — constrain the file input and word-wrap the staged-filename
   status line (which repeats the full filename). */
.new-textbook-dialog .textbook-file {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.new-textbook-dialog .textbook-file-status {
  display: block;
  margin-top: 4px;
  max-width: 100%;
  word-break: break-word;
  overflow-wrap: anywhere;
}
/* Task 253jh: deck-import option + the "Change file" replacement for a staged
   upload (native inputs can't be pre-filled, so the button + filename win). */
.new-textbook-dialog .deck-import-option {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 8px;
}
.new-textbook-dialog .deck-import-option label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.new-textbook-dialog .textbook-change-file { margin-left: 6px; }
.new-textbook-dialog .textbook-file.hidden { display: none; }
/* Task 253fd: a minimal upload-progress LINE (blue while uploading → green when
   done), not a full bar. */
.textbook-upload-progress {
  height: 3px;
  margin-top: 6px;
  border-radius: 2px;
  background: #e1e4e8;
  overflow: hidden;
}
.textbook-upload-progress-line {
  height: 100%;
  width: 0;
  background: #0969da;
  transition: width 0.2s ease, background-color 0.3s ease;
}
.textbook-upload-progress.done .textbook-upload-progress-line {
  background: #1a7f37;
  width: 100%;
}

/* Multiple staged create dialogs (Task 253df) */
.new-textbook-dialog { margin-bottom: 16px; }
#new-textbook-dialogs .new-textbook-dialog { display: block; }

/* Background jobs (Task 253bb) */
.jobs-panel { margin-top: 16px; padding: 12px; background: #f6f8fa; border: 1px solid #e1e4e8; border-radius: 6px; }
.jobs-panel h4 { margin-top: 0; }
.job-row { margin: 8px 0; }
.job-row .job-meta { font-size: 0.85rem; color: #444; }
/* Task 253du: background-jobs rows are swipe-wrapped (full swipe deletes). */
.swipe-wrap.job-swipe-wrap .job-row {
  position: relative;
  z-index: 1;
  background: #fff;
  border: 1px solid #e1e4e8;
  border-radius: 8px;
  padding: 8px 10px;
  margin: 0;
  transition: transform 0.2s ease;
}
.swipe-wrap.job-swipe-wrap .job-row.swiping { transition: none; }
.swipe-wrap.job-swipe-wrap .job-row.snapping { transition: transform 0.2s ease; }
.job-progress-track { background: #e1e4e8; border-radius: 10px; height: 10px; overflow: hidden; margin-top: 4px; }
.job-progress-fill { background: #0969da; height: 100%; border-radius: 10px; transition: width 0.3s ease; }
/* Task 253eq: before the first per-chunk progress lands (progress 0) the bar is
   indeterminate and visibly sweeps, so an import is never a frozen empty track.
   The backend then reports 10..90 per chunk and 100 on completion. */
.job-progress-fill.job-progress-indeterminate {
  width: 35%;
  animation: job-progress-sweep 1.2s ease-in-out infinite;
}
@keyframes job-progress-sweep {
  0% { margin-left: -35%; }
  100% { margin-left: 100%; }
}
/* Task 253dt: failed/retrying import cards get a red/amber bar (not a red card). */
.job-progress-fill.job-progress-failed { background: #cf222e; }
.job-progress-fill.job-progress-retry { background: #9a6700; }
.job-row.status-done .job-progress-fill { background: #1a7f37; }
.job-row.status-failed .job-progress-fill { background: #cf222e; }
.job-row.status-interrupted .job-progress-fill { background: #9a6700; }
.job-row.status-cancelled .job-progress-fill { background: #9a6700; }
/* Task 253ef (REGRESSION): the importing/failed deck card must be a NORMAL card
   (white background, full opacity) with only the progress bar signalling state.
   The previous `opacity: 0.85` let the red .swipe-actions layer show through
   the whole card — reading as a whole-red, see-through card. */
.deck-importing { opacity: 1; }
.job-cancel-btn { margin-left: 8px; font-size: 0.75rem; }

/* Session-card job progress (Task 253bs) */
.session-job-progress { margin-top: 8px; padding-top: 6px; border-top: 1px solid #e1e4e8; }
.session-job-row { margin: 4px 0; }
.session-job-row .job-meta { font-size: 0.8rem; color: #444; }

/* Session source sub-indicator (Task 253dl): x/y line + combined progress bar */
.session-sources-sub { margin-top: 6px; display: flex; align-items: center; gap: 8px; }
.session-sources-sub-count { font-size: 0.8rem; color: #444; white-space: nowrap; }
.session-sources-sub .job-progress-track { flex: 1; }

/* Upload block hint (Task 253dl/253es): ONE shared highlighted box, rendered
   BELOW its section for the typed AND handwritten sections alike. */
.upload-blocked-hint,
#upload-blocked-hint,
#upload-blocked-hint-handwritten {
  margin: 8px 0 16px;
  padding: 8px 10px;
  border: 1px solid #d0a000;
  background: #fff8e1;
  border-radius: 6px;
  font-weight: 600;
  /* Task 253fg: the long reconstructing banner wraps instead of spewing right. */
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* Pageable + zoom source viewer (Task 253do) */
.hw-input-viewer { margin-top: 10px; border: 1px solid #e1e4e8; border-radius: 8px; overflow: hidden; }
.source-viewer-stage {
  position: relative;
  height: 320px;
  overflow: auto;
  background: #2b2b2b;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  /* Wheel zoom is handled in JS (non-passive) so the page must not scroll-zoom. */
  touch-action: pan-x pan-y;
  -webkit-overflow-scrolling: touch;
}
.source-viewer-image {
  max-width: none;
  transform-origin: top center;
  transition: transform 0.08s linear;
  user-select: none;
  -webkit-user-drag: none;
}
.source-viewer-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: #f6f8fa;
  border-top: 1px solid #e1e4e8;
}
.source-viewer-controls input[type="number"] { width: 64px; }
#source-zoom-level { min-width: 48px; text-align: center; font-variant-numeric: tabular-nums; }

/* Task 253fu: standard recorder (record/pause/stop + timeline + duration). */
.hw-recorder { margin-top: 8px; }
.hw-recorder-timeline {
  height: 6px;
  background: #e1e4e8;
  border-radius: 3px;
  overflow: hidden;
}
.hw-recorder-progress {
  height: 100%;
  width: 0;
  background: #cf222e;
  border-radius: 3px;
  transition: width 0.25s linear;
}
.hw-recorder-meta {
  margin: 4px 0;
  font-size: 0.9rem;
  color: #444;
  font-variant-numeric: tabular-nums;
}

/* Subtype + transcript pairing in the typed upload flow (the handwritten
   "voice (with transcript)" subtype was removed from the UI in 253es). */
#typed-transcript-wrap {
  margin: 8px 0;
  padding: 10px;
  background: #f6f8fa;
  border-radius: 6px;
}
#typed-transcript-wrap label { display: block; }

/* Auth: login screen, user area, admin modal (Task 253ch) */
.login-screen {
  position: fixed;
  inset: 0;
  background: #f6f7f9;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.login-card {
  background: #fff;
  padding: 32px;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.1);
  width: 320px;
}
.login-card h1 { margin-bottom: 8px; }
.login-card form label { display: block; margin: 12px 0; }
.login-card form input {
  width: 100%;
  box-sizing: border-box;
  padding: 8px;
  margin-top: 4px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
}
.login-error {
  color: #cf222e;
  margin: 8px 0;
}
/* Task 253hr: social sign-in buttons (light theme, matches the login card). */
.oauth-divider {
  display: flex;
  align-items: center;
  margin: 14px 0 10px;
  color: #6e7781;
  font-size: 12px;
}
.oauth-divider::before,
.oauth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: #d0d7de;
}
.oauth-divider span { padding: 0 10px; }
.oauth-buttons {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.oauth-btn {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 12px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  font-size: 14px;
  color: #24292f;
}
.oauth-btn:hover { background: #f6f8fa; border-color: #afb8c1; }
/* Task 253jj: smean.ai-style split-screen auth (dark brand panel + form panel). */
.auth-split {
  width: 100%;
  min-height: 100vh;
  display: flex;
}
.auth-brand {
  flex: 1 1 45%;
  background: linear-gradient(160deg, #0d1117 0%, #13233f 100%);
  color: #e6edf3;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 48px;
  box-sizing: border-box;
}
.auth-brand-title {
  font-size: 1.8rem;
  margin: 0 0 12px;
  color: #ffffff;
}
.auth-brand-tagline {
  color: #9db2c8;
  font-size: 1.05rem;
  max-width: 380px;
  margin: 0 0 24px;
}
.auth-brand-points {
  list-style: none;
  margin: 0;
  padding: 0;
  color: #c9d6e5;
}
.auth-brand-points li {
  margin: 10px 0;
  padding-left: 22px;
  position: relative;
}
.auth-brand-points li::before {
  content: '✓';
  position: absolute;
  left: 0;
  color: #58a6ff;
}
.auth-panel {
  flex: 1 1 55%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 20px;
  background: #f6f7f9;
  box-sizing: border-box;
}
.auth-view {
  width: 100%;
  max-width: 360px;
}
.auth-view h2 {
  margin: 0 0 18px;
  font-size: 1.4rem;
  color: #24292f;
}
.auth-panel form label { display: block; margin: 12px 0; }
.auth-panel form input {
  width: 100%;
  box-sizing: border-box;
  padding: 8px;
  margin-top: 4px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  background: #fff;
  color: #24292f;
}
.auth-forgot-row {
  text-align: right;
  margin: 4px 0 8px;
}
.auth-forgot-row a,
.auth-switch a,
.auth-legacy a {
  color: #0969da;
  text-decoration: none;
  cursor: pointer;
}
.auth-submit {
  width: 100%;
  margin-top: 8px;
}
.auth-switch {
  margin-top: 14px;
  font-size: 0.9rem;
  color: #57606a;
}
.auth-legacy {
  margin-top: 4px;
  font-size: 0.82rem;
}
.login-sent {
  color: #2da44e;
  margin: 8px 0;
}
.email-verification-status {
  font-size: 0.82rem;
  padding: 2px 8px;
  border-radius: 10px;
}
.email-verification-status.email-verified {
  color: #2da44e;
  background: #e6ffec;
}
.email-verification-status.email-unverified {
  color: #9a6700;
  background: #fff8c5;
}
@media (max-width: 760px) {
  .auth-brand { display: none; }
}

/* Task 253hu: Top-up tab — balance meter + warning thresholds + packs. */
.topup-meter { max-width: 480px; margin-bottom: 16px; }
.topup-meter-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
/* Task 253jf: the wallet balance is a NUMBER, not a second monthly bar — the
   rolling usage limits (rendered by renderPlanLimitMeter) are the single meter. */
.topup-meter .meter-track { display: none; }
.payment-modal-content { width: 480px; max-width: 92vw; }
.payment-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 8px 0; }
.payment-row label { display: inline-flex; align-items: center; gap: 6px; }
.payment-row select, .payment-row input { padding: 6px; border: 1px solid #d0d7de; border-radius: 6px; }
#payment-qr { margin: 10px 0; text-align: center; }
#payment-qr canvas { border: 1px solid #e1e4e8; border-radius: 6px; }
#payment-qr .payment-qr-fallback { font-family: monospace; word-break: break-all; }
.meter-track {
  height: 10px;
  background: #d0d7de;
  border-radius: 6px;
  overflow: hidden;
}
.meter-fill {
  height: 100%;
  width: 0%;
  background: #2da44e;
  transition: width 0.2s ease;
}
.meter-fill.amber { background: #bf8700; }
.meter-fill.amber-red { background: #cf7a00; }
.meter-fill.red { background: #cf222e; }
.meter-fill.at-zero { background: #cf222e; }
/* Task 253ob: red overage text when a window is over its cap. */
.limit-over { color: #cf222e; font-weight: 700; }
.topup-at-zero {
  margin-top: 10px;
  padding: 10px;
  background: #fff8f8;
  border: 1px solid #cf222e;
  border-radius: 6px;
  color: #cf222e;
}
.topup-packs { display: flex; gap: 12px; flex-wrap: wrap; margin: 12px 0; }
.topup-pack {
  padding: 12px;
  min-width: 150px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.topup-plans {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin: 8px 0 12px;
}
.topup-plan {
  padding: 12px;
  min-width: 180px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.topup-plan.current { border-color: #2da44e; background: #f6fff8; }
/* Task 253kd: outcome framing — the "≈N textbooks/month" line is the primary
   meter; credits are secondary. */
.plan-outcome {
  display: block;
  font-size: 1.1rem;
  font-weight: 600;
  color: #0969da;
}
.credit-pause-content { max-width: 460px; }
.credit-pause-countdown {
  margin: 10px 0;
  padding: 10px;
  background: #fff8c5;
  border: 1px solid #d4a72c;
  border-radius: 6px;
  font-weight: 600;
}
.credit-pause-actions { flex-wrap: wrap; }
/* Task 253kn/253kl/253lc: universal box selection + drag reorder. */
.box-select-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin: 8px 0;
}
.box-select-bar button { min-height: 30px; }
.box-select-count { color: #57606a; }
.layout-select-bar {
  padding: 6px;
  background: #f6f8fa;
  border: 1px solid #d0d7de;
  border-radius: 6px;
}
/* Task 253lp: destructive bulk delete is a compact secondary action in its own
   toolbar, never next to Generate layout. */
.layout-selection-toolbar {
  padding: 4px 6px;
  background: #fff;
  border: 1px dashed #d0d7de;
  border-radius: 6px;
}
.layout-selection-toolbar .icon-btn {
  min-height: 26px;
  padding: 2px 8px;
  font-size: 0.85em;
}
button.secondary.danger-o {
  color: #cf222e;
  border-color: #cf222e;
  background: #fff;
}
button.secondary.danger-o:hover { background: #ffebe9; }
/* Task 253mc: dashed delete drop-zone (accepts dropped selected cards). */
.delete-dropzone {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border: 2px dashed #cf222e;
  border-radius: 6px;
  color: #cf222e;
  font-size: 0.85em;
  cursor: pointer;
  background: #fff;
  user-select: none;
  -webkit-user-select: none;
}
.delete-dropzone.drag-over {
  background: #ffebe9;
  border-color: #a40e26;
}
.delete-cards-modal-content { max-width: 420px; }
.delete-cards-modal-content #delete-cards-message { margin: 8px 0 12px; }
/* Task 253mk: the destructive-confirm modal sits EARLIER in the DOM than the
   deck/session/card-editor modals it confirms from, so same-z-index stacking
   rendered it BEHIND them. Pin it frontmost so Delete-confirm is always visible
   and Cancel leaves the underlying modal fully usable. */
#delete-cards-modal { z-index: 1000; }
#card-edit-popup { z-index: 900; }
/* 253lc: the always-visible checkbox is GONE. Selection mode reserves a gutter
   for the checkmark so it never covers the card text (absorbs 253kw item 2). */
.box-selection-mode .session-card,
.box-selection-mode .deck-card,
.box-selection-mode .deck-editor-row,
.box-selection-mode .layout-card-box {
  padding-left: 34px;
  /* Task 253nb: text selection disabled while selecting/dragging boxes (a
     hold/sweep gesture must never select text). */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.session-card.dragging,
.deck-card.dragging {
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
/* The user's design: a colored vertical streak on the LEFT edge of a selected
   box, plus a checkmark (never colour alone — M3 a11y). */
.session-card.box-selected,
.deck-card.box-selected,
.deck-editor-row.box-selected,
.layout-card-box.box-selected {
  box-shadow: inset 4px 0 0 #0969da;
  background-color: #eef5ff;
}
.box-selected::before {
  content: "✓";
  position: absolute;
  left: 8px;
  top: 8px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #0969da;
  color: #fff;
  font-size: 12px;
  line-height: 18px;
  text-align: center;
  z-index: 4;
}
/* Task 253mg: the dedicated drag GRIP is removed. The whole box body is the
   drag surface (a SELECTED box drags its whole selection); an unselected drag
   stays native scroll. */
.dragging { opacity: 0.85; }
/* Task 253nq: toggled onto the dragged box + list container DURING a drag to kill
   text selection and the iOS callout on WebKit (removed on cleanup). */
.is-dragging {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/* Task 253nu: the no-select class kills text selection + the iOS callout on the
   list CONTAINER while selection mode is active (same pattern as is-dragging). */
.no-select {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/* Task 253oc: transient, visible reorder-persist failure (fail loud — never a
   silent inconsistency or hidden boxes). */
.box-reorder-error {
  margin: 6px 0;
  padding: 8px 12px;
  border: 1px solid #cf222e;
  border-radius: 6px;
  background: #ffebe9;
  color: #a40e26;
  font-size: 0.9em;
}
.drag-lift { z-index: 20; box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18); }
/* Task 253mf: the source DIMMS IN PLACE while dragging (no hidden/ghost box and
   no stack-sized placeholder gap). */
.drag-origin { opacity: 0.4; }
.drag-preview {
  opacity: 0.96;
  border-radius: 8px;
  background: #fff;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}
/* Task 253me: 2px insertion line = sibling placement (before/after). */
.drag-insert-line {
  height: 2px;
  margin: 2px 0;
  border-radius: 1px;
  background: #0969da;
  box-shadow: 0 0 0 1px #0969da;
  pointer-events: none;
}
/* Task 253mf: one compact preview + 'N selected' count, offset from the finger. */
.drag-preview .drag-selection-count {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 10px;
  background: #0969da;
  color: #fff;
  font-size: 11px;
  font-weight: 600;
}
.drag-settle { transition: transform 0.18s ease, box-shadow 0.18s ease; }
.drag-count-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: #0969da;
  color: #fff;
  font-size: 11px;
  line-height: 20px;
  text-align: center;
  z-index: 6;
}
.drag-over { outline: 2px dashed #0969da; outline-offset: 2px; }
/* Task 253mf ADDENDUM 2: a tick checkbox on EVERY box while in selection mode.
   Hidden outside selection mode; a checked state follows .box-selected. */
.box-select-tick {
  display: none;
  position: absolute;
  left: 8px;
  top: 8px;
  width: 18px;
  height: 18px;
  border: 2px solid #0969da;
  border-radius: 4px;
  background: #fff;
  box-sizing: border-box;
  z-index: 4;
  pointer-events: none;
}
.box-selection-mode .box-select-tick { display: block; }
/* Task 253nh: in selection mode the tick checkbox must not obscure the card
   text — pad the layout card content clear of the top-left tick. */
.box-selection-mode .layout-card-box { padding-left: 30px; }
.box-select-tick.checked::after {
  content: "✓";
  position: absolute;
  inset: 0;
  color: #0969da;
  font-size: 13px;
  line-height: 14px;
  text-align: center;
  font-weight: 700;
}
.session-card,
.deck-card,
.deck-editor-row,
.layout-card-box {
  position: relative;
}
.topup-usage-history { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.usage-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px solid #f0f3f6;
  font-size: 0.9rem;
}
.cost-preview { margin-top: 8px; }
.topup-plan .hint { margin: 0; }
.topup-custom { margin: 12px 0; display: flex; gap: 12px; align-items: center; }
.topup-custom input { width: 100px; padding: 6px; border: 1px solid #d0d7de; border-radius: 6px; }
#topup-qr {
  margin-top: 12px;
  padding: 12px;
  background: #f6f8fa;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  font-family: monospace;
}
.user-area {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Task 253jm: UI-chrome language picker. */
.ui-language-control {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: #57606a;
}
.ui-language-control select { padding: 4px 6px; border: 1px solid #d0d7de; border-radius: 6px; }
.logged-in-user {
  font-weight: 600;
  color: #0969da;
}
.admin-modal-content {
  width: 460px;
  max-width: 92vw;
}
/* Task 253np: pin the metrics Close button in a dedicated fixed footer,
   completely separated from the scrollable metrics content so it never scrolls
   with the page and never overlaps metrics data. */
#metrics-modal .admin-modal-content {
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  overflow: hidden;
  padding: 0;
}
#metrics-modal .admin-modal-content h3 {
  margin: 0;
  padding: 18px 20px 14px;
  border-bottom: 1px solid #e1e4e8;
  flex-shrink: 0;
}
#metrics-modal .metrics-content {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 20px;
}
#metrics-modal .toolbar {
  flex-shrink: 0;
  position: sticky;
  bottom: 0;
  background: #fff;
  padding: 12px 20px;
  border-top: 1px solid #e1e4e8;
  margin: 0;
  display: flex;
  justify-content: flex-end;
  z-index: 10;
}

#admin-modal .admin-modal-content {
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  overflow: hidden;
  padding: 0;
}
#admin-modal .admin-modal-content h3 {
  margin: 0;
  padding: 18px 20px 14px;
  border-bottom: 1px solid #e1e4e8;
  flex-shrink: 0;
}
#admin-modal .admin-create {
  padding: 14px 20px 8px;
  margin: 0;
  flex-shrink: 0;
}
#admin-modal #admin-users-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 8px 20px;
}
#admin-modal .toolbar {
  flex-shrink: 0;
  position: sticky;
  bottom: 0;
  background: #fff;
  padding: 12px 20px;
  border-top: 1px solid #e1e4e8;
  margin: 0;
  display: flex;
  justify-content: flex-end;
  z-index: 10;
}
/* Task 253je: admin metrics rendered as labeled rows + tables + collapsible JSON. */
.metrics-content { display: flex; flex-direction: column; gap: 14px; }
.metrics-section h4 { margin: 0 0 6px; }
.metrics-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 0;
  border-bottom: 1px solid #f0f3f6;
}
.metrics-label { color: #57606a; text-transform: capitalize; }
.metrics-value { font-variant-numeric: tabular-nums; font-weight: 600; }
.metrics-table { width: 100%; border-collapse: collapse; margin: 6px 0; font-size: 0.85rem; }
.metrics-table th, .metrics-table td { text-align: right; padding: 4px 6px; border-bottom: 1px solid #e1e4e8; }
.metrics-table th:first-child, .metrics-table td:first-child { text-align: left; }
.metrics-details { margin-top: 8px; font-size: 0.85rem; }
.metrics-details summary { cursor: pointer; color: #0969da; }
.metrics-pre {
  background: #f6f8fa;
  padding: 10px;
  border-radius: 6px;
  overflow-x: auto;
  max-height: 300px;
  overflow-y: auto;
  font-size: 0.8rem;
}
.admin-create {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.admin-create input[type="text"], .admin-create input[type="password"] {
  flex: 1;
  min-width: 120px;
  padding: 6px;
  border: 1px solid #d0d7de;
  border-radius: 6px;
}
.inline-label { display: inline-flex; align-items: center; gap: 4px; }
#admin-users-list { max-height: 320px; overflow-y: auto; }
.admin-user-row {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: space-between;
  padding: 8px;
  border-bottom: 1px solid #e1e4e8;
}
.admin-user-row .admin-user-name { font-weight: 600; }
.admin-user-row .admin-user-meta { font-size: 0.8rem; color: #666; }
/* Task 253gj: the Disable / Reset password / Delete buttons in the Users modal
   were out of shape. Give them consistent sizing/spacing and let the actions
   wrap onto their own line on narrow viewports (instead of squashing against
   the username) so they render cleanly at any width. */
.admin-user-row {
  flex-wrap: wrap;
  row-gap: 8px;
}
.admin-user-row .admin-user-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
}
.admin-user-row .admin-user-actions button {
  white-space: nowrap;
  padding: 4px 10px;
  font-size: 0.85rem;
  line-height: 1.3;
  border: 1px solid #d0d7de;
  border-radius: 6px;
  background: #f6f8fa;
  color: #24292f;
  cursor: pointer;
}
.admin-user-row .admin-user-actions button:hover { background: #eaeef2; }
.admin-user-row .admin-user-actions button:last-child { color: #cf222e; border-color: #ffb3b3; }
.admin-user-row .admin-user-actions button:last-child:hover { background: #fff0f0; }

/* Task 253er: mobile focus-zoom. iOS Safari zooms the whole page when a focused
   form control renders below 16px, which reads as "every button tap zooms".
   Fix the ROOT CAUSE — control typography — instead of the viewport hack
   (no maximum-scale / user-scalable=no in index.html). Every control, including
   the small utility classes that set their own rem size, is >=16px on phones. */
@media (max-width: 640px) {
  input,
  select,
  textarea,
  button,
  .search-input,
  .language-filter,
  .job-cancel-btn,
  .deck-delete-btn,
  .tab-btn,
  .sub-tab-btn {
    font-size: 16px;
  }
  .job-cancel-btn { min-height: 32px; padding: 4px 8px; }
}

/* ── Task 253fm: all-device responsive overflow (playbook) ───────────────────
   Round-7 CSS fixes did not actually stop the right-edge spewing (jsdom does no
   layout, so source assertions cannot catch it). These are the root-cause rules
   from `responsive-overflow-playbook-20261021`, verified with a Playwright
   width-sweep. */

/* 5. box-sizing: border-box globally — padding never widens a box past 100%. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* img/video never exceed their container. */
img,
video {
  max-width: 100%;
  height: auto;
}

/* 1. flex/grid items containing text must be allowed to shrink (default
   min-width:auto resolves to the content's intrinsic width and holds a long
   filename/URL open). */
.session-card,
.source-card,
.deck-card,
.upload-card,
.session-card .meta,
.source-card .meta,
.deck-card .meta,
.job-row,
.job-row .job-meta,
.session-job-row,
.session-job-row .job-meta,
.message,
.error,
.url,
.status-text,
.hint,
.loading-status,
.field-error {
  min-width: 0;
}

/* 2. long error / STT / message text wraps instead of spewing off the right edge. */
.message,
.error,
.url,
.status-text,
.session-card strong,
.source-card strong,
.deck-card strong,
.upload-card strong {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* 3. filename rows: one line, ellipsis on overflow (full name in a detail view). */
.file-row {
  display: flex;
  min-width: 0;
  gap: 6px;
  align-items: center;
}
.file-row .filename {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 4. button rows / tab bars wrap; their children never exceed the viewport. */
.actions,
.toolbar,
.sub-tabs,
#top-tabs {
  flex-wrap: wrap;
}
.actions > *,
.toolbar > *,
.sub-tabs > *,
#top-tabs > * {
  max-width: 100%;
}

/* ── Task 253fq: Upload tab INNER panels — file rows + dropdowns stay inside ──
   Round-9 live-test (IMG_9131): round-8 fixed the OUTER tabs/button row, but the
   "Choose File / no file selected" rows and the source-type/subtype <select>s
   inside the "Typed / digital source" and "Handwritten" panels still spewed off
   the right edge on mobile. Apply the responsive playbook to these inner-panel
   elements: min-width:0 on flex children, max-width:100%, constrain the file
   input row + dropdowns to the panel width, overflow-wrap. */
.upload-card {
  max-width: 100%;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.upload-card p,
.upload-card h4,
.upload-card .hint {
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* The native "Choose File / no file selected" row is a single inline control —
   cap it to the panel and ellipsis the (possibly long) filename. */
.upload-card input[type="file"] {
  display: block;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Source-type / subtype dropdowns must never exceed the panel width. */
.upload-card select {
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

/* ── Task 253kw (a): 360px file-input overflow batch ─────────────────────────
   The native "Choose File / no file selected" control is wider than its card
   in the HANDWRITTEN + TYPED create boxes, the deck-file row, and the
   edit-card Front/Back image rows. Constrain the row + let the filename
   truncate; never let a file control push the layout past the viewport. */
.create-upload-box,
.deck-import-option,
.upload-textbook-option,
.card-edit-fields,
.card-edit-fields > label {
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}
.create-upload-box input[type="file"],
.deck-import-option input[type="file"],
.upload-textbook-option input[type="file"],
.textbook-file,
.create-deck-file,
.card-edit-image-file,
#session-deck-import-file,
#import-deck-file {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.create-upload-box input[type="file"]::file-selector-button,
.deck-import-option input[type="file"]::file-selector-button,
.upload-textbook-option input[type="file"]::file-selector-button,
.card-edit-image-file::file-selector-button {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.deck-import-option label,
.upload-textbook-option label {
  display: block;
  max-width: 100%;
  min-width: 0;
}

/* ── Task 253kw (c): reconstructed-source Delete is a COMPACT secondary
   destructive control, not a full-width red slab (IMG_16). ───────────────── */
.source-card-swipe .swipe-actions {
  background: transparent;
  padding-right: 6px;
  justify-content: flex-end;
  align-items: center;
}
.source-card-swipe .swipe-actions button {
  background: #fff;
  color: #cf222e;
  border: 1px solid #ffb3b3;
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  min-height: 36px;
}
.source-card-swipe .swipe-actions button::before {
  content: "⌫ ";
  font-weight: 400;
}
.source-card-swipe .swipe-actions button:hover { background: #fff0f0; }


/* Task 253gx: math segments render inline (KaTeX) and copy their plain-text form. */
.math-segment { display: inline-block; white-space: nowrap; }
.math-segment .katex { font-size: 1.05em; }

/* Task 253hf: page-based formatted review preview + editable layout tree. */
.review-pages { max-height: 60vh; overflow-y: auto; }
.review-page { border: 1px solid #ddd; border-radius: 6px; padding: 12px; margin-bottom: 12px; background: #fff; }
/* Task 253qe (UI-19): off-screen review pages skip layout/paint until scrolled
   near — a 200-page preview renders without paying for every page up front.
   ``contain-intrinsic-size`` keeps the scrollbar stable while a page is skipped. */
.review-page { content-visibility: auto; contain-intrinsic-size: auto 600px; }
.review-page-head { font-weight: bold; font-size: 0.85em; color: #666; border-bottom: 1px solid #eee; padding-bottom: 6px; margin-bottom: 8px; }
.review-page-body { line-height: 1.6; }
.review-layout-tree { max-height: 60vh; overflow-y: auto; }
.review-layout-list { list-style: none; padding-left: 0; }
.review-layout-list ul { list-style: none; padding-left: 1.25em; margin: 4px 0; }
.review-layout-list li { margin: 4px 0; }
.review-layout-list input { margin-left: 4px; }

/* Task 253hg: card diff indicators — added (green) / removed (red). */
.diff-added { color: #1a7f37; font-weight: 600; }
.diff-removed { color: #cf222e; font-weight: 600; }
/* Task 253md: persistent lifecycle-counter badge (N +added −removed). */
.counter-badge { display: inline-flex; align-items: baseline; gap: 4px; margin-left: 8px; font-size: 0.8rem; }
.counter-badge button {
  border: none;
  background: transparent;
  padding: 0 2px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.counter-badge .counter-n.counter-positive { color: #1a7f37; }
.counter-badge .counter-n.counter-negative { color: #cf222e; }
.counter-badge .counter-n.counter-neutral { color: #57606a; }
.counter-badge .counter-add { color: #1a7f37; }
.counter-badge .counter-removed { color: #cf222e; }
/* Task 253md ADDENDUM 2: zero-count nodes are still interactive — a hover
   underline signals the badge/name opens the editor. */
.counter-badge .counter-n:hover,
.counter-badge button:hover { text-decoration: underline; }
.flagged-cards-area { border: 1px solid #d4a72c; background: #fff8e1; border-radius: 6px; padding: 8px 12px; margin: 8px 0; }
.flagged-cards-count { color: #8a6100; font-weight: 700; }
.flagged-card-row { display: flex; gap: 8px; align-items: flex-start; padding: 6px 8px; border: 1px solid #e6cf8b; border-radius: 4px; background: #fffdf4; margin: 4px 0; }
.flagged-card-row .fc-body { flex: 1; min-width: 0; }
.flagged-card-row .fc-front { font-weight: 600; }
.flagged-card-row .fc-back { color: #555; }
.flagged-card-assign { margin-top: 4px; }
.flagged-card-assign select { max-width: 220px; }

/* Task 253hh: natural-vs-words reading mode switch. */
.reading-mode { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; }
.reading-mode-option { display: flex; align-items: flex-start; gap: 6px; padding: 6px 8px; border: 1px solid #e0e0e0; border-radius: 6px; background: #fafafa; cursor: pointer; font-size: 0.85rem; }
.reading-mode-option input { margin-top: 3px; }
.reading-mode-option span { color: #444; }

/* Task 253hi: cut-out box-overlay human review (boxes rendered over the page). */
.cutout-overlay-page { position: relative; display: inline-block; border: 1px solid #ddd; margin: 8px; }
.cutout-overlay-page img { display: block; max-width: 100%; }
.cutout-overlay-box { position: absolute; border: 2px solid #e6a700; background: rgba(230, 167, 0, 0.12); box-sizing: border-box; }
.cutout-overlay-box.invalid { border-color: #cf222e; background: rgba(207, 34, 46, 0.15); }
.cutout-overlay-label { position: absolute; top: 0; left: 0; background: #e6a700; color: #fff; font-size: 0.7rem; padding: 0 4px; }

/* Task 253kz: one-line Card split explainer (i18n-keyed en/km).
   Task 253mz: the explainer is grouped under the Card split control (indented
   so it visually belongs to it, not to the layout/export controls above). */
.deck-split-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 4px 0 6px;
}
.deck-split-group .deck-card-split-explainer {
  margin-left: 8px;
  padding-left: 8px;
  border-left: 2px solid #d0d7de;
}
.deck-card-split-explainer {
  display: block;
  margin: 4px 0 0;
  color: #57606a;
  font-size: 0.85rem;
  line-height: 1.4;
  max-width: 100%;
  overflow-wrap: anywhere;
}
