/* Styles for rendered page content — the HTML that RenderUtils produces from
 * page markdown. Shared by every surface that renders a page: the editor
 * preview, fullscreen presentation mode, the public shared page and shared
 * notebook views, and therefore MathBB Commons.
 *
 * These rules used to live in style.css and a duplicate copy in
 * shared_page.html, which meant the shared *notebook* view — the main Commons
 * reading surface — rendered theorem environments unstyled. One file, linked
 * from all of them, instead.
 *
 * Colors come from the design tokens, so this file follows whichever theme is
 * active (see docs/theming.md).
 */

/* ── Theorem environments (::: {.theorem} … :::) ── */
.mb-theorem { margin: 1em 0; }
.mb-theorem > p:first-of-type { display: inline; }
.mb-theorem-head { font-weight: 700; font-style: normal; }
.mb-theorem-name { font-weight: 400; }
.mb-thm-plain { font-style: italic; }
.mb-thm-plain .mb-theorem-head, .mb-thm-plain .mb-theorem-name { font-style: normal; }
.mb-thm-remark .mb-theorem-head, .mb-thm-proof .mb-theorem-head { font-weight: 400; font-style: italic; }
.mb-qed { text-align: right; }

/* amsthm italicises a theorem's *statement text*, not the math in it. Without
   this reset the block's font-style cascades into KaTeX, and the browser fakes
   an oblique for the faces that have no italic cut — slanting blackboard-bold
   ℝ, digits, parentheses and relation symbols, and disagreeing with the
   compiled PDF. KaTeX still italicises variables itself, via its own rules. */
.mb-theorem .katex { font-style: normal; }

/* ── 3D models (.glb) ──
 * A model has no intrinsic size, so the renderer omits the height and the
 * aspect ratio is set here — that way the box scales with its column instead
 * of being pinned at one pixel height, and a theme can retune it. An explicit
 * ;size=WxH in the markdown drops the class and wins with inline styles. */
.model-viewer-container.model-auto-size {
    width: 100%;
    aspect-ratio: 4 / 3;
    height: auto;
}
/* In a column the box is already narrow; don't also let it get tall. */
.mb-column .model-viewer-container.model-auto-size,
.mb-multicol .model-viewer-container.model-auto-size { max-height: 60vh; }

/* ── Markdown tables ──
 *
 * Scoped to rendered page content, so the app's own tables (admin lists, the
 * tool-permissions matrix, keyboard shortcuts) keep their own styling.
 *
 * The look follows booktabs — horizontal rules only, no vertical lines, plenty
 * of horizontal padding — which is the convention in mathematical typesetting
 * and matches what the LaTeX export already produces (pandoc emits
 * \toprule/\midrule/\bottomrule).
 */
.preview-pane table,
#fullscreen-content table,
.shared-content table,
.snb-content-container table {
    border-collapse: collapse;
    margin: 1.3em 0;
    /* Shrink to fit the content rather than stretching across the pane: a
       three-column table spread over 900px is harder to read, not easier. */
    width: auto;
    max-width: 100%;
    /* Line up digits in numeric columns. */
    font-variant-numeric: tabular-nums;
}
.preview-pane th, .preview-pane td,
#fullscreen-content th, #fullscreen-content td,
.shared-content th, .shared-content td,
.snb-content-container th, .snb-content-container td {
    /* The horizontal padding is the whole point — markdown tables render with
       none by default, which jams the columns together. */
    padding: 0.42em 1.1em;
    vertical-align: top;
    border: none;
}
/* First and last cells sit flush with the surrounding text block. */
.preview-pane tr > :first-child, #fullscreen-content tr > :first-child,
.shared-content tr > :first-child, .snb-content-container tr > :first-child {
    padding-left: 0;
}
.preview-pane tr > :last-child, #fullscreen-content tr > :last-child,
.shared-content tr > :last-child, .snb-content-container tr > :last-child {
    padding-right: 0;
}
/* `:not([align])` because marked emits align="right"/"center" attributes for
   markdown's |---:| syntax, and a plain text-align rule would override them. */
