:root {
  /* Soft pastel palette: warm cream background, dusty-periwinkle accent,
     muted pastel tag chips. Foreground text stays a soft dark plum for
     readable contrast. */
  --bg: #faf6f1; --fg: #3b3540; --muted: #8a8190;
  --card-bg: #ffffff; --card-border: #ebe4ef;
  --accent: #c84a4a; --accent-hover: #a83838;
  --warn: #b97a55; --warn-bg: #fdebd8;
  --ok: #6c9a72; --ok-bg: #ddecd9;
  --tag-source-bg: #fce0ea; --tag-source-fg: #a85878;
  --tag-year-bg: #e0e8f7; --tag-year-fg: #5e76b0;
  --tag-season-bg: #dcebde; --tag-season-fg: #56856a;
  --tag-pola-bg: #e6dffa; --tag-pola-fg: #7867b0;
  --tag-level-bg: #fce0c7; --tag-level-fg: #b97349;
  --tag-section-bg: #fdf1c8; --tag-section-fg: #a88347;
  --tag-points-bg: #ecedef; --tag-points-fg: #5c6477;
  --tag-topic-bg: #e3f1f9; --tag-topic-fg: #5990b5;
  --tag-topic-main-bg: #e7e3f8; --tag-topic-main-fg: #6f659f; --tag-topic-main-border: #d4ccf0;
  --tag-topic-sub-bg:  #e3f1f9; --tag-topic-sub-fg:  #5990b5; --tag-topic-sub-border:  #c9e3f1;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg); color: var(--fg); line-height: 1.5;
}
.container { max-width: 1200px; margin: 0 auto; padding: 1.5rem; }
h1 { margin-top: 0; }
.subtitle { color: var(--muted); margin-top: -0.5rem; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
.back-link { display: inline-block; margin-bottom: 1rem; font-size: 0.9rem; }

.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.5rem 0; }
.tag { display: inline-block; padding: 0.2rem 0.6rem; border-radius: 999px;
       font-size: 0.78rem; font-weight: 500; white-space: nowrap; }
.tag.source  { background: var(--tag-source-bg);  color: var(--tag-source-fg); }
.tag.year    { background: var(--tag-year-bg);    color: var(--tag-year-fg); }
.tag.season  { background: var(--tag-season-bg);  color: var(--tag-season-fg); }
.tag.pola    { background: var(--tag-pola-bg);    color: var(--tag-pola-fg); }
.tag.level   { background: var(--tag-level-bg);   color: var(--tag-level-fg); }
.tag.section { background: var(--tag-section-bg); color: var(--tag-section-fg); }
.tag.points  { background: var(--tag-points-bg);  color: var(--tag-points-fg); }
.tag.book          { background: #f1e3d0; color: #a07a4a; }
.tag.book-chapter  { background: #f5dbb8; color: #b07549; }
.tag.book-section  { background: #fdf1c8; color: #a88347; }
.tag.topic   {
  background: var(--tag-topic-bg);  color: var(--tag-topic-fg);
  border: 1px solid var(--tag-topic-sub-border);
}
.tag.topic.topic-main {
  background: var(--tag-topic-main-bg);
  color:      var(--tag-topic-main-fg);
  border-color: var(--tag-topic-main-border);
  font-weight: 600;
}
.tag.topic.topic-sub {
  background: var(--tag-topic-sub-bg);
  color:      var(--tag-topic-sub-fg);
  border-color: var(--tag-topic-sub-border);
}

/* A main section is rendered as a rectangular box that visually contains
   any of its sub topics as inner pills. */
.topic-group {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 0.3rem;
  background: var(--tag-topic-main-bg);
  color: var(--tag-topic-main-fg);
  border: 1px solid var(--tag-topic-main-border);
  border-radius: 6px;
  padding: 0.18rem 0.45rem;
  font-size: 0.78rem;
  font-weight: 600;
  vertical-align: middle;
  line-height: 1.4;
  margin: 0;
}
.topic-group .topic-group-main {
  display: inline-flex; align-items: center; gap: 0.3rem;
  white-space: nowrap;
}
/* Sub pills inside the rectangular main container — soft sky-blue so they
   contrast with the indigo group background but aren't stark white. */
.topic-group .tag.topic.topic-sub {
  background: #f0f9ff;          /* sky-50 */
  color: var(--tag-topic-sub-fg);
  border: 1px solid var(--tag-topic-sub-border);
  font-weight: 500;
  font-size: 0.72rem;
  padding: 0.06rem 0.5rem;
}
/* Editable: tint the × on the indigo background. */
.topic-group .topic-group-main .topic-remove {
  background: rgba(67, 56, 202, 0.18);
  color: #3730a3;
}
.topic-group .topic-group-main .topic-remove:hover {
  background: rgba(67, 56, 202, 0.34);
  color: #312e81;
}
/* On the index card the chips are tighter. */
.problem-card .topic-group {
  font-size: 0.72rem;
  padding: 0.12rem 0.38rem;
  gap: 0.22rem;
}
.problem-card .topic-group .tag.topic.topic-sub {
  font-size: 0.66rem;
  padding: 0.05rem 0.42rem;
}
.tag.topic.editable {
  display: inline-flex; align-items: center; gap: 0.32rem;
  padding-right: 0.28rem;
}
.topic-remove {
  width: 1.05rem; height: 1.05rem;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0;
  background: rgba(3, 105, 161, 0.18);
  color: #0369a1;            /* sky-700, default for sub chips */
  border-radius: 999px;
  font-size: 0.78rem; line-height: 1;
  padding: 0;
  cursor: pointer;
  font-weight: 700;
}
.topic-remove:hover {
  background: rgba(3, 105, 161, 0.34);
  color: #075985;
}
/* Main-section chip: tint the × in indigo to match. */
.tag.topic.topic-main .topic-remove {
  background: rgba(67, 56, 202, 0.18);
  color: #3730a3;
}
.tag.topic.topic-main .topic-remove:hover {
  background: rgba(67, 56, 202, 0.32);
  color: #312e81;
}
.topic-add {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.6rem; height: 1.4rem;
  padding: 0 0.45rem;
  border: 1px dashed var(--card-border);
  background: transparent; color: var(--muted);
  border-radius: 999px;
  font-size: 0.95rem; line-height: 1;
  cursor: pointer;
  font-weight: 600;
}
.topic-add:hover { color: var(--accent); border-color: var(--accent); }

/* Topic picker popover */
.topic-picker {
  position: absolute; z-index: 200;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
  padding: 0.4rem;
  min-width: 240px; max-width: 320px;
  max-height: 320px;
  overflow: hidden;
  display: flex; flex-direction: column;
}
.topic-picker-search {
  width: 100%;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  margin-bottom: 0.35rem;
  font: inherit; font-size: 0.85rem;
}
.topic-picker-list {
  display: flex; flex-direction: column; gap: 0.12rem;
  overflow-y: auto;
}
.topic-picker-item {
  text-align: left;
  padding: 0.32rem 0.55rem;
  background: transparent;
  border: 0;
  border-radius: 4px;
  font-size: 0.86rem;
  color: var(--fg);
  cursor: pointer;
}
.topic-picker-item:hover {
  background: var(--tag-topic-bg);
  color: var(--tag-topic-fg);
}
.topic-picker-empty {
  padding: 0.4rem 0.55rem;
  color: var(--muted);
  font-style: italic;
  font-size: 0.85rem;
}

/* Grouped layout inside the topic picker: each row is a main + its
   still-available subs, mimicking the search filter & problem-page chips. */
.topic-picker .picker-group {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.22rem 0.45rem;
  border-radius: 6px;
  border: 1px solid var(--tag-topic-main-border);
  background: var(--tag-topic-main-bg);
  color: var(--tag-topic-main-fg);
  font-size: 0.84rem;
  font-weight: 600;
  margin-bottom: 0.25rem;
}
.topic-picker .picker-main {
  background: transparent; border: 0; padding: 0;
  font: inherit; font-weight: inherit; color: inherit;
  cursor: pointer; white-space: nowrap;
}
.topic-picker .picker-main:hover { text-decoration: underline; }
.topic-picker .picker-main-static {
  /* Already-added main shown as a non-clickable header. */
  opacity: 0.6;
  white-space: nowrap;
}
.topic-picker .picker-subs {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 0.3rem;
}
.topic-picker .picker-sub {
  display: inline-block;
  padding: 0.06rem 0.55rem;
  border-radius: 999px;
  background: #f0f9ff;
  color: var(--tag-topic-sub-fg);
  border: 1px solid var(--tag-topic-sub-border);
  font: inherit;
  font-size: 0.74rem;
  font-weight: 500;
  cursor: pointer;
}
.topic-picker .picker-sub:hover { filter: brightness(0.96); }

/* Collapsible source-collection sections on the index page */
.collection {
  margin-top: 1.2rem;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: var(--card-bg);
  /* No `overflow: hidden` here — when an .is-hovered .search-result inside
     the grid expands downward, it needs to escape past the bottom of this
     section. Clipping was previously cutting off the last row's hover
     expansion. The border-radius still draws cleanly because the section's
     own background fills the rounded box; only absolutely-positioned
     descendants overflow it. */
}
.collection > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.7rem 1rem;
  display: flex;
  align-items: center;
  /* Allow the injected subtopic chip row to wrap onto its own full-width
     line below the topic name (chip row has flex-basis: 100%). */
  flex-wrap: wrap;
  gap: 0.55rem;
  user-select: none;
  font-size: 1.05rem;
  font-weight: 600;
}
.collection > summary::-webkit-details-marker { display: none; }
.collection > summary::before {
  content: '▸';
  display: inline-block;
  transition: transform 0.15s ease;
  width: 1em;
  color: var(--muted);
  font-weight: 400;
}
.collection[open] > summary::before { transform: rotate(90deg); }
.collection > summary .count {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.9rem;
}
.collection > .problem-list,
.collection > .search-results {
  margin: 0;
  padding: 0.4rem 1rem 1rem;
}
.collection-empty {
  padding: 0.5rem 1rem 1rem;
  color: var(--muted);
  font-style: italic;
  font-size: 0.9rem;
}

/* Nested collections inside Matura: year > season > level */
.collection .collection {
  border: 0;
  background: transparent;
  border-radius: 0;
  margin: 0;
}
.collection .collection > summary {
  font-weight: 600;
}
.collection .collection-l1 > summary { font-size: 1rem;   padding-left: 2rem;   }
.collection .collection-l2 > summary { font-size: 0.95rem; padding-left: 3rem;   font-weight: 500; }
.collection .collection-l3 > summary { font-size: 0.92rem; padding-left: 4rem;   font-weight: 500; color: var(--muted); }
.collection .collection-l3 > .problem-list,
.collection .collection-l3 > .search-results { padding: 0.3rem 1rem 0.8rem 4rem; }
/* ---- Year-tab Reorder pill + dedicated reorder panel ---- */
/* The pill sits next to "Source" on the Problems-page header and
   matches the same chip+arrow combo style. Hidden unless the Year
   browse mode is the active one. */
.filter-source-cell.is-hidden { display: none; }
.filter-reorder-cell.is-hidden { display: none; }
/* Subtopic chip row inside each main-topic <summary> — a full-width
   flex row of chips, left to right, on the line BELOW the main topic
   title (user request). Matches the search-page subtopic chip style. */
.subtopic-chip-row {
  display: flex; flex-wrap: wrap;
  gap: 0.3rem;
  margin: 0.15rem 0 0;
  align-items: center;
  /* Force the row onto its own line spanning the whole box width. */
  flex-basis: 100%;
  width: 100%;
}
.subtopic-chip {
  padding: 0.12rem 0.55rem;
  font: inherit; font-size: 0.78rem;
  border: 1px solid var(--card-border);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--muted);
  cursor: pointer;
  line-height: 1.3;
}
.subtopic-chip[aria-pressed="true"] {
  background: var(--tag-source-bg);
  color: var(--tag-source-fg);
  border-color: var(--tag-source-fg);
}
.subtopic-chip:hover { border-color: var(--accent); }
.search-result-wrap.subtopic-filter-hidden { display: none !important; }
/* Standalone "Reorder topics" button — visually distinct from the
   Source filter pill. Sits to the right of Source in the year-tab
   filter strip and toggles the reorder grid panel below. */
.reorder-topics-btn {
  font: inherit; font-size: 0.85rem;
  padding: 0.32rem 0.85rem;
  border: 1px dashed var(--card-border);
  border-radius: 6px;
  background: var(--card-bg);
  color: var(--muted);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 0.4rem;
  transition: border-color 120ms ease, color 120ms ease;
}
.reorder-topics-btn.is-hidden { display: none; }
.reorder-topics-btn:hover,
.reorder-topics-btn[aria-expanded="true"] {
  border-color: var(--accent);
  color: var(--accent);
}
.reorder-topics-caret {
  font-size: 0.75rem; line-height: 1;
  transition: transform 140ms ease;
}
.reorder-topics-btn[aria-expanded="true"] .reorder-topics-caret {
  transform: rotate(180deg);
}
#topic-reorder-panel .reorder-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(180px, 1fr));
  gap: 0.6rem;
  padding: 0.6rem;
}
.reorder-year-col {
  background: rgba(0,0,0,0.025);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-height: 4rem;
}
.reorder-year-col .reorder-year-label {
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 0.25rem;
  color: var(--muted);
}
.reorder-topic-pill {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.55rem;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  font-size: 0.85rem;
  cursor: move;
  user-select: none;
}
.reorder-topic-pill .reorder-pill-count {
  margin-left: auto;
  color: var(--muted);
  font-size: 0.78rem;
}
.reorder-topic-pill.is-empty {
  opacity: 0.45;
}
.reorder-topic-pill.dragging {
  opacity: 0.5;
  background: rgba(0,0,0,0.04);
}
.reorder-topic-pill.drop-before {
  box-shadow: 0 -3px 0 var(--accent) inset;
}
.reorder-topic-pill.drop-after {
  box-shadow: 0  3px 0 var(--accent) inset;
}
.reorder-year-col.drop-into {
  background: rgba(120, 150, 255, 0.12);
  border-color: var(--accent);
}
#topic-reorder-panel .reorder-footer {
  display: flex;
  justify-content: flex-end;
  padding: 0 0.6rem 0.6rem;
}
.reorder-reset-btn {
  background: transparent;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 0.3rem 0.8rem;
  font-size: 0.85rem;
  color: var(--muted);
  cursor: pointer;
}
.reorder-reset-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.problem-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.7rem;
  margin-top: 1.5rem;
}
.problem-card {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.7rem 0.9rem;
  background: #f3f4f6;       /* grey by default */
  border: 1px solid var(--card-border);
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
  transition: border-color 0.08s, box-shadow 0.08s, transform 0.08s;
}
.problem-card:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 6px rgba(0,0,0,0.07);
  transform: translateY(-1px);
  text-decoration: none;
}
.problem-card .card-num {
  flex-shrink: 0; font-weight: 600; font-size: 1.05rem;
}
.problem-card .card-content {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  gap: 0.3rem;
}
.problem-card .tags {
  margin: 0; gap: 0.3rem;
  display: flex; flex-wrap: wrap;
}
.problem-card .tag { font-size: 0.72rem; padding: 0.1rem 0.45rem; }

/* Inline-chip preview on each index card. Collapsed: chips fill one line;
   any that don't fit are hidden via max-height + overflow:hidden. A ">"
   chevron sits at the right end. Click → expand all cards' chips and
   flip to "<". */
.problem-card .card-section {
  display: flex; align-items: center; gap: 0.4rem;
  width: 100%;
}
.problem-card .card-section .tags {
  flex: 1; min-width: 0;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.3rem;
  overflow: hidden;
  max-height: 1.55em;            /* clip to one line of chips */
  line-height: 1.4;
}
.problem-card .card-section[data-expanded="true"] .tags {
  max-height: none;
  overflow: visible;
}
.problem-card .card-toggle {
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.6rem;       /* generous click target */
  background: transparent;
  border: 0;
  padding: 0; margin: 0;
  border-radius: 6px;
  font: inherit;
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
  line-height: 1;
  transition: background-color 0.08s, color 0.08s;
}
.problem-card .card-toggle:hover {
  color: var(--accent);
  background: rgba(0, 0, 0, 0.07);     /* visual confirmation of the hit zone */
}
.problem-card .card-chevron::after { content: '>'; }
.problem-card .card-section[data-expanded="true"] .card-chevron::after { content: '<'; }

