/* MJH blog stylesheet.
   Link it and write plain HTML — bare tags are already styled.
   Classes exist only for things HTML can't express (callouts, cards, badges).
   Catalog of everything in here: /styleguide.html
   ponytail: no build step, no minify. It's one file served as-is. */

/* ---------- tokens ---------- */
:root {
  --teal:  #00a388;
  --dark:  #333;
  --body:  #4d4d4d;
  --role:  #5d5d5d;
  --gray:  #838383;
  --rule:  #444;
  --card:  #f7f7f7;
  --border:#e2e2e2;
  --ink:   #1e2228;   /* dark surface for terminal + log blocks */

  /* themed surfaces — redefined wholesale in the dark-mode block below */
  --bg:      #fff;
  --navbg:   rgba(255,255,255,.92);
  --tip-bg:    #f2fbf9;
  --warn-bg:   #fdf8e8;
  --danger-bg: #fdf1f0;
  --add-bg: #e6f6f1; --add-fg: #14684f;
  --del-bg: #fdeceb; --del-fg: #a3312d;

  /* syntax tokens for light code blocks (dark blocks override on the element) */
  --hl-cmt:  #8a9199;
  --hl-key:  #00806b;
  --hl-str:  #a15c00;
  --hl-num:  #b3541e;
  --hl-fn:   #1a6fb5;
  --hl-attr: #2f6f9f;
  --hl-type: #7c4dbe;
  --hl-var:  #c0392b;
  --mono:  ui-monospace, Menlo, Consolas, monospace;
  --sans:  "Source Sans 3", "Source Sans Pro", "Lato", "Segoe UI", system-ui, sans-serif;
}

/* ---------- base ---------- */
* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--sans);
  color: var(--body);
  background: var(--bg);
  line-height: 1.65;
}

a       { color: var(--teal); text-decoration: none; }
a:hover { text-decoration: underline; }

/* 720px for reading, 820px on the index. Add class="wide" for the wider one. */
.wrap      { max-width: 720px; margin: 0 auto; padding: 0 1.4rem; }
.wrap.wide { max-width: 820px; }

/* ---------- nav ---------- */
nav {
  position: sticky; top: 0; z-index: 10;
  background: var(--navbg);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--border);
}
nav .wrap        { display: flex; align-items: center; justify-content: space-between; height: 56px; }
nav .brand       { font-weight: 700; font-size: 1.1rem; letter-spacing: .02em; }
nav .brand a     { color: var(--dark); }
nav .links a     { color: var(--role); font-weight: 600; margin-left: 1.4rem; }
nav .links a:hover { color: var(--teal); text-decoration: none; }

/* ---------- article shell ---------- */
article { padding: 2.5rem 0 3rem; }

/* ---------- headings & text (no class needed) ---------- */
h1 { margin: .3rem 0 1.4rem; font-size: 2.1rem;  color: var(--dark); line-height: 1.15; }
h2 { margin: 2.2rem 0 .6rem; font-size: 1.4rem;  color: var(--dark); }
h3 { margin: 1.6rem 0 .5rem; font-size: 1.15rem; color: var(--dark); }
h4 { margin: 1.3rem 0 .4rem; font-size: 1rem;    color: var(--role); text-transform: uppercase; letter-spacing: .04em; }

p  { margin: 0 0 1rem; }

strong { color: var(--dark); font-weight: 700; }
em     { font-style: italic; }
small  { font-size: .85rem; color: var(--gray); }

/* page title on listing pages: <h1 class="page"><span class="hl">/</span> Blog</h1> */
h1.page      { margin: 2.5rem 0 .3rem; font-size: 2.2rem; }
h1.page .hl  { color: var(--teal); }
.sub         { color: var(--gray); margin-bottom: 2rem; }

/* ---------- lists ---------- */
ul, ol   { padding-left: 1.2rem; margin: 0 0 1rem; }
li       { margin: .25rem 0; }
li > ul, li > ol { margin: .25rem 0; }

