
:root {
  --tt-color-bg: #f4f4f0;
  --tt-color-text: #1a1a1a;
  --tt-color-muted: #666666;
  --tt-color-accent: #007070;
  --tt-color-accent-muted: #487676;
  --tt-color-border: #8c8c85;
  --tt-color-surface: #ffffff;
  --tt-color-code-bg: #eaeae4;
  --tt-color-focus: #007070;
  --tt-color-tag-bg: #e8e8e2;
  --tt-color-tag-text: #555555;
  /* The search highlight is the theme's accent, not the tag chip. A tag is
     meant to sit quietly beside the text; a highlight has to be picked out
     of it, which is 3:1 against the page, and no pale highlighter reaches
     that on a pale page. Every palette already holds its accent to 4.5:1
     there, so following it clears the bar by construction and each theme
     highlights in its own colour. */
  --tt-color-highlight-bg: var(--tt-color-accent);
  --tt-color-highlight-text: #ffffff;
  --tt-color-error: #c53030;
  --tt-color-warning: #7a5200;
  --tt-color-code-keyword: #a6264e;
  --tt-color-code-string: #032f62;
  --tt-color-code-comment: #586069;
  --tt-color-code-function: #6f42c1;
  --tt-color-code-number: #005cc5;
  --tt-color-code-operator: #a6264e;
  --tt-color-code-variable: #953d00;
  --tt-font-body: "Courier New", monospace;
  --tt-font-heading: "Courier New", monospace;
  --tt-font-code: "Courier New", monospace;
  --tt-max-width: 720px;
  --tt-admin-max-width: 1024px;
  --tt-admin-field-max-width: 480px;
  --tt-spacing-page: 2rem;
  --tt-text-heading: 1.75rem;
  --tt-text-body: 1rem;
  --tt-text-small: 0.875rem;
}

:root {
  /* Tell the UA which palette its own chrome (scrollbars, form controls,
     mobile keyboard) should use. Without this, dark mode gets light UA
     chrome. Dark-in-both-modes themes (Hacker) re-declare at :root. */
  color-scheme: light;
}

@media (max-width: 480px) {
  :root {
    --tt-spacing-page: 1rem;
  }
}

[data-theme="dark"] {
  color-scheme: dark;
  --tt-color-bg: #0e0e0e;
  --tt-color-text: #c8c8c0;
  --tt-color-muted: #a3a3a3;
  --tt-color-accent: #00a3a3;
  --tt-color-accent-muted: #598a8a;
  --tt-color-border: #6a6a6a;
  --tt-color-surface: #181818;
  --tt-color-code-bg: #1a1a1a;
  --tt-color-focus: #00a3a3;
  --tt-color-tag-bg: #1e1e1e;
  --tt-color-tag-text: #999999;
  /* The dark accents are light, so the text on them inverts. */
  --tt-color-highlight-text: #000000;
  --tt-color-error: #f87171;
  --tt-color-warning: #e6ac3c;
  --tt-color-code-keyword: #ff7b72;
  --tt-color-code-string: #a5d6ff;
  --tt-color-code-comment: #8b949e;
  --tt-color-code-function: #d2a8ff;
  --tt-color-code-number: #79c0ff;
  --tt-color-code-operator: #ff7b72;
  --tt-color-code-variable: #ffa657;
}

body {
  background: var(--tt-color-bg);
  color: var(--tt-color-text);
  font-family: var(--tt-font-body);
  font-size: var(--tt-text-body);
  line-height: 1.6;
  margin: 0;
}

a {
  color: var(--tt-color-accent);
}

a:hover {
  text-decoration-thickness: 2px;
}

a:visited {
  color: var(--tt-color-accent-muted);
}

button,
a,
input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
  min-height: 44px;
}

:focus-visible {
  outline: 2px solid var(--tt-color-focus);
  outline-offset: 2px;
}