/* status-driven background colours.
   * single status: solid colour
   * outdated + approved: half/half gradient (yellow + green) */
.problem-card.status-outdated:not(.status-approved-me):not(.status-approved-other) {
  background: var(--warn-bg);                                   /* yellow */
}
.problem-card.status-approved-other:not(.status-outdated) {
  background: #ddecd9;                                          /* light green */
}
.problem-card.status-approved-me:not(.status-outdated) {
  background: #b8e0bd;                                          /* dark green */
}
.problem-card.status-outdated.status-approved-other {
  background: linear-gradient(to right, var(--warn-bg) 50%, #ddecd9 50%);
}
.problem-card.status-outdated.status-approved-me {
  background: linear-gradient(to right, var(--warn-bg) 50%, #b8e0bd 50%);
}
.problem-card.status-approved-me .card-num { color: #4a6e51; }

/* Same status-driven background colours, applied to .search-result cards
   on the Problems page. (.search-result-wrap[data-id] > .search-result is
   only generated by the index page, so this scoping doesn't bleed onto
   the Search page or the modal.) */
.search-result-wrap[data-id] > .search-result.status-outdated:not(.status-approved-me):not(.status-approved-other) {
  background: var(--warn-bg);
}
.search-result-wrap[data-id] > .search-result.status-approved-other:not(.status-outdated) {
  background: #ddecd9;
}
.search-result-wrap[data-id] > .search-result.status-approved-me:not(.status-outdated) {
  background: #b8e0bd;
}
.search-result-wrap[data-id] > .search-result.status-outdated.status-approved-other {
  background: linear-gradient(to right, var(--warn-bg) 50%, #ddecd9 50%);
}
.search-result-wrap[data-id] > .search-result.status-outdated.status-approved-me {
  background: linear-gradient(to right, var(--warn-bg) 50%, #b8e0bd 50%);
}
.search-result-wrap[data-id] > .search-result.status-approved-me .result-num { color: #4a6e51; }
/* Match the bottom-fade gradient to the card's status background — without
   this the gradient blends from var(--card-bg) (white) on coloured cards. */
.search-result-wrap[data-id] > .search-result.status-outdated:not(.status-approved-me):not(.status-approved-other)::after {
  background: linear-gradient(to bottom, transparent, var(--warn-bg));
}
.search-result-wrap[data-id] > .search-result.status-approved-other:not(.status-outdated)::after {
  background: linear-gradient(to bottom, transparent, #ddecd9);
}
.search-result-wrap[data-id] > .search-result.status-approved-me:not(.status-outdated)::after {
  background: linear-gradient(to bottom, transparent, #b8e0bd);
}

.status-bar {
  display: flex; align-items: center; gap: 0.75rem; margin: 0;
  padding: 0.5rem 0.9rem; background: var(--card-bg);
  border: 1px solid var(--card-border); border-radius: 6px;
}

/* nav + status-bar share one horizontal row */
.action-row {
  display: flex; align-items: stretch; gap: 0.7rem;
  flex-wrap: wrap;
  margin: 0.5rem 0 1rem;
}
.action-row .problem-nav { margin: 0; }
.action-row .status-bar  { flex: 1; min-width: 0; }
.status-badge { font-size: 0.85rem; padding: 0.2rem 0.7rem; border-radius: 999px; }
.status-badge.ok       { background: var(--ok-bg);   color: var(--ok); }
.status-badge.outdated { background: var(--warn-bg); color: var(--warn); }

/* Approver chip rendering. Other people who approved show as static
   read-only chips; the user's own chip is a button that toggles approval. */
.approvers {
  display: inline-flex; align-items: center;
  flex-wrap: wrap; gap: 0.35rem;
}
.approval-chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.85rem; padding: 0.2rem 0.65rem; border-radius: 999px;
  border: 1px solid transparent;
}
.approval-chip--other {
  background: #ecfeff; color: #0e7490; border-color: #a5f3fc;
  cursor: default;
}
.approval-chip--self {
  font: inherit; font-size: 0.85rem;
  cursor: pointer; user-select: none;
  padding: 0.2rem 0.65rem;
}
.approval-chip--self.is-approved {
  background: #ecfeff; color: #0e7490; border-color: #a5f3fc;
}
.approval-chip--self.is-approved:hover {
  background: #cffafe; border-color: #67e8f9;
}
.approval-chip--self.is-unapproved {
  background: #f3f4f6; color: #6b7280; border-color: #e5e7eb;
}
.approval-chip--self.is-unapproved:hover {
  background: #e5e7eb; border-color: #d1d5db; color: #374151;
}
.approval-chip--self .self-mark {
  font-weight: 700; font-size: 0.95rem; line-height: 1;
}
.approval-chip[hidden] { display: none !important; }

button {
  cursor: pointer; font: inherit; font-size: 0.85rem;
  padding: 0.35rem 0.85rem; border: 1px solid var(--card-border);
  background: white; color: var(--fg); border-radius: 6px;
}
button:hover { border-color: var(--accent); color: var(--accent); }
button.primary { background: var(--accent); color: white; border-color: var(--accent); }
button.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: white; }
button:disabled { opacity: 0.5; cursor: default; }

.problem-body { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-top: 1rem; }
@media (max-width: 800px) { .problem-body { grid-template-columns: 1fr; } }
/* Crops live BELOW the Preview/LaTeX row in a 2-column grid that
   matches the column widths of .problem-body — so each crop is the
   same width as it had when it lived inside the right pane. Extra
   instances flow into the next column / row automatically. */
.problem-crops {
  margin-top: 1.5rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  align-items: start;
}
@media (max-width: 800px) {
  .problem-crops { grid-template-columns: 1fr; }
}
.problem-crops .instance-block {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 1rem;
}

.pane { background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 8px; padding: 1rem; }
.pane h3 { margin: 0; font-size: 1rem; }
.pane-header {
  display: flex; align-items: center; gap: 0.5rem;
  margin-bottom: 0.7rem; flex-wrap: wrap;
}
/* Make h3 inside ANY pane-header (including .crop-view, not just .pane)
   sit at the same size and weight as the .title-picker that may
   replace it. Without this, .crop-view h3 falls back to the browser's
   ~1.5em default and looks much bigger than the dropdown variant. */
.pane-header h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}

/* Title row: H1 and tags side-by-side */
/* Hide the entire "Preview" / "LaTeX" pane header on the problem page —
   the surrounding layout makes the panes' purpose obvious, and removing
   the empty spacer lets the preview/textarea fill the pane. */
.problem-body .pane > .pane-header { display: none; }
/* Status row holds the ✓/⚠ toggle + Approve checkbox. On the problem page
   it sits inside .meta-right at the top; on its own elsewhere it stays a
   simple inline row. */
.status-row {
  display: flex; align-items: center; gap: 0.6rem;
  margin: 0;
}
/* Inline navigation arrows next to the H1 in the title row. */
.title-row .nav-arrow {
  font-size: 1.4rem; line-height: 1;
  text-decoration: none; color: var(--accent);
  padding: 0 0.4rem;
  border-radius: 6px;
}
.title-row .nav-arrow:hover { background: rgba(200, 74, 74, 0.08); }
.title-row .nav-arrow.disabled {
  color: var(--card-border); cursor: default; pointer-events: none;
}
.title-row {
  display: flex; align-items: baseline; gap: 0.4rem;
  flex-wrap: wrap; margin: 0;
}
/* Pin the arrows to fixed positions by giving the title number a
   fixed-width container; this keeps ← and → from shifting depending on
   whether the page is "8." or "868.". The h1 is centred inside. */
.title-row .nav-arrow {
  flex: 0 0 auto;
  min-width: 1.5em;
  text-align: center;
}
.title-row h1 {
  margin: 0;
  font-size: 1.4rem; font-weight: 600;
  color: var(--fg); line-height: 1;
  flex: 0 0 auto;
  width: 3.5em;
  text-align: center;
}
.title-row .tags { margin: 0; }
/* When the title-row sits inside the .top-bar, override its default size
   to match the existing .page-title sizing. */
.top-bar .title-row { align-items: center; }

/* Meta row sits immediately under the top bar: topics on the left,
   status + export stacked on the right. .meta-right's first child
   (.status-row) lines up with the top of .topics-row because of
   align-items: flex-start. */
.meta-row {
  display: flex; align-items: flex-start;
  gap: 1rem; flex-wrap: wrap;
  margin: 0.4rem 0 0;
}
.meta-left {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  /* Same vertical gap as .meta-right uses between its status-row and
     action-row, so the two columns feel consistent. */
  gap: 0.4rem;
}
.tags-row {
  display: flex; align-items: center;
  flex-wrap: wrap; gap: 0.4rem;
  margin: 0;
}
.tags-row .tags { margin: 0; }
.meta-right {
  display: flex; flex-direction: column;
  align-items: flex-end; gap: 0.4rem;
  flex: 0 0 auto;
}
.meta-right .action-row { margin: 0; }

/* Per-figure TikZ-vs-original toggle. The button is added by JS inside
   every .tex-tikz that has a `data-tikz-orig` attribute (i.e. a
   companion original-figure crop is available). The button is pinned to
   the top-right of the figure box. */
.preview-box .tex-tikz { position: relative; }
.tikz-toggle {
  position: absolute; top: 4px; right: 4px;
  font-size: 0.7rem; padding: 0.12rem 0.5rem;
  border-radius: 999px;
  background: var(--card-bg); color: var(--accent);
  border: 1px solid var(--card-border);
  cursor: pointer; z-index: 2;
}
.tikz-toggle:hover {
  background: var(--accent); color: white; border-color: var(--accent);
}
.tikz-orig-img {
  display: block; max-width: 100%; max-height: 100%;
  width: auto; height: auto;
}

/* Topics row: shown right under title-row, distinct color, optional label */
.topics-row {
  display: flex; align-items: center; gap: 0.5rem;
  flex-wrap: wrap; margin: 0;
}
/* Index-card topics-row keeps its own breathing room — it's a card, not the
   tightly-packed problem-page header. */
.problem-card .topics-row { margin: 0 0 0.6rem; }
.topics-row .topics-label {
  font-size: 0.78rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em;
  font-weight: 600;
}
.topics-row .tags { margin: 0; }

/* The two .pane cards in .problem-body are flex columns so their main
   child (preview-box on the left, textarea on the right) fills the
   remaining row height. The grid stretches both panes to the same
   height — without this, a long preview would leave the LaTeX pane
   short and the textarea would scroll. */
.problem-body .pane {
  display: flex; flex-direction: column;
  /* Tighter padding than the default .pane so content fills the visible
     box rather than floating in a wide margin. */
  padding: 0.5rem;
}
textarea#latex-source {
  width: 100%; min-height: 280px;
  flex: 1 1 auto;
  box-sizing: border-box;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9rem;
  border: 1px solid var(--card-border); border-radius: 6px; padding: 0.7rem; resize: vertical;
}

/* LaTeX editor syntax-highlight overlay. The textarea sits on top with
   transparent text; a synchronised <pre> beneath holds the coloured
   spans. Both elements MUST share font/size/padding/line-height so the
   spans align with the live cursor. */
.tex-editor-wrap {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  min-height: 280px;
}
.tex-editor-wrap > textarea#latex-source {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  background: transparent;
  color: transparent;
  caret-color: var(--fg);
  resize: vertical;
}
.tex-editor-wrap > .tex-highlight {
  position: absolute; inset: 0;
  margin: 0;
  width: 100%; height: 100%;
  overflow: auto;
  pointer-events: none;
  /* Match the textarea exactly so wrapping behaviour is identical. */
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9rem;
  line-height: 1.4;
  padding: 0.7rem;
  border: 1px solid transparent;
  border-radius: 6px;
  background: white;
  box-sizing: border-box;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--fg);
}
.tex-editor-wrap > textarea#latex-source {
  line-height: 1.4;
}
.tex-highlight .tex-cmd  { color: #7c5e9a; font-weight: 600; }
.tex-highlight .tex-env  { color: #2a6cb0; font-weight: 600; }
.tex-highlight .tex-math { color: #b85a4b; background: #fdf3ee; border-radius: 2px; }
.tex-highlight .tex-cmt  { color: var(--muted); font-style: italic; }
.problem-body .preview-box {
  flex: 1 1 auto;
  /* Drop the default top margin — there's no header above it on the
     problem page, so the margin only created an empty band. */
  margin: 0;
}

.preview-box {
  margin-top: 0.8rem; padding: 0.8rem; background: #ffffff;
  border-radius: 6px; border: 1px solid var(--card-border);
  font-size: 0.95rem; min-height: 4rem;
}

/* ─── Per-problem layout: signed-out & default signed-in view ────────
   By default we render `<preview> | <crop>` side-by-side (LaTeX is hidden).
   Signed-in users get an "Edit LaTeX" button that toggles `body.show-latex`,
   which restores the full preview+latex grid and stacks the crop below. */
body:not(.show-latex) .problem-body { grid-template-columns: 1fr; }
body:not(.show-latex) .problem-body .pane.latex-pane { display: none; }
/* Pull the crop strip up beside the preview when LaTeX is hidden */
body:not(.show-latex) .compact-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  margin-top: 1rem;
}
body:not(.show-latex) .compact-grid > .problem-body { margin-top: 0; }
body:not(.show-latex) .compact-grid > .problem-crops {
  margin-top: 0;
  /* When sitting beside .preview-box (single column in compact-grid),
     the inner crops grid should collapse to one column so the single
     instance-block expands to fill the column — otherwise it stays at
     half-width because of the default 1fr 1fr layout. */
  grid-template-columns: 1fr;
}
@media (max-width: 800px) {
  body:not(.show-latex) .compact-grid { grid-template-columns: 1fr; }
}

/* "Edit LaTeX" toggle button (only shown signed-in) */
.edit-latex-btn {
  display: none;
  margin-left: 0.4rem;
  padding: 0.18rem 0.55rem;
  background: var(--card-bg); border: 1px solid var(--card-border);
  border-radius: 6px; cursor: pointer; font-size: 0.85rem;
}
body.signed-in .edit-latex-btn { display: inline-block; }
.edit-latex-btn.active { background: var(--accent); color: white; border-color: var(--accent); }

/* When the per-problem page reparents the Edit LaTeX button into the
   preview pane (initProblemPage), pin it to the top-right corner so it
   floats over the preview-box without altering the box itself. The
   parent .pane needs position:relative for absolute positioning to
   anchor against it. z-index keeps it above MathJax/TikZ content. */
.problem-body .pane.has-edit-latex-overlay { position: relative; }
.problem-body .pane.has-edit-latex-overlay > .edit-latex-btn {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  margin-left: 0;
  z-index: 5;
  /* See-through so the underlying preview content remains visible
     through the button. Background uses an rgba over the card colour;
     border softened; opacity drops further until hover. */
  background: rgba(255, 255, 255, 0.35);
  border-color: rgba(0, 0, 0, 0.12);
  color: rgba(0, 0, 0, 0.55);
  opacity: 0.55;
  transition: opacity 120ms ease, background 120ms ease;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.problem-body .pane.has-edit-latex-overlay > .edit-latex-btn:hover {
  opacity: 1;
  background: var(--card-bg);
  color: inherit;
  border-color: var(--card-border);
}
.problem-body .pane.has-edit-latex-overlay > .edit-latex-btn.active {
  opacity: 1;
}

/* "+ Dodaj v test" — same overlay slot + style as Uredi LaTeX, but
   shown only when signed OUT (the two share the corner; one is visible
   at a time). Click to add/remove the current problem from the exam
   collection in localStorage. */
body.signed-in .add-to-exam-btn { display: none; }
.problem-body .pane.has-add-exam-overlay { position: relative; }
.problem-body .pane.has-add-exam-overlay > .add-to-exam-btn {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  z-index: 5;
  padding: 0.18rem 0.6rem;
  font-size: 0.85rem;
  border-radius: 6px;
  border: 1px solid rgba(0, 0, 0, 0.12);
  background: rgba(255, 255, 255, 0.35);
  color: rgba(0, 0, 0, 0.55);
  opacity: 0.55;
  cursor: pointer;
  transition: opacity 120ms ease, background 120ms ease;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  font-family: inherit;
}
.problem-body .pane.has-add-exam-overlay > .add-to-exam-btn:hover {
  opacity: 1;
  background: var(--card-bg);
  color: inherit;
  border-color: var(--card-border);
}
.problem-body .pane.has-add-exam-overlay > .add-to-exam-btn.in-exam {
  opacity: 1;
  background: var(--ok-bg);
  color: var(--ok);
  border-color: var(--ok);
}

/* "Full page" button — shown when signed-out (instead of Edit), shows the
   page image without selection UI */
.full-page-btn {
  display: inline-block;
  padding: 0.18rem 0.55rem;
  background: var(--card-bg); border: 1px solid var(--card-border);
  border-radius: 6px; cursor: pointer; font-size: 0.85rem;
}
body.signed-in .full-page-btn { display: none; }
body:not(.signed-in) .edit-crop-btn { display: none; }

/* ─── Comments thread — rendered as a dropdown anchored to the
   comments-toggle button next to the status badge. It overlays
   surrounding content via position:absolute + a high z-index. ─── */
.meta-row .status-row { position: relative; }
/* Hide the legacy standalone status badge — its role has moved into
   the left half of the comments-toggle split pill. */
.meta-row .status-row > #status-badge { display: none; }

/* Comments trigger — split-pill that mirrors the Matura "source-chip
   + arrow combo" on the Search page. The wrapper is a borderless
   span; the two inner BUTTONS render as a pill split in two thanks
   to matching borders, rounded outside corners, and a 1-pixel gap.
   Each half handles its own click: left = flip outdated state,
   right = toggle dropdown. */
.comments-toggle {
  display: inline-flex;
  align-items: stretch;
  gap: 1px;
  font-size: 0.78rem;
  line-height: 1;
}
.comments-toggle[hidden] { display: none; }
.comments-toggle-status,
.comments-toggle-arrow {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.55rem;
  padding: 0 0.55rem;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.85rem;
  line-height: 1;
  transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
}
/* Status chip — left half. Shows ✓ / ⚠ / N. */
.comments-toggle-status {
  border-top-left-radius: 999px;
  border-bottom-left-radius: 999px;
  font-weight: 600;
  min-width: 1.6rem;
}
/* When the arrow is hidden (problem up-to-date with no comments),
   the chip stands alone as a single fully-rounded pill. */
.comments-toggle.chip-only .comments-toggle-status {
  border-radius: 999px;
}
/* Arrow chip — right half. ▾ rotates 180° when dropdown is open. */
.comments-toggle-arrow {
  border-top-right-radius: 999px;
  border-bottom-right-radius: 999px;
  transition: transform 140ms ease, border-color 120ms ease, color 120ms ease;
}
.comments-toggle-status:hover,
.comments-toggle-arrow:hover {
  color: var(--accent);
  border-color: var(--accent);
}
.comments-toggle-arrow[aria-expanded="true"] {
  color: var(--accent);
  border-color: var(--accent);
  transform: rotate(180deg);
}
/* Has-comments: the count chip glows amber to flag unresolved
   feedback. Same palette for the ⚠ alert variant (outdated, no
   comments). */
.comments-toggle.has-comments .comments-toggle-status,
.comments-toggle.outdated     .comments-toggle-status {
  background: #d4a843;
  color: white;
  border-color: #d4a843;
}
.comments-toggle.has-comments .comments-toggle-status:hover,
.comments-toggle.outdated     .comments-toggle-status:hover {
  background: #b08323;
  border-color: #b08323;
  color: white;
}
.comments-thread {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: min(420px, 90vw);
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--card-border);
  border-radius: 10px;
  background: white;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.12);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  z-index: 30;
}
.comments-thread[hidden] { display: none; }
.comments-header { font-size: 0.85rem; color: var(--fg); }
.comments-header .comments-count { color: var(--muted); font-weight: 400; }
.comments-list { display: flex; flex-direction: column; gap: 0.4rem; }
.comment-bubble {
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 0.4rem 0.6rem;
}
.comment-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.78rem;
  color: var(--muted);
}
.comment-author { font-weight: 600; color: var(--fg); }
.comment-ts    { font-size: 0.72rem; }
.comment-delete {
  margin-left: auto;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.2rem;
}
.comment-delete:hover { color: #c25555; }
.comment-body {
  margin-top: 0.2rem;
  font-size: 0.9rem;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--fg);
}
.comment-composer { display: flex; flex-direction: column; gap: 0.4rem; }
.comment-composer textarea {
  width: 100%;
  min-height: 4.2rem;
  resize: vertical;
  padding: 0.45rem 0.6rem;
  font-family: inherit;
  font-size: 0.9rem;
  line-height: 1.35;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: white;
  color: var(--fg);
  outline: none;
  box-sizing: border-box;
}
.comment-composer textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent);
}
.comment-composer-actions { display: flex; gap: 0.4rem; }
.comment-add-btn {
  align-self: flex-start;
  border: 1px dashed var(--card-border);
  background: transparent;
  color: var(--muted);
  padding: 0.3rem 0.6rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.85rem;
}
.comment-add-btn:hover { color: var(--accent); border-color: var(--accent); }
/* Hide the comments thread for signed-out viewers: only signed-in
   users participate in the feedback loop. */