/* checklists: <ul class="check"> */
ul.check          { list-style: none; padding-left: .2rem; }
ul.check li       { position: relative; padding-left: 1.5rem; }
ul.check li::before {
  content: "\2713"; position: absolute; left: 0;
  color: var(--teal); font-weight: 700;
}

/* ---------- quotes ---------- */
blockquote {
  margin: 0 0 1rem; padding: .1rem 0 .1rem 1.1rem;
  border-left: 3px solid var(--teal);
  color: var(--role); font-style: italic;
}
blockquote p:last-child { margin-bottom: 0; }
blockquote cite { display: block; font-style: normal; font-size: .9rem; color: var(--gray); margin-top: .4rem; }

/* ---------- code ---------- */
code {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: .05rem .35rem;
  font-size: .85rem;
  color: var(--dark);
  font-family: var(--mono);
  white-space: nowrap;
}
pre {
  margin: 0 0 1rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: .9rem 1rem;
  overflow-x: auto;
  color: var(--dark);
}
/* inside a block, undo the inline pill. `color:inherit` matters —
   without it the dark .ink/.shell blocks would render #333 text on a dark bg. */
pre code {
  background: none; border: 0; padding: 0; color: inherit;
  white-space: pre; font-size: .85rem; line-height: 1.5;
}

/* --- labelled code block: filename bar above the code ---
   <div class="code"><p class="code-ttl">docker-compose.yml</p><pre><code>…</code></pre></div> */
.code { margin: 0 0 1.2rem; }
.code-ttl {
  margin: 0;
  font-family: var(--mono); font-size: .78rem;
  color: var(--role); background: var(--card);
  border: 1px solid var(--border); border-bottom: 0;
  border-radius: 6px 6px 0 0;
  padding: .4rem .8rem;
}
.code-ttl + pre { margin: 0; border-radius: 0 0 6px 6px; }
/* js/enhance.js wraps every <pre> in .copywrap to hang the copy button on it,
   which breaks the adjacency above and let the block round all four corners
   under a square-bottomed title bar. Keep the two joined in the wrapped case. */
