/* =============================================================================
   Article pages

   Articles are standalone pages, not panels injected into index.html. They still
   load base.css for shared design tokens, typography, and components.

   Structure every article page follows:

     body.post-<name>
       #wrapper
         .site-header        persistent brand + nav
         .breadcrumb
         #main
           article
             .article-hero   category, title, meta
             .article-toc    generated by article-utils.js
             ...content...
         .site-footer
   ============================================================================= */

/* --- Page shell ---------------------------------------------------------- */
/* Nothing to undo here any more. Article pages load base.css but NOT
   landing.css, so `#main article { opacity: 0 }` and the full-height centring
   wrapper simply are not present -- which is why this file no longer needs a
   single !important to lay the page out. */

/* Background.
   The landing page paints this with a fixed <div id="bg">, which article pages
   do not have. That matters more than it looks: --bg-panel is rgba(...,0.85),
   deliberately semi-transparent so the panel reads AGAINST this backdrop. On a
   flat --bg page the panel is nearly the same colour as what is behind it and
   the article dissolves into the page.

   Painted as a fixed pseudo-element on <body> so no article markup has to
   change. Same three layers as #bg, minus the scale/blur it animates on panel
   open. A fixed element rather than `background-attachment: fixed` -- the
   latter janks badly on iOS, especially with three layers, and this is what
   #bg does on the landing page anyway.

   z-index -1 keeps it behind content; #wrapper is position:relative z-index:3. */
body[class^="post-"]:before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  z-index: -1;
  background-image:
    linear-gradient(to top, var(--bg-overlay), var(--bg-overlay)),
    url("../../images/overlay.png"),
    radial-gradient(circle at 30% 20%, rgba(55, 85, 135, 0.45), rgba(14, 16, 20, 0.88));
  background-size: auto, 256px 256px, cover;
  background-repeat: no-repeat, repeat, no-repeat;
  background-position: center, center, center;
}

body[class^="post-"] #wrapper {
  padding: 0 0 2em 0;
}

/* Entry animation -- deliberately absent.
   There used to be an `article-enter` keyframe here fading the panel in on
   load. It fought the cross-document view transition in base.css and caused a
   visible flicker:

     1. the browser snapshots the incoming page for the crossfade
     2. article-enter has fill-mode `both`, so at snapshot time the article is
        pinned at its `from` state -- opacity 0
     3. so the crossfade faded TO a blank page
     4. only then did article-enter run, fading the content in separately

   The view transition already provides the entry fade, in both directions and
   without a second animation on top. Browsers without it (Firefox) just swap
   pages instantly, which is ordinary web behaviour. Do not reintroduce a
   page-load animation here without removing the view transition first. */

body[class^="post-"] #main {
  width: 100%;
  padding: 0 1.5rem;
}

@media screen and (max-width: 736px) {
  body[class^="post-"] #main {
    padding: 0 0.75rem;
  }
}

/* The old padding was 4.5rem top / 1.5rem bottom -- lopsided because the top
   had to clear the panel's close button, which pages do not have. Even now,
   and enough of it at the bottom that the last line is not flush against the
   panel edge. */
/* No card, and the article's inner width IS the reading measure (~36rem, about
   62-68 characters). Prose, headings and furniture simply fill that inner box,
   so they all share one left edge and one right edge with no per-element
   centring -- which is what killed the earlier version, where left-aligned
   paragraphs and auto-centred headings drifted apart. Margin collapse and the
   vertical rhythm are untouched because nothing here fights the flow.

   36rem measure + 2rem padding each side = 40rem. Because the measure is in rem
   it tracks the root font size, so it stays ~65 characters at every breakpoint,
   including the 16pt root on >1680px screens. */
body[class^="post-"] #main article {
  width: 100%;
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
  padding: 2.5rem 2rem 3.5rem;
  background: none;
}

@media screen and (max-width: 1080px) {
  body[class^="post-"] #main article {
    padding: 2rem 1.25rem 3rem;
  }
}

/* Breakout. Screenshots and tables are wider than the
   prose measure. They cannot exceed a normal-flow parent, so each is pulled to
   the column's centre line and shifted back by half its own width -- a
   wrapper-free full-bleed that stays centred on the text column. width is capped
   at the viewport minus a gutter so it never triggers a horizontal scrollbar.

   Code blocks deliberately do NOT break out: a command belongs with the
   instruction paragraph above it, so <pre> stays at the text measure and shares
   the prose left edge. Long lines wrap (white-space: pre-wrap in
   article-code.css) rather than forcing a wider block. */