body:not(.signed-in) .comments-thread { display: none !important; }

/* ─── Signed-out problem page: hide matura crop + figure toggle, show
   a sidebar with stacked topics + tags boxes in its place. ─── */
body:not(.signed-in) .meta-row { display: none; }
body:not(.signed-in) .problem-crops { display: none; }
body:not(.signed-in) .tikz-toggle { display: none; }
body.signed-in .problem-sidebar { display: none; }
.problem-sidebar {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 1rem;
}
.problem-sidebar .sidebar-box {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 0.9rem;
}
.problem-sidebar .sidebar-box h3 {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}
.problem-sidebar .sidebar-box .tags {
  display: flex; flex-wrap: wrap; gap: 0.35rem;
  margin: 0;
}
.problem-sidebar .sidebar-box .topic-group {
  margin-right: 0.35rem;
}
/* Signed-out: widen the preview pane, narrow the sidebar. */
body:not(.signed-in):not(.show-latex) .compact-grid {
  grid-template-columns: 1.7fr 1fr;
}

/* Textbook problems don't carry a source-PDF page_image / paper_id /
   pola / level / points, so the matura crop pane would render as a
   blank canvas with an empty title — that's the "empty element" users
   were seeing. Hide it for textbook problems; the preview is the only
   thing in the row so the grid collapses to a single column. */
body.textbook-problem .problem-crops { display: none; }
body.textbook-problem.signed-in .compact-grid:not(.show-latex) {
  grid-template-columns: 1fr;
}
body.textbook-problem:not(.signed-in):not(.show-latex) .compact-grid {
  /* Sidebar (topics + tags) is the only side element; keep the slightly
     narrower side ratio so it doesn't dominate. */
  grid-template-columns: 2fr 1fr;
}
/* Mobile / narrow viewports: stack the preview on top and the sidebar
   (topics + tags) below it instead of running them side-by-side. We
   need this dedicated media query because the signed-out rule above
   has higher specificity than the generic `body:not(.show-latex)`
   collapse at line ~837, so without an explicit mobile override the
   1.7fr/1fr split sticks on phones. */
@media (max-width: 800px) {
  body:not(.signed-in):not(.show-latex) .compact-grid {
    grid-template-columns: 1fr;
  }
  /* Drop the redundant margin-top so the stacked sidebar's spacing is
     governed entirely by the grid's `gap`, avoiding double-spacing. */
  body:not(.signed-in):not(.show-latex) .compact-grid > .problem-sidebar {
    margin-top: 0;
  }
}

/* "Full page" mode of the crop editor — hide selection box + Save button,
   show only Cancel ("Close") plus the read-only page view. */
.crop-editor.readonly .selection-box { display: none !important; }
.crop-editor.readonly .save-crop-btn { display: none !important; }
.crop-editor.readonly canvas { cursor: default; }
.crop-editor.readonly .cancel-crop-btn::before { content: ""; }
/* Read-only Full page: don't say "Select an area"; the JS hides the
   editor's own h3 and shows the instance label from .crop-view instead
   so the user sees the paper title (e.g. "2025 Spomladanski rok …"). */
.crop-editor.readonly .pane-header h3 { display: none; }
/* When body has the full-page toggle ON, the active full-page editor
   replaces the crop-view; the standalone .crop-view (with title +
   buttons) is the only header visible. */
body.full-page-on .crop-view { display: none; }
.preview-box .tex-center,
.finishing-block-body .tex-center { text-align: center; margin: 0.4rem 0; }
/* Tables that would otherwise overflow the card get wrapped in
   `.tex-tabular-scroll` (rendered by the tabular handler) so a
   horizontal scroll bar appears instead of the table stretching the
   surrounding chrome past the problem-card width. */
.tex-tabular-scroll {
  max-width: 100%;
  overflow-x: auto;
  margin: 0.5rem auto;
}
.tex-tabular {
  max-width: 100%;
}
.preview-box .tex-tabular,
.finishing-block-body .tex-tabular { margin: 0.5rem auto; border-collapse: collapse; }
.preview-box .tex-tabular td, .preview-box .tex-tabular th,
.finishing-block-body .tex-tabular td, .finishing-block-body .tex-tabular th {
  border: 1px solid #999; padding: 0.55rem 0.9rem; text-align: left; vertical-align: middle;
  line-height: 1.45;
}
/* Mirror the LaTeX column-spec: when the source doesn't contain `|`
   the rendered table should have no cell borders. The renderer adds
   .tex-tabular-borderless to those tables. */
.preview-box .tex-tabular-borderless td, .preview-box .tex-tabular-borderless th,
.finishing-block-body .tex-tabular-borderless td, .finishing-block-body .tex-tabular-borderless th {
  border: none;
}
/* Fill-in tables (any tabular preceded by \arraystretch >= 1.5): give
   each row enough vertical room for handwritten answers, and keep
   cells from wrapping where the content fits. */
.preview-box .tex-tabular-fillin td,
.preview-box .tex-tabular-fillin th,
.finishing-block-body .tex-tabular-fillin td,
.finishing-block-body .tex-tabular-fillin th {
  height: calc(2.2rem * var(--stretch, 1.5));
  padding: 0.4rem 1rem;
  vertical-align: top;
  white-space: nowrap;
}
/* Drop nowrap when the cell holds long prose (heuristic: more than one
   word + at least 24 chars). Implemented via a wrapping class set by
   the renderer when a cell looks prose-y. */
.preview-box .tex-tabular-fillin td.long-cell,
.finishing-block-body .tex-tabular-fillin td.long-cell {
  white-space: normal;
}
/* Proportional full-width tables: when every column is p{...cm} the renderer
   converts the widths to percentages and adds .tex-tabular-prop, so the table
   fills the panel at the original's exact column proportions. */
.preview-box .tex-tabular-prop,
.finishing-block-body .tex-tabular-prop { width: 100%; }
/* No internal vertical rules (colspec like `|p{}p{}|`): keep the outer box and
   horizontal lines, drop the column separators. */
.preview-box .tex-tabular-novert td, .preview-box .tex-tabular-novert th,
.finishing-block-body .tex-tabular-novert td, .finishing-block-body .tex-tabular-novert th {
  border-left: none; border-right: none;
}
.preview-box .tex-tabular-novert td:first-child, .preview-box .tex-tabular-novert th:first-child,
.finishing-block-body .tex-tabular-novert td:first-child, .finishing-block-body .tex-tabular-novert th:first-child {
  border-left: 1px solid #999;
}
.preview-box .tex-tabular-novert td:last-child, .preview-box .tex-tabular-novert th:last-child,
.finishing-block-body .tex-tabular-novert td:last-child, .finishing-block-body .tex-tabular-novert th:last-child {
  border-right: 1px solid #999;
}
/* Compact header row (first bold row): keep it short while the answer rows
   below stay tall — matches the original exam tables. */
.preview-box .tex-tabular .tex-row-head td,
.finishing-block-body .tex-tabular .tex-row-head td {
  height: auto;
  padding-top: 0.3rem; padding-bottom: 0.3rem;
  vertical-align: middle;
}
/* "Namig" (Hint) box — peach background, dashed border, mirrors the
   sidebar callout that sits next to the fill-in tables in the original
   textbook scans. */
.preview-box .tex-namig,
.finishing-block-body .tex-namig {
  display: inline-block;
  background: #ffe9d8;
  border: 1.5px dashed #d98059;
  border-radius: 6px;
  padding: 0.6rem 1rem;
  margin: 0.6rem 0;
  color: #6b3a17;
  font-size: 0.95em;
}
.preview-box .tex-namig .tex-namig-label,
.finishing-block-body .tex-namig .tex-namig-label {
  font-style: italic;
  font-weight: 600;
  margin-right: 0.4rem;
}
/* Two-column hint: left = stacked proportion, right = resolved formula. */
.preview-box .tex-namig-split,
.finishing-block-body .tex-namig-split {
  display: grid;
  grid-template-columns: auto auto auto;
  grid-template-rows: auto auto;
  column-gap: 1.2rem;
  align-items: center;
}
.preview-box .tex-namig-split .tex-namig-label,
.finishing-block-body .tex-namig-split .tex-namig-label {
  grid-row: 1 / span 2;
  grid-column: 1;
  align-self: center;
}
.preview-box .tex-namig-split .tex-namig-left,
.finishing-block-body .tex-namig-split .tex-namig-left {
  grid-row: 1 / span 2;
  grid-column: 2;
  line-height: 1.55;
  white-space: nowrap;
}
.preview-box .tex-namig-split .tex-namig-right,
.finishing-block-body .tex-namig-split .tex-namig-right {
  grid-row: 1 / span 2;
  grid-column: 3;
  align-self: center;
  line-height: 1.55;
  white-space: nowrap;
}
.preview-box .tex-list,
.finishing-block-body .tex-list { margin: 0.4rem 0 0.4rem 1.4rem; padding-left: 0; }
/* When an item carries an explicit a)/b)/c) label, hide the default
   bullet (the label IS the marker). */
.preview-box .tex-list li:has(.tex-item-label),
.finishing-block-body .tex-list li:has(.tex-item-label) {
  list-style: none;
  margin-left: -1.4rem;
}
.tex-item-label {
  display: inline-block;
  font-weight: 600;
  min-width: 1.5rem;
  margin-right: 0.25rem;
}
.preview-box .tex-tikz,
.finishing-block-body .tex-tikz { text-align: center; margin: 0.5rem 0; }
.preview-box .tex-tikz {
  /* Inline-block so width: <px>; height: <px> set by JS after the first
     hydrate locks the figure size for all subsequent edits. The min-*
     fallbacks keep the box from collapsing to text width if a render
     starts before the build-time img has loaded (the sync lock-snapshot
     in renderTeXPreview only works once the image is rendered). */
  /* Block-level flex so the box spans the preview column (was inline-flex,
     which shrank to the image's intrinsic width and kept figures small).
     Now the child img/svg `width:100%` can actually grow to fill it. */
  display: flex;
  align-items: center; justify-content: center;
  background: white; padding: 4px;
  border: 1px solid var(--card-border); border-radius: 4px;
  box-sizing: border-box;
  overflow: hidden;
  width: 100%; max-width: 100%;
  min-width: 200px; min-height: 100px;
  /* Click-to-enlarge: a click on the figure opens a fixed-position
     lightbox (built by JS) — see .figure-lightbox below. The figure
     itself stays in place; we just give the user a cursor hint that
     it's clickable. */
  position: relative;
  cursor: zoom-in;
}

/* Lightbox overlay for an enlarged figure. The cloned SVG/img inside
   has its width/height attributes stripped so the browser re-renders
   it at the overlay's larger intrinsic size — for SVG sources this
   yields a crisp render (no transform-based pixelation). Click anywhere
   to dismiss. */