.tt-skip-link {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.tt-skip-link:focus-visible {
  position: fixed;
  top: 0;
  left: 0;
  width: auto;
  height: auto;
  overflow: visible;
  padding: 0.5rem 1rem;
  background: var(--tt-color-surface);
  color: var(--tt-color-text);
  z-index: 9999;
  outline: 2px solid var(--tt-color-focus);
}

/* Code blocks: global base styles.
   Applies to all code in the admin SPA and, through the public stylesheet,
   to post and page content. */

pre,
code {
  font-family: var(--tt-font-code);
}

pre {
  background: var(--tt-color-code-bg);
  border: 1px solid var(--tt-color-border);
  padding: 1rem;
  overflow-x: auto;
  border-radius: 0;
  font-size: max(14px, 0.875em);
  line-height: 1.6;
  margin: 1rem 0;
}

code {
  background: var(--tt-color-code-bg);
  padding: 0.15em 0.35em;
  border: 1px solid var(--tt-color-border);
  font-size: max(14px, 0.875em);
  border-radius: 0;
}

pre code {
  background: none;
  border: none;
  padding: 0;
  font-size: inherit;
}

/* Syntax highlighting: maps hljs classes to --tt-color-code-* tokens.
   Do NOT import highlight.js theme CSS. One theming system, automatic dark mode,
   overridable via custom_css config key. */

code.hljs {
  color: var(--tt-color-text);
  font-family: var(--tt-font-code);
}

pre code.hljs {
  display: block;
}

.hljs-keyword,
.hljs-built_in,
.hljs-type,
.hljs-literal,
.hljs-meta {
  color: var(--tt-color-code-keyword);
}

.hljs-string,
.hljs-regexp,
.hljs-addition {
  color: var(--tt-color-code-string);
}

.hljs-comment,
.hljs-quote {
  color: var(--tt-color-code-comment);
  font-style: italic;
}

.hljs-title,
.hljs-section,
.hljs-name {
  color: var(--tt-color-code-function);
}

.hljs-number {
  color: var(--tt-color-code-number);
}

.hljs-operator,
.hljs-punctuation {
  color: var(--tt-color-code-operator);
}

.hljs-variable,
.hljs-template-variable,
.hljs-attr,
.hljs-params,
.hljs-property {
  color: var(--tt-color-code-variable);
}

.hljs-deletion {
  color: var(--tt-color-code-keyword);
  background: color-mix(in srgb, var(--tt-color-code-keyword) 10%, transparent);
}

.hljs-emphasis {
  font-style: italic;
}

.hljs-strong {
  font-weight: bold;
}

/* Content embeds: click-to-load placeholders, one class per provider */

/* A column flex box so the placeholder fills it at any height, and the
   minimum heights let it grow when the link wraps on a phone. */
.tt-embed {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  margin: 1.5rem 0;
}

.tt-embed-youtube,
.tt-embed-vimeo,
.tt-embed-peertube {
  aspect-ratio: 16 / 9;
}

.tt-embed-spotify,
.tt-embed-apple-podcasts,
.tt-embed-apple-music,
.tt-embed-castopod {
  min-height: 180px;
}

.tt-embed-mastodon {
  min-height: 200px;
}

/* The top padding clears the provider badge, which is out of flow. */
.tt-embed-placeholder {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  box-sizing: border-box;
  width: 100%;
  padding: 2.25rem 0 1rem;
  background: var(--tt-color-surface);
  border: 1px solid var(--tt-color-border);
  cursor: pointer;
}

/* The link text is the whole URL, one unbreakable word that is wider than a
   phone screen; it breaks anywhere rather than running off the edge. */
.tt-embed-link {
  max-width: 100%;
  box-sizing: border-box;
  padding: 0 1rem;
  text-align: center;
  overflow-wrap: anywhere;
}

.tt-embed-provider-badge {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
}

.tt-embed-play {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: none;
  background: none;
  color: var(--tt-color-accent);
  cursor: pointer;
  transition: transform 0.15s ease;
}

.tt-embed-play:hover {
  transform: scale(1.15);
}

@media (prefers-reduced-motion: reduce) {
  .tt-embed-play {
    transition: none;
  }
}

.tt-embed-play svg {
  width: 48px;
  height: 48px;
}

/* Two classes deep so a content paragraph rule, `.tt-post-content p` in the
   base and in themes, cannot restyle it as body prose. */
.tt-embed .tt-embed-notice {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  margin: 0;
  padding: 0 1rem;
  text-align: center;
  text-indent: 0;
}

.tt-embed-loaded .tt-embed-placeholder {
  display: none;
}

.tt-embed-loaded iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
}

/* Rendered markdown content inside post/page detail */

:is(.tt-post-content, .tt-page-content) h2,
:is(.tt-post-content, .tt-page-content) h3,
:is(.tt-post-content, .tt-page-content) h4,
:is(.tt-post-content, .tt-page-content) h5,
:is(.tt-post-content, .tt-page-content) h6 {
  font-family: var(--tt-font-heading);
  font-weight: bold;
  margin: 2rem 0 1rem;
  color: var(--tt-color-text);
}