body[class^="post-"] #main article > .image,
body[class^="post-"] #main article > table {
  width: min(52rem, 100vw - 3rem);
  max-width: none;
  margin-left: 50%;
  transform: translateX(-50%);
}

/* --- Site header --------------------------------------------------------- */
/* The landing page hides its header when a panel opens. An article is its own
   page, so the header stays -- you always know whose site you are on and how to
   get back. */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  width: 100%;
  margin-bottom: 1.5rem;
  /* The bar spans the viewport, but its content is held to a 52rem band centred
     on the page so the brand and nav do not fly to opposite corners on a wide
     (e.g. 4K) screen. The max() falls back to a 1.5rem gutter once the viewport
     is narrower than the band. */
  padding-block: 1rem;
  padding-inline: max(1.5rem, calc((100% - 52rem) / 2));
  background: rgba(19, 21, 25, 0.92);
  backdrop-filter: blur(0.5rem);
  -webkit-backdrop-filter: blur(0.5rem);
  border-bottom: solid 1px var(--border-bg);
}

.site-header__brand {
  border-bottom: 0;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: var(--tracking);
  text-transform: uppercase;
  white-space: nowrap;
}

.site-header__nav {
  display: flex;
  gap: 1.5rem;
}

.site-header__nav a {
  border-bottom: 0;
  font-size: 0.7rem;
  letter-spacing: var(--tracking);
  text-transform: uppercase;
  opacity: 0.7;
  transition: opacity var(--duration) ease-in-out;
}

.site-header__nav a:hover,
.site-header__nav a:focus-visible {
  opacity: 1;
}

@media screen and (max-width: 480px) {
  .site-header {
    padding: 0.75rem 1rem;
  }

  .site-header__nav {
    gap: 1rem;
  }
}

/* --- Breadcrumb ---------------------------------------------------------- */

/* Aligns with the article's text measure, not the container. The breadcrumb and
   the body text are both centred on the viewport axis, so matching content-box
   widths makes their left edges line up. max-width is the 36rem measure plus the
   1.5rem padding on each side, so the content box lands at exactly 36rem. */
.breadcrumb {
  width: 100%;
  max-width: calc(36rem + 3rem);
  margin: 0 auto 0.75rem auto;
  padding: 0 1.5rem;
}

/* Navigation lists opt out of the markers and indentation used by prose. */
.breadcrumb li,
.article-toc li {
  padding: 0;
}

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.65rem;
  letter-spacing: var(--tracking);
  text-transform: uppercase;
  opacity: 0.6;
}

.breadcrumb li + li:before {
  content: '\203A';
  margin-right: 0.5rem;
  opacity: 0.6;
}

.breadcrumb a {
  border-bottom: 0;
}

.breadcrumb a:hover {
  border-bottom: dotted 1px var(--fg-light);
}

.breadcrumb [aria-current="page"] {
  opacity: 0.85;
}

@media screen and (max-width: 736px) {
  .breadcrumb { padding: 0 0.75rem; }
}

/* --- Article hero -------------------------------------------------------- */

.article-hero {
  margin-bottom: 2rem;
  padding-bottom: 1.25rem;
  border-bottom: solid 1px var(--border-bg);
}

.article-hero h1 {
  margin: 0 0 0.75rem 0;
  font-size: 1.85rem;
  line-height: 1.25;
  /* Sentence case, not the theme's spaced caps -- this is a headline to read,
     not a UI label. */
  text-transform: none;
  letter-spacing: -0.01em;
}

/* Scoped, not a bare class: `body[class^="post-"] #main article p` is 1-1-3 and
   would otherwise win the margin and leave this rule silently inert. */
body[class^="post-"] #main article .article-hero__category {
  margin: 0 0 0.5rem 0;
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--tracking);
  text-transform: uppercase;
}

/* Scoped rather than !important: the competing `#main article p` rule is in
   this same file at 1-1-3, so a bare class would lose. */
body[class^="post-"] #main article .article-hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-size: 0.7rem;
  letter-spacing: 0.1rem;
  text-transform: uppercase;
  /* Colour, not opacity: opacity on the parent creates a group the status pill
     cannot escape, which would mute it to 65% no matter what colour it sets. */
  color: var(--fg-light);
}

.article-hero__meta > * + *:before {
  content: '\00B7';
  margin-right: 0.75rem;
}

/* Reading time is filled in by article-utils.js. With JS off the slot stays
   empty. Hiding it is not enough -- it is still a DOM sibling, so the element
   after it would keep its separator dot and render a leading "· ". */