.figure-lightbox {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.65);
  display: flex; align-items: center; justify-content: center;
  z-index: 9999;
  cursor: zoom-out;
  padding: 2rem;
  animation: figure-lightbox-in 140ms ease;
}
@keyframes figure-lightbox-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.figure-lightbox .figure-lightbox-content {
  background: white;
  padding: 1.5rem;
  border-radius: 10px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
  width: 92vw;
  height: 92vh;
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  cursor: default;
}
/* Give the cloned SVG/img concrete dimensions to fill — for SVG, the
   browser uses preserveAspectRatio (default xMidYMid meet) to scale the
   viewBox to fit while preserving aspect ratio, so we get a crisp full-
   viewport re-render. `width: auto` on SVG would otherwise fall back to
   the 300×150 default and the lightbox content wouldn't actually grow. */
.figure-lightbox .figure-lightbox-content > svg,
.figure-lightbox .figure-lightbox-content > img {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
}
.preview-box .tex-tikz img,
.preview-box .tex-tikz svg {
  /* Scale figures UP to fill the preview column (SVG is vector, so it stays
     crisp) instead of pinning to their small intrinsic pt size. */
  width: 100%; max-width: 600px;
  height: auto; max-height: 600px;
}
/* Original-crop images: match the same height limit as the TikZ SVG so
   toggling between TikZ render and original gives comparable visual size.
   The .is-locked rule below still letterboxes inside the locked box. */
.preview-box .tex-tikz img.tikz-orig-img {
  max-height: 600px;
}
/* Once the JS locks .tex-tikz to {width, height}, child img/svg fills it
   exactly. For the original-crop case we use object-fit:contain so the
   image letterboxes inside the locked box instead of distorting. */
.preview-box .tex-tikz.is-locked img,
.preview-box .tex-tikz.is-locked svg {
  width: 100%; height: 100%;
  max-width: none; max-height: none;
}
.preview-box .tex-tikz.is-locked img.tikz-orig-img {
  object-fit: contain;
}
/* Textbook problems are image-only: a single PNG crop replaces the LaTeX
   preview body. Sizing rules per surface so the same image looks reasonable
   inside a 18em search-result card, on the index, in the exam preview, in
   the collection dropdown, and on the standalone problem page. */
.textbook-body-img {
  display: block; max-width: 100%; height: auto;
  border-radius: 4px;
}
.search-result .result-body .textbook-body-img {
  /* Width-first sizing: the image fills the card's body column, then
     keeps its natural aspect ratio. The card's own `overflow: hidden`
     + 18em fixed height clip anything that doesn't fit vertically,
     and the bottom-fade gradient covers the cut-off. On hover the
     card grows to its auto height and the full image becomes visible.
     (Earlier this used `max-height: 11em; width: auto;`, which made
     wide-aspect matura crops render at a tiny fraction of the card's
     width.) */
  width: 100%; height: auto; max-width: 100%;
}
.search-result-wrap.is-hovered .search-result .result-body .textbook-body-img {
  /* width:100% stays; nothing more needed — the card itself expanded. */
}
.collection-preview .textbook-body-img {
  max-height: 4.5em; width: auto;
}
.finishing-block-body .textbook-body-img {
  max-width: 100%; height: auto;
  margin: 0.2rem 0;
}
.preview-box .textbook-body-img {
  max-width: 100%;
}

.preview-box .tex-tikz .tikz-loading {
  display: inline-block; padding: 0.4rem 0.8rem;
  font-size: 0.8rem; color: var(--muted);
  background: #f5f5f5; border: 1px dashed #ccc; border-radius: 6px;
}
/* When the latest TikZ source fails to compile, we keep whatever was last
   shown visible and overlay a warning badge in the corner. If there's no
   previous render to keep, .tikz-error-msg replaces the body. */
.preview-box .tex-tikz.tikz-compile-error {
  position: relative;
}
.preview-box .tex-tikz.tikz-compile-error::after {
  content: "⚠ TikZ didn't compile";
  position: absolute;
  top: 4px; right: 4px;
  font-size: 0.7rem;
  padding: 0.15rem 0.5rem;
  background: var(--warn-bg);
  color: var(--warn);
  border: 1px solid var(--warn);
  border-radius: 999px;
  pointer-events: none;
}
.preview-box .tex-tikz .tikz-error-msg {
  display: inline-block; padding: 0.4rem 0.8rem;
  font-size: 0.85rem; color: var(--warn);
  background: var(--warn-bg);
  border: 1px dashed var(--warn); border-radius: 6px;
}
.preview-box .tex-figure-placeholder,
.finishing-block-body .tex-figure-placeholder {
  margin: 0.5rem 0; padding: 0.5rem 0.8rem; background: var(--warn-bg);
  border: 1px dashed var(--warn); color: var(--warn); border-radius: 6px;
  text-align: center; font-style: italic; font-size: 0.9rem;
}
.preview-box .tex-fbox,
.finishing-block-body .tex-fbox { border: 1px solid #555; padding: 0 0.3em; }
/* \ansbox{W}{H} — a blank W×H cm write-in answer box (size from inline style). */
.preview-box .tex-ansbox,
.finishing-block-body .tex-ansbox {
  display: inline-block; border: 1px solid #555; vertical-align: middle;
}
/* \encircle{...} — oval ring around a worked-example answer in a table. */
.preview-box .tex-circled,
.finishing-block-body .tex-circled {
  display: inline-block; border: 1.5px solid #333; border-radius: 50%;
  padding: 0.12em 0.6em; line-height: 1.1;
}
.preview-box .tex-rule,
.finishing-block-body .tex-rule { color: #777; letter-spacing: -1px; }
.preview-box p { margin: 0.4rem 0; }
.preview-box p:first-child { margin-top: 0; }
.preview-box p:last-child  { margin-bottom: 0; }

.hint { color: var(--muted); font-size: 0.82rem; margin: 0.4rem 0 0; }

.export-row { margin-top: 1.2rem; display: flex; gap: 0.6rem; flex-wrap: wrap; }
/* Mobile-friendly tap target — disable the iOS long-press callout/share
   sheet, kill double-tap zoom, prevent accidental text selection. */
.export-row button,
#download-tex,
#download-pdf,
.pdf-split-arrow {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}

/* Split button — a primary main button welded to a smaller secondary
   button on its right (Download PDF + ▾ dropdown, Push + 🗑 discard).
   The two pieces share a 1-px seam and stripped corners on the seam side. */
.pdf-split-btn {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  gap: 1px;          /* thin seam between main button and side */
}
.pdf-split-btn > .pdf-split-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  margin: 0;
}
.pdf-split-arrow {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  padding: 0 0.55rem;
  font-size: 0.7rem;
  line-height: 1;
  margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.pdf-split-arrow svg { display: block; }
.pdf-split-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  background: #ffffff;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  padding: 4px;
  z-index: 200;
  min-width: max-content;
}
.pdf-split-menu[hidden] { display: none; }
.pdf-split-menu-item {
  display: block;
  width: 100%;
  background: transparent;
  border: 0;
  border-radius: 4px;
  padding: 6px 12px;
  text-align: left;
  cursor: pointer;
  font: inherit;
  font-size: 0.88rem;
  color: var(--fg);
  white-space: nowrap;
}
.pdf-split-menu-item strong { font-weight: 500; }
.pdf-split-menu-item:hover,
.pdf-split-menu-item:focus-visible {
  background: #f1f5fb;
  outline: none;
}

/* Crop display (canvas) */
canvas.crop-display {
  display: block;
  max-width: 100%; height: auto;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 4px;
}
.image-controls { margin-top: 0.7rem; display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }

/* Per-instance Original blocks. Now laid out as cells in the
   .problem-crops grid, so no margin/border-top between siblings — the
   grid `gap` handles spacing. */
.instance-block {
  display: flex; flex-direction: column;
}

/* The <select> that lets the user switch between Matura instances
   (year/season/level/pola). Sits inside the pane-header next to the
   Edit/Reset buttons, so we match their compact button styling. */
.instance-picker {
  font: inherit;
  font-size: 0.85rem;
  padding: 0.25rem 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  color: inherit;
  cursor: pointer;
  max-width: 18rem;
}
.instance-picker:hover { border-color: var(--accent, #5a90ff); }
.instance-picker:focus { outline: 2px solid var(--accent, #5a90ff); outline-offset: 1px; }

/* When the picker IS the title (no separate h3), size and weight it
   to match the .pane-header h3 it replaces. Keep the native chevron
   so it's obviously a dropdown — drawn via a CSS background image so
   it works even when the <select>'s native styling is suppressed. */
.instance-picker.title-picker {
  font-size: 1rem;
  font-weight: 600;
  padding: 0.15rem 1.5rem 0.15rem 0.4rem;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 0.85rem) calc(50% - 2px),
    calc(100% - 0.55rem) calc(50% - 2px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  max-width: none;
}
.instance-picker.title-picker:hover {
  border-color: var(--card-border);
  background-color: rgba(0, 0, 0, 0.04);
}
.instance-picker.title-picker:focus {
  outline: 2px solid var(--accent, #5a90ff);
  outline-offset: 1px;
}

/* Crop editor */
.crop-editor {
  margin-top: 1rem; border: 1px solid var(--card-border);
  border-radius: 8px; background: white; padding: 1rem;
}
.crop-editor[hidden] { display: none; }
.crop-editor h3 { margin: 0 0 0.6rem; font-size: 1rem; }
.canvas-wrap {
  position: relative; display: inline-block;
  max-width: 100%; line-height: 0;
  background: #f0f0f0;
}
.canvas-wrap canvas {
  display: block; cursor: crosshair;
  touch-action: none; user-select: none;
}
.canvas-wrap .selection-box {
  position: absolute;
  border: 2px solid var(--accent);
  background: rgba(200, 74, 74, 0.10);
  pointer-events: none;
}
.editor-actions {
  margin-top: 0.7rem; display: flex; gap: 0.5rem; flex-wrap: wrap;
}

/* Top bar that holds the GitHub controls on the right */
.top-bar {
  display: flex; align-items: center; gap: 0.75rem;
  margin-bottom: 0.5rem; flex-wrap: wrap;
  min-height: 2.2rem;
}
.top-bar .page-title {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 600;
  color: var(--fg);
  line-height: 1;
}

/* Problem navigation under the H1 — just arrows + menu */
.problem-nav {
  display: flex; gap: 0.4rem; align-items: center;
  margin: 0.3rem 0 0.9rem;
}
.problem-nav .nav-arrow,
.problem-nav .nav-menu {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 3.2rem;
  padding: 0.25rem 1rem;
  font-size: 0.95rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  color: var(--fg);
  text-decoration: none;
  background: white;
}
.problem-nav .nav-arrow:hover,
.problem-nav .nav-menu:hover {
  border-color: var(--accent); color: var(--accent);
  text-decoration: none;
}
.problem-nav .nav-arrow.disabled {
  color: #ccc; background: #f7f7f7;
  cursor: default;
}

/* Collection bar (folder dropdown next to Push) */
.collection-bar { position: relative; display: inline-flex; }
.collection-btn {
  display: inline-flex; align-items: center; gap: 0.32rem;
  padding: 0.35rem 0.75rem;
  font: inherit; font-size: 0.88rem; font-weight: 500;
  background: white;
  color: var(--fg);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  cursor: pointer;
}
.collection-btn:hover { border-color: var(--accent); color: var(--accent); }
.collection-btn .collection-icon { font-size: 1rem; line-height: 1; }
.collection-btn .collection-count {
  background: var(--accent); color: white;
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  font-size: 0.75rem; font-weight: 600;
  min-width: 1.2rem; text-align: center;
}
.collection-dropdown {
  position: absolute; top: calc(100% + 6px); right: 0;
  min-width: 320px; max-width: 480px;
  max-height: 420px; overflow-y: auto;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.10);
  padding: 0.4rem;
  z-index: 100;
}
.collection-dropdown[hidden] { display: none; }
.collection-empty {
  padding: 0.5rem 0.6rem;
  color: var(--muted);
  font-style: italic;
  font-size: 0.85rem;
}
/* Collection-dropdown header row: count summary on the left, Clear-all
   button on the right. Sits above the first problem row, separated by a
   thin divider so it reads as a controls strip. */
.collection-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.6rem;
  padding: 0.35rem 0.55rem 0.45rem;
  margin-bottom: 0.35rem;
  border-bottom: 1px solid var(--card-border);
}
.collection-summary {
  font-size: 0.82rem; color: var(--muted); line-height: 1;
}
.collection-clear {
  appearance: none;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  color: var(--muted);
  border-radius: 999px;
  padding: 0.22rem 0.7rem;
  font-size: 0.8rem; line-height: 1;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.collection-clear:hover {
  background: var(--warn-bg);
  color: var(--warn);
  border-color: var(--warn);
}
.collection-row {
  display: flex; align-items: flex-start; gap: 0.4rem;
  padding: 0.4rem 0.5rem;
  border-radius: 4px;
  border-bottom: 1px solid #f3f4f6;
}
.collection-row:last-child { border-bottom: 0; }
.collection-row:hover { background: #f9fafb; }
.collection-link {
  flex: 1; min-width: 0;
  display: flex; align-items: flex-start; gap: 0.5rem;
  text-decoration: none;
  color: var(--fg);
}
.collection-link:hover { color: var(--accent); }
.collection-num {
  flex-shrink: 0;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--accent);
  min-width: 1.6rem;
}
.collection-preview {
  flex: 1; min-width: 0;
  font-size: 0.82rem;
  color: var(--fg);
  line-height: 1.35;
  max-height: 4em;          /* a few lines of math/text */
  overflow: hidden;
  text-overflow: ellipsis;
  position: relative;
}
.collection-preview::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1em;
  background: linear-gradient(to bottom, transparent, white);
  pointer-events: none;
}
.collection-row:hover .collection-preview::after {
  background: linear-gradient(to bottom, transparent, #f9fafb);
}
.collection-preview p { margin: 0.1rem 0; }
.collection-preview .tex-tikz,
.collection-preview .tex-figure-placeholder { display: none; }
.collection-preview .tex-tabular { font-size: 0.78rem; }
.collection-remove {
  background: rgba(0,0,0,0.08);
  color: var(--muted);
  border: 0;
  border-radius: 999px;
  width: 1.1rem; height: 1.1rem;
  font-size: 0.78rem; line-height: 1; font-weight: 700;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.collection-remove:hover { background: rgba(0,0,0,0.18); color: #111; }

/* GitHub sync — compact button + dropdown in the top-right */
/* Signed-out approval-filter toggle. Sits in the top-right slot where
   the Sign in button used to live (we still emit Sign in, but it's
   display:none — its dropdown is reached through the menu). The toggle's
   aria-pressed reflects "Approved only" mode:
     pressed=true  → filter ON  (default for new visitors)
     pressed=false → showing everything */
.approval-filter-btn {
  appearance: none;
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.36rem 0.7rem;
  border: 1px solid var(--card-border);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--fg);
  font-size: 0.82rem;
  cursor: pointer;
  line-height: 1;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.approval-filter-btn:hover { border-color: var(--accent); color: var(--accent); }
.approval-filter-btn[aria-pressed="true"] {
  background: var(--ok-bg);
  color: var(--ok);
  border-color: var(--ok);
}
.approval-filter-btn[aria-pressed="true"] .af-icon-off { display: none; }
.approval-filter-btn[aria-pressed="false"] .af-icon-on  { display: none; }
.approval-filter-btn .af-icon { flex: none; }
.approval-filter-btn .approval-filter-label { white-space: nowrap; }

/* Filtered-out card: keep it in the DOM so the count badges can reason
   about totals, but pull it out of the layout entirely. */
.unapproved-hidden { display: none !important; }
/* Same idea for the index-page source-filter (By-topic / By-year). */
.filter-hidden { display: none !important; }
/* The index-page source filter is COLLAPSED by default: visitors see
   only a small "Source ▾" pill sitting inline in the browse-mode tab
   row (just left of Export all). Clicking expands the full chip+
   panel UI below as an absolutely-positioned dropdown so the Export
   button doesn't get pushed sideways. */
.index-source-filter-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  align-self: center;
  margin-right: 0.5rem;
}
.index-source-filter-wrap[hidden] { display: none !important; }
.index-source-filter-wrap > summary { list-style: none; }
.index-source-filter-wrap > summary::-webkit-details-marker { display: none; }
.index-source-filter-summary {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.32rem 0.7rem;
  border: 1px solid var(--card-border);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--fg);
  cursor: pointer;
  font-size: 0.84rem; line-height: 1;
  transition: border-color 120ms ease, background 120ms ease, color 120ms ease;
  white-space: nowrap;
}
.index-source-filter-summary:hover { border-color: var(--accent); color: var(--accent); }
.index-source-filter-wrap[open] > .index-source-filter-summary {
  border-color: var(--accent);
  color: var(--accent);
}
.index-source-filter-label { font-weight: 500; }
.index-source-filter-arrow {
  color: var(--muted);
  font-size: 0.85rem; line-height: 1;
  transition: transform 140ms ease;
}
.index-source-filter-wrap[open] > .index-source-filter-summary .index-source-filter-arrow {
  transform: rotate(180deg);
  color: var(--accent);
}
/* Expanded chip/panel container. Popped out as an absolute dropdown
   so opening it doesn't shift the Export-all button. Anchored to the
   pill's right edge so it grows leftward. */
.index-source-filter {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  padding: 0.7rem 0.9rem 0.5rem;
  background: #ffffff;
  border: 1px solid var(--card-border);
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
  min-width: 320px;
  max-width: min(640px, 92vw);
  z-index: 50;
}
.gh-sync { position: relative; display: inline-flex; gap: 0.3rem; }
.gh-sync .gh-state { position: relative; display: inline-flex; gap: 0.3rem; }
.gh-sync .gh-state[hidden] { display: none !important; }
/* The Sign in button has been moved into the hamburger menu — hide the
   duplicate one in the top-right. The dropdown form (#gh-signin-dropdown)
   stays in the DOM, anchored to .gh-sync, and is opened by the menu item
   programmatically clicking #gh-signin-btn. */
#gh-signin-btn { display: none !important; }
.gh-sync .dropdown-toggle {
  width: 2.3rem;
  padding: 0 0 0.32rem 0;
  font-size: 1.5rem; line-height: 1;
}
/* Push + discard split button. When the trashcan is hidden (nothing to
   discard) restore the Push button's right-side rounding so it doesn't
   look like one half of an amputated split control. */
.gh-push-split #gh-discard[hidden] { display: none !important; }
.gh-push-split:has(#gh-discard[hidden]) > #gh-push.pdf-split-main {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}
.gh-sync .gh-dropdown {
  position: absolute; top: calc(100% + 6px); right: 0;
  min-width: 280px;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.10);
  padding: 0.6rem;
  z-index: 100;
}
/* Sign-in dropdown is anchored directly under the Sign in button, not
   spread across the bar. The button itself acts as the positioning
   ancestor via a wrapper. */
.gh-signed-out { position: relative; }
.gh-signed-out .gh-signin-dropdown {
  right: 0;
  top: calc(100% + 6px);
}
/* Name/Key tabs inside the sign-in dropdown. */
.gh-signin-tabs {
  display: flex; gap: 0;
  margin-bottom: 0.5rem;
  border-bottom: 1px solid var(--card-border);
}
.gh-signin-tab {
  flex: 1;
  font: inherit; font-size: 0.85rem;
  padding: 0.4rem 0.6rem;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  cursor: pointer;
}
.gh-signin-tab:hover { color: var(--fg); }
.gh-signin-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}
.gh-signin-tab-panel { margin-bottom: 0.5rem; }
.gh-signin-tab-panel[hidden] { display: none; }
/* Pin BOTH inputs to a complete, identical visual spec — covering the
   subtle defaults browsers apply differently to type="text" vs
   type="password" (Safari uses a smaller, sometimes monospaced font
   for password fields; Chrome adds a slightly different baseline;
   autofill backgrounds also differ). Targeting the input element
   itself (not just the two specific types) makes sure no rule sneaks
   in via attribute selector ordering. */
.gh-signin-tab-panel input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 0.5rem 0.7rem;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: normal;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: white;
  color: var(--fg);
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
}
.gh-signin-tab-panel input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent);
}
/* Browsers sometimes render password placeholders in a monospaced
   font; force the same family as the text input. */
.gh-signin-tab-panel input::placeholder {
  font-family: inherit;
  letter-spacing: normal;
  color: var(--muted);
  opacity: 1;
}
/* Kill autofill yellow on Chrome/Safari so both fields stay white. */
.gh-signin-tab-panel input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px white inset;
  -webkit-text-fill-color: var(--fg);
}
.gh-sync .gh-dropdown[hidden] { display: none; }
/* On narrow viewports the .gh-sync button can sit near the left side
   of the top bar, and a right-anchored 240px-wide dropdown then
   extends past the viewport's left edge. Promote to position:fixed
   on phones, anchored to the viewport's top-right with a small
   gutter, with max-width clamped so it never overflows horizontally. */