:is(.tt-post-content, .tt-page-content) h2 {
  font-size: 1.5rem;
}

:is(.tt-post-content, .tt-page-content) h3 {
  font-size: 1.25rem;
}

:is(.tt-post-content, .tt-page-content) h4 {
  font-size: 1.125rem;
}

:is(.tt-post-content, .tt-page-content) h5 {
  font-size: 1.05rem;
  margin: 1.25rem 0 0.5rem;
}

:is(.tt-post-content, .tt-page-content) h6 {
  font-size: 1rem;
  color: var(--tt-color-muted);
  margin: 1rem 0 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

:is(.tt-post-content, .tt-page-content) p {
  line-height: 1.6;
  margin: 1rem 0;
}

:is(p, h1, h2, h3, h4, h5, h6)[align="center"] {
  text-align: center;
}

:is(p, h1, h2, h3, h4, h5, h6)[align="right"] {
  text-align: right;
}

/* The admin's preflight displays images as blocks; prose images stay inline. */
:is(p, h1, h2, h3, h4, h5, h6):is([align="center"], [align="right"]) img:not(.tt-aligned-image) {
  display: inline;
}

p[align="center"] img.tt-aligned-image,
.tiptap-editor__content img[data-tt-align="center"] {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

p[align="right"] img.tt-aligned-image,
.tiptap-editor__content img[data-tt-align="right"] {
  display: block;
  margin-left: auto;
  margin-right: 0;
}

:is(.tt-post-content, .tt-page-content) a {
  color: var(--tt-color-accent);
  text-decoration: underline;
}

:is(.tt-post-content, .tt-page-content) a:visited {
  color: var(--tt-color-accent-muted);
}

:is(.tt-post-content, .tt-page-content) pre {
  margin: 1.5rem 0;
}

:is(.tt-post-content, .tt-page-content) blockquote {
  border-left: 3px solid var(--tt-color-border);
  padding-left: 1rem;
  margin: 1.5rem 0;
  font-style: italic;
  color: var(--tt-color-muted);
}

:is(.tt-post-content, .tt-page-content) img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  margin: 1.5rem 0;
}

:is(.tt-post-content, .tt-page-content) ul,
:is(.tt-post-content, .tt-page-content) ol {
  padding-left: 1.5rem;
  margin: 1rem 0;
}

:is(.tt-post-content, .tt-page-content) ul ul,
:is(.tt-post-content, .tt-page-content) ul ol,
:is(.tt-post-content, .tt-page-content) ol ul,
:is(.tt-post-content, .tt-page-content) ol ol {
  margin: 0;
}

:is(.tt-post-content, .tt-page-content) li {
  margin: 0.25rem 0;
  line-height: 1.6;
}

:is(.tt-post-content, .tt-page-content) ul {
  list-style: disc;
}

:is(.tt-post-content, .tt-page-content) ul.contains-task-list {
  list-style: none;
  padding-left: 0;
}

:is(.tt-post-content, .tt-page-content) li.task-list-item {
  display: flex;
  align-items: baseline;
  gap: 0.5em;
}

:is(.tt-post-content, .tt-page-content) li.task-list-item input[type="checkbox"] {
  appearance: none;
  width: 1em;
  height: 1em;
  border: 1px solid var(--tt-color-border);
  border-radius: 2px;
  background: var(--tt-color-surface);
  vertical-align: middle;
  margin: 0 0.4em 0 0;
  flex-shrink: 0;
  opacity: 1;
  cursor: default;
  position: relative;
}

:is(.tt-post-content, .tt-page-content) li.task-list-item input[type="checkbox"]:checked {
  background: var(--tt-color-accent);
  border-color: var(--tt-color-accent);
}

:is(.tt-post-content, .tt-page-content) li.task-list-item input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 0.2em;
  top: 0.02em;
  width: 0.35em;
  height: 0.6em;
  border: solid var(--tt-color-bg);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

:is(.tt-post-content, .tt-page-content) ol {
  list-style: decimal;
}

:is(.tt-post-content, .tt-page-content) hr {
  border: none;
  border-top: 1px solid var(--tt-color-border);
  margin: 2rem 0;
}

/* The pipeline wraps every table in a focusable container that does the
   horizontal scrolling, so a wide table can be scrolled from the keyboard
   and the table itself stays a table: it shrink-wraps to its grid, so theme
   borders and shadows hug the visible cells. */
.tt-table-wrap {
  overflow-x: auto;
  max-width: 100%;
  margin: 1.5rem 0;
}

:is(.tt-post-content, .tt-page-content) table {
  border-collapse: collapse;
  font-size: var(--tt-text-small);
}

:is(.tt-post-content, .tt-page-content) th,
:is(.tt-post-content, .tt-page-content) td {
  border: 1px solid var(--tt-color-border);
  padding: 0.5rem 0.75rem;
}

:is(.tt-post-content, .tt-page-content) th {
  font-weight: bold;
  background: var(--tt-color-code-bg);
}

/* Table of contents heading (generated by {{ table_of_contents heading:"..." }}) */

.tt-toc-heading {
  font-family: var(--tt-font-heading);
  font-weight: bold;
  margin: 2rem 0 1rem;
}

/* Collapsed table of contents: a <details> inside nav.tt-toc, its <summary>
   standing in for the heading. */

.tt-toc {
  margin: 2rem 0 1rem;
}

.tt-toc summary {
  cursor: pointer;
  font-family: var(--tt-font-heading);
  /* The size the content h2 rule gives the open form's heading, so
     collapsing a list does not enlarge its title. */
  font-size: 1.5rem;
  font-weight: bold;
  color: var(--tt-color-text);
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.tt-toc summary::-webkit-details-marker {
  display: none;
}

.tt-toc summary::before {
  content: "\25B8";
  font-size: var(--tt-text-small);
  transition: transform 0.15s ease;
}

.tt-toc details[open] summary::before {
  transform: rotate(90deg);
}

/* Marks the marker decorative where the alternative-text syntax is
   understood. Elsewhere the whole declaration would be dropped and the
   marker with it, so the plain form above stays the fallback. */
@supports (content: "x" / "") {
  .tt-toc summary::before {
    content: "\25B8" / "";
  }
}

@media (prefers-reduced-motion: reduce) {
  .tt-toc summary::before {
    transition: none;
  }
}

/* Footnotes (generated by remark-gfm) */

:is(.tt-post-content, .tt-page-content) .footnotes {
  border-top: 1px solid var(--tt-color-border);
  margin-top: 2rem;
  padding-top: 1rem;
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
}

:is(.tt-post-content, .tt-page-content) .footnotes ol {
  padding-left: 1.5rem;
  list-style: decimal;
}

:is(.tt-post-content, .tt-page-content) .footnotes li {
  margin: 0.25rem 0;
}

:is(.tt-post-content, .tt-page-content) [data-footnote-ref] {
  color: var(--tt-color-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

:is(.tt-post-content, .tt-page-content) .data-footnote-backref {
  color: var(--tt-color-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Public-site structural baseline. Served with the tokens from tokens.css as
   one content-hashed immutable asset (loadBaseCssAsset in
   src/server/ssr-config.ts), linked by the SSR document before
   custom_css (including the chosen theme). Not part of any Vite bundle; the server concatenates, so this
   file imports nothing. */

/* All structural selectors are wrapped in :where() to hold them at zero
   specificity. custom_css, including any copied theme CSS, loads later in the cascade, so any
   bare selector it uses overrides these rules without needing !important.
   Within this file, later rules win over earlier ones; keep override rules
   below the rules they replace. */

:where(.tt-site) {
  max-width: var(--tt-max-width);
  margin: 0 auto;
  padding: 0 var(--tt-spacing-page);
  overflow-x: clip;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

@supports (min-height: 100svh) {
  :where(.tt-site) {
    min-height: 100svh;
  }
}

:where(.tt-banner, .tt-sidebar, .tt-post-after) {
  display: none;
}

:where(.tt-banner:not(:empty), .tt-post-after:not(:empty)) {
  display: block;
}

:where(.tt-banner:not(:empty)) {
  padding-top: 2rem;
}

:where(.tt-post-after:not(:empty)) {
  margin-top: 2rem;
  padding-bottom: 2rem;
}

/* Default theme header: two-row grid layout
   Row 1: site title (left) | dark mode toggle (right)
   Row 2: nav links (left)  | search input (right) */

:where(.tt-header) {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 0.75rem 1rem;
  padding: 1.5rem 0 2rem;
}

:where(.tt-site-title) {
  grid-column: 1;
  grid-row: 1;
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
}

:where(.tt-wordmark) {
  font-family: var(--tt-font-heading);
  font-size: var(--tt-text-heading);
  font-weight: bold;
  letter-spacing: 3px;
  color: var(--tt-color-text);
}

:where(.tt-logo) {
  max-height: 3rem;
  width: auto;
}

:where(.tt-tagline) {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
}

/* --- Header layout variants --- */

/* title_only: wordmark only (default) */
:where(
  [data-tt-header-layout="title_only"] .tt-logo,
  [data-tt-header-layout="title_only"] .tt-tagline
) {
  display: none;
}

/* title_desc: wordmark + tagline */
:where([data-tt-header-layout="title_desc"] .tt-logo) {
  display: none;
}

/* logo: logo image only, full-width */
:where([data-tt-header-layout="logo"] .tt-logo) {
  max-height: 4rem;
}
:where([data-tt-header-layout="logo"] .tt-wordmark, [data-tt-header-layout="logo"] .tt-tagline) {
  display: none;
}

/* logo_title: logo + wordmark side by side */
:where([data-tt-header-layout="logo_title"] .tt-site-title) {
  align-items: center;
}
:where([data-tt-header-layout="logo_title"] .tt-tagline) {
  display: none;
}

/* logo_title_desc: logo + wordmark + tagline */
:where([data-tt-header-layout="logo_title_desc"] .tt-site-title) {
  align-items: center;
  flex-wrap: wrap;
}

/* logo_desc: logo + tagline, no wordmark */
:where([data-tt-header-layout="logo_desc"] .tt-site-title) {
  flex-direction: column;
  align-items: flex-start;
}
:where([data-tt-header-layout="logo_desc"] .tt-logo) {
  max-height: 4rem;
}
:where([data-tt-header-layout="logo_desc"] .tt-wordmark) {
  display: none;
}

:where(.tt-dark-toggle) {
  min-width: 44px;
  font: inherit;
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  background: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem;
}

:where(.tt-toggle-icon svg) {
  display: block;
  flex-shrink: 0;
}

/* The `switch` toggle mode. The button carries its mode, so the three modes
   that share one pair of spans are told apart here rather than in the
   markup, and the knob's position keys on the theme attribute the head
   script writes: one write moves the palette and the knob together. */
:where(.tt-toggle-switch) {
  position: relative;
  display: inline-block;
  flex-shrink: 0;
  width: 2.25rem;
  height: 1.25rem;
  border: 1px solid var(--tt-color-border);
  border-radius: 1rem;
  background: var(--tt-color-surface);
}

:where(.tt-toggle-knob) {
  position: absolute;
  top: 1px;
  left: 1px;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background: var(--tt-color-muted);
  transition: transform 0.15s;
}

:where([data-theme="dark"] .tt-toggle-knob) {
  transform: translateX(1rem);
  background: var(--tt-color-accent);
}

@media (prefers-reduced-motion: reduce) {
  :where(.tt-toggle-knob) {
    transition: none;
  }
}

:where(.tt-dark-toggle[data-toggle-mode="icon"] .tt-toggle-label) {
  display: none;
}

:where(.tt-dark-toggle[data-toggle-mode="text"] .tt-toggle-icon) {
  display: none;
}

:where(.tt-header .tt-dark-toggle) {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
  align-self: center;
}

:where(.tt-nav) {
  grid-column: 1;
  grid-row: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1rem;
}

:where(.tt-nav-link) {
  font-size: 1.05rem;
  font-family: var(--tt-font-body);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

:where(
  .tt-nav-link[target="_blank"],
  .tt-post-content a[target="_blank"],
  .tt-page-content a[target="_blank"]
)::after {
  content: "\2197" / "";
  margin-left: 0.25em;
  font-size: var(--tt-text-small);
}

/* Off-screen but in the accessible name, for text that only a screen
   reader needs. The skip link uses the same technique but shows on focus. */
:where(.tt-visually-hidden) {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

:where(.tt-header .tt-search) {
  grid-column: 2;
  grid-row: 2;
  justify-self: end;
}

/* Fills remaining height so the footer sits at the bottom of short pages.
   The min-height lives on .tt-site (flex column), not here: putting a
   viewport min-height on .tt-body forces header + 100vh + footer and leaves
   a viewport of dead space before the footer. */
:where(.tt-body) {
  flex: 1 0 auto;
}

:where(.tt-main) {
  padding-top: 2rem;
  overflow-wrap: break-word;
}

@media (max-width: 480px) {
  :where(.tt-header) {
    grid-template-columns: 1fr;
  }

  :where(.tt-header .tt-dark-toggle) {
    grid-row: 2;
    justify-self: start;
  }

  :where(.tt-nav) {
    grid-row: 3;
  }

  :where(.tt-header .tt-search) {
    grid-row: 4;
    justify-self: start;
  }
}

/* Mobile hamburger nav */

:where(.tt-mobile-toggle) {
  display: none;
}

:where(.tt-mobile-backdrop) {
  display: none;
}

:where(.tt-mobile-close) {
  display: none;
}

:where(.tt-search-btn) {
  display: none;
}

:where(.tt-mobile-drawer) {
  display: contents;
}

:where(.tt-mobile-toggle-line) {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--tt-color-text);
}

@media (max-width: 768px) {
  :where(.tt-header[data-mobile-nav="hamburger"]) {
    grid-template-columns: minmax(0, 1fr) auto auto;
  }

  /* The menu button comes before the dark toggle in the source, so it comes
     before it on the row: tab order follows the source, and the eye has to
     find focus where it expects it. */
  :where(.tt-header[data-mobile-nav="hamburger"] .tt-dark-toggle) {
    grid-column: 3;
    grid-row: 1;
    justify-self: end;
    align-self: center;
  }

  :where(.tt-header[data-mobile-nav="hamburger"] .tt-mobile-toggle) {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
    grid-column: 2;
    grid-row: 1;
    align-self: center;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    min-width: 44px;
  }

  /* A theme that hides the dark toggle renders no second button, and the menu
     button takes the corner rather than sit a column gap inside it. */
  :where(.tt-header[data-mobile-nav="hamburger"] .tt-mobile-toggle:last-of-type) {
    grid-column: 3;
  }

  :where(.tt-header[data-mobile-nav="hamburger"] .tt-mobile-drawer) {
    display: none;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-menu-open] .tt-mobile-drawer) {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    grid-column: 1 / -1;
    grid-row: 2;
    padding: 0.75rem 0 1rem;
    border-top: 1px solid var(--tt-color-border);
    animation: tt-drawer-open 200ms ease;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-menu-open] .tt-nav) {
    flex-direction: column;
    gap: 0.25rem;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-menu-open] .tt-search) {
    width: 100%;
  }

  /* In the drawer the search box fills the width. Its button stays hidden:
     a type="search" input submits on Enter, and mobile keyboards show a
     search key for it. */
  :where(.tt-header[data-mobile-nav="hamburger"][data-menu-open] .tt-search input) {
    max-width: none;
  }
}

@keyframes tt-drawer-open {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
}

@media (prefers-reduced-motion: reduce) {
  @keyframes tt-drawer-open {
    from {
      opacity: 0;
    }
  }
}

/* Slide drawer variants: slide-right and slide-left share everything but
   the side the drawer comes from, its border and its travel. */

@media (max-width: 768px) {
  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"][data-menu-open]
      .tt-mobile-backdrop
  ) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 99;
    background: rgba(0, 0, 0, 0.5);
    border: none;
    padding: 0;
    cursor: default;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"] .tt-mobile-drawer
  ) {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    position: fixed;
    top: 0;
    bottom: 0;
    width: 280px;
    max-width: 80vw;
    z-index: 100;
    background: var(--tt-color-bg);
    padding: 1.5rem;
    overflow-y: auto;
    visibility: hidden;
    transition:
      transform 300ms ease,
      visibility 300ms;
    animation: none;
    grid-column: auto;
    grid-row: auto;
    border-top: none;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style="slide-right"] .tt-mobile-drawer
  ) {
    right: 0;
    border-left: 1px solid var(--tt-color-border);
    transform: translateX(100%);
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style="slide-left"] .tt-mobile-drawer
  ) {
    left: 0;
    border-right: 1px solid var(--tt-color-border);
    transform: translateX(-100%);
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"][data-menu-open]
      .tt-mobile-drawer
  ) {
    transform: translateX(0);
    visibility: visible;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"][data-menu-open]
      .tt-mobile-close
  ) {
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: flex-end;
    width: 44px;
    height: 44px;
    background: none;
    border: none;
    padding: 0;
    font-size: 1.5rem;
    color: var(--tt-color-text);
    cursor: pointer;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"][data-menu-open] .tt-nav
  ) {
    flex-direction: column;
    gap: 0.25rem;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"][data-menu-open]
      .tt-search
  ) {
    width: 100%;
  }
}

@media (max-width: 768px) and (prefers-reduced-motion: reduce) {
  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"] .tt-mobile-drawer
  ) {
    transform: none;
    opacity: 0;
    transition:
      opacity 200ms ease,
      visibility 200ms;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-style^="slide-"][data-menu-open]
      .tt-mobile-drawer
  ) {
    opacity: 1;
  }
}

