/* ============================================================
   viewer.css — how a file looks when it is shown as what it is.
   ------------------------------------------------------------
   The markup is built by www/js/viewer.js. One root, `.fileview`,
   carrying a `data-viewer` attribute that names the tier drawing
   it, then a quiet meta line, any warnings, and a body.

   Everything here is spent from the tokens in variables.css, so
   the eleven palettes and the two skins are covered by not having
   an opinion about colour. Two things do have an opinion:

     * the hex dump keeps a monospace face and a fixed measure
       whatever the skin says about de-teching telemetry, because
       its columns ARE the information; and
     * everything wide -- the dump, a table, a framed page --
       scrolls inside its own box. The panel is 380px on a phone
       and the page itself must never scroll sideways.
   ============================================================ */

/* The viewer owns whatever element it is handed, and fills it. */
.fileview {
	flex: 1; min-height: 0;
	display: flex; flex-direction: column;
	overflow: hidden;
	background: var(--bg-primary);
}

/* ── The line that says what this is ─────────────────────────── */
.fv-meta {
	flex: none;
	display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
	padding: 6px 12px;
	border-bottom: 1px solid var(--border);
	font-size: var(--fs-2xs);
	color: var(--text-secondary);
}
.fv-fmt  { font-weight: 600; letter-spacing: 0.02em; }
.fv-size { font-family: var(--font-mono); white-space: nowrap; }

/* A note explains; a warning says something is not as it seems. Both are
   quiet -- neither is an error, and a file whose name and bytes disagree is
   interesting rather than broken. */
.fv-note,
.fv-warn {
	flex: none; margin: 0;
	padding: 6px 12px;
	font-size: var(--fs-xs);
	line-height: 1.45;
	border-bottom: 1px solid var(--border);
}
.fv-note { color: var(--text-muted); }
.fv-warn { color: var(--warn); background: var(--warn-bg); }

/* ── The body ────────────────────────────────────────────────── */
.fv-body {
	flex: 1; min-height: 0;
	display: flex; flex-direction: column;
	overflow: auto;
}

/* ── Tier 1: what the browser decodes ────────────────────────── */

/* A soft chequer behind a picture, so a transparent PNG is a picture with
   holes in it rather than a picture that half vanished into the panel. Built
   from two surface tokens, so it follows every palette. */
.fv-img {
	flex: 1; min-height: 0;
	max-width: 100%;
	object-fit: contain;
	align-self: center;
	background-color: var(--bg-tertiary);
	background-image:
		linear-gradient(45deg, var(--bg-hover) 25%, transparent 25%, transparent 75%, var(--bg-hover) 75%),
		linear-gradient(45deg, var(--bg-hover) 25%, transparent 25%, transparent 75%, var(--bg-hover) 75%);
	background-size: 16px 16px;
	background-position: 0 0, 8px 8px;
}

.fv-audio {
	flex: none;
	width: calc(100% - 24px);
	margin: 12px;
}

.fv-video {
	flex: 1; min-height: 0;
	width: 100%;
	background: #000;		/* a letterbox is black in every palette */
}

/* A PDF, in the browser's own viewer. It is an <embed> and not a frame because
   a sandbox attribute of any value stops Chrome instantiating that viewer; what
   keeps the file from running as us is the blob's type, set in the JS. */
.fv-doc {
	flex: 1; min-height: 0;
	width: 100%;
	border: 0;
	background: var(--bg-tertiary);
}

/* A framed file runs in an opaque origin (sandbox="allow-scripts", set in the
   JS and nowhere else). Nothing here may add a permission to it. */
.fv-frame {
	flex: 1; min-height: 0;
	width: 100%;
	border: 0;
	background: var(--bg-tertiary);
}

/* ── Tier 2: text-shaped structure ───────────────────────────── */

.fv-plain {
	flex: 1; min-height: 0; margin: 0;
	padding: 12px 14px; overflow: auto;
	white-space: pre-wrap; word-break: break-word;
	font-family: var(--font-mono); font-size: var(--fs-sm);
	color: var(--text-primary);
}

.fv-md {
	flex: 1; min-height: 0;
	padding: 12px 14px; overflow: auto;
	font-size: var(--fs-base); line-height: 1.55;
	color: var(--text-primary);
}
/* The renderer's own furniture -- code blocks, links, token colours -- comes
   from render.css. What is left is the plain document flow, which the chat gets
   from the bubble around it and a document has to be given. */