@media (max-width: 640px) {
  .gh-sync .gh-dropdown {
    position: fixed;
    top: 60px;
    right: 8px;
    left: auto;
    min-width: 0;
    width: auto;
    max-width: calc(100vw - 16px);
  }
}
.gh-sync .gh-row {
  font-size: 0.85rem; padding: 0.25rem 0.4rem;
}
.gh-sync .gh-hint {
  font-size: 0.78rem; color: var(--muted);
  margin: 0 0 0.5rem 0;
}
.gh-sync .gh-hint code {
  background: #f3f4f6; padding: 0 0.3em; border-radius: 3px;
}
.gh-sync input[type=password] {
  font: inherit; font-size: 0.85rem;
  width: 100%;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
}
.gh-sync .gh-actions {
  display: flex; gap: 0.4rem; margin-top: 0.5rem;
}
.gh-sync .pending {
  background: var(--warn-bg); color: var(--warn);
  font-size: 0.75rem; padding: 0.15rem 0.55rem; border-radius: 999px;
}
.gh-sync .pending.none { background: var(--ok-bg); color: var(--ok); }
.gh-sync hr {
  border: 0; border-top: 1px solid var(--card-border);
  margin: 0.4rem 0;
}
.gh-sync .dropdown-item {
  display: block; width: 100%;
  text-align: left;
  padding: 0.35rem 0.55rem;
  background: transparent; border: 0;
  font-size: 0.88rem;
  border-radius: 4px;
  cursor: pointer;
}
.gh-sync .dropdown-item:hover { background: #f3f4f6; color: var(--accent); }
.gh-sync .gh-muted { color: var(--muted); }
.gh-sync .gh-row strong { color: var(--fg); }
/* Clicking the displayed name opens an inline rename. We hint at
   interactivity with a hover-only color shift — no underline, no
   special static styling, so it sits naturally in the menu. */
.gh-sync .gh-display-clickable { cursor: pointer; }
.gh-sync .gh-display-clickable:hover { color: var(--accent); }
/* While the user is renaming inline: accent outline + text caret so
   it reads as an active text field. */
.gh-sync .gh-display-clickable.is-editing {
  cursor: text;
  outline: 1px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}
.gh-sync .gh-login-row { padding-top: 0; padding-bottom: 0.4rem; font-size: 0.78rem; }
.gh-sync .gh-display-form { padding: 0.2rem 0.2rem 0; }
.gh-sync .gh-display-form input[type=text] {
  font: inherit; font-size: 0.85rem;
  width: 100%;
  padding: 0.35rem 0.55rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
}

/* Top-left hamburger menu */
.menu-bar { position: relative; display: inline-flex; }
.menu-bar .menu-toggle {
  width: 2.6rem; height: 2.2rem;
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.menu-bar .bars,
.menu-bar .bars::before,
.menu-bar .bars::after {
  display: block; content: '';
  width: 22px; height: 2px;
  background: currentColor;
  border-radius: 2px;
}
.menu-bar .bars { position: relative; }
.menu-bar .bars::before { position: absolute; top: -7px; left: 0; }
.menu-bar .bars::after  { position: absolute; top:  7px; left: 0; }
.menu-bar .menu-dropdown {
  position: absolute; top: calc(100% + 6px); left: 0;
  min-width: 240px;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.10);
  padding: 0.5rem;
  z-index: 100;
}
.menu-bar .menu-dropdown[hidden] { display: none; }
.menu-bar .menu-h {
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 0.3rem 0.55rem 0.2rem;
}
.menu-bar .menu-tree { display: flex; flex-direction: column; gap: 0.05rem; }
/* Deep menu branches stay hidden until JS marks the matching path active. */
.menu-bar .menu-branch { display: none; }
.menu-bar .menu-branch[data-active] { display: block; }
.menu-bar .menu-link {
  display: block;
  padding: 0.32rem 0.55rem;
  font-size: 0.92rem;
  color: var(--fg);
  border-radius: 4px;
  text-decoration: none;
}
.menu-bar .menu-link.l1 { padding-left: 0.9rem; }
.menu-bar .menu-link.l2 { padding-left: 1.7rem; font-size: 0.88rem; }
.menu-bar .menu-link.l3 { padding-left: 2.5rem; font-size: 0.86rem; color: var(--muted); }
.menu-bar .menu-link.l4 { padding-left: 3.3rem; font-size: 0.84rem; color: var(--muted); font-weight: 500; }
.menu-bar .menu-link.l3:hover,
.menu-bar .menu-link.l4:hover { color: var(--accent); }
.menu-bar .menu-link:hover {
  background: #f3f4f6; color: var(--accent);
  text-decoration: none;
}
/* The Sign in entry is a <button>, not an <a> — strip the default browser
   chrome so it matches the surrounding menu links. */
.menu-bar button.menu-link {
  background: transparent; border: 0; cursor: pointer;
  font: inherit; text-align: left; width: 100%;
}
.menu-bar button.menu-link:hover { background: #f3f4f6; }
/* Prijava reads in a soft pastel red — enough to flag it as the
   sign-in affordance without the eye-magnet pull of the bright accent
   red the menu used originally. */
.menu-bar button.menu-link.menu-signin { color: #c96666; font-weight: 500; }
.menu-bar button.menu-link.menu-signin:hover { color: #b14e4e; }
.menu-bar button.menu-link.menu-signin[hidden] { display: none !important; }

/* Current-page menu link: grayed-out + non-interactive so it reads as
   "you are here". Added by initMenuBar() based on location.pathname. */
.menu-bar .menu-link.is-current {
  color: var(--muted) !important;
  cursor: default;
  pointer-events: none;
  background: rgba(0, 0, 0, 0.04);
}
.menu-bar .menu-current {
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.22rem 0.55rem 0.22rem 1.9rem;
  font-size: 0.85rem;
  color: var(--accent);
  font-weight: 600;
}
.menu-bar .menu-current.l5 { padding-left: 4rem; }
.menu-bar .menu-tags { display: inline-flex; gap: 0.2rem; flex-wrap: wrap; }
.menu-bar .menu-tags .tag {
  font-size: 0.66rem; padding: 0.06rem 0.4rem;
}

/* Search page */
.filters-panel {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 1rem 1.1rem;
  margin: 0.8rem 0 1.2rem;
}
.filter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.9rem 1.5rem;
  margin-bottom: 1rem;
}
.filter-cell { display: flex; flex-direction: column; gap: 0.3rem; }
/* Search-page keyword input — sits at the top of the filter strip,
   above Source. Substring match against the transcribed LaTeX. */
.filter-keyword-cell { width: 100%; }
.filter-keyword-input {
  font: inherit; font-size: 0.95rem;
  padding: 0.45rem 0.75rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  background: var(--card-bg); color: var(--fg);
  width: 100%; max-width: 32rem;
  box-sizing: border-box;
  transition: border-color 120ms ease;
}
.filter-keyword-input:focus {
  outline: none; border-color: var(--accent);
}
.filter-keyword-input::placeholder { color: var(--muted); }
.filter-label {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}
.filter-label-row {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 0.3rem;
}
.range-inputs {
  display: flex; align-items: center; gap: 0.45rem;
}
.range-inputs input[type=number] {
  width: 5.5rem;
  padding: 0.3rem 0.55rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  font: inherit;
  font-size: 0.88rem;
}
.range-inputs span { color: var(--muted); }
.checkbox-group {
  display: flex; flex-wrap: wrap; gap: 0.5rem 0.9rem;
  font-size: 0.88rem;
}
.checkbox-group label {
  display: inline-flex; align-items: center; gap: 0.3rem;
  cursor: pointer; user-select: none;
}

/* Chip-toggle filter group (Source/Pola/Level/Section). Each chip starts
   selected (filled with its tag color) and can be clicked to deselect
   (turns into a struck-through outlined chip). */
.filter-chip-group {
  display: flex; flex-wrap: wrap; gap: 0.4rem;
}
.filter-chip {
  display: inline-block;
  padding: 0.22rem 0.7rem;
  border-radius: 999px;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  border: 1px solid var(--card-border);
  background: white;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.filter-chip[aria-pressed="false"] {
  text-decoration: line-through;
  opacity: 0.7;
}
.filter-chip[aria-pressed="true"] { border-color: transparent; }
.filter-chip-source[aria-pressed="true"]  { background: var(--tag-source-bg);  color: var(--tag-source-fg); }
.filter-chip-pola[aria-pressed="true"]    { background: var(--tag-pola-bg);    color: var(--tag-pola-fg); }
.filter-chip-level[aria-pressed="true"]   { background: var(--tag-level-bg);   color: var(--tag-level-fg); }
.filter-chip-section[aria-pressed="true"] { background: var(--tag-section-bg); color: var(--tag-section-fg); }
/* Textbook section chips use the book-section palette so they read as
   Textbook-coloured (not Matura-coloured). */
.filter-chip-section-textbook[aria-pressed="true"] {
  background: #fdf1c8;
  color: #a88347;
}
.filter-chip:hover { filter: brightness(0.97); }

/* Source-aware filter panels — a panel is shown beneath the Source
   chip row whenever its source's dropdown arrow is open. Closed by
   default; click the ▾ inside the Source chip to open it. */
.filter-panel { margin: 0.4rem 0; }
.filter-panel[hidden] { display: none; }
.filter-panel > .filter-grid {
  background: color-mix(in srgb, var(--tag-source-bg) 25%, transparent);
  border: 1px solid color-mix(in srgb, var(--tag-source-fg) 22%, var(--card-border));
  border-radius: 10px;
  padding: 0.6rem 0.85rem 0.5rem;
}
/* Textbook panel intentionally re-uses the Matura panel's pink tint —
   the source-coloured badge on the chip itself is enough to disambiguate
   the two; the expanded panel doesn't need its own colour. */

/* Source chip + welded dropdown arrow. The chip on the left keeps the
   existing aria-pressed (un)selected styling; the arrow is a separate
   button that controls panel visibility but doesn't change selection.
   Strips the chip's right-side rounding and the arrow's left-side so
   they read as one pill split by a thin seam. */
.filter-source-chip-combo {
  display: inline-flex; align-items: stretch; gap: 1px;
}
.filter-chip-source-combo {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.filter-source-arrow {
  appearance: none;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 0.55rem;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  color: var(--muted);
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-top-right-radius: 999px;
  border-bottom-right-radius: 999px;
  font-size: 0.78rem; line-height: 1;
  cursor: pointer;
  transition: transform 140ms ease, border-color 120ms ease, color 120ms ease;
}
.filter-source-arrow:hover {
  color: var(--accent);
  border-color: var(--accent);
}
.filter-source-arrow[aria-expanded="true"] {
  color: var(--accent);
  border-color: var(--accent);
}
/* Open state: flip the chevron via transform. The text content stays "▾"
   so screen readers still announce it sensibly. */
.filter-source-arrow[aria-expanded="true"] > * { display: inline-block; }
.filter-source-arrow {
  /* Wrap the literal "▾" in a span at runtime would be nicer, but a
     direct transform on the button content also works because the
     <button> is its own inline-flex container. */
}
.filter-source-arrow[aria-expanded="true"] {
  transform: rotate(180deg);
}

/* Hide the matura / textbook panel when its source chip is off. */
#filters.no-matura   #panel-matura,
#filters.no-matura   .filter-source-chip-combo:has(.filter-chip-source-matura)   .filter-source-arrow,
#filters.no-textbook #panel-textbook,
#filters.no-textbook .filter-source-chip-combo:has(.filter-chip-source-textbook) .filter-source-arrow {
  display: none;
}
.topics-cell { margin-top: 0.2rem; }
.topics-actions { display: flex; gap: 0.6rem; }
.link-btn {
  background: none; border: 0; padding: 0;
  color: var(--accent); font-size: 0.8rem; cursor: pointer;
  font-weight: 500;
}
.link-btn:hover { text-decoration: underline; color: var(--accent-hover); }

.filter-topic-chips {
  display: flex; flex-wrap: wrap; gap: 0.35rem;
  max-height: 11rem; overflow-y: auto;
  padding: 0.2rem 0.05rem;
}
/* Filter chip groups: rectangular main rectangle that visually contains its
   sub pills. Selection is synced — the parent is "pressed" iff every sub
   is pressed; toggling the parent toggles every sub in lockstep. */
.filter-topic-group {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.18rem 0.45rem;
  border-radius: 6px;
  border: 1px solid var(--tag-topic-main-border);
  background: var(--tag-topic-main-bg);
  color: var(--tag-topic-main-fg);
  font-size: 0.82rem;
  font-weight: 600;
}
.filter-topic-group[data-pressed="false"] {
  background: white;
  border-color: var(--card-border);
  color: var(--muted);
}
/* Partial selection (some but not all subtopics chosen): angled zebra
   stripes alternating the selected violet and the deselected white. */
.filter-topic-group[data-pressed="partial"] {
  background: repeating-linear-gradient(45deg,
    var(--tag-topic-main-bg) 0 7px,
    #ffffff 7px 14px);
  border-color: var(--tag-topic-main-border);
  color: var(--tag-topic-main-fg);
}
.filter-chip-main {
  background: transparent;
  border: 0; padding: 0;
  font: inherit;
  color: inherit;
  font-weight: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.filter-topic-group[data-pressed="false"] .filter-chip-main {
  text-decoration: line-through;
  opacity: 0.85;
}
.filter-group-subs {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 0.3rem;
  /* When the dropdown is open, subs occupy their own row under the
     main-topic name inside the group box. */
  flex-basis: 100%;
}
.filter-group-subs[hidden] { display: none; }
/* Dropdown arrow that reveals a main topic's subtopic chips. */
.filter-topic-arrow {
  background: transparent;
  border: 0;
  padding: 0 0.15rem;
  font: inherit;
  font-size: 0.72rem;
  color: inherit;
  cursor: pointer;
  opacity: 0.65;
  transition: transform 0.15s ease;
}
.filter-topic-arrow:hover { opacity: 1; }
.filter-topic-arrow[aria-expanded="true"] { transform: rotate(180deg); }
.filter-chip-sub {
  display: inline-block;
  padding: 0.06rem 0.55rem;
  border-radius: 999px;
  background: #f0f9ff;        /* sky-50 — soft sub default */
  color: var(--tag-topic-sub-fg);
  border: 1px solid var(--tag-topic-sub-border);
  font: inherit;
  font-size: 0.74rem;
  font-weight: 500;
  cursor: pointer;
}
.filter-chip-sub[aria-pressed="false"] {
  background: white;
  color: var(--muted);
  border-color: var(--card-border);
  text-decoration: line-through;
  opacity: 0.75;
}
.filter-chip-sub:hover,
.filter-chip-main:hover { filter: brightness(0.97); }

.tex-flushleft  { text-align: left;  margin: 0.4rem 0; }
.tex-flushright { text-align: right; margin: 0.4rem 0; }

.search-summary {
  font-size: 0.92rem; color: var(--muted);
  margin: 0.2rem 0 0.8rem;
}

.search-results {
  /* Grid that fits as many ~360 px-wide problem cards as the window
     allows: 1 column on phones, 2 on a typical laptop, 3 on a wide
     desktop display. */
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  /* Fixed row height — when one card grows on hover its content
     overflows visibly INSTEAD of pushing the rows below down. */
  grid-auto-rows: 18em;
  gap: 0.6rem;
  align-items: start;
}
@media (max-width: 720px) {
  .search-results { grid-template-columns: 1fr; }
}
/* Each problem occupies a `.search-result-wrap` cell that's 18em tall
   in the grid. Inside the cell are TWO sibling absolutely-positioned
   layers:
     • `.search-result-hot-zone` — invisible 18em rectangle that IS the
       hover (and click-to-navigate) target.
     • `.search-result` — the visible card, drawn over the hot zone with
       `pointer-events: none` so the cursor falls through to the hot
       zone underneath. Only the Add button re-enables pointer events.
   When the hot zone (or the Add button) is hovered, `:has()` flips the
   card to `height: auto`, so it grows downward, painting OVER the row
   below. The instant the cursor leaves the 18em footprint the hot zone
   loses :hover and the card snaps back. */
.search-result-wrap {
  position: relative;
  height: 18em;
  /* The `.is-hovered` class is toggled by JS (mouseenter/leave on the
     hot zone + Add button) — not CSS `:has()` — because some browsers
     have a 1-frame paint delay between :has() reevaluation and z-index
     application. JS firing synchronously eliminates that hiccup. */
  z-index: 1;
}
.search-result-wrap.is-hovered { z-index: 10; }
.search-result-hot-zone {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 18em;
  z-index: 0;
}
.search-result-hot-zone[data-href] { cursor: pointer; }
.search-result {
  position: absolute;
  top: 0; left: 0; right: 0;          /* NO bottom — let height grow */
  height: 18em;
  display: flex; align-items: flex-start; gap: 0.7rem;
  padding: 0.85rem 1rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  color: var(--fg);
  text-decoration: none;
  overflow: hidden;
  z-index: 1;
  pointer-events: none;                /* let cursor reach hot zone */
  transition: height 0.25s ease, box-shadow 0.08s, border-color 0.08s,
              z-index 0s linear 0.25s;
}
/* The Add icon stays clickable. */
.search-result .result-actions,
.search-result .result-add { pointer-events: auto; }
/* Expand the card when its wrap is marked hovered (by JS).
   The card grows for tall content but never shrinks below the original
   18em footprint. Horizontal overflow stays clipped to the card's width
   (so long math lines cannot escape to the right); the `.result-body`
   below gets `overflow-x: auto` so the user can scroll horizontally
   inside the card if a math expression is too wide. */
.search-result-wrap.is-hovered .search-result {
  height: auto;
  min-height: 18em;
  max-height: 100em;
  overflow: hidden;
  z-index: 5;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.search-result-wrap.is-hovered .search-result .result-body {
  /* Long math lines (e.g. multi-term sums) scroll horizontally inside
     the body instead of bleeding past the right edge of the card. */
  overflow-x: auto;
  overflow-y: visible;
}
.search-result-wrap.is-hovered .search-result::after { opacity: 0; }
.search-result::after {
  /* Fade gradient covering the bottom of the card. Inherit the parent's
     rounded bottom corners so the gradient doesn't poke out past them
     when the card is expanded (overflow: visible). */
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2.5em;
  background: linear-gradient(to bottom, transparent, var(--card-bg));
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.2s ease;
}
.search-result:hover::after { opacity: 0; }
.search-result:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 6px rgba(0,0,0,0.07);
  transform: translateY(-1px);
  text-decoration: none;
}
.search-result .result-num {
  font-weight: 600; flex-shrink: 0; min-width: 1.6rem;
  color: var(--accent);
}
.search-result .result-body {
  flex: 1; min-width: 0; font-size: 0.95rem;
  line-height: 1.5;
  /* Render the problem content at a much smaller scale so more of the
     problem fits into the unexpanded card (user request). `zoom` scales
     layout too (unlike transform), so text, MathJax math, TikZ figures
     and textbook images all shrink together and the expanded height
     stays correct. */
  zoom: 0.65;
}
.search-result .result-body p { margin: 0.2rem 0; }
.search-result .result-body p:first-child { margin-top: 0; }
.search-result .result-body p:last-child  { margin-bottom: 0; }
.search-result .result-body .tex-tikz img {
  max-width: 100%; max-height: 260px;
  background: white; padding: 4px;
  border: 1px solid var(--card-border); border-radius: 4px;
}
.search-result .result-body .tex-figure-placeholder { font-size: 0.85rem; }
.search-result .result-arrow {
  flex-shrink: 0; color: var(--muted);
  font-size: 1.1rem; line-height: 1;
}
.search-result:hover .result-arrow { color: var(--accent); }

/* Action icons (+ Add and ✎ Edit) overlay the top-right corner of each
   card with reduced opacity so they don't obscure the problem text. */
.search-result .result-actions {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  flex-shrink: 0;
  display: flex; flex-direction: row; gap: 0.3rem;
  align-items: center;
  opacity: 0.55;
  transition: opacity 0.15s ease;
  z-index: 2;
}
.search-result:hover .result-actions { opacity: 1; }
.search-result .result-edit,
.search-result .result-add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem;
  padding: 0;
  border-radius: 50%;
  font: inherit;
  font-size: 1rem; line-height: 1;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid var(--card-border);
  background: white;
  color: var(--fg);
  text-decoration: none;
}
.search-result .result-edit:hover { border-color: var(--accent); color: var(--accent); }
.search-result .result-add { background: var(--accent); color: white; border-color: var(--accent); font-size: 1.1rem; }
.search-result .result-add:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.search-result .result-add.is-selected {
  background: white; color: var(--warn); border-color: var(--warn);
  font-size: 1.1rem;
}
.search-result .result-add.is-selected:hover { background: var(--warn-bg); }

/* Border-collapsed tables inside search result cards (same look as the
   index/preview-box and Finishing preview). */
.search-result .result-body .tex-tabular {
  margin: 0.5rem auto; border-collapse: collapse;
}
.search-result .result-body .tex-tabular td,
.search-result .result-body .tex-tabular th {
  border: 1px solid #999; padding: 0.3rem 0.6rem;
  text-align: left; vertical-align: middle;
}
/* Borderless tables: when the LaTeX source omitted `|` in the column
   spec the renderer adds .tex-tabular-borderless and we drop the cell
   borders. Mirror the rule that applies in .preview-box. */
.search-result .result-body .tex-tabular-borderless td,
.search-result .result-body .tex-tabular-borderless th,
.exam-row .result-body .tex-tabular-borderless td,
.exam-row .result-body .tex-tabular-borderless th {
  border: none;
}
/* Enumerate / itemize lists inside search-result cards: when an item
   carries an explicit a)/b)/c) label, hide the default <ol> counter
   (the label IS the marker). Mirror the rule that applies in .preview-box. */
.search-result .result-body .tex-list,
.exam-row .result-body .tex-list { margin: 0.4rem 0 0.4rem 1.4rem; padding-left: 0; }
.search-result .result-body .tex-list li:has(.tex-item-label),
.exam-row .result-body .tex-list li:has(.tex-item-label) {
  list-style: none;
  margin-left: -1.4rem;
}
/* Centred TikZ figures + tex-center inside cards. */
.search-result .result-body .tex-tikz,
.search-result .result-body .tex-center { text-align: center; margin: 0.5rem 0; }

.search-results-bar {
  display: flex; align-items: center;
  gap: 0.5rem; margin: 0.2rem 0 0.8rem;
  flex-wrap: wrap;
}
.search-results-bar .search-summary { margin: 0; flex: 1; min-width: 0; }
.add-all-btn {
  background: white;
  color: var(--accent);
  border: 1px dashed var(--accent);
  border-radius: 6px;
  padding: 0.35rem 0.85rem;
  font: inherit; font-size: 0.85rem; font-weight: 500;
  cursor: pointer;
}
.add-all-btn:hover { background: var(--accent); color: white; }
.add-all-btn:disabled { opacity: 0.6; cursor: default; background: white; color: var(--muted); border-color: var(--card-border); }

.menu-h-secondary { margin-top: 0.5rem; }

/* Home page: centered hero + a row of feature cards. */
.home-hero {
  text-align: center;
  margin: 2.2rem auto 2.5rem;
  padding: 0 1rem;
  max-width: 44rem;
}
.home-lead {
  margin: 0;
  font-size: 1.6rem; font-weight: 600; line-height: 1.25;
  color: var(--fg);
  letter-spacing: -0.01em;
}
.home-sublead {
  margin: 0.6rem 0 0;
  font-size: 0.95rem; color: var(--muted);
  letter-spacing: 0.04em;
}
@media (max-width: 600px) {
  .home-lead { font-size: 1.3rem; }
}
.home-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
  max-width: 60rem;
  margin: 0 auto 1.8rem;
}
.home-card {
  display: block;
  padding: 1.1rem 1.2rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  text-decoration: none;
  color: var(--fg);
  transition: border-color 0.08s, box-shadow 0.08s, transform 0.08s;
}
.home-card:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 10px rgba(0,0,0,0.07);
  transform: translateY(-1px);
  text-decoration: none;
}
.home-card-title {
  margin: 0 0 0.35rem; font-size: 1.1rem; font-weight: 600;
  color: var(--accent);
}
.home-card-desc {
  margin: 0; font-size: 0.92rem; color: var(--muted); line-height: 1.45;
}

/* Generic page-level tabs (Problems: Matura/Textbook · Exam: Selection/Finishing) */
.page-tabs, .exam-tabs {
  display: flex; gap: 0.4rem;
  margin: 0.5rem 0 1rem;
  border-bottom: 1px solid var(--card-border);
}
.page-tab, .exam-tab {
  background: transparent;
  border: 0;
  padding: 0.55rem 1rem;
  font: inherit; font-size: 0.95rem; font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.page-tab:hover, .exam-tab:hover { color: var(--accent); }
.page-tab.active, .exam-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}
/* Spacer that pushes any trailing action (e.g. "Export (JSON)" on the
   Problems page) to the far right of the tab row. */
.page-tabs-spacer { flex: 1 1 auto; }
.page-tabs-action { align-self: center; margin-bottom: 0.4rem; }
.page-tab .count {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.85em;
  margin-left: 0.18em;
}
.page-tab.active .count { color: var(--accent); }
/* Sub-row of Matura/Textbook tabs sits inside the by-source mode panel.
   Visually subordinate: lighter text, a small left indent, and a
   shallower active underline so the eye reads "top-level mode → sub
   filter" without ambiguity. */
.page-tabs-sub {
  margin-top: 0.4rem;
  padding-left: 0.25rem;
}
.page-tabs-sub .page-tab {
  font-size: 0.88rem;
  padding: 0.32rem 0.7rem 0.42rem;
  color: var(--muted);
}
.page-tabs-sub .page-tab.active {
  color: var(--fg);
}
.exam-options {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.7rem 1.5rem;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 0.8rem 1rem;
  margin-bottom: 1rem;
}
.exam-option-row {
  display: flex; align-items: center; gap: 0.5rem;
  font-size: 0.92rem;
}
.exam-num-input {
  width: 4.5rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  font: inherit; font-size: 0.9rem;
}
.exam-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 800px) {
  .exam-columns { grid-template-columns: 1fr; }
}
.exam-column {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 0.8rem 1rem;
}
.exam-column h3 { margin: 0 0 0.6rem; font-size: 1rem; }
.exam-list { display: flex; flex-direction: column; gap: 0.5rem; }
.exam-empty { color: var(--muted); font-style: italic; font-size: 0.9rem; padding: 0.4rem 0; }
.exam-row {
  display: flex; align-items: flex-start; gap: 0.6rem;
  padding: 0.6rem 0.7rem;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 6px;
}
.exam-row .result-num {
  font-weight: 600;
  color: var(--accent);
  flex-shrink: 0;
  min-width: 1.6rem;
}
.exam-row .result-body {
  flex: 1; min-width: 0;
  font-size: 0.9rem; line-height: 1.45;
}
.exam-row .result-body p { margin: 0.2rem 0; }
.exam-row .result-body .tex-tikz img {
  max-width: 100%; max-height: 160px;
  background: white; padding: 4px;
  border: 1px solid var(--card-border); border-radius: 4px;
}
.exam-row .result-actions {
  display: flex; flex-direction: column; gap: 0.3rem;
  flex-shrink: 0;
}
.exam-action {
  min-width: 5.4rem;
  padding: 0.26rem 0.7rem;
  border-radius: 6px;
  font: inherit; font-size: 0.8rem; font-weight: 500;
  cursor: pointer;
  border: 1px solid var(--card-border);
  background: white;
  color: var(--fg);
}
.exam-action:hover { border-color: var(--accent); color: var(--accent); }
.exam-action.primary { background: var(--accent); color: white; border-color: var(--accent); }
.exam-action.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: white; }
.exam-action.warn { color: var(--warn); border-color: var(--warn-bg); }
.exam-action.warn:hover { background: var(--warn-bg); }
.exam-action.is-disabled { color: var(--muted); cursor: default; opacity: 0.7; }
.exam-action.is-disabled:hover { border-color: var(--card-border); color: var(--muted); }

/* Finishing tab — composer layout */
.finishing-toolbar {
  display: flex; align-items: center; gap: 0.6rem;
  margin-bottom: 0.8rem;
  flex-wrap: wrap;
}
.finishing-toolbar .hint { color: var(--muted); font-size: 0.85rem; }
.finishing-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
/* Hide the "Preview" / "LaTeX" h3 labels on the Exam page (the panes are
   self-explanatory once chrome is removed). */
body.page-exam .finishing-left .pane-header h3,
body.page-exam .finishing-right .pane-header h3 { display: none; }
/* Default: only the Preview pane is shown — LaTeX is collapsed. The
   "Edit LaTeX" toolbar button toggles the `latex-open` class. */
body.page-exam .finishing-body { grid-template-columns: 1fr; }
body.page-exam.latex-open .finishing-body { grid-template-columns: 1fr 1fr; }
body.page-exam .finishing-right { display: none; }
body.page-exam.latex-open .finishing-right { display: flex; }
.toggle-latex-btn { white-space: nowrap; }
@media (max-width: 900px) {
  .finishing-body { grid-template-columns: 1fr; }
  body.page-exam.latex-open .finishing-body { grid-template-columns: 1fr; }
  /* On narrow screens the panes stack — the textarea must not extend past
     its card. Drop the "fill-the-grid-cell" 100% height; rely on min-height. */
  #finishing-tex {
    height: auto !important;
    min-height: 320px;
    max-height: 60vh;
    box-sizing: border-box;
  }
}
.finishing-left, .finishing-right {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 0.9rem 1rem;
  box-sizing: border-box;
  min-width: 0;             /* allow grid item to shrink so the textarea
                               doesn't push the card past its column */
}
/* Make the LaTeX pane a column flex container so its single big child
   (the textarea) fills exactly the available space — no overflow past
   the card border, no wasted whitespace. (LaTeX pane lives on the right
   in the Exam page now, hence .finishing-right.) */