.code-ttl + .copywrap { margin: 0; }
.code-ttl + .copywrap > pre { margin: 0; border-radius: 0 0 6px 6px; }
/* a dark block under a title bar keeps the bar dark too */
.code-ttl.ink { color: #b8c2cc; background: var(--ink); border-color: var(--ink); }

/* --- terminal / shell session ---
   <pre class="shell"><span class="cmd">kubectl get pods</span>
   output line</pre>
   The $ prompt is drawn by CSS — don't type it. */
pre.shell, pre.log {
  background: var(--ink);
  border-color: var(--ink);
  color: #cfd6dd;
}
pre.shell code, pre.log code { color: inherit; }

pre.shell .cmd { color: #fff; font-weight: 600; display: block; }
pre.shell .cmd::before { content: "$ "; color: var(--teal); font-weight: 700; }
pre.shell .cmd.root::before { content: "# "; color: #e0a800; }
pre.shell .out { color: #98a3ad; }      /* command output */
pre.shell .hl  { color: #ffb454; }      /* draw the eye to one value — amber, so it
                                           reads as "look here" and never blends with
                                           the teal $ prompt sitting next to it */
pre.shell .cm  { color: #6f7b86; }      /* # a comment */

/* --- log viewer ---
   <pre class="log"><span class="ts">10:04:12</span> <span class="lv-error">ERROR</span> connection refused</pre>
   Severities are namespaced lv-* so they never collide with the .warn callout. */
pre.log { white-space: pre-wrap; word-break: break-word; }
pre.log .ts       { color: #6f7b86; }
pre.log .lv-debug { color: #8a94a0; font-weight: 700; }
pre.log .lv-info  { color: #4aa3df; font-weight: 700; }
pre.log .lv-warn  { color: #e0a800; font-weight: 700; }
pre.log .lv-error { color: #ff6b66; font-weight: 700; }
pre.log .lv-fatal { color: #fff; background: #d9534f; font-weight: 700; padding: 0 .3rem; border-radius: 3px; }
pre.log .dim      { color: #7c8792; }

/* --- syntax highlighting (highlight.js) ---
   <pre><code class="language-yaml">…</code></pre>, then load js/highlight.min.js.
   Token colors are defined here against our own palette, so there is no
   second theme stylesheet to load and no CDN request.
   Opt a block out with class="nohighlight". */
/* dark code block: <pre class="ink"><code class="language-go"> */
pre.ink { background: var(--ink); border-color: var(--ink); color: #cfd6dd; }
pre.ink, pre.shell, pre.log {
  --hl-cmt:  #6f7b86;
  --hl-key:  #7ee2c8;
  --hl-str:  #d8b57a;
  --hl-num:  #e0a06a;
  --hl-fn:   #7cc4f0;
  --hl-attr: #9fd0ea;
  --hl-type: #c4a6f0;
  --hl-var:  #ff8b80;
}
pre code.hljs { display: block; padding: 0; background: none; }

.hljs-comment, .hljs-quote                        { color: var(--hl-cmt); font-style: italic; }
.hljs-keyword, .hljs-selector-tag, .hljs-literal,
.hljs-built_in, .hljs-doctag                      { color: var(--hl-key); font-weight: 600; }
.hljs-string, .hljs-regexp, .hljs-symbol, .hljs-bullet { color: var(--hl-str); }
.hljs-number                                      { color: var(--hl-num); }
.hljs-title, .hljs-title.class_, .hljs-title.function_,
.hljs-section, .hljs-name                         { color: var(--hl-fn); font-weight: 600; }
.hljs-attr, .hljs-attribute, .hljs-property,
.hljs-selector-attr, .hljs-selector-class         { color: var(--hl-attr); }
.hljs-type, .hljs-class, .hljs-meta, .hljs-tag    { color: var(--hl-type); }
.hljs-variable, .hljs-template-variable, .hljs-params { color: var(--hl-var); }
.hljs-emphasis { font-style: italic; }
.hljs-strong   { font-weight: 700; }
.hljs-link     { text-decoration: underline; }
.hljs-addition { background: var(--add-bg); color: var(--add-fg); }
.hljs-deletion { background: var(--del-bg); color: var(--del-fg); }

/* --- diff ---
   Paste raw diff output into <pre><code class="language-diff"> and highlight.js
   colors the +/- lines itself. The .hljs-addition/.hljs-deletion rules above do the work.
   ponytail: hand-rolled <ins>/<del> lines were dropped — inside <pre> the source
   newlines around a display:block element render as stray blank lines. */

kbd {
  font-family: var(--mono); font-size: .8rem;
  background: #fff; color: var(--dark);
  border: 1px solid var(--border); border-bottom-width: 2px;
  border-radius: 4px; padding: .1rem .4rem;
  white-space: nowrap;
}

/* ---------- tables ---------- */
table { width: 100%; border-collapse: collapse; margin: 0 0 1rem; font-size: .95rem; }
th {
  text-align: left; padding: .45rem .6rem;
  color: var(--dark); font-weight: 700;
  border-bottom: 2px solid var(--border);
}
td { padding: .4rem .6rem; border-top: 1px solid var(--border); vertical-align: top; }
tbody tr:last-child td { border-bottom: 1px solid var(--border); }

/* key/value cheatsheet table: <table class="cheat"> — no header row */
table.cheat td              { padding: .35rem .6rem; }
table.cheat td:first-child  { white-space: nowrap; width: 1%; }
table.cheat tr:last-child td { border-bottom: 1px solid var(--border); }

/* ---------- media ---------- */
img { max-width: 100%; height: auto; border-radius: 8px; border: 1px solid var(--border); display: block; }

/* full-width header image under the title */
img.hero { margin: 0 0 1.6rem; }

/* borderless — for logos, diagrams, transparent PNGs */
img.plain { border: 0; border-radius: 0; }

figure          { margin: 0 0 1.4rem; }
figure img      { margin-bottom: .5rem; }
figcaption      { font-size: .88rem; color: var(--gray); text-align: center; }

hr { border: 0; border-top: 1px solid var(--border); margin: 2rem 0; }

/* --- image gallery ---
   <div class="gallery">
     <figure><a href="big.jpg"><img src="thumb.jpg" alt="…"></a><figcaption>…</figcaption></figure>
   </div>
   The <a> is the point: with JS off it still opens the full image.
   js/lightbox.js upgrades it to an overlay. Add class="wide"/"tight" for 2/4 columns. */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .8rem;
  margin: 0 0 1.4rem;
}
.gallery.wide  { grid-template-columns: repeat(2, 1fr); }
.gallery.tight { grid-template-columns: repeat(4, 1fr); }

.gallery figure { margin: 0; }
.gallery a { display: block; overflow: hidden; border-radius: 8px; }
.gallery img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: 8px; display: block;
  transition: transform .18s ease;
}
.gallery a:hover img { transform: scale(1.04); }
.gallery a:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }
.gallery figcaption { font-size: .82rem; color: var(--gray); margin-top: .35rem; text-align: left; }

/* single zoomable image outside a gallery: <a class="zoom" href="big.jpg"><img …></a> */
a.zoom { display: block; cursor: zoom-in; }

/* --- lightbox (native <dialog>, so Esc and focus handling are free) --- */
dialog.lightbox {
  border: 0; padding: 0; background: none;
  max-width: 94vw; max-height: 94vh;
  overflow: visible;
  color: #fff;
}
dialog.lightbox::backdrop { background: rgba(18,20,24,.92); }
dialog.lightbox img {
  display: block; border: 0; border-radius: 8px;
  max-width: 94vw; max-height: 84vh;
  width: auto; height: auto;
  margin: 0 auto;
}
dialog.lightbox .cap {
  margin: .6rem auto 0; text-align: center;
  font-size: .88rem; color: #cfd6dd; max-width: 60ch;
}
dialog.lightbox button {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: rgba(0,0,0,.5); color: #fff;
  border: 1px solid rgba(255,255,255,.25); border-radius: 6px;
  font: 600 1.1rem/1 var(--sans);
  padding: .6rem .8rem; cursor: pointer;
}
dialog.lightbox button:hover { background: var(--teal); border-color: var(--teal); }
/* arrows sit inside the image — outside the dialog they clip at the viewport edge */
dialog.lightbox .prev  { left: .6rem; }
dialog.lightbox .next  { right: .6rem; }
dialog.lightbox .close {
  top: .6rem; right: .6rem; transform: none;
  font-size: .85rem; padding: .4rem .7rem;
}

/* --- audio ---
   <figure class="audio"><figcaption>Title</figcaption>
     <audio controls preload="none" src="…"></audio></figure>
   Native controls on purpose: keyboard and screen-reader support for free. */
figure.audio {
  margin: 0 0 1.4rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: .8rem 1rem;
}
figure.audio figcaption {
  text-align: left; font-weight: 700; color: var(--dark);
  font-size: .9rem; margin: 0 0 .5rem;
}
figure.audio audio { width: 100%; display: block; }

/* --- video ---
   <figure class="video"><video controls preload="none" poster="…" src="…"></video>
     <figcaption>…</figcaption></figure>
   preload="none" keeps the page light until someone presses play. */
figure.video { margin: 0 0 1.4rem; }
figure.video video {
  width: 100%; aspect-ratio: 16 / 9;
  background: #000; object-fit: contain;
  border: 1px solid var(--border); border-radius: 8px;
  display: block;
}
figure.video figcaption { margin-top: .5rem; }

/* --- diagrams (draw.io / diagrams.net, or any SVG) ---
   Export from draw.io as SVG with "Include a copy of my diagram" ticked: the file
   stays re-openable in draw.io, but here it is just an image. No library.

   <figure class="diagram">
     <a class="zoom" href="../images/thing.svg"><img src="../images/thing.svg" alt="…"></a>
     <figcaption>…</figcaption>
   </figure>

   The light surface is deliberate and not a theme bug: draw.io draws dark strokes
   and dark text on a transparent background, which would vanish on the dark theme. */
figure.diagram { margin: 0 0 1.6rem; }
figure.diagram a, figure.diagram img { display: block; }
figure.diagram img {
  width: 100%; height: auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: .9rem;
}
figure.diagram figcaption { margin-top: .5rem; }

/* --- interactive draw.io viewer ---
   <div class="drawio mxgraph" data-mxgraph='{…,"xml":"<mxfile>…"}'></div>
   plus viewer-static.min.js. Pan by dragging, zoom with the hover toolbar or
   the wheel, fullscreen via the lightbox button. Read-only: there is no editor
   in this build, and "edit":null keeps the pencil away.
   Light surface for the same reason as .diagram — draw.io draws dark on clear. */
.drawio {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin: 0 0 1.6rem;
  min-height: 8rem;
  overflow: hidden;
}
.drawio svg { max-width: 100%; height: auto; }
figure.drawio-fig { margin: 0 0 1.6rem; }
figure.drawio-fig .drawio { margin-bottom: .5rem; }

/* --- responsive iframe embed (YouTube, asciinema, anything) ---
   <div class="embed"><iframe …></iframe></div> */
.embed {
  aspect-ratio: 16 / 9;
  margin: 0 0 1.4rem;
  border: 1px solid var(--border); border-radius: 8px;
  overflow: hidden; background: #000;
}
.embed iframe, .embed > * { width: 100%; height: 100%; border: 0; display: block; }

/* ---------- post meta ---------- */
.date  { font-family: var(--mono); font-size: .85rem; color: var(--gray); }
.tags  { display: flex; flex-wrap: wrap; gap: .4rem; margin: .6rem 0 0; padding: 0; list-style: none; }
.tag   {
  font-size: .78rem; color: var(--role);
  background: var(--card); border: 1px solid var(--border);
  border-radius: 999px; padding: .1rem .6rem;
}
a.tag:hover { color: var(--teal); text-decoration: none; border-color: var(--teal); }

.lead { font-size: 1.15rem; color: var(--role); margin-bottom: 1.4rem; }

/* ---------- callouts ---------- */
.note, .tip, .warn, .danger {
  margin: 0 0 1.2rem;
  padding: .8rem 1rem;
  border-left: 4px solid var(--gray);
  border-radius: 0 6px 6px 0;
  background: var(--card);
}
.note   { border-left-color: var(--gray); }
.tip    { border-left-color: var(--teal);    background: var(--tip-bg); }
.warn   { border-left-color: #e0a800;        background: var(--warn-bg); }
.danger { border-left-color: #d9534f;        background: var(--danger-bg); }

.note > :last-child, .tip > :last-child,
.warn > :last-child, .danger > :last-child { margin-bottom: 0; }

/* optional heading inside a callout: <p class="ttl">Heads up</p> */
.note .ttl, .tip .ttl, .warn .ttl, .danger .ttl {
  font-weight: 700; color: var(--dark); margin: 0 0 .3rem;
  text-transform: uppercase; font-size: .78rem; letter-spacing: .05em;
}

/* ---------- cards ---------- */
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; margin: 0 0 1.4rem; }

.card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem 1.1rem;
}
.card h3 { margin: 0 0 .4rem; font-size: 1.05rem; }
.card > :last-child { margin-bottom: 0; }
a.card:hover { border-color: var(--teal); text-decoration: none; }

/* ---------- table of contents ---------- */
.toc {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: .9rem 1.1rem;
  margin: 0 0 1.6rem;
}
.toc .ttl {
  font-weight: 700; color: var(--dark); margin: 0 0 .4rem;
  text-transform: uppercase; font-size: .78rem; letter-spacing: .05em;
}
.toc ul { margin: 0; padding-left: 1.1rem; }
.toc li { margin: .15rem 0; }

/* ---------- badge ---------- */
.badge {
  display: inline-block;
  font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: #fff; background: var(--teal);
  border-radius: 4px; padding: .12rem .45rem;
  vertical-align: middle;
}
.badge.gray { background: var(--gray); }

/* ---------- footnotes ---------- */
.footnotes {
  margin-top: 2.5rem; padding-top: 1rem;
  border-top: 1px solid var(--border);
  font-size: .9rem; color: var(--role);
}
.footnotes ol { padding-left: 1.2rem; }

/* ---------- back link ---------- */
.back { display: inline-block; margin-top: 2rem; font-weight: 600; }

/* ---------- utilities. three of them, on purpose. ---------- */
.center { text-align: center; }
.mono   { font-family: var(--mono); }
.muted  { color: var(--gray); }

/* ---------- post index (blog.html) ---------- */
ul.posts            { list-style: none; padding: 0; margin: 0; }
ul.posts li         { padding: 1rem 0; margin: 0; border-top: 1px solid var(--border); }
ul.posts li:last-child { border-bottom: 1px solid var(--border); }
ul.posts li a       { display: flex; gap: 1rem; align-items: flex-start; }
ul.posts .thumb     { width: 96px; height: 96px; object-fit: cover; border-radius: 6px; flex-shrink: 0; border: 0; }
ul.posts .date      { display: block; }
ul.posts .title     { font-size: 1.2rem; font-weight: 700; color: var(--dark); }
ul.posts a:hover .title { color: var(--teal); }
ul.posts .excerpt   { margin: .2rem 0 0; color: var(--body); }

footer { color: var(--gray); font-size: .9rem; padding: 2rem 0 3rem; }

/* ---------- responsive ---------- */
@media (max-width: 620px) {
  .grid { grid-template-columns: 1fr; }
  h1    { font-size: 1.8rem; }
  h1.page { font-size: 1.9rem; }
}
@media (max-width: 480px) {
  ul.posts .thumb { width: 64px; height: 64px; }
}

/* =========================================================================
   Enhancements driven by js/enhance.js (all opt-in, all degrade to nothing)
   ========================================================================= */

/* --- heading anchors: a ¶ that appears on hover --- */
.anchor {
  margin-left: .4rem; color: var(--gray); font-weight: 400;
  text-decoration: none; opacity: 0; transition: opacity .12s;
}
h2:hover .anchor, h3:hover .anchor, .anchor:focus { opacity: 1; }

/* --- copy button on code blocks --- */
.copywrap { position: relative; }
.copywrap .copybtn {
  position: absolute; top: .45rem; right: .45rem;
  font: 600 .7rem/1 var(--sans); letter-spacing: .04em; text-transform: uppercase;
  color: var(--role); background: var(--bg);
  border: 1px solid var(--border); border-radius: 4px;
  padding: .3rem .5rem; cursor: pointer; opacity: 0; transition: opacity .12s;
}
.copywrap:hover .copybtn, .copybtn:focus { opacity: 1; }
.copybtn:hover { color: var(--teal); border-color: var(--teal); }
.copybtn.done  { color: #fff; background: var(--teal); border-color: var(--teal); opacity: 1; }
/* dark blocks need a button that reads on dark */
.copywrap:has(pre.ink) .copybtn,
.copywrap:has(pre.shell) .copybtn,
.copywrap:has(pre.log) .copybtn { color: #cfd6dd; background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.2); }

/* --- live filter over a table: <table class="cheat filterable"> --- */
.tablefilter {
  width: 100%; margin: 0 0 .6rem;
  font: inherit; font-size: .9rem;
  color: var(--body); background: var(--bg);
  border: 1px solid var(--border); border-radius: 6px;
  padding: .45rem .7rem;
}
.tablefilter:focus { outline: 2px solid var(--teal); outline-offset: 1px; border-color: var(--teal); }
.filtercount { font-size: .8rem; color: var(--gray); margin: -.3rem 0 .6rem; }

/* --- sticky table of contents on wide screens --- */
@media (min-width: 1180px) {
  .toc.stick { position: sticky; top: 72px; }
}

/* --- series / prev-next navigation --- */
.series {
  display: flex; justify-content: space-between; gap: 1rem;
  margin-top: 2.5rem; padding-top: 1rem;
  border-top: 1px solid var(--border);
  font-weight: 600; font-size: .95rem;
}
.series a { display: block; max-width: 48%; }
.series .lbl { display: block; font-size: .75rem; font-weight: 700; color: var(--gray); text-transform: uppercase; letter-spacing: .05em; }
.series .next { text-align: right; margin-left: auto; }

/* =========================================================================
   Figures for mathematical / interactive posts
   ========================================================================= */

/* --- numbered equation: <div class="eqn"><div class="body">$$…$$</div><span class="num">(1)</span></div> --- */
.eqn { display: flex; align-items: center; gap: 1rem; margin: 0 0 1.2rem; }
.eqn .body { flex: 1; overflow-x: auto; text-align: center; }
.eqn .num  { color: var(--gray); font-variant-numeric: tabular-nums; }

/* --- interactive sketch: canvas + controls + caption ---
   <figure class="sketch">
     <canvas></canvas>
     <div class="controls">
       <label>K<sub>p</sub> <input type="range" min="0" max="5" step=".1"><output>1.0</output></label>
       <button type="button">Reset</button>
     </div>
     <figcaption>…</figcaption>
   </figure> */
figure.sketch {
  margin: 0 0 1.6rem;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--card); overflow: hidden;
}
figure.sketch > canvas, figure.sketch > .stage {
  display: block; width: 100%; aspect-ratio: 16 / 9;
  background: var(--bg); border: 0; border-radius: 0;
}
figure.sketch .controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: .55rem 1.2rem;
  padding: .7rem .9rem; border-top: 1px solid var(--border);
  font-size: .85rem;
}
figure.sketch label { display: flex; align-items: center; gap: .45rem; color: var(--role); }
figure.sketch output { font-family: var(--mono); color: var(--dark); min-width: 3.5ch; }
figure.sketch figcaption {
  padding: .6rem .9rem; border-top: 1px solid var(--border);
  text-align: left; font-size: .85rem;
}
input[type="range"] { accent-color: var(--teal); max-width: 9rem; }

/* small button used inside sketches and elsewhere */
.btn {
  font: 600 .78rem/1 var(--sans);
  color: var(--role); background: var(--bg);
  border: 1px solid var(--border); border-radius: 5px;
  padding: .35rem .65rem; cursor: pointer;
}
.btn:hover { color: var(--teal); border-color: var(--teal); }

/* --- full-bleed figure: escapes the reading column --- */
.bleed {
  width: min(1100px, 94vw);
  margin-left: 50%; transform: translateX(-50%);
}

/* --- "show the code that made this" --- */
details.src {
  margin: -.6rem 0 1.4rem;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--card); overflow: hidden;
}
details.src summary {
  cursor: pointer; padding: .5rem .9rem;
  font-size: .82rem; font-weight: 600; color: var(--role);
}
details.src summary:hover { color: var(--teal); }
details.src[open] summary { border-bottom: 1px solid var(--border); }
details.src pre { margin: 0; border: 0; border-radius: 0; }

/* --- lazily-loaded library containers ---
   The libraries themselves are NOT vendored. Import them per post; these
   just reserve a correctly-sized, correctly-themed box so nothing jumps. */
.scene {                      /* three.js / WebGL */
  aspect-ratio: 16 / 9; width: 100%;
  background: var(--ink); border: 1px solid var(--border); border-radius: 8px;
  overflow: hidden; display: block;
}
.scene > canvas { display: block; width: 100%; height: 100%; border: 0; border-radius: 0; }
.mermaid, .wavedrom {          /* diagram targets */
  margin: 0 0 1.4rem; padding: .8rem;
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  overflow-x: auto; text-align: center;
}
.mermaid[data-src], .wavedrom[data-src] { min-height: 4rem; }

/* =========================================================================
   Hardware / electronics
   ========================================================================= */

/* --- annotated photo: numbered pins over an image + matching legend ---
   <figure class="annotated">
     <img src="board.jpg" alt="">
     <span class="pin" style="left:32%; top:44%">1</span>
     <figcaption>…</figcaption>
   </figure>
   <ol class="legend"><li>Regulator</li>…</ol> */
figure.annotated { position: relative; margin: 0 0 .6rem; }
figure.annotated img { width: 100%; }
figure.annotated .pin {
  position: absolute; transform: translate(-50%, -50%);
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--teal); color: #fff;
  font: 700 .78rem/1.6rem var(--sans); text-align: center;
  box-shadow: 0 0 0 2px rgba(255,255,255,.85);
}
figure.annotated figcaption { position: static; margin-top: .5rem; }

ol.legend { counter-reset: pin; list-style: none; padding-left: 0; margin: 0 0 1.4rem; }
ol.legend li { counter-increment: pin; position: relative; padding-left: 2.1rem; margin: .3rem 0; }
ol.legend li::before {
  content: counter(pin); position: absolute; left: 0; top: .05rem;
  width: 1.5rem; height: 1.5rem; border-radius: 50%;
  background: var(--teal); color: #fff;
  font: 700 .75rem/1.5rem var(--sans); text-align: center;
}

/* --- bill of materials + spec sheet tables --- */
table.bom td:first-child  { font-family: var(--mono); white-space: nowrap; }
table.bom td:nth-child(2) { font-variant-numeric: tabular-nums; }

table.specs th {
  width: 34%; text-align: left; vertical-align: top;
  font-weight: 600; color: var(--role);
  border-bottom: 1px solid var(--border);
}
table.specs td { font-variant-numeric: tabular-nums; }

/* =========================================================================
   Dark mode
   Auto by system preference; the [data-theme] attribute wins either way so a
   toggle can override. Only tokens change — no component rule is duplicated.
   ========================================================================= */
/* Light is the default on purpose: dark is opt-in via the nav toggle, which
   sets data-theme="dark" and remembers it. (Deliberately NOT following
   prefers-color-scheme, so a visitor on a dark OS still lands on light.) */
:root[data-theme="dark"] {
  --bg:     #14171a;
  --navbg:  rgba(20,23,26,.92);
  --card:   #1c2024;
  --border: #2b3238;
  --dark:   #e8ecef;
  --body:   #c3cad1;
  --role:   #a8b1b9;
  --gray:   #8a949d;
  --rule:   #3a4249;
  --teal:   #2ec4a6;
  --tip-bg:    #14302b;
  --warn-bg:   #332b12;
  --danger-bg: #331d1c;
  --add-bg: #13322a; --add-fg: #7ee2c8;
  --del-bg: #3a1f1e; --del-fg: #ff9d99;
  --hl-cmt:  #6f7b86;
  --hl-key:  #7ee2c8;
  --hl-str:  #d8b57a;
  --hl-num:  #e0a06a;
  --hl-fn:   #7cc4f0;
  --hl-attr: #9fd0ea;
  --hl-type: #c4a6f0;
  --hl-var:  #ff8b80;
}

/* theme toggle button in the nav */
.themetoggle {
  background: none; border: 0; cursor: pointer;
  color: var(--role); font-size: 1rem; padding: .2rem .3rem; margin-left: 1.4rem;
  line-height: 1;
}
.themetoggle:hover { color: var(--teal); }

/* =========================================================================
   Print — cheatsheets should print cleanly
   ========================================================================= */
@media print {
  nav, .copybtn, .tablefilter, .filtercount, .series, .back,
  .themetoggle, dialog.lightbox { display: none !important; }
  body { background: #fff; color: #000; line-height: 1.4; }
  .wrap, .wrap.wide { max-width: none; padding: 0; }
  article { padding: 0; }
  a { color: #000; text-decoration: underline; }
  h1, h2, h3, h4 { color: #000; break-after: avoid; }
  pre, table, figure, .note, .tip, .warn, .danger { break-inside: avoid; }
  pre, pre.ink, pre.shell, pre.log {
    background: #fff !important; color: #000 !important;
    border: 1px solid #999 !important;
  }
  pre.shell .cmd, pre.log .lv-error, pre.log .lv-warn { color: #000 !important; }
  .gallery { grid-template-columns: repeat(4, 1fr); }
}