/* Left-positioned hamburger toggle */

@media (max-width: 768px) {
  :where(.tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"]) {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"] .tt-mobile-toggle
  ) {
    grid-column: 1;
    grid-row: 1;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"] .tt-site-title) {
    grid-column: 2;
    grid-row: 1;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"] .tt-dark-toggle) {
    grid-column: 3;
    grid-row: 1;
  }
}

/* Narrow mobile: drop dark toggle off the title row */

@media (max-width: 480px) {
  :where(.tt-header[data-mobile-nav="hamburger"]) {
    grid-template-columns: 1fr auto;
  }

  :where(.tt-header[data-mobile-nav="hamburger"] .tt-mobile-toggle) {
    grid-column: 2;
    grid-row: 1;
  }

  :where(.tt-header[data-mobile-nav="hamburger"] .tt-dark-toggle) {
    grid-column: 1;
    grid-row: 2;
    justify-self: start;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-menu-open] .tt-mobile-drawer) {
    grid-row: 3;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"]) {
    grid-template-columns: auto 1fr;
  }

  :where(
    .tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"] .tt-mobile-toggle
  ) {
    grid-column: 1;
    grid-row: 1;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"] .tt-site-title) {
    grid-column: 2;
    grid-row: 1;
  }

  :where(.tt-header[data-mobile-nav="hamburger"][data-mobile-nav-position="left"] .tt-dark-toggle) {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: start;
  }
}

