/*
 * The only stylesheet in this theme written for WordPress.
 *
 * Quire Ink's sheet styles the ELEMENTS inside `.prose` - p, h2, ul, blockquote, pre, table -
 * so most of what Gutenberg emits is already styled the moment it lands in the right wrapper.
 * What is left is the handful of places where the block editor invents a class name or an
 * extra element that Quire Ink's markdown pipeline never produced. Those are below, and
 * nothing else belongs here: a rule that is really about how the site LOOKS belongs upstream
 * in the blog engine, where tools/extract.ts will bring it across on the next run.
 *
 * Every rule is a translation, never a new opinion. If a value appears here that is not
 * already a Quire Ink variable, that is a bug in this file.
 */

/* ---------- alignment: nothing here, and that is the point ------------------------
 * Gutenberg names a block's placement `alignwide` / `alignleft` / `aligncenter`; Quire Ink
 * names the same four things `img-wide` / `img-left` / `img-center`. The first version of
 * this file copied the declarations across, which put the gutter geometry in two places -
 * and check:bridge caught the 4rem literal that made it obvious.
 *
 * They are ALIASED instead, in PHP: `quireink_align_classes()` adds Quire Ink's class name
 * next to WordPress's on the way out, so there is exactly one definition of what wide means
 * and it lives upstream, where the extractor keeps it current.
 */

/* ---------- images ----------------------------------------------------------------
 * `figure` and `figcaption` are already styled. The block editor adds a wrapper class and,
 * for a linked image, an <a> that would otherwise take the link underline into the picture. */
.prose .wp-block-image { margin: calc(var(--sp) * 1.75) 0; }
.prose .wp-block-image a { text-decoration: none; border: 0; }
.prose .wp-block-image img { max-width: 100%; height: auto; }
.prose .wp-block-image.is-style-rounded img { border-radius: var(--radius); }

/* ---------- gallery ----------------------------------------------------------------
 * Quire Ink's gallery is `.gallery` with a column count; Gutenberg's is a flex container with
 * the count in `.columns-N`. The mapping is one line each because the sheet upstream already
 * describes what a gallery IS. */
.prose .wp-block-gallery { display: grid; gap: var(--sp); margin: calc(var(--sp) * 1.75) 0; }
.prose .wp-block-gallery.columns-2 { grid-template-columns: repeat(2, 1fr); }
.prose .wp-block-gallery.columns-3 { grid-template-columns: repeat(3, 1fr); }
.prose .wp-block-gallery.columns-4 { grid-template-columns: repeat(4, 1fr); }
.prose .wp-block-gallery figure { margin: 0; }

/* ---------- quotes ------------------------------------------------------------------
 * `blockquote` is styled upstream. Gutenberg adds a <cite>, which markdown had no way to
 * express, so this is the one place the theme decides something the blog engine never had to. */
.prose .wp-block-quote cite,
.prose .wp-block-pullquote cite {
	display: block;
	margin-top: calc(var(--sp) * .5);
	font-size: var(--fs-small);
	line-height: var(--lh-small);
	letter-spacing: var(--ls-small);
	font-style: normal;
	color: var(--c-meta);
}
.prose .wp-block-pullquote {
	border-left: 2px solid var(--c-accent);
	padding: calc(var(--sp) * .75) 0 calc(var(--sp) * .75) var(--sp);
	margin: calc(var(--sp) * 1.75) 0;
	/* Core centres a pull quote. Quire Ink ranges every quote left, and a centred one in a
	   left-ranged column reads as a different site's furniture. */
	text-align: left;
}
/* A pull quote is a <figure> WRAPPING a <blockquote>, and `.prose blockquote` upstream draws
   a rule down the left of any blockquote. So the quote came out with TWO rules: the accent
   one on the figure, and the engine's own hairline 16px inside it. Invisible until there was
   a pattern that inserted one. The figure keeps the rule; the blockquote gives up its own. */