.fv-md > :first-child { margin-top: 0; }
.fv-md h1, .fv-md h2, .fv-md h3, .fv-md h4 { margin: 1.1em 0 0.45em; line-height: 1.25; }
.fv-md h1 { font-size: var(--fs-3xl); }
.fv-md h2 { font-size: var(--fs-2xl); }
.fv-md h3 { font-size: var(--fs-xl); }
.fv-md h4 { font-size: var(--fs-lg); }
.fv-md p, .fv-md ul, .fv-md ol, .fv-md blockquote { margin: 0.55em 0; }
.fv-md ul, .fv-md ol { padding-left: 1.4em; }
.fv-md blockquote {
	padding-left: 0.8em; border-left: 2px solid var(--border-2);
	color: var(--text-secondary);
}
.fv-md hr { border: 0; border-top: 1px solid var(--border); margin: 1.2em 0; }
.fv-md img { max-width: 100%; height: auto; }
/* A wide table in a document scrolls in its own box, like every other wide
   thing here. `display: block` on the table is what gives it one. */
.fv-md table {
	display: block; overflow-x: auto; max-width: 100%;
	border-collapse: collapse; font-size: var(--fs-sm);
}
.fv-md th, .fv-md td { border: 1px solid var(--border); padding: 4px 8px; text-align: left; }
.fv-md th { background: var(--bg-tertiary); color: var(--text-secondary); }

/* A JSON tree. The disclosure marker is the browser's; the indent is one
   ruled line per level, which is what makes a deep document readable at a
   glance on a narrow panel. */
.fv-jnode  { padding: 0; }
.fv-body > .fv-jnode,
.fv-body > .fv-jrow { padding: 10px 12px; }
.fv-jsum {
	cursor: pointer; list-style: none;
	display: flex; gap: 8px; align-items: baseline;
	padding: 1px 0;
	font-family: var(--font-mono); font-size: var(--fs-xs);
}
.fv-jsum::-webkit-details-marker { display: none; }
.fv-jsum::before {
	content: '▸'; color: var(--text-muted);
	font-size: var(--fs-3xs); line-height: 1.6; width: 0.8em;
}
.fv-jnode[open] > .fv-jsum::before { content: '▾'; }
.fv-jsum:hover  { background: var(--bg-hover); }
.fv-jsum:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.fv-jkids {
	margin-left: 0.55em; padding-left: 0.75em;
	border-left: 1px solid var(--border);
}
.fv-jrow {
	display: flex; gap: 8px; align-items: baseline;
	padding: 1px 0;
	font-family: var(--font-mono); font-size: var(--fs-xs);
	word-break: break-word;
}
.fv-jkey   { color: var(--text-secondary); flex: none; }
.fv-jkey::after { content: ':'; opacity: 0.6; }
.fv-jshape { color: var(--text-muted); }
.fv-jval   { color: var(--text-primary); min-width: 0; }
.fv-j-string  { color: var(--accent-text); }
.fv-j-number  { color: var(--ok); }
.fv-j-boolean { color: var(--warn); }
.fv-j-null    { color: var(--text-muted); font-style: italic; }

/* A table scrolls inside its own box, in both directions. Fifty columns of
   CSV must not push the panel -- or the page behind it -- sideways. */
.fv-tablewrap {
	flex: 1; min-height: 0;
	overflow: auto;
	padding: 0 0 8px 0;
}
.fv-table {
	border-collapse: collapse;
	font-size: var(--fs-xs);
	font-variant-numeric: tabular-nums;
}
.fv-table th,
.fv-table td {
	border: 1px solid var(--border);
	padding: 3px 8px;
	text-align: left; vertical-align: top;
	max-width: 28ch; overflow-wrap: anywhere;
	color: var(--text-primary);
}
.fv-table th {
	position: sticky; top: 0; z-index: 1;
	background: var(--bg-tertiary);
	color: var(--text-secondary);
	font-weight: 600; white-space: nowrap;
}
.fv-table tr:nth-child(even) td { background: var(--bg-secondary); }