.article-hero__meta [data-reading-time]:empty {
  display: none;
}

.article-hero__meta [data-reading-time]:empty + *:before {
  content: none;
  margin-right: 0;
}

/* --- Table of contents ---------------------------------------------------
   Generated from the article's <h2>s by article-utils.js, and inserted INSIDE
   <article> -- so every selector here needs the same
   `body[class^="post-"] #main article` prefix as the typography rules further
   down, or those win on specificity and put a 1.5rem list indent back.
   -------------------------------------------------------------------------- */

body[class^="post-"] #main article .article-toc {
  margin: 0 0 2.25rem 0;
  padding: 1.125rem 1.375rem;
  border: solid 1px var(--border-bg);
  border-radius: var(--radius);
  background: var(--bg-raised);
}

body[class^="post-"] #main article .article-toc__summary {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--tracking);
  text-transform: uppercase;
  opacity: 0.75;
  cursor: pointer;
  list-style: none;
}

.article-toc__summary::-webkit-details-marker {
  display: none;
}

.article-toc__summary:before {
  content: '\25B8';
  display: inline-block;
  margin-right: 0.5rem;
  transition: transform var(--duration) ease-in-out;
}

.article-toc[open] .article-toc__summary:before {
  transform: rotate(90deg);
}

body[class^="post-"] #main article .article-toc ol {
  margin: 1rem 0 0 0;
  padding: 0;
  list-style: none;
}

body[class^="post-"] #main article .article-toc li {
  margin: 0;
  padding: 0;
  list-style: none;
}

body[class^="post-"] #main article .article-toc li + li {
  margin-top: 0.55rem;
}

body[class^="post-"] #main article .article-toc a {
  display: block;
  border-bottom: 0;
  font-size: 0.85rem;
  line-height: 1.4;
  opacity: 0.8;
  transition: opacity var(--duration) ease-in-out, color var(--duration) ease-in-out;
}

body[class^="post-"] #main article .article-toc a:hover,
body[class^="post-"] #main article .article-toc a:focus-visible {
  opacity: 1;
}

body[class^="post-"] #main article .article-toc a.is-current {
  color: var(--accent);
  opacity: 1;
}

/* --- Site footer --------------------------------------------------------- */

.site-footer {
  width: 100%;
  max-width: calc(36rem + 3rem);
  margin: 2rem auto 0 auto;
  padding: 1.5rem 1.5rem 0 1.5rem;
  border-top: solid 1px var(--border-bg);
  text-align: center;
  font-size: 0.65rem;
  letter-spacing: var(--tracking);
  text-transform: uppercase;
  opacity: 0.6;
}

.site-footer p {
  margin: 0;
}

/* --- Article typography --------------------------------------------------

   Vertical rhythm. The old values here were panel-era: content was squeezed
   into a 40rem modal, so everything was compressed (0.6rem between paragraphs,
   1.48 line-height, no space above headings at all). On a full page these are
   long-form reading documents and need room to breathe.

   The scale, loosely a 0.5rem grid:

     2.75rem   above an h2 -- separates one section from the last
     1.75rem   above an h3, and around images
     1rem      below a heading, between paragraphs, after a list
     0.4rem    between list items

   Headings carry their space ABOVE them, so a section always leads with a gap
   rather than trailing one. Margins collapse (the article is a normal block,
   not flex), so an <hr /> before an h2 does not stack with it.
   -------------------------------------------------------------------------- */

body[class^="post-"] #main article {
  line-height: 1.6;
}

/* Sentence case for section headings. The base theme sets uppercase + 0.2rem
   tracking on all h1-h6, which is a label treatment -- fine for the landing
   panels, wrong for article prose and harder to scan. h3 also needs to be
   bigger than body text, which the base 1rem does not give it. */
body[class^="post-"] #main article h2 {
  margin: 2.75rem 0 1rem;
  font-size: 1.45rem;
  text-transform: none;
  letter-spacing: 0;
  scroll-margin-top: 5rem;   /* clears the sticky header on anchor jumps */
}

body[class^="post-"] #main article h3 {
  margin: 1.75rem 0 0.6rem;
  font-size: 1.15rem;
  text-transform: none;
  letter-spacing: 0;
  scroll-margin-top: 5rem;
}

body[class^="post-"] #main article h4 {
  text-transform: none;
  letter-spacing: 0;
}

body[class^="post-"] #main article p {
  margin: 0 0 1rem;
}

