/* ============================================================================
   docs — LAYOUT ONLY
   ============================================================================

   Loaded after `tokens.css` and `components.css`, which the `{{head}}` slot
   links into every templated page. Those two are the design system: 298
   values and the rules that spend them. This file adds a three-column frame
   and nothing else, and the rule that keeps it that way is absolute — no
   colour, no font family, no font size, no duration and no easing is written
   here as a literal. Every one of them is a `var(--pkmd-*)`. Six templates
   therefore cost six layouts rather than six design systems, which is the
   whole reason a template is allowed to have a stylesheet at all.

   Two consequences of the substitution model are load-bearing below:

   1. An empty slot substitutes the empty string and a block slot emits either
      a complete element or nothing, so a region is hidden with `:empty` (or
      `:has()` where the region also carries a static heading) and never with
      a conditional, because there are no conditionals.
   2. Every URL in the markup came out of a slot already relativised, so there
      is nothing here that needs to know where the site root is.

   MOTION. Measured on this codebase's target: paint and composite are free —
   a full-viewport 40-pixel `backdrop-filter: blur()` and four-layer shadows
   cost nothing — while layout is not: animating a width dropped 63 frames in
   200. So the only animated properties in this file are `transform` and
   colour, every transition is tokenised, and the whole lot is switched off
   under `prefers-reduced-motion` at the end of the file.
   ========================================================================= */


/* ── the page canvas ───────────────────────────────────────────────────────
   `components.css` paints the canvas from `body:has(> .pkmd-note)`, which is
   true of a bare exported note and false of every templated page, because our
   body's own child is the shell. Without this the UA paints literal white in
   light and its own near-black in dark — the one pair of neutrals this system
   never uses, since every surface here is tinted (H72 warm, H280 cool). */
[data-pkmd-template="docs"] body {
  margin: 0;
  background: var(--pkmd-surface-page);
  color: var(--pkmd-text-1);
  font-family: var(--pkmd-font-ui);
  font-size: var(--pkmd-fs-ui);
  line-height: var(--pkmd-lh-ui);
}

/* The token layer ships the ring and nothing selects it, because a focus ring
   belongs to whatever owns the interactive element — here, the template. */
[data-pkmd-template="docs"] a:focus-visible {
  outline: none;
  border-radius: var(--pkmd-radius-1);
  box-shadow: var(--pkmd-focus-ring);
}

/* ── skip link ─────────────────────────────────────────────────────────────
   Hidden by a transform rather than by `display: none` or a negative offset:
   a display-none link is not focusable at all, and a transform is the one way
   to move it that costs no layout. */
[data-pkmd-template="docs"] .pkmd-skip {
  position: fixed;
  inset-block-start: var(--pkmd-space-8);
  inset-inline-start: var(--pkmd-space-8);
  z-index: var(--pkmd-z-toast);
  padding: var(--pkmd-space-8) var(--pkmd-space-12);
  border-radius: var(--pkmd-radius-2);
  background: var(--pkmd-surface-raised);
  box-shadow: var(--pkmd-shadow-2);
  color: var(--pkmd-text-1);
  text-decoration: none;
  transform: translateY(calc(-100% - var(--pkmd-space-16)));
  transition: transform var(--pkmd-dur-2) var(--pkmd-ease-enter);
}
/* `:focus`, not `:focus-visible`: a skip link is reached by keyboard or by a
   screen reader moving focus programmatically, and the second does not always
   satisfy the heuristic. */
[data-pkmd-template="docs"] .pkmd-skip:focus {
  transform: none;
}

/* ── the shell ─────────────────────────────────────────────────────────────
   Exactly as wide as its three columns need, composed from the same tokens
   the columns are sized from — so widening a rail widens the page with it and
   there is no second number to keep in step. `--pkmd-reading-width-full` is
   deliberately not used here: a documentation site on a 27-inch display with
   no cap puts the navigation and the table of contents a head-turn apart. */
[data-pkmd-template="docs"] .pkmd-shell {
  max-inline-size: calc(
    var(--pkmd-sidebar-l-w) + var(--pkmd-reading-width) + var(--pkmd-sidebar-r-min)
    + 2 * var(--pkmd-space-32) + 2 * var(--pkmd-space-24)
  );
  margin-inline: auto;
}