:where(.tt-search-result mark) {
  background: var(--tt-color-highlight-bg);
  color: var(--tt-color-highlight-text);
}

/* Search form and results, listing typography, pagination and the 404 page.
   Everything here is :where() so a theme's own rule wins on specificity; link
   colour and 44px targets come from tokens.css. */

:where(.tt-search) {
  display: flex;
  align-items: stretch;
}

:where(.tt-search input) {
  font-size: var(--tt-text-body);
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--tt-color-border);
  background: var(--tt-color-surface);
  color: var(--tt-color-text);
  width: 100%;
  max-width: 10rem;
  min-width: 7.5rem;
}

:where(.tt-search-btn) {
  font: inherit;
  font-size: var(--tt-text-small);
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--tt-color-border);
  background: var(--tt-color-surface);
  color: var(--tt-color-text);
  cursor: pointer;
  min-width: 44px;
  white-space: nowrap;
}

:where(.tt-search-result) {
  margin: 0 0 1rem;
}

:where(.tt-search-result a) {
  font-weight: bold;
  text-decoration: none;
}

:where(.tt-search-result p) {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  margin: 0.25rem 0 0;
}

:where(.tt-site-notice) {
  font-size: var(--tt-text-small);
  font-family: var(--tt-font-body);
  color: var(--tt-color-muted);
  margin: 0;
}