.prose .wp-block-pullquote blockquote {
	border-left: 0;
	padding-left: 0;
}
.prose .wp-block-pullquote p { font-size: var(--fs-h4); line-height: var(--lh-h4); }

/* ---------- code --------------------------------------------------------------------
 * `pre code` is styled upstream. The window frame Quire Ink draws around a code block keys
 * off `pre.shiki`, which only its own highlighter emits - a WordPress code block is plain,
 * so it gets the plain panel and not the chrome. */
.prose .wp-block-code { margin: calc(var(--sp) * 1.5) 0; }
.prose .wp-block-preformatted pre { white-space: pre-wrap; }

/* ---------- embeds ------------------------------------------------------------------- */
.prose .wp-block-embed { margin: calc(var(--sp) * 2) 0; }
.prose .wp-block-embed__wrapper { position: relative; }
.prose .wp-block-embed.wp-has-aspect-ratio .wp-block-embed__wrapper { padding-top: 56.25%; }
.prose .wp-block-embed.wp-has-aspect-ratio iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.prose .wp-block-embed figcaption { text-align: center; }

/* ---------- separators, buttons, lists ------------------------------------------------ */
.prose .wp-block-separator { border: 0; border-top: 1px solid var(--c-rule); }
.prose .wp-block-separator.is-style-wide { max-width: none; }
.prose .wp-block-button__link {
	display: inline-block;
	padding: calc(var(--sp) * .5) var(--sp);
	border-radius: var(--radius);
	background: var(--c-accent);
	color: var(--c-bg);
	text-decoration: none;
	font-size: var(--fs-small);
}
/* The outline variant was arriving FILLED. Core's `is-style-outline` sets a border and a
 * transparent background, but its background declaration is inside a `:where()` and carries
 * no specificity, so the accent above simply outranked it: an author who chose "Outline" got
 * the same solid button with a light rule drawn around it, which reads as a mistake rather
 * than a choice. Undoing the fill is enough - core supplies the border - and the label takes
 * the link colour, because on the page's own ground it is a link that looks like a button. */
.prose .is-style-outline .wp-block-button__link {
	background: none;
	color: var(--c-link);
}

.prose .wp-block-list { /* the ul/ol rules upstream already cover it; this exists so a future
	   Gutenberg change that moves padding onto the class has a place to be undone */ }

/* ---------- table ---------------------------------------------------------------------
 * `.prose table` is styled upstream, including the striping mixed from --c-rule. Gutenberg
 * wraps it in a figure, which would otherwise inherit the picture margins. */
.prose .wp-block-table { margin: calc(var(--sp) * 1.75) 0; overflow-x: auto; }
.prose .wp-block-table table { margin: 0; }
.prose .wp-block-table figcaption { text-align: center; }

/* ---------- things WordPress prints that the sheet has no opinion about ---------------- */
.prose .wp-caption-text,
.prose .screen-reader-text:focus { color: var(--c-meta); }
.sticky .reveal h2::after { content: " *"; color: var(--c-accent); }
.comment-list { list-style: none; padding-left: 0; }
.comment-list .children { list-style: none; padding-left: var(--sp); }

/* ---------- the cookie checkbox -------------------------------------------------------
 * WordPress's comment form has one control Quire Ink's never had: the "remember me"
 * checkbox. It lands in `.comment-actions` beside the button, and the sheet's
 * `.comment-form input{width:100%}` - written for text fields, which is all that form had -
 * stretches it across the row and pushes its own label onto the next line.
 *
 * Two declarations, both undoing a rule that was right for the inputs it was written for. */
.comment-actions label {
	display: inline-flex;
	align-items: center;
	gap: calc(var(--sp) * .4);
	margin: 0;
	color: var(--c-meta);
}
.comment-actions input[type="checkbox"] {
	width: auto;
	margin: 0;
}

/* The parenthetical beside a field label: quieter than the label, same line. */
.comment-note {
	color: var(--c-meta);
}