[data-pkmd-template="docs"] .pkmd-masthead {
  display: flex;
  align-items: center;
  gap: var(--pkmd-space-16);
  padding: var(--pkmd-space-16) var(--pkmd-space-24);
  border-block-end: var(--pkmd-divider) solid var(--pkmd-border-subtle);
}
[data-pkmd-template="docs"] .pkmd-brand {
  font-size: var(--pkmd-fs-ui-lg);
  font-weight: var(--pkmd-weight-ui-bold);
  color: var(--pkmd-text-1);
  text-decoration: none;
}

/* ── the three columns ─────────────────────────────────────────────────────
   Flex and not grid, for one specific reason: a rail whose slot was empty is
   `display: none`, and a grid keeps the empty track's gap while flex does
   not, so a single-page site would carry two 32-pixel voids where its rails
   would have been. `flex-wrap` then replaces every breakpoint — the rails
   carry a flex-basis and the column carries the measure, so the table of
   contents drops below the column, and then the navigation does, purely
   because the bases stop fitting. There is no media query in this file, which
   is why there is no pixel literal in it either. */
[data-pkmd-template="docs"] .pkmd-body {
  display: flex;
  flex-wrap: wrap;
  /* Load-bearing: a stretched flex item is as tall as its row, and `position:
     sticky` inside a full-height box has nowhere to travel. The rails are
     content-height, and therefore sticky at all, because of this line. */
  align-items: flex-start;
  justify-content: center;
  gap: var(--pkmd-space-32);
  padding-inline: var(--pkmd-space-24);
}

/* `flex-grow: 1` and a cap, both of which matter only once a rail has
   wrapped. On its own row the rail then fills the row rather than sitting at
   its basis width with the page centred around it — which is how a stacked
   layout ends up as three blocks each centred at a different width — and the
   cap stops it growing past the column it is now stacked above, so the two
   share one left edge. On the three-column row both are inert: there is no
   free space to grow into, because the shell is capped at exactly the sum of
   the bases, and neither basis is anywhere near the cap. */
[data-pkmd-template="docs"] .pkmd-nav-rail,
[data-pkmd-template="docs"] .pkmd-toc-rail {
  max-inline-size: var(--pkmd-reading-width);
}
[data-pkmd-template="docs"] .pkmd-nav-rail {
  flex: 1 1 var(--pkmd-sidebar-l-w);
}
[data-pkmd-template="docs"] .pkmd-toc-rail {
  flex: 1 1 var(--pkmd-sidebar-r-min);
}

/* ── sticky, but only while a rail is genuinely beside the column ──────────
   `position: sticky` resolves against the rail's containing block, which is
   the whole row — so a rail that has WRAPPED into the flow pins itself over
   the article for the entire length of the page instead of sitting next to
   it. On a phone that is a navigation list covering the text you came to
   read, and it is the one thing in this layout that intrinsic sizing cannot
   express: CSS can wrap on available space but cannot tell an element that it
   wrapped.

   Hence the file's only two thresholds. Each is arithmetic on the column
   tokens rather than a taste decision, in `rem` against the same 16-unit root
   basis the whole type scale is derived from:

     the navigation fits beside the column at 48 + 264 + 32 + 720 = 1064
     all three fit at              1064 + 32 + 240 = 1336

   (page padding, rail, gap, column.) There is no token for either, because a
   breakpoint is not a design value — it is what these three tokens add up
   to, and if one of them changes these two numbers are the recalculation. */