body[class^="post-"] #main article ul,
body[class^="post-"] #main article ol {
  margin: 0 0 1rem 1.5rem;
}

body[class^="post-"] #main article ul li {
  list-style: square inside;
}

body[class^="post-"] #main article ul li + li,
body[class^="post-"] #main article ol li + li {
  margin-top: 0.4rem;
}

body[class^="post-"] #main article blockquote {
  margin: 0 0 1.75rem;
}

body[class^="post-"] #main article hr {
  margin: 2.75rem 0;
}

/* Anchor affordance on headings, so a step in a long guide is linkable. */
body[class^="post-"] #main article h2 .heading-anchor {
  margin-left: 0.5rem;
  border-bottom: 0;
  font-size: 0.7em;
  opacity: 0;
  transition: opacity var(--duration) ease-in-out;
}

body[class^="post-"] #main article h2:hover .heading-anchor,
body[class^="post-"] #main article h2 .heading-anchor:focus-visible {
  opacity: 0.5;
}

/* --- Note block ---------------------------------------------------------- */

body[class^="post-"] #main article .note {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 1.25rem 0;
  padding: 0.75rem 0.875rem;
  border-left: 3px solid var(--accent);
  background: rgba(var(--accent-rgb), 0.08);
  border-radius: var(--radius);
  color: inherit;
}

body[class^="post-"] #main article .note svg {
  width: 1em;
  height: 1em;
  flex: none;
  margin-top: 0.15em;
  color: var(--accent);
}

body[class^="post-"] #main article ul li.note {
  list-style: none;
  margin-left: 0;
  padding-left: 0;
}

/* --- Images -------------------------------------------------------------- */

/* Horizontal size and centring come from the breakout rule above; only the
   vertical margin lives here (a `margin: ... auto` shorthand would clobber the
   breakout's margin-left). */
body[class^="post-"] #main article .image {
  display: block;
  border-bottom: 0;
  margin-top: 1.75rem;
  margin-bottom: 1.75rem;
}

/* These guides read as "here is the step, here is what it looks like", so a
   screenshot belongs to the list or paragraph directly above it. Tighten the
   gap above to keep that pairing, and keep the full gap below to separate it
   from the next step. */
body[class^="post-"] #main article ul + .image,
body[class^="post-"] #main article ol + .image,
body[class^="post-"] #main article p + .image {
  margin-top: 0.75rem;
}

/* Consecutive screenshots are one sequence, not separate points. */
body[class^="post-"] #main article .image + .image {
  margin-top: 0.75rem;
}

body[class^="post-"] #main article .image img {
  display: block;
  width: 100%;
  height: auto;
}

/* Width modifiers. Every current screenshot is image--medium, so that sits a
   little wider than the 36rem text; full spans the breakout width; narrow tucks
   inside the measure. All are click-to-zoom for full resolution regardless. */
body[class^="post-"] #main article .image.image--medium { max-width: 46rem; }
body[class^="post-"] #main article .image.image--narrow { max-width: 26rem; }
body[class^="post-"] #main article .image.image--full   { max-width: 52rem; }

/* The tint overlay these used to cancel (.image:before, plus a pile of
   opacity/filter/blend resets) is gone from base.css entirely -- .image is only
   ever used inside articles, so the overlay had no one left to serve. */

/* --- Image lightbox ------------------------------------------------------ */

.article-image-modal {
  position: fixed;
  inset: 0;
  background: rgba(5, 8, 20, 0.95);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  z-index: 10000;
  cursor: zoom-out;
}

.article-image-modal.is-visible {
  display: flex;
}

body.is-image-modal-open {
  overflow: hidden;
}

.article-image-modal__inner {
  position: relative;
  max-width: min(96vw, 1600px);
  max-height: 92vh;
  cursor: default;
}

.article-image-modal__inner img {
  display: block;
  width: auto;
  max-width: 96vw;
  height: auto;
  max-height: 90vh;
  object-fit: contain;
  border-radius: var(--radius-lg);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
  margin: 0 auto;
}

.article-image-modal__close {
  position: absolute;
  top: -2.75rem;
  right: -0.75rem;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  border: none;
  background: rgba(255, 255, 255, 0.2);
  color: var(--fg);
  font-size: 1.35rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  cursor: pointer;
  transition: background var(--duration) ease, transform var(--duration) ease;
}

.article-image-modal__close:hover {
  background: rgba(255, 255, 255, 0.35);
  transform: scale(1.05);
}

.article-image-modal__caption {
  margin-top: 0.75rem;
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.95rem;
  text-align: center;
}