/* ---------- the heading WordPress puts in front of the form ---------------------------
 * Quire Ink's form has no title. The thread ends, and the box begins one `.comment-form`
 * top margin later. WordPress prints a heading and prints it OUTSIDE the form - it is also
 * the "Reply to X" target and it carries the cancel link - so that margin now opens BELOW
 * the title, and the title itself sits on the last comment's Reply link with nothing
 * between them.
 *
 * The space moves to the wrapper, and the box is drawn back up under its own heading: one
 * gap before the pair, a smaller one inside it. Nothing here is a new measurement - it is
 * the blog engine's own 2rem and 0.75rem, re-pointed at the element that now needs them,
 * in `--sp` so they still answer the density setting.
 */
#respond {
	margin-top: calc(var(--sp) * 2);
}
#respond .comment-form {
	margin-top: calc(var(--sp) * .75);
}
/* comment-reply.js MOVES #respond inside the comment being answered. The blog engine's
 * `.comment .comment-form` already tightens the box there; the wrapper it now sits in has
 * to be tightened with it, or the reply form opens two lines below the comment. */
.comment #respond {
	margin-top: calc(var(--sp) * .75);
}

/* ---------- the class names WordPress guarantees ---------------------------------------
 * Nine class names that core writes into content and that a theme is expected to answer for.
 * They are here, and not upstream, for the same reason everything else in this file is:
 * Quire Ink's editor never emits them, so the blog engine has nothing to say about them.
 *
 * The four `align*` names ALSO get Quire Ink's own geometry, on figures, through
 * `quireink_align_classes()` in PHP - that alias is what gives a picture the real gutter
 * pull. What is below is the fallback for everything that is NOT a figure: an aligned
 * paragraph, an aligned embed, a `<div>` a plugin wrote. Two different jobs, so the pair is
 * not a duplicate. */
.alignleft {
	float: left;
	margin-right: var(--sp);
	margin-bottom: calc(var(--sp) * .5);
}
.alignright {
	float: right;
	margin-left: var(--sp);
	margin-bottom: calc(var(--sp) * .5);
}
.aligncenter {
	display: block;
	margin-left: auto;
	margin-right: auto;
}
.alignnone {
	margin-left: 0;
	margin-right: 0;
}

/* A caption is the same voice as any other aside on the page. */
.wp-caption {
	max-width: 100%;
}
.wp-caption-text,
.gallery-caption {
	color: var(--c-meta);
	font-size: var(--fs-caption);
	line-height: var(--lh-caption);
	letter-spacing: var(--ls-caption);
	text-align: center;
	margin-top: calc(var(--sp) * .5);
}

/* A comment by the person who wrote the post. Their name in the accent ink, and nothing
   else - a badge would be a second thing to read on every reply they have ever left. */
.bypostauthor > .comment-meta .comment-name {
	color: var(--c-accent);
}

/* A pinned post in a list. A marker in the gutter, in the same language the timeline
   already speaks, rather than a background wash: the list has one ground and it stays. */
.post-list article.sticky .t-h3 a::before,
.post-list article.sticky h2 a::before {
	content: "\2022";
	color: var(--c-accent);
	margin-inline-end: .35em;
}

/* Off-screen but focusable, exactly as `.skip-link` upstream is - and for the same reason:
   a zero-size element is skipped by some screen readers and `display:none` takes it out of
   the tab order entirely. */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}
.screen-reader-text:focus {
	position: static;
	width: auto;
	height: auto;
	overflow: visible;
	clip-path: none;
	white-space: normal;
	color: var(--c-heading);
}

/* ---------- footer menu ----------------------------------------------------------------
 * A second nav location, and the only block on the page with no counterpart upstream: the
 * blog engine's footer is one line and has never had a menu under it. So this is the one
 * place the theme states a layout rather than translating one, and it states as little as it
 * can - a flat centred run, on the same line rhythm as the credit above it. `footer.site a`
 * already supplies the colour, the underline, the hover and the tap target.
 */