@media (min-width: 66.5rem) {
  [data-pkmd-template="docs"] .pkmd-nav-rail {
    position: sticky;
    inset-block-start: var(--pkmd-space-24);
    /* The rail scrolls itself, so a 200-page tree cannot push the footer off
       the bottom of the document. `dvh` rather than `vh` because a mobile
       browser's collapsing toolbar makes `vh` taller than the viewport. */
    max-block-size: calc(100dvh - 2 * var(--pkmd-space-24));
    overflow: auto;
    overscroll-behavior: contain;
  }
}
@media (min-width: 83.5rem) {
  [data-pkmd-template="docs"] .pkmd-toc-rail {
    position: sticky;
    inset-block-start: var(--pkmd-space-24);
    max-block-size: calc(100dvh - 2 * var(--pkmd-space-24));
    overflow: auto;
    overscroll-behavior: contain;
  }
}
/* `{{nav}}` is empty on a single-page site and the aside holds nothing else,
   so `:empty` is exact — provided the markup keeps the slot and the tags on
   one line, which is why page.html says so twice. */
[data-pkmd-template="docs"] .pkmd-nav-rail:empty {
  display: none;
}
/* The table-of-contents aside carries a static heading, so it is never
   `:empty`; it is hidden on the child the slot actually produced. `:has()` is
   the same tool `components.css` already uses for the page canvas and for a
   completed task, so this is the file's existing idiom rather than a new one. */
[data-pkmd-template="docs"] .pkmd-toc-rail:not(:has(.pkmd-toc)) {
  display: none;
}

[data-pkmd-template="docs"] .pkmd-main {
  flex: 1 1 var(--pkmd-reading-width);
  /* Without this a long unbroken token — a URL in a code block — sets the
     flex item's minimum and shoves the rails off the row. */
  min-inline-size: 0;
  max-inline-size: var(--pkmd-reading-width);
  padding-block: var(--pkmd-space-32) var(--pkmd-space-64);
}

/* ── taking back the prose column's editor affordance ──────────────────────
   `.pkmd-note` reserves `45vh` of padding below its last line so the caret
   can sit mid-screen while you type. On a published page that is half a
   screen of blank between the last paragraph and the sibling links, so the
   block padding is the one thing a template has to take back. The INLINE
   padding stays: it is the 40-pixel marker rail that holds the measure at 640
   and 75.8 characters, and the template's own chrome matches it — see the
   pager below — instead of fighting it. */
[data-pkmd-template="docs"] .pkmd-note {
  padding-block: 0;
}

/* `.pkmd-note > :first-child` zeroes the top margin of a column's first
   element, which is right when the column IS the page and wrong here: the
   title lives in a column of its own, so the body's first element is no
   longer the first thing on the page. A note opening with a heading — which
   in documentation is most of them — otherwise sits one half-rhythm under the
   title and reads as its subtitle rather than as a section. These two rules
   restore exactly the two values `components.css` would have given the
   heading, which is why there are two of them and not one average. */
[data-pkmd-template="docs"] article.pkmd-note > :is(h1, h2):first-child {
  margin-block-start: var(--pkmd-prose-space-h-up);
}
[data-pkmd-template="docs"] article.pkmd-note > :is(h3, h4, h5, h6):first-child {
  margin-block-start: var(--pkmd-prose-space-block);
}

/* ── the synthesised root's introduction ───────────────────────────────── */
/* Specificity, not taste: `.pkmd-note p` (0,1,1) outranks `.pkmd-lede`
   (0,1,0), so a lede inside the prose column silently loses its step back to
   body size. Restoring it costs one declaration and references the same token
   `.pkmd-lede` does; moving the element out of the column instead would cost
   the alignment the column is there for. */
[data-pkmd-template="docs"] .pkmd-note p.pkmd-lede {
  font-size: var(--pkmd-fs-h3-em);
}
/* A site with no description substitutes nothing, and an empty paragraph
   still carries a bottom margin. */
[data-pkmd-template="docs"] .pkmd-intro > p:empty {
  display: none;
}

[data-pkmd-template="docs"] .pkmd-section {
  margin-block-start: var(--pkmd-prose-space-h-up);
  padding-inline: var(--pkmd-gutter-marker);
}
[data-pkmd-template="docs"] .pkmd-section-title {
  margin-block: 0 var(--pkmd-space-8);
}
/* Both `{{nav}}` and `{{tags}}` emit a list or nothing, so "the slot said
   nothing" and "there is no list in here" are the same condition, and one
   rule hides every empty section in every one of this template's pages. */
[data-pkmd-template="docs"] .pkmd-section:not(:has(ul)) {
  display: none;
}