.finishing-right {
  display: flex;
  flex-direction: column;
}
#finishing-tex {
  width: 100%;
  min-height: 540px;        /* tall LaTeX editor */
  flex: 1 1 auto;           /* fill the rest of the card vertically */
  box-sizing: border-box;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 0.6rem;
  resize: vertical;
  background: #fafafa;
  color: var(--fg);
  white-space: pre;
  overflow-x: auto;
}

/* Right pane — interactive preview with drag/space/page-break */
.finishing-preview-pane {
  /* A4-shaped page. Width = 21 cm, padding = 1.5 cm (matches the PDF
     margin), so the typeset content visually matches what you'll get
     after pdflatex. Min-height keeps a full A4 height (29.7 cm) even
     when the content is short — short exams still look like a page. */
  position: relative;
  display: flex; flex-direction: column;
  gap: 0;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 4px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
  width: 21cm;
  max-width: 100%;
  margin: 0 auto;
  padding: 1.5cm;
  box-sizing: border-box;
  min-height: 29.7cm;
  max-height: none;
  overflow-y: visible;
}
/* On phones the A4 simulation crushes the content area — most of the
   viewport ends up as the cm-sized print margin. Drop the page metaphor
   on small screens so problems use the full available width. */
@media (max-width: 720px) {
  .finishing-preview-pane {
    width: 100%;
    padding: 0.6rem;
    min-height: 0;
    box-shadow: none;
  }
  .finishing-block { padding: 0.4rem 0.4rem 0.5rem; }
  .finishing-block-body { font-size: 0.95rem; }
}
/* Drag insertion indicator: a thin accent-colored line that shows where a
   dragged problem would land if dropped now. */