.preview-pane th:not([align]), #fullscreen-content th:not([align]),
.shared-content th:not([align]), .snb-content-container th:not([align]) {
    text-align: left;
}
.preview-pane thead th, #fullscreen-content thead th,
.shared-content thead th, .snb-content-container thead th {
    font-weight: 700;
    border-bottom: 2px solid var(--border-6);
    padding-bottom: 0.5em;
}
.preview-pane tbody tr:not(:last-child) td,
#fullscreen-content tbody tr:not(:last-child) td,
.shared-content tbody tr:not(:last-child) td,
.snb-content-container tbody tr:not(:last-child) td {
    border-bottom: 1px solid var(--border-2);
}
.preview-pane tbody tr:last-child td, #fullscreen-content tbody tr:last-child td,
.shared-content tbody tr:last-child td, .snb-content-container tbody tr:last-child td {
    border-bottom: 2px solid var(--border-6);
}

/* ── Side-by-side columns (::: {.columns} / ::: {.column width="…"}) ── */
.mb-columns {
    display: flex;
    gap: 1.6rem;
    align-items: flex-start;
    margin: 1em 0;
}
/* Unsized columns share whatever the sized ones leave. min-width:0 stops a
   wide equation or code block from forcing the column past its share. */
.mb-column { flex: 1 1 0; min-width: 0; }
/* The first and last child of a column shouldn't add margin that breaks
   alignment with the neighbouring column's top edge. */
.mb-column > :first-child { margin-top: 0; }
.mb-column > :last-child { margin-bottom: 0; }

/* ── Flowed columns (::: {.multicol count="N"}) ── */
.mb-multicol {
    column-gap: 1.6rem;
    margin: 1em 0;
}
/* Keep the indivisible things whole across a column break — but NOT
   paragraphs, which have to be splittable or the text never flows into the
   second column at all. */
.mb-multicol .math-display,
.mb-multicol img,
.mb-multicol pre,
.mb-multicol table,
.mb-multicol .mb-theorem { break-inside: avoid; }
.mb-multicol > :first-child { margin-top: 0; }

/* Display math, figures and tables overflow a narrow column rather than
   wrapping, so let them scroll inside it instead of widening the layout. */
.mb-column .math-display, .mb-multicol .math-display { overflow-x: auto; }
.mb-column img, .mb-multicol img { max-width: 100%; height: auto; }
/* A table only scrolls if it's a block box, so switch it inside columns. */
.mb-column table, .mb-multicol table { display: block; overflow-x: auto; }

/* Collapse to a single column when there isn't room. The threshold is where
   a two-way split drops under ~230px a side, which is about the narrowest a
   column of prose-with-math stays readable.

   Viewport width is the fallback (phones, and browsers without container
   queries); the container query below is what actually matters, because the
   editor's preview pane can be narrow on a very wide screen. With all three
   panes open the preview sits under the threshold and columns stack — hide
   the chat pane (Cmd+D) to see the layout a reader will get. */
@media (max-width: 700px) {
    .mb-columns { flex-direction: column; gap: 1rem; }
    .mb-multicol { column-count: 1 !important; }
}

@supports (container-type: inline-size) {
    .preview-pane, .shared-content, .snb-content-container, #fullscreen-content {
        container-type: inline-size;
    }
    @container (max-width: 480px) {
        .mb-columns { flex-direction: column; gap: 1rem; }
        .mb-multicol { column-count: 1 !important; }
    }
}

/* Print / PDF export: keep a column row on one page where possible. */
@media print {
    .mb-columns { break-inside: avoid; }
}

/* ── Markdown tables in chat messages ──
 *
 * Same markdown renderer, very different constraints: the chat pane is a few
 * hundred pixels wide, so a table that wraps would end up with one word per
 * column. These are tuned for that instead — smaller type, tight padding,
 * cells that don't wrap, and the table itself as a scroll container so a wide
 * table slides sideways rather than blowing out the pane.
 *
 * Covers the Dora and collaborator chats (.chat-bubble) and the Relay chat
 * (.ar-text-content).
 */