/* ── the page tree ─────────────────────────────────────────────────────────
   `{{nav}}` emits `<nav class="pkmd-nav"><ul>` with `<li class="pkmd-nav-section">`
   group labels and `aria-current="page"` on the current item. The current
   item is styled off that attribute and not off a class, because the
   attribute is the accessible answer and CSS can select it — one attribute
   doing both jobs is the engine's own stated reason for emitting it. */
[data-pkmd-template="docs"] .pkmd-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
[data-pkmd-template="docs"] .pkmd-nav-section {
  margin-block: var(--pkmd-space-16) var(--pkmd-space-4);
  padding-inline: var(--pkmd-space-8);
  font-size: var(--pkmd-fs-label);
  font-weight: var(--pkmd-weight-ui-strong);
  letter-spacing: var(--pkmd-tracking-caps);
  text-transform: uppercase;
  color: var(--pkmd-text-3);
}
[data-pkmd-template="docs"] .pkmd-nav-section:first-child {
  margin-block-start: 0;
}
[data-pkmd-template="docs"] .pkmd-nav a {
  display: block;
  padding: var(--pkmd-space-6) var(--pkmd-space-8);
  border-radius: var(--pkmd-radius-2);
  color: var(--pkmd-text-2);
  text-decoration: none;
  /* Colour only. `background-color` and `color` composite; nothing here
     resizes the containing block, so the rail cannot drop a frame. */
  transition:
    background-color var(--pkmd-dur-1) var(--pkmd-ease-state),
    color var(--pkmd-dur-1) var(--pkmd-ease-state);
}
[data-pkmd-template="docs"] .pkmd-nav a:hover {
  background: var(--pkmd-state-hover);
  color: var(--pkmd-text-1);
}
[data-pkmd-template="docs"] .pkmd-nav a[aria-current="page"] {
  background: var(--pkmd-state-selected);
  color: var(--pkmd-text-1);
  font-weight: var(--pkmd-weight-ui-medium);
}

/* ── the table of contents ─────────────────────────────────────────────────
   `<pkmd-toc>` is an unknown element until its definition loads, so it needs
   a display of its own or the published list renders inline. The active
   section's `aria-current` is set by the component at runtime and is matched
   here on PRESENCE rather than on a value, so it holds whichever of `true`,
   `page` or `location` the component decides is right. */
[data-pkmd-template="docs"] pkmd-toc {
  display: block;
}
[data-pkmd-template="docs"] .pkmd-toc ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
[data-pkmd-template="docs"] .pkmd-toc a {
  display: block;
  padding: var(--pkmd-space-4) var(--pkmd-space-12);
  border-inline-start: var(--pkmd-divider) solid var(--pkmd-border-subtle);
  font-size: var(--pkmd-fs-ui-sm);
  color: var(--pkmd-text-2);
  text-decoration: none;
  transition:
    color var(--pkmd-dur-1) var(--pkmd-ease-state),
    border-color var(--pkmd-dur-1) var(--pkmd-ease-state),
    box-shadow var(--pkmd-dur-1) var(--pkmd-ease-state);
}
/* h3 under h2. The engine emits only these two levels, so this is the whole
   ladder and not the first rung of one. */
[data-pkmd-template="docs"] .pkmd-toc-h3 a {
  padding-inline-start: calc(var(--pkmd-space-12) + var(--pkmd-space-12));
}
[data-pkmd-template="docs"] .pkmd-toc a:hover {
  color: var(--pkmd-text-1);
}
/* The rail segment thickens by one step with an inset shadow rather than a
   wider border, because a border width is a layout property and this one
   changes while the reader scrolls. */
[data-pkmd-template="docs"] .pkmd-toc a[aria-current] {
  border-inline-start-color: var(--pkmd-accent-solid);
  box-shadow: inset var(--pkmd-space-2) 0 0 var(--pkmd-accent-solid);
  color: var(--pkmd-text-1);
}

/* ── previous / next ───────────────────────────────────────────────────────
   `{{prev}}` and `{{next}}` emit `<a class="pkmd-prev"><span>Previous</span>Title</a>`
   and nothing at either end of the site, so the pager holds both slots and no
   whitespace and hides itself with `:empty`. The inline padding matches the
   prose column's marker rail so the links sit under the body text rather than
   40 pixels outside it. */