:where(.tt-page-updated) {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  margin: 1.5rem 0 0;
}

:where(.tt-list-heading) {
  font-size: var(--tt-text-heading);
  font-weight: bold;
  margin: 0 0 1rem;
}

:where(.tt-page-indicator) {
  font-size: var(--tt-text-small);
  font-weight: normal;
  color: var(--tt-color-muted);
  margin-left: 0.5em;
}

:where(.tt-clear-filter) {
  font-size: var(--tt-text-small);
  margin: 0 0 1rem;
}

:where(.tt-post-count) {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  margin: 0 0 1.5rem;
}

:where(.tt-no-posts) {
  color: var(--tt-color-muted);
}

:where(.tt-post-item) {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  margin: 0 0 0.5rem;
}

:where(.tt-post-item .tt-post-date) {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  white-space: nowrap;
}

:where(.tt-post-separator) {
  color: var(--tt-color-muted);
  white-space: pre;
}

/* Equal-width digits, so a column of numeric dates puts every separator in
   the same place. A font without tabular figures ignores it. */
:where(.tt-post-date, .tt-archive-date) {
  font-variant-numeric: tabular-nums;
}

:where(.tt-archive-separator) {
  white-space: pre;
}

:where(.tt-post-title) {
  color: var(--tt-color-accent);
  font-weight: bold;
  text-decoration: none;
}