/* ── What a reader may DO to the document ─────────────────────
   `fv-bar` holds the controls, `fv-editrow` the fields one of them
   opens. Both are rows of the panel and neither floats over the
   document: the whole point of a reading view is that it stays
   readable while somebody works on it, and a sheet over the top is
   the same as taking it away. The typst live view above says this
   about a rebuild and it is just as true of an edit.

   The buttons wear `.fv-btn`, which the hex bar already defined, so
   a control added here looks like a control already in the panel
   rather than like a control from somewhere else. */
.fv-bar {
	flex: none;
	display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
	padding: 6px 12px;
	border-bottom: 1px solid var(--border);
}

.fv-editrow {
	flex: none;
	display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
	padding: 6px 12px;
	border-bottom: 1px solid var(--border);
	background: var(--bg-secondary);
	font-size: var(--fs-xs);
}
.fv-editrow[hidden] { display: none; }
.fv-editrow label {
	display: flex; align-items: center; gap: 5px;
	color: var(--text-secondary);
}
/* The fields are TOOLBAR-SIZED, and the SELECTOR is the whole of how, which is a
   bug fixed rather than a style.

   `skin-warm.css` gives every `input[type="text"]` room to type --
   `:root[data-skin="warm"] input[type="text"]`, padding of 12.6px and 18.2px at
   that skin's scale. It is loaded AFTER this file and its specificity is (0,3,1),
   so `.fileview .fv-editrow input` at (0,2,1) lost: measured, the boxes came out
   43px tall in a row of 22px buttons. That is the same rule that left `.tl-page`
   above a tall empty pill with its digit clipped out, one step short of doing it
   again -- a `width: 5ch` box under 18.2px of side padding has NO content width
   at all.

   Naming the type here is not enough on its own: `[type="text"]` counts on BOTH
   sides, so `.fileview .fv-editrow input[type="text"]` is also (0,3,1) and a tie
   goes to whichever file loads last, which is the skin. `.fv-body` is the third
   class -- the row is always inside the panel's body -- and (0,4,1) wins
   outright rather than on load order. Measured under both skins at 640px and
   380px: 22px boxes in a row of 22px buttons.

   The skin's rule is right for a form and wrong for a toolbar; this says which
   this is. */
.fileview .fv-body .fv-editrow input[type="text"],
.fileview .fv-body .fv-editrow input[type="number"],
.fileview .fv-body .fv-editrow select,
.fileview .fv-body .fv-bar select {
	background: var(--bg-tertiary); border: 1px solid var(--border-strong);
	color: var(--text-primary); border-radius: var(--radius-sm);
	padding: 2px 6px; height: auto; min-height: 0;
	font-size: var(--fs-xs); line-height: 1.3;
}
.fileview .fv-body .fv-editrow input[type="text"]   { width: 14ch; }
.fileview .fv-body .fv-editrow input[type="number"] { width: 5ch; text-align: right; }
.fv-editrow input:focus-visible,
.fv-editrow select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* The row's own sentence takes the whole width under the fields, since it is a
   sentence and not a field. It keeps `fv-note`'s colour and loses its border, so
   the row reads as one thing. */
.fv-editrow .fv-note {
	flex: 1 0 100%;
	padding: 2px 0 0 0;
	border-bottom: 0;
}

/* On a phone the fields stack rather than shrink: a 14ch box squeezed into a
   380px row is a box nobody can read what they typed in. */
@media (max-width: 380px) {
	.fv-bar     { padding: 6px 10px; }
	.fv-editrow { padding: 6px 10px; }
	.fv-editrow label { flex: 1 0 100%; }
	.fileview .fv-body .fv-editrow input[type="text"] { flex: 1 1 auto; width: auto; }
}

/* ── Tier 3: the honest floor ────────────────────────────────── */

.fv-hexbar {
	flex: none;
	display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
	padding: 6px 12px;
	border-bottom: 1px solid var(--border);
}
.fv-btn {
	background: transparent; border: 1px solid var(--border-strong);
	color: var(--text-secondary); border-radius: var(--radius-sm);
	padding: 3px 8px; cursor: pointer;
	font-size: var(--fs-xs); line-height: 1.2;
}
.fv-btn:hover:not(:disabled) { color: var(--text-primary); border-color: var(--accent); }
.fv-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.fv-btn:disabled { opacity: 0.5; cursor: default; }
.fv-hexat {
	font-family: var(--font-mono); font-size: var(--fs-2xs);
	color: var(--text-muted); white-space: nowrap;
}

