/* ============================================================
   Asides — the publish module's prose
   ============================================================

   Loaded by two pages that are not the same page: the app shell, where
   asides render inside a tab, and the standalone page the server renders
   at /asides and /asides/<slug>. Both want prose to look the same, so
   the rules live here rather than in either.

   The server emits structural HTML and names no styling: an <h2>, not an
   <h2 class="...">. So these rules select plain elements, scoped under
   .aside so nothing leaks into the app around them.
   ============================================================ */

.aside {
	font-family: var(--aside-font);
	font-size: var(--aside-size);
	line-height: var(--aside-lh);
	color: var(--aside-color);
	padding-bottom: var(--aside-gap);
}
.aside + .aside {
	border-top: 1px solid var(--aside-rule-color);
	padding-top: var(--aside-gap);
}
.aside-date {
	font-family: var(--aside-date-font);
	font-size: var(--aside-date-size);
	color: var(--aside-date-color);
	letter-spacing: 0.06em;
}
/* The reading time sits beside the date and inherits its whole look, so it needs
   only the separator that keeps the two apart -- and only where a date precedes it,
   or a dateless post would wear a leading dot with nothing before it. */
.aside-date + .aside-read::before {
	content: "·";
	margin: 0 0.5em;
	opacity: 0.6;
}
.aside h1, .aside h2, .aside h3,
.aside h4, .aside h5, .aside h6 {
	color: var(--aside-heading-color);
	line-height: 1.2;
	margin: 1.2em 0 0.4em;
}
.aside h1 { font-size: 1.6em; margin-top: 0.2em; }
.aside h2 { font-size: 1.3em; }
.aside h3 { font-size: 1.1em; }
.aside p { margin: 0 0 0.8em; }
.aside ul, .aside ol { margin: 0 0 0.8em 1.4em; }
.aside li { margin-bottom: 0.3em; }
.aside a {
	color: var(--aside-link-color);
	text-decoration: underline;
}
.aside blockquote {
	margin: 0 0 0.8em;
	padding-left: 1em;
	border-left: 3px solid var(--aside-rule-color);
	color: var(--aside-quote-color);
	font-style: italic;
}
.aside code {
	font-family: var(--aside-code-font);
	font-size: var(--aside-code-size);
	background: var(--aside-code-bg);
	padding: 0.1em 0.3em;
	border-radius: 3px;
}
.aside pre {
	background: var(--aside-code-bg);
	padding: 12px 14px;
	border-radius: var(--radius-lg);
	overflow-x: auto;   /* A long line scrolls itself rather than the page. */
	margin: 0 0 0.8em;
}
.aside pre code {
	background: none;
	padding: 0;
}
.aside hr {
	border: 0;
	border-top: 1px solid var(--aside-rule-color);
	margin: 1.6em 0;
}
.aside img { max-width: 100%; height: auto; }
.aside table {
	border-collapse: collapse;
	margin: 0 0 0.8em;
	font-size: 0.9em;
	display: block;
	overflow-x: auto;   /* A wide table scrolls itself, so the page never does. */
}
.aside th, .aside td {
	border: 1px solid var(--aside-rule-color);
	padding: 6px 10px;
}
.aside th { color: var(--aside-heading-color); }
/* ============================================================
   The standalone page
   ============================================================
   Only the server-rendered page uses these; inside the app the tab
   panel already provides the frame. */