.footer-menu,
/* A child menu item joins the same centred run rather than opening a second block: the
   <li> becomes a flex row holding its own link and its children's, on the gap the run
   already uses. A footer line has no gutter to indent into. */
.footer-menu li,
.footer-menu .sub-menu {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: calc(var(--sp) * .1) calc(var(--sp) * .75);
}
.footer-menu {
	margin-bottom: calc(var(--sp) * .5);
}

/* ---------- the content footer -----------------------------------------------------------
 * Only the central reading column gets this line. It sits at the foot of the column itself,
 * keeps the text grey and unobtrusive, and still gives the visitor the required record ID.
 */
.content-footer {
	margin-top: auto;
	padding: 1rem 0 1.5rem;
	text-align: left;
	color: var(--c-meta);
	font-size: .75rem;
	line-height: 1.5;
	letter-spacing: .01em;
}
.content-footer__text {
	margin: 0;
	display: flex;
	justify-content: flex-start;
	align-items: center;
	gap: .2rem;
	flex-wrap: wrap;
}
.content-footer a {
	color: inherit;
	text-decoration: none;
}
.content-footer a:hover {
	color: var(--c-text);
	text-decoration: none;
}

/* ---------- the foot of the page, with no footer to stand on -------------------------------
 * The footer line is off by default - `footer.php` reads the switch and answers it there, so a
 * reader is never sent the markup - and the space it leaves behind is `main`'s own bottom
 * padding: 1rem, which was never the page's foot. The footer's 3rem of padding stood under it,
 * so a page ended on the footer and not on the article, and with the line switched off the last
 * block sits 16px off the bottom edge: a page that reads as cut short rather than closed.
 *
 * 1.5rem is the rail's own answer to the same question, read off the rail rather than chosen.
 * The generated cap on the gutter column is `calc(100dvh - 2.5rem - 1.5rem)`, and the 1.5rem of
 * that is the room left under its foot once the column is pinned below the site bar. So the
 * article's last line and the foot of the rail's dock come off the page at the same distance -
 * which is the relation a reader sees at a glance, and the one thing that gives a missing footer
 * away: a column of links hanging clear of the fold beside an article pressed against it. It is
 * a plain `rem` and not `--sp`, because what it is matching is a number in that generated cap
 * and the two have to stay level when the reader moves density or type scale.
 *
 * The test is on the WRAP, because the footer is the wrap's child and not the article's, and `>`
 * there so a footer inside the content cannot answer for the site's. That is what keeps the
 * Customizer switch in one place: a class on the wrap would be the same condition written down
 * twice, and the copy in `header.php` would be the one forgotten. Screen-only, and that is
 * load-bearing rather than tidy - the print sheet sets `main{padding:0}` and hides `footer.site`,
 * so a rule keyed on the footer's absence would carry a screen decision onto paper. A browser
 * without `:has()` keeps the 1rem it has always had.
 *
 * THE RULE BESIDE THE RAIL WAS STILL STANDING ON THE EDGE. `.rail::after` is the hairline the
 * generated sheet draws down the side of the gutter column, `top:0;bottom:0` on a box whose
 * bottom IS the foot of the page - so with the footer gone it was the one mark left touching the
 * last pixel, and a page that now ends 1.5rem in everywhere else with a line running past the
 * foot of the column reads as a rule waiting for something that is never printed. The same
 * 1.5rem, and the same test, for the same reason: `.rail` spans the wrap and not the page, so
 * with the footer printed the line already stops at the footer's own top - and one foot of room
 * above THAT would lift it clear of the last row of the dock, which stands flush there. Only the
 * line moves; the column, the dock and the article keep the foot the sheet gave them. */
@media screen {
	.wrap:not(:has(> footer.site)) main {
		padding-bottom: 1.5rem;
	}
	.wrap:not(:has(> footer.site)) .rail::after {
		bottom: 1.5rem;
	}
}