.chat-bubble table,
.ar-text-content table {
    display: block;             /* a table only scrolls if it's a block box */
    overflow-x: auto;
    border-collapse: collapse;
    max-width: 100%;
    margin: 0.6em 0;
    font-size: 0.88em;
    font-variant-numeric: tabular-nums;
}
.chat-bubble th, .chat-bubble td,
.ar-text-content th, .ar-text-content td {
    padding: 0.24em 0.65em;
    border: none;
    vertical-align: top;
    /* Prefer sideways scrolling over columns collapsing to one word wide. */
    white-space: nowrap;
}
.chat-bubble tr > :first-child, .ar-text-content tr > :first-child { padding-left: 0; }
.chat-bubble tr > :last-child, .ar-text-content tr > :last-child { padding-right: 0; }
/* marked emits align="right"/"center" for |---:|; only default the rest. */
.chat-bubble th:not([align]), .ar-text-content th:not([align]) { text-align: left; }
.chat-bubble thead th, .ar-text-content thead th {
    font-weight: 700;
    border-bottom: 1px solid var(--border-5);
    padding-bottom: 0.34em;
}
.chat-bubble tbody tr:not(:last-child) td,
.ar-text-content tbody tr:not(:last-child) td {
    border-bottom: 1px solid var(--border-2);
}
/* The user's own bubble is filled with the accent color, so token greys would
   disappear into it — use the on-accent text color at low emphasis instead. */
.chat-bubble.chat-mine thead th,
.chat-bubble.chat-mine tbody tr:not(:last-child) td {
    border-bottom-color: var(--text-inverse-dim);
}

/* ── Collapsible content (static/js/content-fold.js) ──
 *
 * Headers, list-item bullets and the head region of a \collapsehere-marked
 * ::: environment keep their normal appearance until hovered, when they pick
 * up the accent color to show they're clickable. A folded span of content is
 * replaced by a "⋯" capsule that expands it again.
 */

.foldable {
    cursor: pointer;
    transition: color 0.12s ease;
}
h1.foldable:hover, h2.foldable:hover, h3.foldable:hover,
h4.foldable:hover, h5.foldable:hover, h6.foldable:hover {
    color: var(--accent);
}
li.foldable, .mb-theorem.foldable { position: relative; cursor: auto; }

/* The head region of a tail fold: everything before the marker. The inline run
   is wrapped in its own span (content-fold.js explains why), so no trigger ever
   contains a fold body and :hover is exact — hovering the visible tail does not
   light the head. Hovering any part of the region lights all of it, the way a
   header lights along its full width.

   The two-deep selector is what "all of it" costs: a head region is either a
   direct child of the owner (an environment's `.mb-theorem-head`) or one level
   in (the run wrapped inside the run-in paragraph). Bounding it at two also
   keeps a *nested* fold's trigger, which is always deeper, from lighting its
   ancestor's head. */
.fold-trigger { cursor: pointer; transition: color 0.12s ease; }
.foldable:has(> .fold-trigger:is(:hover, :focus-visible),
              > * > .fold-trigger:is(:hover, :focus-visible)) > .fold-trigger,
.foldable:has(> .fold-trigger:is(:hover, :focus-visible),
              > * > .fold-trigger:is(:hover, :focus-visible)) > * > .fold-trigger {
    color: var(--accent);
}
.fold-trigger:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}

/* Invisible click target over the browser-drawn list marker, which can't take
   events itself. It sits just outside the item's content box, where the bullet
   or number is painted. */
.fold-handle {
    position: absolute;
    right: 100%;
    top: 0;
    width: 1.6em;
    height: 1.5em;
    cursor: pointer;
}
li.foldable:has(> .fold-handle:hover)::marker,
li.foldable:has(> .fold-handle:focus-visible)::marker {
    color: var(--accent);
}
.fold-handle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
    border-radius: 3px;
}