.aside-body {
	background: var(--body-bg);
	margin: 0;
	padding: var(--sp-md);
	/* The app shell locks `html, body` to the viewport and never scrolls the body -- its panels
	   scroll inside themselves. A post opened on its own is not the app, though: it is an ordinary
	   document served under the same base stylesheet, so it inherits that lock and a long post is
	   clipped with no way down, which is exactly what happened on a phone. The body becomes the
	   scroller here -- viewport tall, its own overflow -- so the document scrolls while the shell
	   stays put. */
	height: 100dvh;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
}
.aside-page {
	max-width: var(--aside-max-w);
	margin: 0 auto;
	background: var(--window-bg, #fff5fc);
	border-radius: var(--radius-lg);
	padding: var(--panel-pad);
}
.aside-nav {
	font-family: var(--aside-date-font);
	font-size: var(--aside-date-size);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	margin-bottom: var(--sp-lg);
}
.aside-nav a {
	color: var(--aside-date-color);
	text-decoration: none;
}
.aside-nav a:hover { text-decoration: underline; }

/* The index */
.aside-index-head h1 {
	font-family: var(--aside-font);
	color: var(--aside-heading-color);
	margin-bottom: var(--sp-lg);
}
.aside-index {
	list-style: none;
	margin: 0;
	padding: 0;
}
/* One post in the index: a title to open, the date and reading time to weigh it by, and its chips.
   A list of choices, so the items sit close -- the roomy `--aside-gap` between whole notes was for
   prose, and there is none here now. A rule between rows, not around them, in the same ink as the
   rest. */
.aside-index {
	list-style: none;
	margin: 0;
	padding: 0;
}
.aside-index-item {
	padding: 0.9em 0;
}
.aside-index-item + .aside-index-item {
	border-top: 1px solid var(--aside-rule-color);
}
/* Date and reading time on one line above the title, quiet, the facts a reader scans. */
.aside-item-meta {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	margin: 0 0 0.3em;
}
.aside-item-title {
	font-family: var(--aside-font);
	font-size: 1.3em;
	line-height: 1.2;
	margin: 0.1em 0 0.5em;
}
.aside-item-title a {
	color: var(--aside-heading-color);
	text-decoration: none;
}
.aside-item-title a:hover { text-decoration: underline; }
/* The chips sit tighter under a list item than they do under a whole post: the roomy top margin
   the post foot uses would open a gap the list does not want. */
.aside-index-item .post-tags { margin-top: 0.5em; }
.aside-empty {
	font-family: var(--placeholder-font);
	color: var(--placeholder-color);
}

/* ============================================================
   Djot callout boxes

   A Djot `::: warning` becomes <div class="warning">, and the
   class is only a name until a stylesheet gives it a look. These
   are the looks for the common names, so the usual boxes read as
   callouts out of the box; a site adds its own classes as its
   prose wants them.

   Scoped under .aside, so they dress prose and nothing else, and
   apply the same on the standalone /asides page, in the app's
   stream, and in the editor's live preview -- all of which wrap a
   post in .aside.

   Class names are case-sensitive: .warning is not .Warning. These
   match the lowercase forms, which is the convention.
   ============================================================ */
.aside .note,
.aside .info,
.aside .tip,
.aside .warning,
.aside .sidebar {
	margin: 1.1em 0;
	padding: 0.7em 1.1em;
	border-radius: 6px;
	background: var(--aside-code-bg);
}
/* The first and last thing in a box sits flush, so the padding is even. */
.aside .note > :first-child,
.aside .info > :first-child,
.aside .tip > :first-child,
.aside .warning > :first-child,
.aside .sidebar > :first-child { margin-top: 0; }
.aside .note > :last-child,
.aside .info > :last-child,
.aside .tip > :last-child,
.aside .warning > :last-child,
.aside .sidebar > :last-child { margin-bottom: 0; }

/* A left accent names the kind at a glance. */
.aside .note,
.aside .info    { border-left: 4px solid var(--aside-link-color); }
.aside .tip     { border-left: 4px solid #4f8f57; }
.aside .warning { border-left: 4px solid #d9776f; }
.aside .sidebar { border: 1px solid var(--aside-rule-color); }

/* "Also on …" — where a post has been syndicated, linked from the foot of the piece.
   Muted, in teal rather than the loud pink of the date, since it is a footer note and
   not the headline: a reader who wants the conversation elsewhere can find it, and one
   who does not is not distracted by it. */
.aside-also {
	margin-top: 2em;
	padding-top: 1em;
	border-top: 1px solid rgba(0, 124, 119, 0.2);
	font-size: 0.9em;
	color: var(--col-teal);
}
.aside-also-lbl {
	font-weight: 600;
	margin-right: 0.2em;
}
.aside-also-link {
	color: var(--col-teal);
	text-decoration: underline;
	margin: 0 0.15em;
}
.aside-also-link:hover { color: var(--col-pink); }

/* ============================================================
   Tags on a read surface

   A post's tags, under the prose and on each index card, as small
   pills a reader can press to narrow the index to that tag. Pink-light
   ground and teal ink: the same pairing links already wear here, so a
   tag reads as the link it is rather than as a second kind of badge.
   The pressed state turns the pill pink, since by then it is a heading
   for the page it produced.
   ============================================================ */
.post-tags {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-sm);
	margin: 1.4em 0 0;
	padding: 0;
}
.post-tags li { margin: 0; }

.aside a.tag,
.tag {
	display: inline-block;
	font-family: var(--font-ui);
	font-size: 13px;
	line-height: 1;
	color: var(--col-teal);
	text-decoration: none;
	background: var(--col-pink-light);
	border-radius: 999px;
	padding: 7px 13px;
	text-decoration: none;
	transition: background var(--tr-fast), color var(--tr-fast);
}
a.tag:hover {
	background: var(--col-pink);
	color: var(--col-pink-bg);
	text-decoration: none;
}

/* A category chip, ahead of the tags on the same row.
   The site's own fixed vocabulary rather than a word the author reached for, so it reads as the
   solid one: filled in the site's teal, where a tag is the soft pink pill. Same shape and same
   metrics, so the row still scans as one row -- it is the weight that says which is which, not a
   second geometry. */
/* Named through `.aside` to outrank `.aside a`, which colours every link in the prose the site's
   link colour and underlines it. That is right for a link in a sentence and wrong for a chip --
   and the link colour here is the same teal the chip is filled with, so the words vanished into
   their own pill. A tag has always survived that rule only by coincidence, its colour happening
   to match; both are stated plainly now rather than left to luck. */
.aside a.post-cat,
.post-cat {
	display: inline-block;
	font-family: var(--font-ui);
	font-size: 13px;
	font-weight: 600;
	line-height: 1;
	color: var(--col-pink-bg, #fff);
	background: var(--col-teal);
	border-radius: 999px;
	padding: 7px 13px;
	text-decoration: none;
	transition: opacity var(--tr-fast), background var(--tr-fast);
}
.aside a.post-cat:hover,
a.post-cat:hover {
	background: var(--col-purple);
	color: var(--col-pink-bg, #fff);
	text-decoration: none;
}
/* The "Tagged <tag>" line above an index narrowed by ?tag=. The pill in it is
   a span, not a link, so it takes the resting look and no hover. */
.aside-index-tag {
	font-family: var(--font-ui);
	font-size: var(--aside-date-size);
	color: var(--col-teal);
	margin: -0.6em 0 var(--sp-lg);
}

/* ============================================================
   Newsletter sign-up

   Three surfaces, one form: the block under the index, the standalone
   /asides/subscribe page, and the result pages a confirmation or an
   unsubscribe link lands on. The block is set apart by a rule and the
   pink-bg card ground rather than a border, as the Asides cards are;
   the button is the app's purple send-button, so the site has one
   primary action and not two that merely resemble each other.
   ============================================================ */
.aside-subscribe-inline {
	margin: var(--aside-gap) 0 0;
	padding-top: var(--sp-lg);
	border-top: 1px solid var(--aside-rule-color);
}
.aside-subscribe-inline h2 {
	font-family: var(--aside-font);
	font-size: 1.3em;
	color: var(--aside-heading-color);
	margin: 0 0 0.2em;
}
.aside-subscribe-inline p {
	font-family: var(--aside-font);
	font-size: var(--aside-size);
	line-height: var(--aside-lh);
	color: var(--aside-color);
	margin: 0 0 0.8em;
}
.aside-subscribe {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: var(--sp-sm);
}
.aside-subscribe label {
	display: block;
	flex-basis: 100%;
	font-family: var(--font-ui);
	font-size: 0.74em;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--col-purple);
	opacity: 0.65;
	margin: 0 0 -0.2em;
}
/* The field grows to fill the line and drops the button beneath it when the
   line is too narrow to hold both -- which is every phone. */
.aside-subscribe input[type="email"] {
	flex: 1 1 15rem;
	min-width: 0;
	box-sizing: border-box;
	font-family: var(--input-font);
	font-size: var(--input-font-size);
	background: var(--input-bg);
	color: var(--input-color);
	border: 1px solid var(--col-pink-light);
	border-radius: var(--input-radius);
	padding: var(--input-pad);
}
.aside-subscribe input[type="email"]::placeholder { color: var(--input-placeholder); }
.aside-subscribe input[type="email"]:focus {
	outline: none;
	border-color: var(--col-pink);
}
.aside-subscribe-btn {
	font-family: var(--send-btn-font);
	font-size: var(--send-btn-font-size);
	cursor: pointer;
	white-space: nowrap;
	background: var(--send-btn-bg);
	color: var(--send-btn-color);
	border: none;
	border-radius: var(--send-btn-radius);
	padding: var(--send-btn-pad);
	transition: opacity var(--tr-fast);
}
.aside-subscribe-btn:hover { opacity: var(--send-btn-hover-opacity); }
/* The standalone page and the result pages: prose measure, not the full
   column, since each is a heading and a sentence or two. */
.aside-subscribe-page,
.aside-subscribe-result {
	max-width: 34em;
}
@media (max-width: 767px) {
	/* On a phone the button takes the whole line under the field rather than a
	   stub beside it. */
	.aside-subscribe-btn { flex: 1 1 100%; }
}

/* ============================================================
   The Manage tab's tag editor

   Furniture for the composer, so it lives with the tags it edits
   rather than in manage.css: the reader's pills above and the
   author's chips here are one idea seen from two sides, and keeping
   them together is what stops them drifting apart.

   The text field is the source of truth -- it carries the
   comma-separated list the save posts -- and the chips are a view of
   it. The palette below is the site's existing vocabulary, so a tag
   already in use is picked rather than retyped and mis-spelled.
   ============================================================ */
.manage-tags {
	margin: 0.9em 0 0.2em;
	padding-top: 0.8em;
	border-top: 1px solid var(--col-pink-light);
}
.manage-tags label { margin-bottom: 0.5em; }
/* The current set. Purple ink on pink-light, matching the form's own borders
   rather than the reader's teal, since here a tag is a thing being edited. */
.manage-tag-chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-sm);
}
.manage-tag-chips:empty { display: none; }
.manage-tag-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.35em;
	font-family: var(--font-ui);
	font-size: 13px;
	line-height: 1;
	color: var(--col-purple);
	background: var(--col-pink-light);
	border-radius: 999px;
	padding: 6px 8px 6px 13px;
}
.manage-tag-chip-x {
	font: inherit;
	font-size: 15px;
	line-height: 1;
	cursor: pointer;
	color: var(--col-purple);
	background: none;
	border: none;
	border-radius: 999px;
	padding: 0 0.25em;
	opacity: 0.55;
}
.manage-tag-chip-x:hover { opacity: 1; color: var(--col-pink); }
/* The vocabulary. Outlined rather than filled, so the set above reads as what
   the post has and this as what it could have. */