/* ---------- the rail: a full-height column, its furniture docked at the foot -------------
 *
 * THE COLUMN HAS A HEIGHT, and `.rail-inner` is what gives it one. `.rail` is a definite box
 * already - `height:calc(100% - var(--rail-top))` in the gutter, `top:0;bottom:0` in the
 * drawer - but `.rail-inner` was a normal block, so it was only ever as tall as its own
 * words: a rail with three blocks ended a third of the way down the page, and the dock had
 * nothing to sit against. The box that scrolls is the box a sticky child measures, so the
 * fill has to be here and not on `.rail`.
 *
 * `overflow-y:auto` is on `.rail-inner` for BOTH shapes, not only the gutter where the
 * generated sheet already sets it. In the drawer `.rail` used to scroll, but a child that
 * fills it exactly leaves it nothing of its own to scroll - so the scroller moves inward, or
 * the categories below the fold would be clipped with no way to reach them.
 *
 * `display:flex; flex-direction:column` is what lets the dock's `margin-top:auto` mean
 * "bottom": with the column filled and little to put in it, the auto margin takes the slack
 * and the dock reaches the foot of the rail instead of floating under the tags.
 *
 * THE GUTTER'S COLUMN IS ONE HEIGHT, TAKEN FROM THE WINDOW AND THEN LEFT ALONE.
 * `quireink_rail_room_js()` in functions.php writes it inline, because the top it has to be
 * taken from is the site bar's height - 2.5rem of controls on one site and a 61px custom logo
 * on the next - and no rule here can know it. The generated cap is still the room a column
 * pinned at the sheet's own `2.5rem` would have and our height is always under it, so the cap
 * keeps its old hold as the second bound. The script reads that cap off the element on every pass
 * and the sheet's pin off it once - kept against the element from then on, because the offset it
 * writes back is the same property the pin is read from, and a second read would return the
 * resting top as though it were the pin. The arithmetic lives there because the other number in
 * it is the bar, not the rail.
 *
 * AND IT IS WRITTEN ONCE, WITH NOWHERE TO TRAVEL. On DOM-ready, on `load` and on `resize` -
 * never on scroll, which is what this used to do. The height is a property of the window, not of
 * how far the page has moved, and the offset the column pins at is written with it as the
 * column's own resting top: a column left pinned at the sheet's `2.5rem` sits 104px above where
 * it starts - the height of the site bar above it - so it used to spend the first stretch of
 * every scroll climbing the window to get to its pin. One height, one offset, and the column is
 * standing still from the first pixel, with the page moving under it. This box was resized on
 * every scrolling frame instead, which held its foot on the fold by growing it exactly as much
 * as `sticky` carried the top up - a column changing shape under a moving page, with the dock
 * standing still while the heading above it slid away.
 *
 * THE FLOOR is the one thing here that is not measured. `min-height`, said in the sheet's own
 * `--sp` so it answers the density and type-scale settings like every other measurement, and
 * keyed on `data-rail-room` - the mark the script puts on the columns whose height it has
 * taken. That mark is what keeps the floor off the DRAWER, where the column fills the drawer
 * and its foot IS the drawer's foot: a floor there would push the dock, and the only way to
 * the blocks under it, past the bottom of an open drawer on a phone held sideways. Without it
 * a short window turns the column into a peephole: at 400px tall the room left is 232px, one
 * heading and seven rows, and the dock's own two blocks are taller than that on their own.
 *
 * `overscroll-behavior` IS `auto` HERE, AND THE PAGE IS WHO PAYS. `contain` came from the
 * generated sheets, and it is right for the DRAWER: an open drawer lies over the page and the
 * page behind it should not move when the list inside runs out. In the GUTTER the same
 * declaration was wrong, because there the rail is an absolutely positioned column beside the
 * article the reader is actually scrolling. A wheel over the column did nothing once the rail's
 * own list had ended, and nothing at all while the list was short enough not to scroll - the
 * pointer had to leave the rail before the page would move, in the one column a reader passes
 * through on the way to the article. `auto` is the ordinary chain, put back: the rail scrolls
 * while it has somewhere to go, and the page takes over when it does not.
 *
 * The drawer needs no exception, and gets none: `.rail` is `overflow-y:auto` with
 * `overscroll-behavior:contain` in the base sheet, one level out, and it is what stops the
 * chain while a drawer is over the page. Nothing here names the rail breakpoint - the
 * difference between the two shapes is that box's `overflow`, not a width (invariant 3).
 *
 * The selector carries `.rail`, and that is the one reason it does: the generated cap is
 * written `.rail-inner` as well, so this value would be decided by load order if the two
 * weighed the same. One class more and the answer is the same whichever sheet is read last. */