:where(.tt-pagination) {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 2rem 0 0;
  font-size: var(--tt-text-small);
}

:where(.tt-pagination a) {
  color: var(--tt-color-accent);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

:where(.tt-not-found) {
  padding: 2rem 0;
}

:where(.tt-not-found h1) {
  font-size: var(--tt-text-heading);
  font-weight: bold;
}

:where(.tt-not-found p) {
  margin-top: 1rem;
}

:where(.tt-not-found p + p) {
  margin-top: 0.5rem;
}

:where(.tt-outcome) {
  padding: 2rem 0;
}

:where(.tt-outcome h1) {
  font-size: var(--tt-text-heading);
  font-weight: bold;
}

:where(.tt-outcome p) {
  margin-top: 1rem;
}

:where(.tt-outcome p + p) {
  margin-top: 0.5rem;
}

:where(.tt-post-blob) {
  border: 1px solid var(--tt-color-border);
  background: var(--tt-color-surface);
  padding: 0.75rem 1rem;
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
}

:where(.tt-post-blob-before) {
  margin-bottom: 1.5rem;
}

:where(.tt-post-blob-after) {
  margin-top: 1.5rem;
  text-align: center;
}

:where(.tt-footer) {
  text-align: center;
  border-top: 1px solid var(--tt-color-border);
  padding: 1.5rem 0;
  font-size: var(--tt-text-small);
  font-family: var(--tt-font-body);
  color: var(--tt-color-muted);
}

/* Hidden, not removed: the empty footer keeps its box, so the page still ends
   with the theme's footer spacing, and paints no border, line or shadow. */
:where(.tt-footer:empty) {
  visibility: hidden;
}

/* Keyed on :not([hidden]): an author display rule outranks the UA's
   [hidden] rule, so a plain display here would show the button with
   scripting off and at the top of the page. */
:where(.tt-back-to-top:not([hidden])) {
  position: fixed;
  bottom: calc(1.5rem + env(safe-area-inset-bottom));
  right: 1.5rem;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--tt-color-border);
  background: var(--tt-color-surface);
  color: var(--tt-color-muted);
  font-size: var(--tt-text-body);
  font-family: var(--tt-font-body);
  cursor: pointer;
  z-index: 50;
}