.manage-tag-palette {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-sm);
	margin-top: 0.6em;
}
/* The class sets display, so it must also honour the hidden attribute the script
   uses before the vocabulary arrives. */
.manage-tag-palette[hidden] { display: none; }
.manage-tag-palette-lbl {
	flex-basis: 100%;
	font-family: var(--font-ui);
	font-size: 0.74em;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--col-purple);
	opacity: 0.65;
	margin-bottom: -0.2em;
}
.manage-tag-pick {
	font-family: var(--font-ui);
	font-size: 13px;
	line-height: 1;
	cursor: pointer;
	color: var(--col-teal);
	background: transparent;
	border: 1px solid var(--col-pink-light);
	border-radius: 999px;
	padding: 6px 13px;
	transition: border-color var(--tr-fast), color var(--tr-fast);
}
.manage-tag-pick:hover { border-color: var(--col-pink); color: var(--col-pink); }
/* A tag the post already wears is still shown, greyed and inert, so the
   vocabulary does not reshuffle under the pointer as tags are picked. */
.manage-tag-pick[disabled] {
	cursor: default;
	opacity: 0.35;
}
.manage-tag-pick[disabled]:hover { border-color: var(--col-pink-light); color: var(--col-teal); }
/* The vocabulary word and its closer travel together, so the closer sits against
   the word it deletes rather than floating in the row's gap. */