[data-pkmd-template="docs"] .pkmd-pager {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pkmd-space-12);
  margin-block-start: var(--pkmd-prose-space-rule);
  padding-block-start: var(--pkmd-space-24);
  padding-inline: var(--pkmd-gutter-marker);
  border-block-start: var(--pkmd-divider) solid var(--pkmd-border-subtle);
}
[data-pkmd-template="docs"] .pkmd-pager:empty {
  display: none;
}
[data-pkmd-template="docs"] :is(.pkmd-prev, .pkmd-next) {
  display: flex;
  flex: 0 1 auto;
  flex-direction: column;
  gap: var(--pkmd-space-2);
  padding: var(--pkmd-space-12) var(--pkmd-space-16);
  border: var(--pkmd-divider) solid var(--pkmd-border-subtle);
  border-radius: var(--pkmd-radius-3);
  color: var(--pkmd-text-1);
  text-decoration: none;
  transition:
    background-color var(--pkmd-dur-1) var(--pkmd-ease-state),
    border-color var(--pkmd-dur-1) var(--pkmd-ease-state);
}
/* The forward link sits at the end of the row even when it is the only one,
   which is the whole reason the two are not simply `flex: 1`. */
[data-pkmd-template="docs"] .pkmd-next {
  margin-inline-start: auto;
  text-align: end;
}
[data-pkmd-template="docs"] :is(.pkmd-prev, .pkmd-next) > span {
  font-size: var(--pkmd-fs-label);
  letter-spacing: var(--pkmd-tracking-caps);
  text-transform: uppercase;
  color: var(--pkmd-text-3);
}
[data-pkmd-template="docs"] :is(.pkmd-prev, .pkmd-next):hover {
  background: var(--pkmd-state-hover);
  border-color: var(--pkmd-border-default);
}

[data-pkmd-template="docs"] .pkmd-colophon {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--pkmd-space-8);
  padding: var(--pkmd-space-24);
  border-block-start: var(--pkmd-divider) solid var(--pkmd-border-subtle);
}
[data-pkmd-template="docs"] .pkmd-colophon p {
  margin: 0;
}
/* A site with no name emits nothing, and the gap would otherwise survive it. */
[data-pkmd-template="docs"] .pkmd-colophon p:empty {
  display: none;
}


/* ── reduced motion ────────────────────────────────────────────────────────
   Named selectors rather than `* { transition: none !important }`: the four
   rules above are the only animated things in this template, so listing them
   is both exhaustive and readable, and it cannot reach into a component's own
   motion — which honours the same query on its own terms. */
@media (prefers-reduced-motion: reduce) {
  [data-pkmd-template="docs"] .pkmd-skip,
  [data-pkmd-template="docs"] .pkmd-nav a,
  [data-pkmd-template="docs"] .pkmd-toc a,
  [data-pkmd-template="docs"] :is(.pkmd-prev, .pkmd-next) {
    transition: none;
  }
}


/* ── The note's own h1 wins ────────────────────────────────────────────────
   A note almost always opens with `# Title`, and the manifest takes
   `page.title` FROM that first heading — so emitting the slot as an h1 above
   the body prints the same words twice and gives the page two h1 elements,
   which is a real accessibility defect and not a cosmetic one. Measured on a
   live page before this rule existed: two visible h1s, both "About".

   The title block still earns its place, because a note with no heading at
   all has nothing else to name it — so the block is kept and *hidden* when
   the body brings its own. `:has()` is what makes that expressible: the
   question "does the article below me have an h1" cannot be answered by the
   header, only by their shared parent.

   `article.pkmd-note h1` and not `.pkmd-note h1`, deliberately: this header
   carries `.pkmd-note` itself to inherit the prose typography, so the looser
   selector would match the header's own heading and hide it unconditionally.
   ────────────────────────────────────────────────────────────────────────── */
[data-pkmd-template="docs"] .pkmd-main:has(article.pkmd-note h1) > header.pkmd-note { display: none; }