.finishing-insert-line {
  position: absolute;
  left: 0.6rem; right: 0.8rem;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
  pointer-events: none;
  box-shadow: 0 0 0 2px rgba(200, 74, 74, 0.18);
  display: none;
  z-index: 5;
}
.finishing-block {
  display: flex; align-items: flex-start; gap: 0.45rem;
  position: relative;
  padding: 0.4rem 0.5rem 0.5rem;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 6px;
}
.finishing-block + .finishing-block { margin-top: 0; }
.finishing-block.dragging { opacity: 0.45; }
.finishing-block .drag-handle {
  flex-shrink: 0;
  color: var(--muted);
  font-size: 1.05rem; line-height: 1.5;
  user-select: none;
  cursor: grab;
}
.finishing-block-body {
  flex: 1; min-width: 0;
  font-size: 0.92rem; line-height: 1.5;
}
.finishing-block-body p { margin: 0.25rem 0; }
.finishing-block-body .result-num {
  font-weight: 700; color: var(--accent);
  margin-right: 0.2em;
}
.finishing-block-body .tex-tikz img { max-width: 100%; max-height: 280px; }
/* × button to remove a problem from the exam, pinned in the corner. */
.finishing-block { /* enable absolute positioning of the × */
  position: relative;
}
.finishing-block-remove {
  position: absolute;
  top: 0.25rem;
  right: 0.25rem;
}
@media print {
  body.print-finishing .finishing-block-remove { display: none !important; }
}
/* × inside a .tex-namig block on the Finishing tab — sits in the top
   corner of the peach hint box and lets the user hide that hint from
   the rendered exam. Hidden in print. */
.finishing-block-body .tex-namig {
  position: relative;
}
.tex-namig-remove {
  position: absolute;
  top: 0.2rem;
  right: 0.25rem;
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  font-size: 0.9rem;
  line-height: 1;
}
@media print {
  body.print-finishing .tex-namig-remove { display: none !important; }
}
/* "+ Hint" affordance shown beneath a problem whose hint is hidden.
   Styled to match the dashed peach hint box but at half-opacity so it
   doesn't compete with real content. */
.finishing-add-hint {
  display: inline-block;
  margin-top: 0.4rem;
  padding: 0.3rem 0.8rem;
  background: transparent;
  border: 1.5px dashed #d98059;
  color: #6b3a17;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.85rem;
  font-style: italic;
}
.finishing-add-hint:hover {
  background: #ffe9d8;
}
@media print {
  body.print-finishing .finishing-add-hint { display: none !important; }
}

/* "+ Add N random" — styled to match the .add-all-btn neighbour with
   the number input integrated as part of the same pill. */
.add-random-control {
  display: inline-flex; align-items: stretch;
  background: white;
  border: 1px dashed var(--accent);
  border-radius: 6px;
  font: inherit; font-size: 0.85rem;
  color: var(--accent);
  overflow: hidden;
  cursor: pointer;
}
.add-random-control:hover { background: rgba(200, 74, 74, 0.06); }
.add-random-control:hover button { color: var(--accent); }
.add-random-prefix,
.add-random-suffix {
  display: flex; align-items: center;
  font-weight: 500;
  padding: 0.35rem 0;
  user-select: none;
}
.add-random-prefix { padding-left: 0.7rem; padding-right: 0.25rem; }
.add-random-suffix { padding-left: 0.05rem; padding-right: 0.15rem; }
.add-random-control input {
  width: 2.4rem;
  padding: 0.35rem 0.1rem;
  font: inherit; font-size: 0.85rem; font-weight: 600;
  border: 0;
  background: transparent;
  text-align: center;
  color: var(--accent);
  -moz-appearance: textfield;
}
.add-random-control input::-webkit-inner-spin-button,
.add-random-control input::-webkit-outer-spin-button {
  -webkit-appearance: none; margin: 0;
}
.add-random-control input:focus { outline: none; background: rgba(200, 74, 74, 0.08); }
.add-random-control button {
  background: transparent;
  border: 0;
  padding: 0.35rem 0.7rem 0.35rem 0.3rem;
  font: inherit; font-size: 0.85rem; font-weight: 500;
  color: var(--accent);
  cursor: pointer;
}
.add-random-control button:disabled { color: var(--muted); cursor: default; }
.add-random-control:has(button:disabled) {
  opacity: 0.6; cursor: default;
  border-color: var(--card-border);
  background: white !important;
}

/* "+ Dodaj nalogo" tile at the end of the preview — the whole card is
   the click target (it opens the search modal). No inner buttons. */
.finishing-add-block {
  display: block;
  width: 100%;
  margin-top: 0.6rem;
  padding: 1rem 0.9rem;
  border: 1px dashed var(--card-border);
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.015);
  cursor: pointer;
  font: inherit;
  color: var(--accent);
  text-align: center;
  transition: background 120ms ease, border-color 120ms ease;
}
.finishing-add-block:hover {
  background: rgba(0, 0, 0, 0.04);
  border-color: var(--accent);
}
.finishing-add-header {
  font-size: 0.95rem;
  font-weight: 500;
}
.finishing-add-actions {
  display: none;
}

/* "Dodaj N naključnih" control on the search-results toolbar.
   Inline-X layout: "+ Dodaj [N] naključnih →" — the number input sits
   embedded between two text spans, with a small arrow button as the
   action. The whole thing reads like one continuous control. */
.add-random-control {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.18rem 0.5rem;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 5px;
  font-size: 0.85rem;
  color: var(--accent);
}
.add-random-control .add-random-prefix,
.add-random-control .add-random-suffix {
  white-space: nowrap;
}
.add-random-control input[type=number] {
  width: 3em;
  padding: 0.1rem 0.3rem;
  border: 1px solid var(--card-border);
  border-radius: 4px;
  background: white;
  font: inherit; font-size: 0.85rem;
  text-align: right;
  color: var(--fg);
  /* Hide spinner arrows in WebKit/Firefox so the number reads cleanly. */
  -moz-appearance: textfield;
}
.add-random-control input[type=number]::-webkit-outer-spin-button,
.add-random-control input[type=number]::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.add-random-control button {
  font: inherit; font-size: 0.9rem;
  padding: 0.05rem 0.45rem;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 4px;
  color: white;
  cursor: pointer;
  line-height: 1.2;
}
.add-random-control button:hover { background: var(--accent-hover); }
.add-random-control button:disabled {
  opacity: 0.5; cursor: default;
}
.finishing-add-from-coll,
.finishing-add-search {
  font: inherit; font-size: 0.85rem;
  padding: 0.32rem 0.7rem;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 5px;
  color: var(--accent);
  text-decoration: none;
  cursor: pointer;
}
.finishing-add-from-coll:hover,
.finishing-add-search:hover {
  background: rgba(200, 74, 74, 0.06);
  border-color: var(--accent);
}
.finishing-add-coll-list {
  margin-top: 0.5rem;
  display: flex; flex-wrap: wrap; gap: 0.3rem;
}
.finishing-add-coll-item {
  font: inherit; font-size: 0.85rem;
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.2rem 0.55rem;
  background: white;
  border: 1px solid var(--card-border);
  border-radius: 4px;
  cursor: pointer;
}
.finishing-add-coll-item:hover {
  background: rgba(200, 74, 74, 0.08);
  border-color: var(--accent);
  color: var(--accent);
}
.finishing-add-coll-num { font-weight: 600; }
.finishing-add-coll-sec {
  font-size: 0.7rem; color: var(--muted);
  background: rgba(0, 0, 0, 0.05);
  padding: 0.05rem 0.3rem; border-radius: 3px;
}
.finishing-add-empty {
  font-size: 0.85rem; color: var(--muted); font-style: italic;
}

/* "Add a problem" modal -------------------------------------------------*/
.exam-modal {
  position: fixed; inset: 0;
  z-index: 1000;
}
.exam-modal[hidden] { display: none; }
.exam-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.45);
}
.exam-modal-window {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(960px, 94vw);
  height: min(86vh, 880px);
  background: white;
  border-radius: 10px;
  display: flex; flex-direction: column;
  box-shadow: 0 14px 44px rgba(0, 0, 0, 0.32);
  overflow: hidden;
}
.exam-modal-header {
  display: flex; align-items: center;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--card-border);
  flex-shrink: 0;
}
.exam-modal-title {
  margin: 0; flex: 1;
  font-size: 1.05rem; font-weight: 600;
}
.exam-modal-close {
  background: transparent; border: 0;
  font-size: 1.7rem; line-height: 1;
  color: var(--muted);
  padding: 0.05rem 0.55rem;
  border-radius: 4px;
  cursor: pointer;
}
.exam-modal-close:hover { background: rgba(0, 0, 0, 0.05); color: var(--fg); }
.exam-modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 0.8rem 1rem 1rem;
}
.modal-empty-msg {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--muted);
  font-style: italic;
}

/* Greyed-out search-result card when the problem is already in the exam */
.search-result.is-in-exam {
  opacity: 0.5;
  background: rgba(0, 0, 0, 0.02);
}
.search-result.is-in-exam .result-add[disabled] {
  cursor: default;
  background: rgba(0, 0, 0, 0.05);
  color: var(--muted);
  border-color: var(--card-border);
}

/* Separator between two consecutive problems */
.finishing-separator {
  display: flex; flex-direction: column; align-items: stretch;
  margin: 0.2rem 0;
}
.finishing-separator .page-break-toggle {
  align-self: center;
  background: white;
  border: 1px dashed var(--card-border);
  color: var(--muted);
  font: inherit; font-size: 0.78rem;
  padding: 0.18rem 0.7rem;
  border-radius: 999px;
  cursor: pointer;
  margin-bottom: 0.2rem;
}
.finishing-separator .page-break-toggle:hover { color: var(--accent); border-color: var(--accent); }
.finishing-separator .page-break-toggle.is-active {
  background: var(--accent); color: white; border-color: var(--accent); border-style: solid;
}
.finishing-separator .finishing-space {
  background: rgba(0,0,0,0.025);
  border-top: 1px dashed transparent;
  border-bottom: 1px dashed transparent;
}
.finishing-controls-row {
  display: flex; flex-direction: row; align-items: center; justify-content: center;
  gap: 0.7rem;
  margin-bottom: 0.2rem;
  flex-wrap: wrap;
}
.finishing-separator .finishing-space-control {
  font-size: 0.82rem;
  color: var(--muted);
  display: inline-flex; align-items: center; gap: 0.3rem;
}
.finishing-separator .finishing-space-control input {
  width: 4rem;
  padding: 0.18rem 0.4rem;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  font: inherit;
  font-size: 0.82rem;
}

/* Wrapper that lets the heading-add chips float at the top-right corner
   above the Preview content. */
.finishing-preview-frame {
  position: relative;
  flex: 1;
  display: flex; flex-direction: column;
  min-height: 0;
}
.finishing-preview-frame > .finishing-heading-adds {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  z-index: 4;
  margin-left: 0;
}
/* "+ Title / + Ime / ..." chips next to the Preview pane header */
.finishing-heading-adds {
  display: inline-flex; align-items: center; flex-wrap: wrap;
  gap: 0.35rem;
  margin-left: 0.6rem;
}
.finishing-heading-add {
  display: inline-flex; align-items: center;
  padding: 0.15rem 0.55rem;
  font: inherit;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--muted);
  background: var(--card-bg);
  border: 1px dashed var(--card-border);
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.finishing-heading-add:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(200, 74, 74, 0.06);
}