.manage-tag-pal {
	display: inline-flex;
	align-items: center;
}
.manage-tag-pal .manage-tag-pick {
	border-top-right-radius: 0;
	border-bottom-right-radius: 0;
	border-right: none;
}
/* Deleting a tag reaches every author's posts, so the closer reads as a warning
   rather than as the neutral one on the post's own chips. */
.manage-tag-del {
	font-family: var(--font-ui);
	font-size: 15px;
	line-height: 1;
	cursor: pointer;
	color: #b23b34;
	background: transparent;
	border: 1px solid var(--col-pink-light);
	border-left: none;
	border-radius: 0 999px 999px 0;
	padding: 5px 10px 6px;
	opacity: 0.55;
	transition: opacity var(--tr-fast), border-color var(--tr-fast);
}
.manage-tag-del:hover { opacity: 1; border-color: #b23b34; }

/* ── Index filter ─────────────────────────────────────────────────────────
   The reader's instrument for narrowing the post list, wired by filter.js.
   Written with variable fallbacks so it sits in either site's stylesheet:
   where a site defines a token the value follows it, otherwise a neutral
   default stands in. Structural only -- the prose's own look is the site's. */

/* ── Two-column reader ─────────────────────────────────────────────────────
   On a wide screen the tab is the posts on the left and the filter on the right.
   On a narrow one it is a single column of posts, the filter folded behind a
   button into a sheet (see the mobile block at the foot of this file). */
.aside-layout {
	display: grid;
	grid-template-columns: 1fr;
	gap: 1.4rem;
}
@media (min-width: 768px) {
	.aside-layout {
		grid-template-columns: minmax(0, 1fr) 19rem;
		align-items: start;
	}
}
.aside-main { min-width: 0; }

/* ── Post boxes (left column) ──────────────────────────────────────────────
   Each post is a card: a head with the facts a reader weighs and the title that
   opens it, over a fixed-height window onto the formatted prose that fades out
   at its foot, with a "Read more" beneath. A filled card on the window's tint,
   so the list reads as raised boxes rather than rules on a flat field. */
.aside-cards {
	display: flex;
	flex-direction: column;
	gap: 1.1rem;
}
.aside-card {
	background: #ffffff;
	border: 1px solid var(--col-pink-light);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-card);
	overflow: hidden;
}
.aside-card-head { padding: 0.9rem 1.1rem 0.2rem; }
.aside-card-title {
	font-family: var(--font-body);
	font-size: 1.35rem;
	line-height: 1.25;
	margin: 0.15rem 0 0;
}
.aside-card-title a {
	color: var(--col-purple);
	text-decoration: none;
}
.aside-card-title a:hover { color: var(--col-pink); }
/* The fixed-height window onto the prose. It clips and fades so the column stays
   a set of choices, not the whole blog inlined. */