/* The body is the wrapper holding everything a fold hides. Height is animated
   between 0 and its measured height; `fold-hidden` is the resting collapsed
   state, so nothing carries inline styles between animations. */
.fold-body.fold-animating {
    overflow: hidden;
    transition: height 0.22s ease, opacity 0.18s ease;
}
/* A tail fold's first part stays on the head's line, so it is a span and
   heights mean nothing to it: the owner animates instead (below) and the part
   only fades. Declared before .fold-hidden, which has the same specificity and
   must win when both apply. */
.fold-body.fold-inline { display: inline; }
.fold-body.fold-fading { transition: opacity 0.18s ease; }
.fold-body.fold-hidden { display: none; }
li > .fold-body { margin: 0; }

/* The owner of a tail fold while its own height travels. Kept distinct from
   .fold-animating on the body so the two never fight — and note that the
   parts under it deliberately do *not* get overflow:hidden, which would give a
   block part a formatting context and change the height being animated to.

   `clip` rather than `hidden` for exactly that reason, one level up: `hidden`
   establishes a block formatting context on the owner, so the margins of the
   paragraphs inside stop collapsing through it and it measures taller than it
   renders — +32px on a two-paragraph list item, measured. Animating to that
   figure jolts at the start and snaps back when the inline height is cleared.
   `clip` clips without the formatting context.

   The clip margin keeps the browser-drawn list marker, which is painted
   outside the padding box and would otherwise blink out for the length of the
   animation. It lets the tail spill the same distance below, but the tail is
   fading out while that happens. Browsers without either property just don't
   clip — a 220ms cosmetic difference, nothing more. */
.fold-owner-animating {
    overflow: clip;
    overflow-clip-margin: 2em;
    transition: height 0.22s ease;
}

.fold-capsule {
    display: none;
    box-sizing: border-box;
    height: 19px;
    padding: 0 9px;
    color: var(--accent-deep);
    background: var(--accent-bg);
    border: 1px solid var(--accent-faint);
    border-radius: 999px;
    margin-left: 0.35em;
    cursor: pointer;
    /* Optical alignment. `middle` centres on the x-height, which leaves the
       capsule sitting low against a line of caps and ascenders — noticeably so
       next to a header. Nudging up by 0.093em lands it on the cap-height
       centre instead; measured at 0.095em against 16px body text and 0.092em
       against a 24px header, so one constant serves every size. font-size is
       inherited for no other reason than to make that em track the text —
       nothing in the capsule is typeset (the dots are drawn). */
    font-size: inherit;
    vertical-align: middle;
    position: relative;
    top: -0.093em;
}
/* The dots are drawn, not typeset — see content-fold.js. Flex centring puts
   them exactly on the capsule's centreline in any font. */
.fold-capsule > span {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: currentColor;
}
/* A tail fold's capsule sits where the marker was — inside the head region,
   so not necessarily a direct child of the owner. CSS can't reach it from
   `.folded >`, so its state is a class of its own, set alongside `folded`. */
.foldable.folded > .fold-capsule,
.fold-capsule.fold-shown {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    animation: fold-capsule-in 0.16s ease-out;
}
/* In a folded list item the capsule is all that's left, so it sits directly
   against the marker rather than after a gap where text used to be. A tail
   capsule follows the item's own text and keeps the gap. */
li.foldable.folded > .fold-capsule:not(.fold-capsule-tail) { margin-left: 0; }
.fold-capsule:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--text-inverse);
}
.fold-capsule:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}
@keyframes fold-capsule-in {
    from { opacity: 0; transform: scale(0.8); }
    to   { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .fold-body.fold-animating,
    .fold-body.fold-fading,
    .fold-owner-animating { transition: none; }
    .foldable.folded > .fold-capsule,
    .fold-capsule.fold-shown { animation: none; }
}