/* The dump keeps its measure. `white-space: pre` and its own horizontal
   scrollbar: sixteen bytes to a line is the format, and a line that wraps at
   380px is no longer a hex dump. The skin does not get to soften this face
   either -- the columns only line up in a monospace. */
.fv-hex {
	flex: 1; min-height: 0; margin: 0;
	padding: 10px 12px;
	overflow: auto;
	white-space: pre;
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	line-height: 1.45;
	color: var(--text-primary);
	tab-size: 4;
}

/* On a phone the dump is the widest thing in the app. It still scrolls in its
   own box rather than wrapping, and the type drops one rung so that more of a
   line is on screen before anybody has to swipe. */
@media (max-width: 380px) {
	.fv-hex   { font-size: var(--fs-3xs); padding: 8px 10px; }
	.fv-meta  { padding: 6px 10px; }
	.fv-note,
	.fv-warn  { padding: 6px 10px; }
	.fv-hexbar { padding: 6px 10px; }
	.fv-hexat { white-space: normal; }
}

/* ============================================================
   The watched live document — www/js/typstwatch.js
   ------------------------------------------------------------
   The pages the author is looking at while he writes. It sits
   INSIDE the Doc panel, over the <embed> the Compile button
   filled, and takes nothing away: closing it puts the PDF back.

   Two rules here are load-bearing and neither is decoration.

   NOTHING MAY OVERLAY THE PAGES. The mark that a rebuild is
   running is a dot and a few words in a bar ABOVE the document,
   never a veil over it and never a spinner in the middle of it.
   The whole point of the loop is that the last good pages stay
   readable while the next ones are built, and dimming them is
   the same as taking them away for anybody actually reading.

   AND THE PAGES ARE NOT SKINNED. They are the book: the paper is
   white because the paper prints white, and the ink is the ink
   the PDF carries. The app's palette stops at the bar. A dark
   theme that tinted the page would be showing the author a book
   that does not exist.
   ============================================================ */

/* A ROW OF THE PANEL, NOT A SHEET OVER IT, and that is a bug fixed rather than a
   style. Laid out first as `position: absolute; inset: 0`, which covered the
   panel's own header — so the ✕ that closes the document was underneath it and the
   reader could not put the document down. The live view is a third rendering of
   the Doc panel beside the text view and the <embed>, so it takes its place in the
   same column as the other two and leaves the header alone. */
.typst-live {
	flex: 1 1 auto;
	display: flex; flex-direction: column;
	min-height: 0;
	background: var(--bg-tertiary);
}