.rail .rail-inner {
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow-y: auto;
	overscroll-behavior: auto;
}
/* THE FLOOR, and only under a column the script has sized. `24 * --sp` is 24rem at the default
 * density and type scale, which is a heading and eleven rows of `.rail-row` - 36px of heading
 * and 32px a row, out of the sheet's own `--fs-small`, `--lh-small` and `.rail li` margin:
 * enough for the block above the dock to still be a list rather than a glimpse. The mark is the
 * whole test - it cannot be on a drawer, because the script never writes it where the sheet has
 * not capped the column. The cap is the harder bound of the two, and this the softer one: under
 * a window about 448px tall - the floor plus the 2.5rem and 1.5rem the cap takes out - the cap
 * is already below the floor, so the column is the room a pinned column has. Nothing there is
 * cut off that a taller window would have shown: a column taller than the window cannot be
 * shown whole in any case. */
.rail .rail-inner[data-rail-room] {
	min-height: calc(var(--sp) * 24);
}

/* THE DOCK: the site's own two blocks, held at the foot. The menu and the featured posts are
 * the site's furniture rather than this page's index, so `parts/rail-blocks.php` prints them
 * last and wraps them in `.rail-dock`. This rule holds that wrapper against the bottom of the
 * column while the categories, the archive and the tags scroll above it.
 *
 * `position:sticky` AND NOT `fixed`. It resolves against whatever actually scrolls the column
 * - `.rail-inner`, in both shapes - so one rule covers the gutter and the drawer without
 * knowing the rail breakpoint, which the blog engine computes and this repository is not
 * allowed to write down (invariant 3). A `fixed` box would instead be laid out against the
 * viewport: it would keep its place while the whole page scrolled past the rail, and it would
 * have to be hidden again at every width where the rail is not a column.
 *
 * `margin-top:auto` is what puts it at the FOOT of a short rail rather than under the tags:
 * the column above is filled to the rail's full height, so the auto margin takes all the
 * slack. On a rail tall enough to scroll there is no slack and the same declaration resolves
 * to zero - which is why the gap the dock needs is carried by `padding-block-start` and not
 * by the margin. A margin would have to be one or the other; padding and an auto margin stack.
 *
 * THE GROUND IS A PSEUDO. A pinned rail covers the rows it passes over, and a fill drawn as
 * the dock's own `background` would sit behind the dock's content but under its own border,
 * so a rule on the dock would stay put while rows showed through above it. The `::before` is
 * painted at `z-index:-1` inside the dock's own stacking context instead, so it travels with
 * the dock, covers the rows scrolling underneath - and the gap above them - and still lets the
 * dock's content draw over it. It is full width and no wider: `.rail-inner` already spans the
 * gutter the IDE chrome's numbered rings sit in, so there is nothing to reach for and no
 * horizontal overflow to add to a box whose `overflow-y` is `auto`. */