/* Input and button on one row, wrapping under each other on a narrow
   column such as the sidebar. Borders are set outright: the browser's
   default is a bevel that belongs to no theme. */
:where(.tt-subscribe-form) {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

:where(button.tt-subscribe-btn) {
  background-color: var(--tt-color-accent) !important;
  color: var(--tt-color-bg) !important;
  border: 1px solid var(--tt-color-accent);
  padding: 0.5rem 1rem;
  font: inherit;
  cursor: pointer;
}

:where(input.tt-subscribe-input) {
  background-color: var(--tt-color-surface) !important;
  color: var(--tt-color-text) !important;
  text-transform: none !important;
  flex: 1 1 12rem;
  min-width: 0;
  max-width: 24rem;
  border: 1px solid var(--tt-color-border);
  padding: 0.5rem 0.75rem;
  font: inherit;
}

:where(.tt-subscribe-status) {
  margin-top: 0.5rem;
}

/* Present while empty, so the live region exists before its message lands
   and is announced; only its gap is removed. Both rules have zero
   specificity, so this one wins by coming second. */
:where(.tt-subscribe-status:empty) {
  margin-top: 0;
}

:where(.tt-privacy-notice:not(:empty)) {
  border-top: 1px solid var(--tt-color-border);
  padding: 1rem 0;
}

/* Post and page detail headings */

:where(.tt-post-heading, .tt-page-heading) {
  font-family: var(--tt-font-heading);
  font-size: var(--tt-text-heading);
  font-weight: bold;
  margin: 0.5rem 0 0.5rem;
}

:where(.tt-post-meta) {
  font-size: var(--tt-text-small);
  color: var(--tt-color-muted);
  margin: 0.25rem 0 1.5rem;
}

:where(.tt-post-author)::before,
:where(.tt-post-updated)::before {
  content: "\00B7" / "";
  margin: 0 0.5em;
}

:where(.tt-page-detail h1) {
  font-family: var(--tt-font-heading);
  font-size: var(--tt-text-heading);
  font-weight: bold;
  margin: 0 0 1.5rem;
}