.aside-card-preview {
	position: relative;
	max-height: 11rem;
	overflow: hidden;
	padding: 0 1.1rem;
	margin-top: 0.4rem;
}
.aside-card-preview::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 3.5rem;
	background: linear-gradient(to bottom, rgba(255,255,255,0), #ffffff);
	pointer-events: none;
}
/* A preview that is not cut promises no more, so it wears no fade. */
.aside-card-preview.aside-card-fit::after { display: none; }
.aside-card-prose {
	font-size: 0.95rem;
	line-height: 1.55;
}
.aside-card-prose > :first-child { margin-top: 0; }
.aside-card-foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.9rem;
	padding: 0.6rem 1.1rem 0.9rem;
}
.aside-card-foot .post-tags { margin: 0; }
.aside-readmore {
	font-family: var(--font-ui);
	font-size: 0.8rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	color: var(--col-pink-bg);
	background: var(--col-purple);
	border: none;
	border-radius: var(--radius-md);
	padding: 0.4rem 0.9rem;
	cursor: pointer;
	transition: background var(--tr-fast);
}
.aside-readmore:hover { background: var(--col-pink); }

/* ── Filter panel ──────────────────────────────────────────────────────────
   A white card on the window's tint, so it reads as its own surface, its wells
   and chips carrying fills rather than thin outlines. */
.aside-filter {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	margin: 0;
	padding: 1rem 1.1rem;
	border: 1px solid var(--col-pink-light);
	border-radius: var(--radius-lg);
	background: #ffffff;
	box-shadow: var(--shadow-card);
}

/* The search box, in the whole site's own search look: a pill of pink-light with
   the search glyph, the input riding transparent within it. */
.aside-search-box {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	height: 2.4rem;
	padding: 0 0.75rem;
	background: var(--col-pink-light);
	border: 1px solid transparent;
	border-radius: var(--radius-lg);
	transition: border-color var(--tr-fast);
}
.aside-search-box:focus-within { border-color: var(--col-teal); }
.aside-search-box img {
	width: 1.1rem;
	height: 1.1rem;
	opacity: 0.65;
	flex: 0 0 auto;
}
.aside-filter-search {
	flex: 1 1 auto;
	min-width: 0;
	border: none;
	background: transparent;
	outline: none;
	font-family: var(--font-ui);
	font-size: 0.9rem;
	color: var(--col-purple);
}
.aside-filter-search::placeholder { color: var(--col-purple); opacity: 0.5; }

/* The author faces. A pressed face is the one the list is narrowed to -- teal, the
   filter's accent, not the browser's blue. */
.aside-filter-authors {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}
.aside-author {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	font-family: var(--font-ui);
	font-size: 0.85rem;
	padding: 0.25rem 0.7rem 0.25rem 0.3rem;
	border: 1px solid var(--col-pink-light);
	border-radius: 999px;
	background: var(--col-pink-bg);
	color: var(--col-purple);
	cursor: pointer;
	transition: border-color var(--tr-fast), background var(--tr-fast), color var(--tr-fast);
}
.aside-author:hover { border-color: var(--col-teal); }
.aside-author[aria-pressed="true"] {
	border-color: var(--col-teal);
	background: var(--col-teal);
	color: #ffffff;
}
/* A single author cannot be deselected, so their face is an indicator, not a control. */
.aside-authors-lone .aside-author { cursor: default; }
.aside-author-pic,
.aside-author-initial {
	width: 1.7rem;
	height: 1.7rem;
	border-radius: 50%;
	flex: 0 0 auto;
	object-fit: cover;
}
.aside-author-initial {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: 0.8rem;
	font-weight: 600;
	color: #ffffff;
	background: var(--col-teal);
}
.aside-author[aria-pressed="true"] .aside-author-initial {
	background: rgba(255,255,255,0.28);
}

/* One mode label, shared by the search and both facet families. */
.aside-mode {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	cursor: pointer;
}

/* The search and the two vocabularies are the same block three times: a heading, a
   mode row, then what the block narrows on. They share every rule here. */