.rail-dock {
	position: sticky;
	bottom: 0;
	z-index: 1;
	margin-top: auto;
	padding-block-start: 1.75rem;
}
.rail-dock::before {
	content: "";
	position: absolute;
	inset-block: 0;
	inset-inline: 0;
	background: var(--c-bg);
	z-index: -1;
}
/* ONE BLOCK APART, inside the dock. The siblings' spacing upstream is `.rail-inner > * + *`,
 * which stops at the wrapper: without this the menu and the featured list would touch, and
 * they are two blocks the sheet has always held 1.75rem apart. The same distance, said again
 * for the one level the upstream rule cannot see. */
.rail-dock > * + * {
	margin-top: 1.75rem;
}

/* ---------- the site's menu, and no numbers on it, in either of its two homes ------------
 * The menu is printed twice from one renderer. `quireink_toc()` puts it under the table of
 * contents, so a post whose own contents are too short to index still has a way back to the
 * site; and `parts/rail-blocks.php` puts it in the dock of every rail that is the listing's
 * own - the front page, the archive, the search - where it is the first thing in the dock.
 * Both are a `<ul>` of `.rail-row`, and neither wants the furniture the contents have.
 *
 * NO NUMBERS ON THE MENU. The IDE chrome numbers rail rows like lines of source, which earns
 * its keep on a table of contents: the numbers are the outline. On four navigation links they
 * are decoration standing where information should be, and worse, they collide with the rule
 * that unnumbers the row repeating the article's title - that exception is written
 * `.toc li:first-child`, so inside the menu it landed on the first link, and a two-level menu
 * read 1, 2, 1 with the stray ring 22px out of the column. Gone, so the question does not
 * arise. The CONTENTS keep theirs: a numbered heading is what a table of contents IS.
 *
 * THIS RULE USED TO BE WRITTEN `.toc ...`, so it covered the article's gutter and nothing
 * else, and the listing's rail went on ringing its menu 1, 2, 3, 4 beside blocks that carry
 * no numbers at all - a sequence counting nothing, in the one column a reader is looking at
 * for words. Dropping the context is the whole change: one rule now owns the menu wherever
 * the rail stands, and the ring is switched off for the menu rather than deleted from the
 * sheet that draws it for the contents too.
 *
 * There is no indent to undo and no sub-menu to unnumber: `quireink_flatten_rail_menu()`
 * flattens the tree before WordPress walks it, so every row of the menu is a sibling of every
 * other. `li.menu-item` is WordPress's own mark on its own rows, and it is what keeps this
 * off every other list in the rail: the contents never carry it, and the featured block is a
 * plain `<ul>` of `.rail-row` outside any `<nav>`. */
.rail .rail-inner nav > ul li.menu-item::before {
	content: none;
}

/* ---------- the admin bar, and what it sits on top of ---------------------------------
 * WordPress prints its own bar above the page for a logged-in reader, fixed to the top of
 * the viewport at z-index 99999. `.skip-link:focus` places itself 8px from the top of the
 * page, which is 24px UNDER that bar - so the first thing a keyboard reaches on every page
 * of a logged-in site was a control drawn behind something else.
 *
 * The bar's height is WordPress's own to say and it says it: `--wp-admin--admin-bar--height`
 * is declared on `html` by the admin bar's stylesheet, 32px on a desktop and 46px under
 * 782px, where the bar is taller. Reading it is the only way this can stay correct when that
 * number changes; the 0px fallback is the case where the bar is not there at all, and then
 * this rule does nothing. */
.admin-bar .skip-link:focus {
	margin-top: var(--wp-admin--admin-bar--height, 0px);
}