.tl-bar {
	display: flex; align-items: center; gap: 8px;
	padding: 5px 10px;
	border-bottom: 1px solid var(--border-subtle);
	background: var(--bg-secondary);
	font-size: var(--fs-2xs);
	color: var(--text-muted);
	flex: 0 0 auto;
}
.tl-says { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* THE RAIL'S OWN SWITCH, at the far left of the bar, which is where every
   document viewer puts it and therefore where a reader looks for it. */
.tl-toc {
	flex: 0 0 auto;
	background: transparent; border: 1px solid var(--border-subtle);
	color: var(--text-secondary); border-radius: var(--radius-sm);
	padding: 0 6px; cursor: pointer;
	font-size: var(--fs-xs); line-height: 1.5;
}
.tl-toc:hover { color: var(--text-primary); border-color: var(--accent); }
.tl-toc:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tl-toc[aria-pressed="true"] { color: var(--text-primary); border-color: var(--accent); }

/* A dot, and what it means. Quiet on purpose: it reports, it does not ask. */
.tl-mark {
	width: 7px; height: 7px; border-radius: 50%;
	flex: 0 0 auto;
	background: var(--text-muted);
}
.tl-mark.tl-live     { background: var(--ok, #3fa66a); }
.tl-mark.tl-building { background: var(--accent); animation: tl-pulse 1.1s ease-in-out infinite; }
.tl-mark.tl-stale,
.tl-mark.tl-held     { background: var(--warn, #c9932b); }
.tl-mark.tl-dead     { background: var(--danger, #c0453c); }
@keyframes tl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
/* A reader who has asked for less movement gets a steady dot rather than none:
   the state is still legible, it simply stops moving. */
@media (prefers-reduced-motion: reduce) {
	.tl-mark.tl-building { animation: none; }
}

.tl-rebuild {
	flex: 0 0 auto;
	background: transparent; border: 1px solid var(--border-strong);
	color: var(--text-secondary); border-radius: var(--radius-sm);
	padding: 2px 8px; cursor: pointer;
	font-size: var(--fs-2xs); line-height: 1.2;
}
.tl-rebuild:hover { color: var(--text-primary); border-color: var(--accent); }
.tl-rebuild:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* THE SETTINGS THE VIEW SHIPPED WITHOUT. A page box, a zoom and dark paper, in
   the bar it already had rather than behind a menu: there are three of them, and
   a menu holding three things is a place to hide them. They ride at the right so
   the status keeps the left, which is where a reader looks first. */
.tl-set {
	flex: 0 0 auto;
	display: flex; align-items: center; gap: 4px;
}
.tl-set button {
	background: transparent; border: 1px solid var(--border-subtle);
	color: var(--text-secondary); border-radius: var(--radius-sm);
	padding: 1px 6px; cursor: pointer;
	font-size: var(--fs-2xs); line-height: 1.3;
	min-width: 22px;
}
.tl-set button:hover { color: var(--text-primary); border-color: var(--accent); }
.tl-set button:focus-visible,
.tl-page:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tl-set .tl-fit  { min-width: 42px; font-variant-numeric: tabular-nums; }
.tl-set .tl-night { margin-left: 4px; }
.tl-page {
	width: 3.2em;
	background: var(--bg-tertiary); border: 1px solid var(--border-subtle);
	color: var(--text-primary); border-radius: var(--radius-sm);
	padding: 1px 4px; text-align: right;
	font-size: var(--fs-2xs); line-height: 1.3;
	font-variant-numeric: tabular-nums;
}
/* AND THE PAGE NUMBER HAS TO FIT IN THE BOX, which it did not.

   `skin-warm.css` gives every `input[type="text"]` room to type --
   `padding: calc(9px * var(--space-scale)) calc(13px * var(--space-scale))`,
   which at the warm skin's scale is 12.6px and 18.2px. That selector is
   `:root[data-skin="warm"] input[type="text"]` and beats a bare `.tl-page`,
   so on a box 36px wide with `box-sizing: border-box` the content width came
   out at ZERO and `overflow: clip` took the digit away: the page box was a
   tall empty pill beside "/ 4", in a bar of 20px controls, and had been since
   it shipped. Measured, not guessed -- the computed padding is above and the
   crop that found it is in the report.

   The id wins the specificity, and the height is stated rather than left to
   the padding so that the box matches the buttons it sits between. The skin's
   rule is right for a form and wrong for a toolbar; this says which this is. */
#typst-live .tl-page {
	padding: 1px 4px;
	height: auto;
	min-height: 0;
	border-radius: var(--radius-sm);
}
.tl-of { color: var(--text-muted); font-variant-numeric: tabular-nums; margin-right: 4px; }

/* THE RAIL AND THE PAGES SHARE A ROW. The rail takes width from the pages
   rather than sitting over them, so nothing is ever hidden behind it and the
   zoom keeps meaning "as wide as what is left". */
.tl-body {
	flex: 1 1 auto; min-height: 0;
	display: flex; align-items: stretch;
}

/* THE SECTIONS, HYPERLINKED. Its own scroller, because a long book's contents
   is longer than the panel and the pages must not move when it is scrolled.
   The page number rides right, as it does in a printed contents. */
.tl-rail {
	flex: 0 0 auto;
	width: 210px; max-width: 45%;
	overflow: auto;
	border-right: 1px solid var(--border-subtle);
	background: var(--bg-secondary);
	padding: 6px 0;
}
.tl-rail[hidden] { display: none; }
.tl-toclist { list-style: none; margin: 0; padding: 0; }
.tl-toclist li { margin: 0; }
.tl-tocgo {
	display: flex; align-items: baseline; gap: 6px;
	width: 100%;
	background: transparent; border: 0;
	color: var(--text-secondary);
	text-align: left; cursor: pointer;
	padding: 3px 8px 3px 10px;
	font-size: var(--fs-2xs); line-height: 1.35;
}
.tl-tocgo:hover:not(:disabled) { color: var(--text-primary); background: var(--bg-tertiary); }
.tl-tocgo:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* An entry whose page is not known yet still READS -- it is the document's own
   contents -- it simply cannot be jumped to. Dimming it says which. */
.tl-tocgo:disabled { cursor: default; opacity: 0.55; }
.tl-tocpage {
	margin-left: auto; flex: 0 0 auto;
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}
/* The level is the indent, and nothing else: a rail that also changed the size
   of every level reads as six typefaces rather than one contents. */
.tl-toclist li[data-level="2"] .tl-tocgo { padding-left: 22px; }
.tl-toclist li[data-level="3"] .tl-tocgo { padding-left: 34px; }
.tl-toclist li[data-level="4"] .tl-tocgo { padding-left: 46px; }
.tl-toclist li[data-level="5"] .tl-tocgo { padding-left: 58px; }
.tl-toclist li[data-level="6"] .tl-tocgo { padding-left: 70px; }
.tl-toclist li[data-level="1"] .tl-tocgo { color: var(--text-primary); }
/* Where the reader is, marked on the rail rather than announced anywhere. */
.tl-toclist li[data-here="1"] .tl-tocgo {
	color: var(--text-primary);
	box-shadow: inset 2px 0 0 var(--accent);
}
.tl-tocnone {
	margin: 0; padding: 8px 10px;
	color: var(--text-muted);
	font-size: var(--fs-2xs); line-height: 1.4;
}

/* The scroller, and the reader's place in it. Nothing else scrolls: the pages
   are one tall column, so the scroll position IS the place in the book. */
.tl-scroll {
	flex: 1 1 auto; min-height: 0;
	overflow: auto;
	background: var(--bg-tertiary);
	padding: 8px;
}
/* THE STACK, WHICH IS NOT ITSELF PAPER. Each page is its own sheet inside the
   shadow root and carries its own white and its own shadow (`SHEET_CSS` in
   `www/js/typstwatch.js`, because the app's stylesheet does not reach into a
   shadow root); what shows between two sheets is the panel's own ground, and
   that gap is the whole of "distinct pages, not a continuous one".

   THE CONTAINER CARRIES THE HEIGHT AND EACH SHEET CARRIES ONE PAGE, which is
   why this is `position: relative` with its height set from JavaScript. An SVG
   as tall as a 251-page book is 192,000 pixels, and Chrome rasterises that far
   from its origin at a reduced resolution: page 1 came out at 5.6% dark pixels
   and page 40 at 0.00% -- the words still there in outline, the page a pale
   wash. Measured, and it looks exactly like a colour bug. */
.tl-pages {
	display: block;
	position: relative;
	background: transparent;
	margin: 0 auto;
	/* The WIDTH IS SET FROM JAVASCRIPT, like the height, because the reader can
	   now ask for pages wider than the panel. A `max-width: 100%` here would have
	   clamped every zoom past "fit" back to the panel and made the control look
	   broken while doing exactly what it said. */
	max-width: none;
}

/* DARK PAPER. The pages are inverted where they are drawn, so the panel around
   them keeps the app's own ground and only the paper turns over; `hue-rotate`
   after the inversion puts colours back roughly where they were, so a red figure
   stays red instead of turning cyan. Nothing is recompiled and nothing about the
   document changes: what is exported and printed is what it always was. */
.typst-live[data-night="1"] .tl-pages {
	filter: invert(1) hue-rotate(180deg);
}

/* The compiler's own words, under the document rather than over it, so a broken
   build costs the reader a strip at the bottom and not the page. */
.tl-err {
	flex: 0 0 auto;
	max-height: 32%;
	overflow: auto;
	margin: 0;
	padding: 8px 10px;
	border-top: 1px solid var(--border-subtle);
	background: var(--bg-secondary);
	color: var(--danger, #c0453c);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	line-height: 1.45;
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}

/* On a phone the bar loses the word and keeps the dot: the state is still
   there, and the document gets the width. */
@media (max-width: 380px) {
	.tl-bar    { padding: 4px 8px; }
	.tl-scroll { padding: 4px; }
	.tl-err    { max-height: 40%; }
	/* The page box and the percentage go; the zoom and the paper stay, because
	   those are the two a phone actually needs. The status keeps its dot. */
	.tl-page, .tl-of, .tl-set .tl-fit { display: none; }
	/* And the rail takes the whole panel rather than a slice of it: 210px of a
	   360px screen leaves a column of paper nobody can read. */
	.tl-rail { width: 100%; max-width: none; border-right: 0; }
	.typst-live[data-rail="1"] .tl-scroll { display: none; }
}
