/* Shared manual-page stylesheet — one file, reused by every converted manual,
   so a future palette/type change is a single edit here instead of per-page
   surgery. Linked by render_page.py's template.

   Colors and box/divider treatments are deliberately the same ones used on
   lunaticoastro.com/caterpillar.html (navy/gold/mist), per explicit request —
   that page is a visual-style reference only, never a content or rendering
   source (see tools/manuals/DESIGN_NOTES.md). The dark topbar color matches
   the CloudWatcher product-dossier mockup's own header-bg, which happens to
   already be near-identical to Caterpillar's own header tone, so both
   references agree here rather than pulling in different directions.

   Typography: Karla (body) + Exo 2 (all headings, including in-document
   h1-h3), per explicit request. Small label/mono text (breadcrumb, TOC
   label, device tags) uses a system monospace stack, matching how
   Caterpillar's own reference treats that role, rather than adding a third
   Google Font nobody asked for.
*/

:root {
  --manual-navy:   #1B3A6B; /* manual hero background -- matches the CloudWatcher dossier's own hero (--display-color) */
  --manual-gold:   #C8A84B;
  --manual-gold-d: #A88A35;
  --manual-void:   #0A1628; /* site-wide header/footer stand-in only -- matches the CloudWatcher dossier's own header-bg */
  --manual-mist:   #F0F2F5;
  --border: rgba(27,58,107,0.12);
  --ink-body: #3A4A5E;
  --ink-muted: #8896B0;
  --manual-link: #1F5AA8;

  --f-heading: 'Exo 2', -apple-system, sans-serif;
  --f-body: 'Karla', -apple-system, 'Segoe UI', sans-serif;
  --f-mono: 'Courier New', Courier, monospace; /* site-wide: breadcrumb, TOC label, device tags, pdf-link */
  --f-mono-code: var(--f-mono); /* code blocks -- same for now, kept separate so it can change on its own once the site's mono pairing is settled */

  --sidebar-w: 280px;
  --manual-r: 6px;
  --site-chrome-h: 64px; /* Web2026's real `.hinner{height:64px}` header -- was a 2.5rem placeholder guess before the real chrome was wired in */
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: #fff;
  color: var(--ink-body);
  font-family: var(--f-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
/* A footnote marker is just one digit -- the browser default UA rule
   (vertical-align: super; font-size: smaller, roughly 0.83x) is too subtle
   a size difference on a single character to read as a real superscript,
   confirmed by the user directly on a real sample. Set explicitly rather
   than relying on that default: a stronger, deliberate size cut, and
   line-height: 0 so the raised glyph doesn't add its own extra height to
   the line it sits in. */
sup, sub { font-size: 0.7em; line-height: 0; }
sup { vertical-align: super; }
sub { vertical-align: sub; }
/* A footnote reference marker specifically needs to be spotted while
   skimming a sentence, not just technically present -- confirmed a plain-
   weight link-blue "1" at this size reads as easy to miss entirely.
   Bumped up in weight only (not size again -- a genuinely small, raised
   digit is still the point, it just needs to stand out more). */
sup a { font-weight: 700; }
img { max-width: 100%; height: auto; vertical-align: middle; }
/* An image that's the ONLY thing in its paragraph is a standalone figure --
   centered on its own line, as before.

   An image sharing a paragraph with real text is a genuinely different
   case, confirmed on a real sample against both the HTML and the original
   PDF: the PDF shows several lines of that paragraph wrapping beside the
   image, which sits at the left margin -- real print "wrap text" layout.
   Google's own HTML export carries NO trace of that at all (checked the raw
   markup directly): the image is just dropped inline in the character
   stream with no position/wrap metadata whatsoever, indistinguishable from
   any other inline image once exported. A plain inline image in a browser
   only ever lets ONE line sit beside it, never several -- that gap (not a
   table-layout issue) is the actual bug behind "images next to text don't
   work". Since the wrap side/mode can't be recovered from the export, the
   one signal that's still real and available -- sharing a paragraph with
   text at all -- drives this; render_page.py adds `.img-float-right` for
   exactly that case, but only when the image is narrow enough to leave the
   wrapped text a readable width (a 602px-wide image with one short trailing
   sentence, confirmed on a real sample, would otherwise squeeze that
   sentence into a sliver of leftover space -- left in normal flow instead).
   Side defaults to right (the site's default preference) for a source like
   Google's where which side the original was actually wrapped to is one of
   the things lost above. Zoho Writer's export is the exception -- it keeps
   real position data, so clean_zoho_html.py sets img-float-left/-right
   itself based on the image's real original side instead of the default.
   A solo image is unaffected and stays the centered block figure it
   already was. */
/* A fixed, consistent margin regardless of whatever the source document's
   own images happened to have -- confirmed necessary on a real sample: the
   author sometimes has to zero out a Zoho image's own margin just to get it
   positioned where they want (a Zoho editor quirk, not a real design
   choice), and since neither cleaner reads/preserves that source margin
   value anyway, a solo image relying on nothing but its wrapping <p>'s own
   1rem bottom margin looked cramped next to surrounding text. Own vertical
   margin here regardless of source. */
.doc-content p > img:only-child,
.doc-content figure img {
  display: block;
  margin: 1.25rem auto;
}
.img-float-right {
  float: right;
  margin: 0.3rem 0 1rem 1.5rem;
}
.img-float-left {
  float: left;
  margin: 0.3rem 1.5rem 1rem 0;
}
.chapter-heading, .section-heading, h3 {
  clear: both;
}

/* Plain "#" href scrolls to the document's own top by default browser
   behavior -- no JS, no id target needed. Always visible rather than
   fade-in-on-scroll: that would need a scroll listener, and this is a
   long-established, perfectly normal pattern on its own (most manuals here
   run long enough that it's never in the way at the very top anyway). */
.back-to-top {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--manual-navy);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(10,22,40,0.35);
  z-index: 25;
  transition: background 0.15s ease, transform 0.15s ease;
}
.back-to-top:hover { background: var(--manual-gold-d); transform: translateY(-2px); }
@media (max-width: 640px) {
  .back-to-top { right: 1rem; bottom: 1rem; width: 40px; height: 40px; }
}

/* ── MANUAL FOOTER (name + revision) ─────────────────────────────────────
   Most manuals end with a hand-typed footer mimicking what a printed page
   would repeat -- name, revision, page number (meaningless in HTML) --
   confirmed on a real sample. Extracted out of the body and shown here
   instead: sticky to the bottom of the viewport while there's still content
   below it, so it stays visible while reading, and it's the LAST thing
   inside `.doc-content`, so once the page is actually scrolled to its real
   end, it stops "sticking" and settles in just above the site footer below
   it rather than floating over it. Spans only the content column's own
   width, not the sidebar, since it's part of `.doc-content`, not the page. */
.manual-footer-sticky {
  position: sticky;
  bottom: 0;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2.5rem;
  padding: 0.6rem 0;
  background: #fff;
  border-top: 2px solid var(--manual-gold);
  font-family: var(--f-mono);
  font-size: 0.76rem;
  color: var(--ink-muted);
}

/* A relocated footnote (see relocate_footnotes) reads as a distinct "note"
   at the end of its section, not another body paragraph -- the top border
   and spacing alone carry that, not a reduced font-size: shrinking the
   whole line, per the user directly, made the note read as roughly the
   same size as the tiny raised reference marker itself, when the actual
   contrast that matters is "raised marker" vs "normal-size note", not
   "small marker" vs "even smaller note". */
p.footnote-def {
  margin-top: 1.25rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  color: var(--ink-muted);
  text-align: left;
}

/* A footnote jump (either direction) lands only a short distance away --
   often still inside the same viewport -- so without this, clicking looks
   like nothing happened at all, confirmed directly by the user ("leads to
   itself"). :target needs no JS: the browser already flags whichever
   element's id matches the current URL fragment, so a brief highlight on
   arrival makes the jump -- and exactly where it landed -- unmistakable.

   scroll-margin-top here too: .site-header-stub is `position: sticky; top:
   0`, so once scrolled it permanently covers the first --site-chrome-h of
   the viewport -- confirmed directly by the user that a footnote jump was
   landing partly or fully underneath it. Applying this to :target directly
   (rather than only to specific heading classes, which is ALSO fixed
   below, and had the same bug -- its own scroll-margin-top was smaller than
   the header's real height) covers every anchor target uniformly, footnote
   or heading, without having to enumerate each one.

   Deliberately kept as its OWN rule, not combined into one comma list with
   the :has() rules below: unlike :is()/:where(), a plain :has() is NOT a
   "forgiving" selector -- confirmed via spec research, not assumption -- so
   on a browser without :has() support (Firefox before v121, released Dec
   2023; anything pre-2022 generally), a combined selector list would drop
   the ENTIRE rule, losing this base scroll-position/highlight fix too, not
   just the bonus below. Kept separate so the base behavior degrades to
   nothing worse than "no :has() support" instead of "no fix at all". */
:target {
  scroll-margin-top: calc(var(--site-chrome-h) + 1.5rem);
  animation: target-flash 2s ease-out;
}
@keyframes target-flash {
  from { background: rgba(216, 182, 93, 0.55); }
  to { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  :target { animation: none; background: rgba(216, 182, 93, 0.55); }
}

/* Purely additive on top of the :target rule above: on a browser that
   doesn't support :has() (see note above), this rule alone is silently
   skipped by the parser -- the plain :target highlight above still applies
   to the reference/definition marker itself, just without also washing the
   whole enclosing line/paragraph. Graceful degradation, not a broken page. */
p.footnote-def:has(:target),
li:has(> sup :target) {
  animation: target-flash 2s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  p.footnote-def:has(:target),
  li:has(> sup :target) {
    animation: none;
    background: rgba(216, 182, 93, 0.55);
  }
}

/* ── MANUAL HERO: title + device tags (+ cover photo, if the source has one)
   Styled like the CloudWatcher product-dossier mockup's own hero band
   (same background color, same Exo 2 display heading, same rotated small
   tag treatment) per explicit request -- this is the manual's own heading,
   distinct from the site-wide header/footer above (which stays the darker
   --manual-void navy). ── */
/* position/border-bottom reset: Web2026's own style.css has a bare
   `header{position:sticky;top:0;z-index:100;border-bottom:...}` rule for
   ITS real site header -- since our own hero is also a `<header>` tag, that
   rule applies here too unless overridden (confirmed directly: without
   this, our hero would try to stick to the viewport top exactly like the
   real nav bar, fighting it for the same spot once scrolled). We want a
   normal in-flow banner, not a second sticky bar. */
.manual-hero { position: static; border-bottom: none; background: var(--manual-navy); padding: 2.25rem 1.5rem; }
.manual-hero.no-photo { padding: 1.75rem 1.5rem; }
.manual-hero-inner {
  max-width: 980px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 2rem;
  flex-wrap: wrap;
}
.no-photo .manual-hero-inner { justify-content: center; text-align: center; }
.manual-hero-text { flex: 1 1 320px; }
.manual-title {
  font-family: var(--f-heading);
  font-weight: 700;
  font-size: clamp(1.5rem, 3.4vw, 2.2rem);
  color: #fff;
  margin: 0 0 0.7rem;
  line-height: 1.1;
}
.device-tags { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.no-photo .device-tags { justify-content: center; }
.device-tag {
  display: inline-flex;
  align-items: center;
  font-family: var(--f-mono);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #12233f;
  background: var(--manual-gold);
  border-radius: 3px;
  padding: 0.3rem 0.7rem;
  transform: rotate(-2deg);
  box-shadow: 0 4px 10px -4px rgba(0,0,0,0.4);
}
.hero-photo-wrap { flex: 0 0 auto; }
.hero-photo-wrap img {
  max-width: 190px;
  max-height: 190px;
  width: auto;
  border-radius: var(--manual-r);
  background: #fff;
  box-shadow: 0 16px 34px -14px rgba(0,0,0,0.5);
}

/* ── SECONDARY BAR: breadcrumb + download link, one compact row ─────────── */
.doc-subbar {
  background: var(--manual-mist);
  border-bottom: 1px solid var(--border);
  padding: 0.55rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.doc-breadcrumb {
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  color: var(--ink-muted);
}
.doc-breadcrumb a { color: var(--manual-link); }
.doc-breadcrumb span { margin: 0 0.35rem; color: #b7c0cc; }
.doc-breadcrumb strong { color: var(--manual-navy); }
.pdf-link {
  display: inline-block;
  font-family: var(--f-mono);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--manual-gold-d);
  border: 1px solid var(--manual-gold);
  border-radius: 4px;
  padding: 0.3rem 0.8rem;
  white-space: nowrap;
}
.pdf-link:hover { background: var(--manual-gold); color: #fff; }

/* ── LAYOUT: sidebar TOC + content ─────────────────────────────────────────
   `.doc-sidebar` (the grey column itself) stretches to the full height of
   the grid row -- so the grey fill runs the whole page even when the TOC is
   much shorter than the content next to it -- while `.doc-sidebar-inner` is
   the part that's actually sticky and independently scrollable, pinned
   below the site-header stand-in. On a document short enough that the TOC
   fits without scrolling (like this one), the inner scroll never kicks in;
   it's there for whenever a longer manual's TOC needs it. */
.manual-doc-layout {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  align-items: stretch;
  /* Caps the SIDEBAR+CONTENT PAIR together, not just the content column alone --
     centering only `.doc-content` inside its own leftover grid space (1fr, which
     can be huge on a wide screen) left the text floating far from the sidebar
     with empty space in between, while still technically having "balanced"
     margins around itself. Capping the whole pair keeps the sidebar directly
     against the text and pushes the actual leftover space to the outside of
     the pair instead. */
  max-width: calc(var(--sidebar-w) + 820px);
  margin: 0 auto;
}
@media (max-width: 860px) {
  .manual-doc-layout { grid-template-columns: 1fr; }
  .doc-sidebar { border-right: none !important; border-bottom: 1px solid var(--border); }
  .doc-sidebar-inner { position: static !important; max-height: none !important; }
}

.doc-sidebar {
  /* display: block reset: Web2026's own style.css has a bare
     `nav{display:flex;align-items:center;gap:0.1rem}` rule for ITS real
     top nav -- since our TOC column is also a `<nav>` tag, that rule
     applies here too unless overridden. Confirmed the real cause of a
     genuinely confusing bug: with align-items:center inherited, the
     sticky `.doc-sidebar-inner` child was vertically centered inside this
     column's full (very tall, whole-page-height) box instead of pinned
     near the top -- so the TOC rendered thousands of pixels below the
     fold, reading as simply blank/missing on any normal viewport. */
  display: block;
  /* Grid items default to min-width: auto -- meaning, without this, the
     column refuses to shrink below its CONTENT's own natural width (a long
     TOC entry that doesn't wrap) rather than the 1fr/var(--sidebar-w) track
     size actually asked for. Confirmed the real cause of a narrow-viewport
     bug: the whole page was forced to ~916px and every line of body text
     got clipped at the visible edge, on a phone-width screen. */
  min-width: 0;
  border-right: 1px solid var(--border);
  background: var(--manual-mist);
}
.doc-sidebar-inner {
  position: sticky;
  top: var(--site-chrome-h);
  max-height: calc(100vh - var(--site-chrome-h));
  overflow-y: auto;
  padding: 1.25rem 0 2rem;
}
.toc-label {
  font-family: var(--f-mono);
  font-size: 0.65rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding: 0 1.25rem;
  margin: 0 0 0.5rem;
  display: block;
}
ul.toc-root, ul.toc-sublist { list-style: none; margin: 0; padding: 0; }
.toc-item a {
  display: block;
  padding: 0.25rem 1.25rem;
  font-size: 0.84rem;
  color: #4a5a6a;
}
.toc-item a:hover { color: var(--manual-navy); background: rgba(200,168,75,0.08); }
.toc-chapter { margin-top: 0.3rem; }
.toc-chapter:first-child { margin-top: 0; }
.toc-chapter details summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 1.25rem;
}
.toc-chapter details summary::-webkit-details-marker { display: none; }
.toc-chapter details summary::before {
  content: '▸';
  font-size: 0.62rem;
  color: var(--ink-muted);
  transition: transform 0.15s ease;
  flex-shrink: 0;
}
.toc-chapter details[open] summary::before { transform: rotate(90deg); }
.toc-chapter summary a { font-family: var(--f-heading); font-weight: 700; font-size: 0.9rem; color: var(--manual-navy); }
.toc-chapter summary a:hover { color: var(--manual-gold-d); }
/* Indented relative to its own chapter link (1.25rem base + extra) so the
   hierarchy is visible at a glance -- "5-a)", "5-b)" clearly sit inside "5)",
   not just in a smaller font next to it. */
.toc-sublist .toc-item a { font-size: 0.81rem; padding: 0.22rem 1.25rem 0.22rem 2.1rem; }

/* A chapter with no sections underneath it has nothing to collapse -- a
   plain link, matching the chapter-with-sections' own typography (same
   font/weight/color as `.toc-chapter summary a` above) but with no chevron
   implying it expands, since it doesn't. The chevron on a collapsible
   chapter pushes ITS text right of the shared 1.25rem padding by the
   chevron's own width plus its gap -- so a flat chapter needs an identical,
   just invisible, placeholder in the same spot, or its text sits further
   left than every other chapter's. Same glyph/size/gap as the real chevron
   (just hidden) guarantees they line up exactly, rather than a hand-tuned
   padding number that only approximately matches. */
.toc-chapter-flat > a {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 1.25rem;
  font-family: var(--f-heading);
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--manual-navy);
}
.toc-chapter-flat > a::before {
  content: '▸';
  font-size: 0.62rem;
  visibility: hidden;
  flex-shrink: 0;
}
.toc-chapter-flat > a:hover { color: var(--manual-gold-d); }

/* No max-width/margin of its own needed here: `.manual-doc-layout` above already
   caps the sidebar+content pair as a unit and centers that whole pair, so
   this column is already exactly the right width, directly against the
   sidebar. min-width: 0 for the same reason as `.doc-sidebar` above -- a
   grid item's default min-width: auto lets its own content (a wide table,
   an unbroken word) force the column wider than its track instead of
   wrapping/scrolling within it. */
.doc-content { min-width: 0; padding: 2.5rem 2.75rem 5rem; }
@media (max-width: 640px) { .doc-content { padding: 1.75rem 1.25rem 3rem; } }

/* ── CHAPTERS / SECTIONS ─────────────────────────────────────────────────── */
.chapter-heading {
  font-family: var(--f-heading);
  font-weight: 700;
  font-size: 1.8rem;
  color: var(--manual-navy);
  margin: 3.5rem 0 1.4rem;
  padding-bottom: 0.85rem;
  border-bottom: 3px solid var(--manual-gold);
  /* .site-header-stub is `position: sticky; top: 0`, permanently covering
     the first --site-chrome-h of the viewport once scrolled -- 1.5rem alone
     (smaller than that header) let it land partly hidden underneath.
     Confirmed the same bug affecting a footnote jump; fixed there via
     :target's own scroll-margin-top, fixed here for a direct TOC/cross-
     reference jump to a heading. */
  scroll-margin-top: calc(var(--site-chrome-h) + 1rem);
}
.chapter-heading:first-child { margin-top: 0; }
.chapter-number { color: var(--manual-gold-d); margin-right: 0.5rem; }

.section-heading {
  font-family: var(--f-heading);
  font-weight: 700;
  font-size: 1.3rem;
  color: var(--manual-navy);
  margin: 2.25rem 0 1.1rem;
  scroll-margin-top: calc(var(--site-chrome-h) + 1rem);
}
h3 {
  font-family: var(--f-heading);
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--manual-navy);
  margin: 1.6rem 0 0.55rem;
  scroll-margin-top: calc(var(--site-chrome-h) + 1rem);
}
h4 { scroll-margin-top: calc(var(--site-chrome-h) + 1rem); }

/* A divider between adjacent sections -- Caterpillar's own treatment: a
   plain hairline, nothing fancier. A chapter heading already provides its
   own visual break, so a section immediately following one doesn't get a
   second, redundant rule. */
.doc-section + .doc-section { padding-top: 1.1rem; border-top: 1px solid var(--border); }
.chapter-heading + .doc-section { padding-top: 0; border-top: none; }

p { margin: 0 0 1rem; font-size: 0.97rem; text-align: justify; }
strong { color: var(--manual-navy); }
.doc-content p a, .doc-content li a, .doc-content td a { color: var(--manual-link); text-decoration: underline; }
.doc-content p a:hover, .doc-content li a:hover, .doc-content td a:hover { color: var(--manual-gold-d); }

/* ── LISTS: gold marker, shape by nesting depth (circle / triangle / square) ──
   Scoped to `.doc-content` specifically -- the sidebar table of contents is
   also a <ul> but is an intentionally different, exceptional list (no
   marker of its own), so it must never pick up these rules.

   Default markers are suppressed in favor of an absolutely-positioned
   ::before with no explicit top -- its "static position" fallback sits
   correctly inline with the first line of text, the same technique already
   proven on the CloudWatcher mockup's own lists. Getting that alignment
   right at a SMALLER size than the surrounding text took a real fix: sizing
   the glyph down with `font-size` shifted its own internal vertical metrics
   enough to visibly float above the text line (confirmed by the user with a
   screenshot) -- `transform: scale()` shrinks it purely visually, without
   touching the box the static-position calculation is based on, so the
   glyph still lands exactly where the full-size character would have.

   Depth is real DOM nesting (clean_docs_html.py reconstructs the source's
   own nesting rather than leaving it flat), so a plain descendant selector
   is enough -- no per-item depth bookkeeping. */
.doc-content ul, .doc-content ol { margin: 0.6rem 0 1.1rem 1.6rem; padding: 0; }
.doc-content ul { list-style: none; }
.doc-content ul > li {
  position: relative;
  padding-left: 1.3rem;
}
.doc-content ul > li::before {
  content: "●";
  position: absolute;
  left: 0;
  color: var(--manual-gold);
  transform: scale(0.5);
  transform-origin: left center;
}
.doc-content ul ul { margin: 0.4rem 0 0.4rem 1.4rem; }
.doc-content ul ul > li::before { content: "▸"; transform: scale(0.8); }
.doc-content ul ul ul > li::before { content: "▪"; transform: scale(0.7); }
li { font-size: 0.95rem; margin-bottom: 0.4rem; line-height: 1.6; text-align: justify; }

/* ── CODE (monospace-font runs and lines from the source, e.g. a VBScript
   walkthrough) -- kept in a real monospace font with preserved whitespace
   instead of being force-justified like prose. ── */
code {
  font-family: var(--f-mono-code);
  font-size: 0.85em;
  background: var(--manual-mist);
  padding: 0.1em 0.35em;
  border-radius: 3px;
}
pre {
  background: #1c2734;
  color: #e8ecf1;
  border-radius: var(--manual-r);
  padding: 1rem 1.25rem;
  margin: 1rem 0;
  overflow-x: auto;
}
pre code {
  background: none;
  padding: 0;
  color: inherit;
  font-size: 0.88rem;
  white-space: pre;
}

/* ── STEPS (numbered procedure) ──────────────────────────────────────────── */
ol.steps { list-style: none; margin-left: 0; counter-reset: steps; }
ol.steps > li {
  counter-increment: steps;
  position: relative;
  padding-left: 2.6rem;
  margin-bottom: 0.85rem;
}
ol.steps > li::before {
  content: counter(steps);
  position: absolute; left: 0; top: 0;
  width: 1.6rem; height: 1.6rem;
  background: var(--manual-navy);
  color: #fff;
  border-radius: 50%;
  font-family: var(--f-heading);
  font-size: 0.78rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}

/* ── SPEC TABLE (real multi-cell tables) ─────────────────────────────────── */
/* A genuinely wide table (several columns, e.g. Dragonfly's own function
   reference: Function / Description / Example(s)) has no reasonable way to
   also fit a narrow phone width -- rather than crushing every cell's text
   into an unreadably thin column, it scrolls horizontally within its own
   box, the same pattern already used for `pre` code blocks. display:block
   on the table itself is what makes it a scrollable box; its row/cell
   children keep their normal table-row/table-cell rendering from the UA
   stylesheet, so the grid itself is unaffected on a wide-enough screen. */
table.manual-spec-table { display: block; overflow-x: auto; width: 100%; border-collapse: collapse; margin: 1rem 0; font-size: 0.92rem; }
table.manual-spec-table tr { border-bottom: 1px solid var(--border); }
table.manual-spec-table tr:last-child { border-bottom: none; }
table.manual-spec-table td, table.manual-spec-table th { padding: 0.65rem 1.2rem 0.65rem 0; text-align: left; vertical-align: top; }
table.manual-spec-table th { color: var(--manual-navy); font-weight: 700; border-bottom: 2px solid var(--border); }

/* ── CALLOUT (a single-cell table in the source is the author's own way of
   drawing a bordered note box -- confirmed on a real sample, a PocketCW2
   manual table containing only "Important: the app must be active at all
   times..." -- so it's rendered as a callout, not a one-row data table). ── */
.manual-callout {
  border-radius: var(--manual-r);
  padding: 1rem 1.25rem;
  margin: 1.25rem 0;
  font-size: 0.92rem;
  line-height: 1.65;
  background: rgba(27,58,107,0.06);
  border: 1px solid rgba(27,58,107,0.18);
  border-left: 3px solid var(--manual-navy);
}
.manual-callout p { margin-bottom: 0.5rem; text-align: justify; }
.manual-callout p:last-child { margin-bottom: 0; }

/* ── FIGURE / IMAGE ───────────────────────────────────────────────────────── */
figure { margin: 1.5rem 0; text-align: center; }
figcaption { font-size: 0.82rem; color: var(--ink-muted); margin-top: 0.5rem; font-style: italic; }

/* ── SCROLLBAR (sidebar) ──────────────────────────────────────────────────── */
.doc-sidebar-inner::-webkit-scrollbar { width: 4px; }
.doc-sidebar-inner::-webkit-scrollbar-track { background: transparent; }
.doc-sidebar-inner::-webkit-scrollbar-thumb { background: rgba(27,58,107,0.2); border-radius: 2px; }