/* ---------- the lightbox's arrows are a picture of an arrow ------------------------------
 * The two arrows in the viewer's gutters are kept for what they SAY - that the gallery pages
 * left and right - but the whole dialog is the tap zone now, and a button standing inside a tap
 * zone is a second, smaller answer to a question the sheet has already answered. Worse, it
 * answers it with feedback of its own: `.lightbox button:hover` washes the circle white and the
 * shared press rule drops it 1px under a carved-in shadow, right where the picture is about to
 * change anyway.
 *
 * `pointer-events:none` is the whole change. With no hit test there is no hover, no press and no
 * click for the button's own handler to answer, and a tap where the arrow is falls through to
 * whatever is under it - the dialog, or the picture on top of it - which is the half the arrow
 * sits in, so the gallery still pages from there. The glyph, its size and its place are
 * untouched: the arrow stopped being a control, it did not move.
 *
 * KEYBOARD IS DELIBERATELY NOT TOUCHED. `pointer-events` says nothing about focus, so the
 * arrows stay in the tab order and Enter on one still pages - a reader who cannot tap keeps the
 * control, and the tap zone is an enhancement rather than a replacement. That is also why
 * `quireink_lightbox_taps_js()` in functions.php can still page by clicking the arrow it was
 * told to leave alone: hit testing is what was removed, not activation.
 *
 * THE SCRIPT ASKS BEFORE IT SPEAKS. `pointer-events` is declared here and nowhere else; the tap
 * script reads the computed value off each arrow and states it inline only when the copy of this
 * sheet the browser is holding predates the rule - a stale `?ver=`, which is what the version
 * constant exists to prevent and cannot guarantee. So there is one rule with one owner, and the
 * script is its stand-in rather than a second edition of it. */
.lightbox-prev,
.lightbox-next {
	pointer-events: none;
}

/* ---------- the lightbox wears the page's own ink ----------------------------------------
 * The viewer upstream is deliberately NOT themed: a dark panel behind a photograph is the
 * convention, and a light one is a worse reading of the photograph. This theme is asked for the
 * page's ground instead, so the panel takes the palette rather than a fixed black - and because
 * it takes the palette, light, dark and the reader's own colour choice all come for free. That
 * is the whole point of doing it with tokens: `--c-bg` is what every scheme and every palette
 * rewrites, so a second rule for dark mode would be a copy of a decision already made.
 *
 * Every declaration is a role the sheet already has, which is also why no value is written here.
 * The ground is the page's ground; the ink is the reading ink; the caption and the position
 * count take the quiet ink the sheet gives every other caption and count; and the controls take
 * the header's own icon-button treatment - meta at rest, heading ink on the hairline colour.
 * Copying `rgba(0,0,0,.9)` and `#fff` across instead would have been the bug this file's header
 * warns about: a colour retyped is the one thing it must not contain.
 *
 * The `::backdrop` is the same ground for the same reason. It shows through nowhere while the
 * dialog fills the window, which it does - it is set for the shape that is ever less than the
 * window, a phone where the dialog is shorter or a later sheet, where a black curtain behind a
 * light panel would be the seam this rule exists to close.
 *
 * THE PHOTOGRAPH IS NOT FRAMED HERE. A hairline around every picture is a decision about the
 * pictures rather than about the panel, and the theme already offers a frame as a site setting;
 * a second one, unremovable, would be an opinion rather than a translation. */
.lightbox,
.lightbox::backdrop {
	background: var(--c-bg);
	color: var(--c-text);
}
.lightbox-caption,
.lightbox-count,
.lightbox button {
	color: var(--c-meta);
}
.lightbox button:hover {
	background: var(--c-rule);
	color: var(--c-heading);
}

/* ---------- a title nobody can break ---------------------------------------------------
 * A post title is a form field: whatever is typed into it is what the page has to set. One
 * long unbroken string - a URL, a German compound, a hostname - is a single word by every
 * line-breaking rule there is, so it ran straight out of the reading column and gave the
 * whole document a horizontal scrollbar. Measured on an 87-character title at 1440px: the
 * page scrolled to 1905px against a 1440px viewport.
 *
 * `break-word` rather than `anywhere`: it breaks a word only when that word cannot fit on a
 * line of its own, and it does not change how any box measures its minimum width, so no
 * layout that fits today moves. It is set once on the shell and inherited, because the same
 * string can arrive in a heading, a rail row, a term name, a comment or a caption, and a
 * list of selectors is a list that goes stale. */
.wrap {
	overflow-wrap: break-word;
}