.aside-facet { margin: 0; }
.aside-facet-head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.35rem 1rem;
	margin: 0 0 0.5rem;
}
.aside-facet-lbl {
	font-family: var(--font-ui);
	font-size: 0.72rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.07em;
	color: var(--col-purple);
}
.aside-facet-mode {
	display: flex;
	flex-wrap: wrap;
	gap: 0.15rem 0.85rem;
	font-family: var(--font-ui);
	font-size: 0.78rem;
	color: var(--col-purple);
}
.aside-facet-mode .aside-mode { gap: 0.25rem; }
.aside-facet-mode input[type="radio"] {
	accent-color: var(--col-teal);
	width: 0.85rem;
	height: 0.85rem;
	margin: 0;
}
.aside-facet-boxes {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 0.7rem;
}
.aside-facetbox { min-width: 0; }
.aside-facetbox-lbl {
	display: block;
	font-family: var(--font-ui);
	font-size: 0.66rem;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	margin: 0 0 0.35rem;
	color: var(--col-purple);
	opacity: 0.55;
}
/* A well: a filled inset the chips sit in, so a box a reader drops into is a shaded
   field rather than a dashed ghost. */
.aside-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	align-content: flex-start;
	min-height: 2.9rem;
	padding: 0.45rem;
	border: 1px solid var(--col-pink-light);
	border-radius: var(--radius-md);
	background: rgba(76, 26, 87, 0.05);
}
.aside-chips.aside-drop {
	border-color: var(--col-teal);
	background: var(--col-pink-light);
}

/* A chip -- one geometry for the filter's chips and a post's own, so the two read as the same
   thing wherever they appear. The metrics are the post chip's (`.tag` / `.post-cat` below): the
   same font, the same pill, a height set to match. */
.aside-chip {
	--chip-h: 1.35rem;
	position: relative;
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	height: var(--chip-h);
	padding: 0 13px;
	border: 1px solid transparent;
	border-radius: 999px;
	font-family: var(--font-ui);
	font-size: 13px;
	line-height: 1;
	cursor: pointer;
	user-select: none;
	transition: background var(--tr-fast), color var(--tr-fast), border-color var(--tr-fast);
}
.aside-chip-lbl { white-space: nowrap; }
/* A closer sits in the right cap, so the label gives it room. */
.aside-chips-selected .aside-chip { padding-right: var(--chip-h); }

/* The closer: a square filling the chip's height, pinned to the right cap so the cross sits on
   its centre.

   `height: 100%` is the whole trick and the thing the last version got wrong. The pill's right
   cap is a semicircle whose centre is half the FULL height in from the border edge. An absolutely
   positioned box measures from the padding box, which the 1px border insets -- so a box sized to
   the full height (as before) ends up a pixel low and a pixel left, which is exactly what showed.
   Sized to `100%` it is the padding box's height, and half of that in from the padding edge is
   `1px + (H-2)/2 = H/2` from the border edge: the cap centre, on both axes, border and all.

   The character is in the markup for anything reading the DOM as text, and hidden here -- the
   site's display face draws U+00D7 as a heavy asterisk, an ornament rather than a way out. Two
   bars instead, so the stroke weight is a decision and not the font's whim. */
.aside-chip-x {
	position: absolute;
	right: 0;
	top: 0;
	height: 100%;
	aspect-ratio: 1;
	font-size: 0;
	opacity: 0.72;
}
.aside-chip-x::before,
.aside-chip-x::after {
	content: "";
	position: absolute;
	left: 50%;
	top: 50%;
	/* Off `--chip-h`, not `em`: the closer carries `font-size:0` to kill the × glyph, which would
	   also zero any `em` here. */
	width: calc(var(--chip-h) * 0.36);
	height: 1.5px;
	border-radius: 2px;
	background: currentColor;
}
.aside-chip-x::before { transform: translate(-50%, -50%) rotate(45deg); }
.aside-chip-x::after  { transform: translate(-50%, -50%) rotate(-45deg); }
.aside-chips-source .aside-chip-x { display: none; }
.aside-chip:hover .aside-chip-x { opacity: 1; }

/* Selected chips wear the colours a post's own chips wear, so what the filter is holding and
   what a post is labelled with read as the same vocabulary: a category solid, a tag soft. */
.aside-chips-selected .aside-chip-cat {
	background: var(--col-teal);
	border-color: var(--col-teal);
	color: var(--col-pink-bg);
	font-weight: 600;
}
.aside-chips-selected .aside-chip-tag {
	background: var(--col-pink-light);
	border-color: var(--col-pink-light);
	color: var(--col-teal);
}
/* An available chip is the same shape, filled white on the shaded well so it reads as a raised
   thing to pick up, its family named by the border colour rather than by a wash. */
.aside-chips-source .aside-chip {
	background: #ffffff;
	color: var(--col-purple);
}
.aside-chips-source .aside-chip-cat { border-color: var(--col-teal); }
.aside-chips-source .aside-chip-tag { border-color: var(--col-pink); }
.aside-chips-source .aside-chip-cat:hover {
	background: var(--col-teal);
	color: var(--col-pink-bg);
}
.aside-chips-source .aside-chip-tag:hover {
	background: var(--col-pink-light);
	color: var(--col-teal);
}

/* ── Reading-time slider ───────────────────────────────────────────────────
   Two thumbs on one rail, the span between them filled teal so the chosen band
   reads at a glance. The label above, the read-out beside, on their own lines so
   the track has the width. */