/* Heading preview (Title + name/surname/points/grade fields) */
.exam-heading {
  margin: 0 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--card-border);
}
.exam-heading-title-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-bottom: 0.8rem;
}
.exam-heading-title {
  text-align: center;
  font-size: 1.4rem;
  font-weight: 700;
  outline: none;
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  cursor: text;
}
.exam-heading-title[contenteditable="true"]:hover {
  background: rgba(200, 74, 74, 0.06);
}
.exam-heading-title[contenteditable="true"]:focus {
  background: rgba(200, 74, 74, 0.10);
  outline: 1px dashed var(--accent);
  outline-offset: 2px;
}
@media print {
  body.print-finishing .exam-heading-title,
  body.page-exam .exam-heading-title {
    background: transparent !important;
    outline: 0 !important;
    padding: 0 !important;
    cursor: default;
    /* If the user was still in the contenteditable title when they hit
       Print, Chrome captures the focused element's caret onto the page. */
    caret-color: transparent !important;
  }
}
/* Same caret hide outside @media print, so the on-tab Download PDF path
   (body.print-finishing) gets it too. */
body.print-finishing .exam-heading-title { caret-color: transparent !important; }
.exam-heading-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 1.6rem;
  row-gap: 0.5rem;
}
.exam-heading-field {
  display: flex; align-items: baseline; gap: 0.5rem;
  font-size: 0.95rem;
}
.exam-heading-field .exam-field-label {
  font-weight: 500; color: var(--fg);
  flex-shrink: 0;
}
.exam-heading-field .exam-field-blank {
  flex: 1;
  border-bottom: 1px dotted #888;
  height: 1.1em;
}
.exam-field-remove {
  background: rgba(0, 0, 0, 0.06);
  color: var(--muted);
  border: 0;
  border-radius: 999px;
  width: 1rem; height: 1rem;
  font-size: 0.7rem; line-height: 1; font-weight: 700;
  margin-left: 0.3rem;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: baseline;
  padding: 0;
}
.exam-field-remove:hover {
  background: var(--warn-bg);
  color: var(--warn);
}
@media print {
  body.print-finishing .exam-field-remove { display: none !important; }
}

/* Page-break visual indicator: a dashed blue line drawn at the bottom of
   the previous problem (so it visually attaches to where the page ends). */
.finishing-page-break-line {
  height: 0;
  border-bottom: 2px dashed var(--accent);
  margin: 0.35rem 0 0.1rem;
}

/* Print: clean PDF — keep #finishing-preview in normal document flow
   (NOT absolute-positioned) so page-break-before/inside work. Suppress
   chrome by display:none so it doesn't take layout space. @page provides
   the print margins. (User should disable "Headers and footers" in the
   browser print dialog to suppress the date/title/page-X-of-Y line.)

   The rules below apply whenever <body> has the "print-finishing" class,
   regardless of @media print. This matters on mobile, where some "Save
   as PDF" flows render the screen view rather than the print view. */
@page { size: A4; margin: 1.5cm; }
body.print-finishing { background: white !important; margin: 0; padding: 0; }
/* Hide every direct child of <body> except the finishing preview chain. */
body.print-finishing .top-bar,
body.print-finishing > .container > .page-tabs,
body.print-finishing > .container > .exam-tabs,
body.print-finishing > .container > .export-row,
body.print-finishing > .container > h1,
body.print-finishing section[data-panel="selection"],
body.print-finishing .finishing-toolbar,
body.print-finishing .finishing-heading-adds,
body.print-finishing .finishing-right,
body.print-finishing .pane-header { display: none !important; }
/* Heading section in print */
body.print-finishing .exam-heading {
  border-bottom: 0;
  margin-bottom: 1rem;
}
body.print-finishing .exam-heading-title { color: black; }
/* Force the body grid to a single column so the preview takes full width. */
body.print-finishing .finishing-body {
  display: block !important;
  grid-template-columns: 1fr !important;
  gap: 0 !important;
}
body.print-finishing .finishing-left {
  border: 0 !important;
  padding: 0 !important;
  background: white !important;
}
body.print-finishing #finishing-preview {
  /* Block layout (NOT flex) so page-break-before on children works. */
  display: block !important;
  border: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  /* The on-screen preview is min-height: 29.7cm so the page metaphor
     stays intact for short exams. In print that's deadly: the @page
     margins (1.5cm top + 1.5cm bottom) leave only ~26.7cm of usable
     space, so a 29.7cm preview always overflows by 3cm and forces a
     second blank page. Reset it here. */
  min-height: 0 !important;
  max-height: none !important;
  overflow: visible !important;
  background: white !important;
  box-shadow: none !important;
}
/* Each problem block: clean styling, avoid splitting across pages. */
body.print-finishing .finishing-block {
  display: block !important;
  border: 0 !important;
  padding: 0 !important;
  margin: 0;
  page-break-inside: avoid;
  break-inside: avoid;
}
body.print-finishing .finishing-block.is-page-break {
  page-break-before: always !important;
  break-before: page !important;
}
body.print-finishing .finishing-page-break-line { display: none !important; }
/* Hide every interactive widget — controls row + drag handle + page-break line. */
body.print-finishing .finishing-controls-row,
body.print-finishing .page-break-toggle,
body.print-finishing .finishing-space-control,
body.print-finishing .finishing-block .drag-handle,
body.print-finishing .finishing-page-break-line,
body.print-finishing .finishing-add-block {
  display: none !important;
}
body.print-finishing .finishing-separator { margin: 0; }
body.print-finishing .finishing-separator .finishing-space {
  background: transparent !important; border: 0 !important;
}
body.print-finishing .finishing-block-body .result-num {
  color: black;
}

/* Same rules under @media print, but scoped to body.page-exam — so they
   fire even when the user invokes the browser's own Print / Save-as-PDF
   command (Share → Print on iOS, ⌘P on desktop) without clicking our
   Download PDF button. */
@media print {
  body.page-exam { background: white !important; margin: 0; padding: 0; }
  body.page-exam .top-bar,
  body.page-exam > .container > .page-tabs,
  body.page-exam > .container > .exam-tabs,
  body.page-exam > .container > .export-row,
  body.page-exam > .container > h1,
  body.page-exam section[data-panel="selection"],
  body.page-exam .finishing-toolbar,
  body.page-exam .finishing-heading-adds,
  body.page-exam .finishing-right,
  body.page-exam .pane-header { display: none !important; }
  body.page-exam .exam-heading {
    border-bottom: 0;
    margin-bottom: 1rem;
  }
  body.page-exam .exam-heading-title { color: black; }
  body.page-exam .finishing-body {
    display: block !important;
    grid-template-columns: 1fr !important;
    gap: 0 !important;
  }
  body.page-exam .finishing-left {
    border: 0 !important;
    padding: 0 !important;
    background: white !important;
  }
  body.page-exam #finishing-preview {
    display: block !important;
    border: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow: visible !important;
    background: white !important;
    box-shadow: none !important;
  }
  body.page-exam .finishing-block {
    display: block !important;
    border: 0 !important;
    padding: 0 !important;
    margin: 0;
    page-break-inside: avoid;
    break-inside: avoid;
  }
  body.page-exam .finishing-block.is-page-break {
    page-break-before: always !important;
    break-before: page !important;
  }
  body.page-exam .finishing-controls-row,
  body.page-exam .page-break-toggle,
  body.page-exam .finishing-space-control,
  body.page-exam .finishing-block .drag-handle,
  body.page-exam .finishing-page-break-line,
  body.page-exam .finishing-add-block,
  body.page-exam .exam-field-remove {
    display: none !important;
  }
  body.page-exam .finishing-separator { margin: 0; }
  body.page-exam .finishing-separator .finishing-space {
    background: transparent !important; border: 0 !important;
  }
  body.page-exam .finishing-block-body .result-num {
    color: black;
  }
}

/* Collection bar — removed. The concept is scrapped; everything that
   used to add to the collection now adds directly to the exam. The
   button still exists in the static HTML across all 670+ pages, so we
   nuke it via CSS rather than edit every file. */
#collection-bar { display: none !important; }

/* Clickable meta-row tag (year/topic) on the problem page — hover
   underline + pointer cursor so the affordance reads. */
.tag.is-clickable,
.topic-group-main.is-clickable,
.tag.topic.is-clickable {
  cursor: pointer;
}
.tag.is-clickable:hover,
.topic-group-main.is-clickable:hover,
.tag.topic.is-clickable:hover {
  filter: brightness(0.92);
  text-decoration: underline;
}

/* The status badge is now a clickable toggle */
button.status-badge {
  cursor: pointer;
  border: 0;
  font: inherit;
  font-size: 0.85rem;
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
}
button.status-badge:hover { filter: brightness(0.97); }

/* ───────────────────────────────────────────────────────────────────
   Naloge page palette: 5 cycling colors used on the by-topic grid and
   the by-source year folders. Tones chosen from the user's reference
   image (coral / yellow / cream / teal / sky blue). Backgrounds are
   pastel for readability; the matching darker tone is used for borders
   and the summary text color.
   ─────────────────────────────────────────────────────────────────── */
:root {
  /* Rectangular tetrad on the colour wheel — two complementary pairs
     60° apart (15°/195° and 75°/255°). Pastel saturation + L≈86% on
     backgrounds and L≈42% on text/borders keeps the soft, calm feel
     while the underlying hue math makes the four colours feel related
     rather than ad-hoc. See https://www.canva.com/colors/color-wheel/
     for the layout. */
  --palette-1-bg: #f8d5c5;  --palette-1-fg: #ad5d36;  /* coral red    (15°) */
  --palette-2-bg: #e2ecc6;  --palette-2-fg: #7a8939;  /* lime yellow  (75°) */
  --palette-3-bg: #c7dee9;  --palette-3-fg: #307991;  /* teal blue   (195°) */
  --palette-4-bg: #d9d1f0;  --palette-4-fg: #6350a9;  /* lavender    (255°) */
}

/* ----- By-topic grid: 3 boxes per row, colored cycling backgrounds ---- */
/* The [hidden] override is needed because `display: grid` has higher
   specificity than the UA's `[hidden] { display: none }`. Without it,
   the topic grid leaks through when the user switches to the Seznam
   (by-source) tab. */
.browse-mode-panel[data-mode="by-topic"][hidden] { display: none; }
.browse-mode-panel[data-mode="by-topic"] {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin-top: 1.2rem;
}
@media (max-width: 800px) {
  .browse-mode-panel[data-mode="by-topic"] {
    grid-template-columns: 1fr;
  }
}
.browse-mode-panel[data-mode="by-topic"] > .collection {
  margin-top: 0;
  border-width: 2px;
  transition: transform 120ms ease, filter 120ms ease;
}
.browse-mode-panel[data-mode="by-topic"] > .collection:not([open]):hover {
  filter: brightness(0.97);
  transform: translateY(-1px);
}
/* Closed grid card: chevron-free summary, centred label looks like a chip */
.browse-mode-panel[data-mode="by-topic"] > .collection:not([open]) > summary {
  padding: 1.1rem 1rem;
  font-size: 1.05rem;
}
.browse-mode-panel[data-mode="by-topic"] > .collection:not([open]) > summary::before {
  display: none;
}
/* Open state: the box spans the full row, gets a white background so
   the problem list inside is readable, and keeps a thick coloured top
   border (the per-nth-child border-color tints it). */
.browse-mode-panel[data-mode="by-topic"] > .collection[open] {
  grid-column: 1 / -1;
  background: var(--card-bg);
  border-top-width: 6px;
}
.browse-mode-panel[data-mode="by-topic"] > .collection[open] > summary {
  background: transparent;
}

/* Per-position cycling colour. Applies to direct main-topic children. */
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+1) {
  background: var(--palette-1-bg); border-color: var(--palette-1-fg);
}
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+1) > summary { color: var(--palette-1-fg); }
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+2) {
  background: var(--palette-2-bg); border-color: var(--palette-2-fg);
}
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+2) > summary { color: var(--palette-2-fg); }
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+3) {
  background: var(--palette-3-bg); border-color: var(--palette-3-fg);
}
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+3) > summary { color: var(--palette-3-fg); }
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+4) {
  background: var(--palette-4-bg); border-color: var(--palette-4-fg);
}
.browse-mode-panel[data-mode="by-topic"] > .collection:nth-child(4n+4) > summary { color: var(--palette-4-fg); }

/* When OPEN the box returns to a white card so the problem list reads
   normally — but keep the coloured top border so the section still
   reads as part of its colour group. */
.browse-mode-panel[data-mode="by-topic"] > .collection[open] {
  background: var(--card-bg);
}
/* Subtopic chips inside Po temah boxes — the inline pills next to each
   main topic name (e.g. "Polinomska funkcija"). Force a white surface
   for BOTH default and pressed states so they read on the coloured
   parent box; the pressed state is signalled by border + text color
   instead of a tinted fill. */
.browse-mode-panel[data-mode="by-topic"] .subtopic-chip,
.browse-mode-panel[data-mode="by-topic"] .subtopic-chip[aria-pressed="true"] {
  background: #ffffff;
  color: var(--fg);
  border-color: rgba(0, 0, 0, 0.18);
}
.browse-mode-panel[data-mode="by-topic"] .subtopic-chip[aria-pressed="true"] {
  border-color: rgba(0, 0, 0, 0.55);
  font-weight: 600;
}

/* ----- Matura year folders: 3-per-row coloured grid, same expand-in-place
   behaviour as the by-topic panel above. The .page-panel container becomes
   a CSS grid and each year `.collection-l1` is a coloured box that spans
   the full row when opened. -------------------------------------------- */
/* Same [hidden] override reason as above: display:grid would otherwise
   keep the matura year grid visible when the Učbenik sub-tab is active. */
.page-panel[data-panel="matura"][hidden] { display: none; }
.page-panel[data-panel="matura"] {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin-top: 1rem;
}
@media (max-width: 800px) {
  .page-panel[data-panel="matura"] { grid-template-columns: 1fr; }
}
.page-panel[data-panel="matura"] > .collection-l1 {
  margin-top: 0;
  border-width: 2px;
  transition: transform 120ms ease, filter 120ms ease;
}
.page-panel[data-panel="matura"] > .collection-l1:not([open]):hover {
  filter: brightness(0.97);
  transform: translateY(-1px);
}
.page-panel[data-panel="matura"] > .collection-l1:not([open]) > summary {
  padding: 1.1rem 1rem;
  font-size: 1.05rem;
}
.page-panel[data-panel="matura"] > .collection-l1:not([open]) > summary::before {
  display: none;
}
.page-panel[data-panel="matura"] > .collection-l1[open] {
  grid-column: 1 / -1;
  background: var(--card-bg);
  border-top-width: 6px;
}
/* Per-position cycling colour for year boxes. */
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+1) {
  background: var(--palette-1-bg); border-color: var(--palette-1-fg);
}
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+1) > summary { color: var(--palette-1-fg); }
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+2) {
  background: var(--palette-2-bg); border-color: var(--palette-2-fg);
}
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+2) > summary { color: var(--palette-2-fg); }
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+3) {
  background: var(--palette-3-bg); border-color: var(--palette-3-fg);
}
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+3) > summary { color: var(--palette-3-fg); }
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+4) {
  background: var(--palette-4-bg); border-color: var(--palette-4-fg);
}
.page-panel[data-panel="matura"] > .collection-l1:nth-child(4n+4) > summary { color: var(--palette-4-fg); }
/* Inside an opened year, the nested season/level <details> stay
   transparent so they read on the white parent background. */
.page-panel[data-panel="matura"] > .collection-l1[open] .collection {
  background: transparent;
  border-color: transparent;
}
/* Re-declare the open-state white background AFTER the nth-child colour
   rules so [open] wins on tie-break (both selectors have equal CSS
   specificity, so order decides). Without this duplicate, opened year
   boxes stay tinted; with it they revert to a white card and keep only
   the coloured top border, matching the Po temah behaviour. */
.page-panel[data-panel="matura"] > .collection-l1[open] {
  background: var(--card-bg);
  border-top-width: 6px;
}
.page-panel[data-panel="matura"] > .collection-l1[open] > summary {
  background: transparent;
}