.aside-filter-time {
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: center;
	gap: 0.35rem 0.75rem;
	font-family: var(--font-ui);
	font-size: 0.78rem;
	color: var(--col-purple);
}
.aside-time-lbl {
	grid-column: 1 / -1;
	text-transform: uppercase;
	letter-spacing: 0.07em;
	font-weight: 700;
}
.aside-time-track {
	position: relative;
	height: 1.4rem;
	min-width: 8rem;
}
/* The rail and the filled span sit at the track's midline, under the thumbs. */
.aside-time-rail,
.aside-time-fill {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	height: 5px;
	border-radius: 5px;
	pointer-events: none;
}
.aside-time-rail {
	left: 0;
	right: 0;
	background: var(--col-pink-light);
}
.aside-time-fill {
	/* left and right are set by the script from the thumb positions. */
	left: 0;
	right: 0;
	background: var(--col-teal);
}
/* The input, its track and the thumb are all one height, and the input is centred on the rail's
   midline. Blink centres a thumb within a taller track (so Android looked right) but WebKit/iOS
   top-aligns it (so iOS sat high); making the three heights equal removes the choice -- the thumb
   fills the track and lands on the midline on both engines. */
.aside-time-track input[type="range"] {
	position: absolute;
	top: calc(50% - 0.525rem);
	left: 0;
	width: 100%;
	height: 1.05rem;
	margin: 0;
	pointer-events: none;
	-webkit-appearance: none;
	appearance: none;
	background: transparent;
}
.aside-time-track input[type="range"]::-webkit-slider-runnable-track {
	height: 1.05rem;
	background: transparent;
}
.aside-time-track input[type="range"]::-moz-range-track {
	height: 1.05rem;
	background: transparent;
}
.aside-time-track input[type="range"]::-webkit-slider-thumb {
	-webkit-appearance: none;
	appearance: none;
	pointer-events: auto;
	margin-top: 0;
	width: 1.05rem;
	height: 1.05rem;
	border-radius: 50%;
	border: 2px solid #ffffff;
	background: var(--col-teal);
	box-shadow: 0 1px 3px rgba(76, 26, 87, 0.35);
	cursor: pointer;
}
.aside-time-track input[type="range"]::-moz-range-thumb {
	pointer-events: auto;
	width: 1.05rem;
	height: 1.05rem;
	border-radius: 50%;
	border: 2px solid #ffffff;
	background: var(--col-teal);
	box-shadow: 0 1px 3px rgba(76, 26, 87, 0.35);
	cursor: pointer;
}
.aside-time-out {
	font-variant-numeric: tabular-nums;
	text-align: right;
	color: var(--col-teal);
	font-weight: 600;
}

/* The stream once a filter is over it. Hiding an aside leaves its neighbour
   wearing the rule that used to separate them from something now gone, so the
   topmost aside still showing takes its rule off and the list keeps a clean top
   edge however much the filter has taken away. */
.aside-list .aside-index-item.aside-first {
	border-top: 0;
}

/* ============================================================
   Who writes here.

   The description an author keeps in their profile, met above the posts, and
   the byline and note that carry the same words onto a post's own page. On a
   blog one person writes, this block is what the blog is about; where several
   write, each says their own piece and is named.
   ============================================================ */

.aside-about {
	display: flex;
	flex-direction: column;
	gap: 0.9rem;
	margin: 0 0 1.4rem;
	padding: 1rem 1.1rem;
	border-left: 3px solid var(--accent, var(--aside-link-color, #4a90d9));
	background: var(--surface, var(--aside-card-bg, rgba(128,140,155,0.05)));
	border-radius: 0 10px 10px 0;
}
.aside-about-who {
	display: flex;
	align-items: flex-start;
	gap: 0.8rem;
}
.aside-about-who .aside-author-pic,
.aside-about-who .aside-author-initial {
	width: 2.6rem;
	height: 2.6rem;
	font-size: 1.05rem;
}
.aside-about-body { min-width: 0; }
.aside-about-name {
	display: block;
	font-family: var(--aside-date-font, inherit);
	font-size: 0.85rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-secondary, var(--aside-date-color, #8a97a6));
	margin: 0 0 0.15rem;
}
.aside-about-bio {
	font-family: var(--aside-font, inherit);
	font-size: 1.02rem;
	line-height: 1.5;
	color: var(--aside-color, inherit);
	margin: 0;
}

/* The byline: who wrote the piece, above the piece. */
.aside-byline {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	margin: 0 0 0.6rem;
}
.aside-byline-name {
	font-family: var(--aside-date-font, inherit);
	font-size: 0.85rem;
	letter-spacing: 0.06em;
	color: var(--aside-date-color, #8a97a6);
}

/* The note beneath a post: the same description, where the reader has just
   finished and is deciding whether to read another. */
.aside-author-note {
	display: flex;
	align-items: flex-start;
	gap: 0.8rem;
	margin: 1.2rem 0 0;
	padding: 0.9rem 1rem;
	border-top: 1px solid var(--border, var(--aside-rule-color, rgba(128,140,155,0.28)));
	background: var(--surface, var(--aside-card-bg, rgba(128,140,155,0.04)));
	border-radius: 0 0 10px 10px;
}
.aside-author-note .aside-author-pic,
.aside-author-note .aside-author-initial {
	width: 2.4rem;
	height: 2.4rem;
	font-size: 1rem;
}
.aside-author-note-name {
	display: block;
	font-family: var(--aside-date-font, inherit);
	font-size: 0.8rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--text-secondary, var(--aside-date-color, #8a97a6));
	margin: 0 0 0.2rem;
}
.aside-author-note-body p {
	font-family: var(--aside-font, inherit);
	font-size: 0.98rem;
	line-height: 1.5;
	margin: 0;
}

/* ============================================================
   In-app post reading (the Asides tab draws a post itself)
   A tap on a post opens it here with a way back, so a home-screen
   app on iOS -- which has no browser chrome to navigate with --
   never strands a reader on a page they cannot leave.
   ============================================================ */
.aside-detail-view { position: relative; }
/* The way out of a post is a closer in the top-right, exactly as a book's detail closer works
   in the Read tab: it sits inside the content, top-right, and scrolls away WITH the prose rather
   than staying pinned. */
.aside-detail-close {
	position: absolute;
	top: 0;
	right: 0;
	z-index: 1;
	width: var(--close-size, 16px);
	height: var(--close-size, 16px);
	padding: var(--close-pad, 12px);
	box-sizing: content-box;
	cursor: pointer;
	opacity: var(--close-opacity, 0.85);
	-webkit-tap-highlight-color: transparent;
}
.aside-detail-close:hover { opacity: var(--close-opacity-hover, 1); }
/* The post itself reuses the reader's prose styling (.aside); the title is the
   post's own first heading, in the feed's HTML, so nothing is drawn twice. */
.aside-detail { padding-bottom: var(--sp-lg); }
.aside-detail .aside-byline { margin-bottom: 0.3em; }

/* ── Mobile: the filter as a sheet ─────────────────────────────────────────
   The two-column layout has no room on a narrow screen, so the filter folds
   away behind a button in the post list and returns as a sheet over the tab,
   dismissed by its own closer top-right. The same element is only shown and
   hidden, never redrawn, so every selection the reader made is still there. */
.aside-filter-toggle { display: none; }
.aside-filter-close { display: none; }
@media (max-width: 767px) {
	.aside-filter-toggle {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		align-self: flex-start;
		margin: 0 0 1rem;
		padding: 0.5rem 0.9rem;
		font-family: var(--font-ui);
		font-size: 0.9rem;
		font-weight: 700;
		color: var(--col-pink-bg);
		background: var(--col-purple);
		border: none;
		border-radius: var(--radius-lg);
		cursor: pointer;
	}
	.aside-filter-toggle img {
		width: 1.15rem;
		height: 1.15rem;
		/* The icon is dark; invert it to sit on the purple button. */
		filter: brightness(0) invert(1);
	}
	/* The chip boxes stack rather than sit side by side -- two half-width columns on a phone
	   leave a chip nowhere to go. Selected is first in the markup, so it lands above Available. */
	.aside-facet-boxes { grid-template-columns: 1fr; }

	/* Folded away until summoned. */
	.aside-side { display: none; }
	/* The filter is a panel over the CONTENT AREA, exactly as the Cart panel is -- `position:
	   absolute; inset:0` against the window box, so the tabs above and the search bar below stay in
	   view and it never swallows the whole screen. The window box already sits inside the app's
	   safe-area insets, so no cutout handling is needed here. It is its own scroller, and the closer
	   rides at the top of that scroll (in flow, right-aligned) so it scrolls away with the content --
	   the same as the Cart's header closer. */
	.aside-side.open {
		display: flex;
		flex-direction: column;
		position: absolute;
		inset: 0;
		z-index: var(--z-panel, 60);
		overflow-y: auto;
		-webkit-overflow-scrolling: touch;
		padding: var(--panel-pad);
		background: var(--window-bg);
	}
	.aside-side.open .aside-filter {
		box-shadow: none;
		border: none;
		background: transparent;
		padding: 0;
	}
	.aside-filter-close {
		display: block;
		align-self: flex-end;
		margin: 0 0 0.4rem;
		width: var(--close-size, 16px);
		height: var(--close-size, 16px);
		cursor: pointer;
		opacity: var(--close-opacity, 0.85);
	}
	.aside-filter-close:hover { opacity: 1; }
}
