/* ============================================================================
   pkmd — CONTENT AND COMPONENT LAYER
   ============================================================================

   This file and `tokens.css` are the two stylesheets a page authored into a
   vault links. Together they are the whole contract:

       tokens.css       298 custom properties. Values, no rules.
       components.css   rules, and NOT ONE literal colour, size or duration.

   Read `README.md` in this folder before writing a page. Read
   `components.html` for every component rendered next to its own markup.

   ── WHY THIS FILE IS IN THE VAULT AND NOT IN THE APP ───────────────────────

   `pkmd_core::render` is the only HTML renderer in the product: the editor's
   reading mode, `pkmd render`, and a published page all come out of it
   (render.rs:4). That guarantee is worth nothing if the *rules* that style its
   output live somewhere only the app can reach — which is exactly what was
   true before this file existed. The app linked a bundle stylesheet holding
   the whole prose layer; `pkmd render --document` linked `tokens.css` and
   nothing else; a vault `.html` page opened over `file://` linked whatever it
   could see, which was 298 values and zero rules.

   So the source of the content layer is here, in the vault, next to the pages
   that consume it. `apps/desktop/build.mjs` copies it byte-for-byte into the
   app bundle exactly as it already does for `tokens.css`. The app, an export
   and a published page therefore read the same bytes and cannot drift; a
   `cmp` between the two copies is the check.

   ── WHAT IS SAFE TO EDIT ───────────────────────────────────────────────────

   This folder belongs to the user. Editing a value in `tokens.css` restyles
   the app, every export and every published page at once, which is the point.
   Editing THIS file changes how content renders everywhere too — but the
   selectors in section 1 are a contract with the renderer, not a preference:
   `pkmd_core::render` emits exactly these elements, classes and attributes,
   and a selector deleted here is content silently unstyled everywhere.
   Sections 2 and 3 are yours to extend.

   Add rules at the end. Never introduce a literal: if a value is missing,
   the answer is a token, not a hex code — see README.md § "Adding a value".
   ========================================================================= */


/* ═══════════════════════════════════════════════════════════════════════════
   1. THE RENDERER CONTRACT
   ═══════════════════════════════════════════════════════════════════════════

   Everything `pkmd_core::render` emits, scoped to the `<article
   class="pkmd-note">` it wraps every document in (render.rs:139). An authored
   page supplies that wrapper itself; the renderer supplies it for markdown.

   This file is the only copy: the duplicate that once lived in
   `apps/desktop/src/static/components.css` is gone, and the app loads these
   bytes through `dist/design-components.css` (`build.mjs`). */

/* ═══════════════════════════════════════════════════════════════════════════
   PROSE SURFACE — owner: TypeSystem
   ═══════════════════════════════════════════════════════════════════════════ */
.pkmd-note {
  max-inline-size: var(--pkmd-reading-width);        /* 720px, LayoutChrome */
  padding-inline: var(--pkmd-gutter-marker);         /* 40px  → 640px text  */
  padding-block: var(--pkmd-space-40) 45vh;          /* LayoutChrome */
  margin-inline: auto;
  text-wrap: pretty;
  /* max-inline-size is deliberately NOT transitioned. MotionDepth measured
     that animating anything which resizes the prose containing block costs
     median 16.70 ms / p95 41.70 ms per frame with 31.5% dropped frames on the
     534 KB note, against 8.30 ms and zero drops for a transform-only control.
     The width toggle is one discrete step, wrapped in a scoped view
     transition where one is available. --pkmd-reading-width-full is 100% and
     not `none` because .pkmd-bleed's centring arithmetic needs a resolvable
     width. */

  font-family: var(--pkmd-font-prose);
  /* the ONE rem anchor for prose; descendants use the em family so
     --pkmd-prose-zoom propagates */
  font-size: calc(var(--pkmd-fs-body) * var(--pkmd-prose-zoom));
  line-height: var(--pkmd-lh-body);                  /* 30px line box */
  font-weight: var(--pkmd-weight-regular);
  letter-spacing: var(--pkmd-tracking-body);
  color: var(--pkmd-text-1);                         /* 12.89:1 / 13.29:1 */

  font-optical-sizing: auto;      /* SF and Literata opsz track the size */
  font-kerning: normal;
  font-variant-ligatures: common-ligatures contextual;
  font-variant-numeric: proportional-nums;
  hyphens: manual;                /* auto-hyphenation shifts while typing */
  overflow-wrap: break-word;      /* long URLs and wikilinks */
  word-break: normal;

  /* deliberately NOT text-rendering: optimizeLegibility. Kerning and common
     ligatures are already on in Chromium; it only adds shaping cost. */
}

/* ── reading styles ─────────────────────────────────────────────────────────
   Three faces, and only the family changes. Because line-height is unitless
   and Literata's advance matches SF Pro Text to 0.13%, neither the 30px line
   box nor the 75.8-character measure moves.

   The attribute is always written, `sans` included: a page states a face
   rather than inheriting one, which is what makes a page's choice survive a
   change to the vault default.

   Each block reassigns the **token** rather than declaring `font-family`.
   `.pkmd-note` already paints itself from `var(--pkmd-font-prose)` above, so
   the article looks the same either way — but a custom property inherits,
   and a `font-family` declared on an element does not reach a descendant
   that declares its own. The editor's `.cm-content` declares
   `font-family: var(--pkmd-font-prose)`, so reassigning the token is what
   carries a page's face into the CodeMirror view nested inside the article;
   declaring the property here left body text on the vault default while the
   inline title, which declares nothing, followed the page. */
.pkmd-note[data-prose="sans"] {
  --pkmd-font-prose: var(--pkmd-font-prose-sans);
}
.pkmd-note[data-prose="serif"] {
  --pkmd-font-prose: var(--pkmd-font-prose-serif);
  font-feature-settings: "onum" 0, "lnum" 1;   /* Literata defaults to onum */
}

/* The third face. Not a reading face in the sense the two above are — it is
   a deliberate choice for a page that is mostly code or data, and it says
   so. */
.pkmd-note[data-prose="mono"] {
  --pkmd-font-prose: var(--pkmd-font-prose-mono);
}

/* ── headings ─────────────────────────────────────────────────────────────── */
.pkmd-note :is(h1, h2, h3, h4, h5, h6) {
  text-wrap: balance;
  color: var(--pkmd-text-1);
  margin-block: var(--pkmd-prose-space-block) var(--pkmd-prose-space-h-down);
}
.pkmd-note h1 {
  font-size: var(--pkmd-fs-h1-em);
  line-height: var(--pkmd-lh-h1);
  letter-spacing: var(--pkmd-tracking-h1);
  font-weight: var(--pkmd-weight-h1);
  margin-block-start: var(--pkmd-prose-space-h-up);   /* collapses to 45px */
}
.pkmd-note h2 {
  font-size: var(--pkmd-fs-h2-em);
  line-height: var(--pkmd-lh-h2);
  letter-spacing: var(--pkmd-tracking-h2);
  font-weight: var(--pkmd-weight-h2);
  margin-block-start: var(--pkmd-prose-space-h-up);
}
.pkmd-note h3 {
  font-size: var(--pkmd-fs-h3-em);
  line-height: var(--pkmd-lh-h3);
  letter-spacing: var(--pkmd-tracking-h3);
  font-weight: var(--pkmd-weight-h3);
}
.pkmd-note h4 {
  font-size: var(--pkmd-fs-h4-em);      /* = body size; weight carries it */
  line-height: var(--pkmd-lh-h4);
  letter-spacing: var(--pkmd-tracking-h4);
  font-weight: var(--pkmd-weight-h4);
}
.pkmd-note h5 {
  font-size: var(--pkmd-fs-h5-em);
  line-height: var(--pkmd-lh-h5);
  letter-spacing: var(--pkmd-tracking-h5);
  font-weight: var(--pkmd-weight-h5);
}
.pkmd-note h6 {
  font-size: var(--pkmd-fs-h6-em);
  line-height: var(--pkmd-lh-h6);
  letter-spacing: var(--pkmd-tracking-h6);
  font-weight: var(--pkmd-weight-h6);
  text-transform: uppercase;
  color: var(--pkmd-text-2);                /* 7.56:1 / 9.61:1 */
  font-feature-settings: "case" 1;          /* 45 uc-height punct subs */
}
.pkmd-note > :first-child { margin-block-start: 0; }

/* ── paragraphs ─────────────────────────────────────────────────────────────
   30px gap = one rhythm unit = exactly one blank source line in live
   preview, which is what makes edit and reading mode pixel-identical. */
.pkmd-note p {
  margin-block: 0 var(--pkmd-prose-space-para);
  /* Chromium adjusts only the LAST FOUR LINES of a paragraph, so this is an
     orphan fix, not a rag optimiser. MUST be reset in the editor. */
  text-wrap: pretty;
}
.pkmd-note strong { font-weight: var(--pkmd-weight-strong); }
.pkmd-note :is(h1, h2, h3, h4, h5, h6) strong { font-weight: var(--pkmd-weight-bold); }
.pkmd-note em { font-style: italic; }
/* ==highlight== has its own solved fill in the colour layer, kept on this
   theme's side of L=0.5 so the text on top never needs to change tier. */
.pkmd-note mark {
  background: var(--pkmd-editor-highlight);
  color: var(--pkmd-text-1);
  padding-inline: 0.1em;
  border-radius: 2px;
}

/* ── lists ──────────────────────────────────────────────────────────────────
   Intra-list gaps use a tighter 0/6px sub-scale: list items are lines, not
   blocks, and the 15px rhythm governs block separation only. */
.pkmd-note :is(ul, ol) {
  margin-block: 0 var(--pkmd-prose-space-para);
  padding-inline-start: var(--pkmd-list-indent);       /* 24px per level */
}
.pkmd-note :is(ul, ol) :is(ul, ol) { margin-block: var(--pkmd-list-gap) 0; }
.pkmd-note li { margin-block: 0; text-wrap: pretty; }
.pkmd-note li + li { margin-block-start: var(--pkmd-list-gap); }
.pkmd-note li > p { margin-block: 0; }
.pkmd-note li > p + p { margin-block-start: var(--pkmd-prose-space-para); }
.pkmd-note ul       { list-style-type: disc; }
.pkmd-note ul ul    { list-style-type: circle; }
.pkmd-note ul ul ul { list-style-type: square; }
.pkmd-note ol       { list-style-type: decimal; font-variant-numeric: tabular-nums; }
.pkmd-note ol ol    { list-style-type: lower-alpha; }
.pkmd-note ol ol ol { list-style-type: lower-roman; }
.pkmd-note ::marker { color: var(--pkmd-text-3); }     /* 4.83:1 / 6.13:1 */

/* task lists */
.pkmd-note li:has(> input[type="checkbox"]) { list-style: none; }
.pkmd-note li > input[type="checkbox"] {
  inline-size: 1em; block-size: 1em;
  margin-inline: -1.25em 0.35em;
  vertical-align: baseline;
}
.pkmd-note li[data-task="x"] { color: var(--pkmd-text-2); }

/* ── blockquote ── upright, never italic: italic is not a reading face ───── */
.pkmd-note blockquote {
  margin: var(--pkmd-prose-space-block) 0;
  padding-inline-start: 1.125rem;                      /* 18px */
  border-inline-start: 2px solid var(--pkmd-border-subtle);
  color: var(--pkmd-text-2);
  font-style: normal;
}
.pkmd-note blockquote > :last-child { margin-block-end: 0; }
.pkmd-note blockquote blockquote { margin-block: var(--pkmd-list-gap); }

/* Manual hanging punctuation. `hanging-punctuation` is unsupported in every
   Chromium version, and CSS cannot detect a first character — so
   pkmd-core::render, which knows the first byte of the block, emits
   data-pkmd-hang. Deliberately not attempted for arbitrary inline content. */
.pkmd-note [data-pkmd-hang="dquote"] { text-indent: calc(-1 * var(--pkmd-hang-dquote)); }
.pkmd-note [data-pkmd-hang="cquote"] { text-indent: calc(-1 * var(--pkmd-hang-cquote)); }
.pkmd-note [data-pkmd-hang="squote"] { text-indent: calc(-1 * var(--pkmd-hang-squote)); }

/* ── callouts ───────────────────────────────────────────────────────────── */
.pkmd-note .pkmd-callout {
  margin-block: var(--pkmd-prose-space-block);
  padding: var(--pkmd-rhythm-half) 1.125rem;           /* 15px / 18px */
  border-radius: var(--pkmd-radius-3);
  background: var(--pkmd-surface-2);
}
.pkmd-note .pkmd-callout-title {
  font-size: var(--pkmd-fs-body-sm);
  line-height: var(--pkmd-lh-body-sm);
  font-weight: var(--pkmd-weight-strong);
  letter-spacing: 0;
  margin-block: 0 var(--pkmd-list-gap);
}
.pkmd-note .pkmd-callout > :last-child { margin-block-end: 0; }

/* ── tables ── bleed: a prose measure is not a table measure ─────────────── */
.pkmd-note table {
  margin-block: var(--pkmd-prose-space-block);
  font-size: var(--pkmd-fs-body-sm);
  line-height: var(--pkmd-lh-table);
  font-variant-numeric: tabular-nums;
  border-collapse: collapse;
  inline-size: 100%;
}
.pkmd-note :is(th, td) {
  padding: 0.4375rem 0.75rem;                          /* 7px / 12px */
  border-block-end: 1px solid var(--pkmd-border-subtle);
  text-align: start;
  vertical-align: baseline;
}
.pkmd-note th {
  font-size: var(--pkmd-fs-caption);
  letter-spacing: var(--pkmd-tracking-caption);
  font-weight: var(--pkmd-weight-strong);
  color: var(--pkmd-text-2);
}
.pkmd-note :is(th, td)[data-pkmd-numeric] { text-align: end; }

/* ── code ── no ligatures anywhere, ever ────────────────────────────────────
   font-feature-settings REPLACES an inherited value rather than merging, so
   any rule that sets one tag must restate every tag it still needs. */
.pkmd-note :is(code, kbd, samp, pre) {
  font-family: var(--pkmd-font-mono);
  font-variant-ligatures: none;
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--pkmd-tracking-code);
  font-feature-settings: "calt" 0;
}
.pkmd-note :not(pre) > code {                          /* inline */
  font-size: var(--pkmd-fs-code-em);                   /* 17px at 18px base */
  /* 0.15em vertical padding = 2.55px against 4.99px of half-leading for a
     17px face in a 30px line box, so the pill cannot touch the line above.
     Vertical padding on an inline non-replaced box does not affect line
     height, so this is layout-safe; at tighter line-heights use
     `box-shadow: 0 0 0 0.18em <bg>` instead, which has zero layout cost. */
  padding: 0.15em 0.3em;
  border-radius: var(--pkmd-radius-1);
  background: var(--pkmd-surface-2);
}
.pkmd-note pre {                                       /* block */
  margin-block: var(--pkmd-prose-space-block);
  padding: var(--pkmd-rhythm-half) 1.125rem;
  font-size: var(--pkmd-fs-code-block);                /* 16px, rem: code
                                                          blocks must match
                                                          each other, not
                                                          their nesting */
  line-height: var(--pkmd-lh-code);                    /* 26px */
  tab-size: 2;
  white-space: pre;              /* scroll code, never wrap it */
  overflow-x: auto;
  border-radius: var(--pkmd-radius-3);
  background: var(--pkmd-surface-2);
  /* capacity: 63.1 columns at 640px, 72.8 at the 720px bleed */
}
.pkmd-note pre > code {
  font-size: inherit; padding: 0; background: none; border-radius: 0;
}

/* ── hr ─────────────────────────────────────────────────────────────────── */
/* The separator is the one piece of prose furniture a page's look restyles,
   because it is the only rule the reader reads as the page's own. Both
   custom properties default in `tokens.css`, so with no look applied — and
   over bare `file://` with no app at all — this is the plain solid hairline
   it has always been.

   Each attribute rule sets BOTH channels. A look paints attributes only, so
   there is no inline custom property to supply the style half, and the
   selector is where the pairing lives. */
.pkmd-note hr {
  margin-block: var(--pkmd-prose-space-rule);          /* 45px */
  border: 0;
  border-block-start: var(--pkmd-page-rule-size, 1px)
    var(--pkmd-page-rule-style, solid) var(--pkmd-border-subtle);
}
.pkmd-note[data-pkmd-rule="line"] hr {
  --pkmd-page-rule-size: 1px;
  --pkmd-page-rule-style: solid;
}
.pkmd-note[data-pkmd-rule="dotted"] hr {
  --pkmd-page-rule-size: 2px;
  --pkmd-page-rule-style: dotted;
}
.pkmd-note[data-pkmd-rule="dashed"] hr {
  --pkmd-page-rule-size: 2px;
  --pkmd-page-rule-style: dashed;
}
.pkmd-note[data-pkmd-rule="thick"] hr {
  --pkmd-page-rule-size: 3px;
  --pkmd-page-rule-style: solid;
}

/* ── links ──────────────────────────────────────────────────────────────── */
.pkmd-note a {
  color: var(--pkmd-text-link);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

/* ── assets, transclusions, math ────────────────────────────────────────────
   These five class names come out of `pkmd-core::render` and had ZERO rules in
   any of the three stylesheets, so every image, transclusion and formula in a
   rendered note has been unstyled prose-flow content — a published-page gap
   rather than an editor one, found by `Widgets` while matching its widget DOM
   to the renderer's byte for byte.

   Scoped `.pkmd-note`, not `.cm-editor`: the editor's content root sits inside
   `article.pkmd-note`, so one selector now covers live preview and a page from
   the same declaration. One renderer, one scope — the same reason the
   tag→class `HighlightStyle` in `view.ts` carries no values. */
.pkmd-note img.pkmd-asset {
  max-inline-size: 100%;
  block-size: auto;
  border-radius: var(--pkmd-radius-2);
}
/* `render.rs` picks the element: `div` when the embed owns its line, `span`
   when it is inline, and the class is identical either way. */
.pkmd-note div.pkmd-embed {
  display: block;
  margin-block: var(--pkmd-prose-space-block);
  padding-inline-start: 1.125rem;
  border-inline-start: 2px solid var(--pkmd-border-subtle);
}
.pkmd-note span.pkmd-embed { display: inline; }
.pkmd-note div.pkmd-embed > :last-child { margin-block-end: 0; }
/* An embed's first child is usually a heading, whose `margin-block-start`
   would push it off its own rail. `.pkmd-note > :first-child` already solves
   this for a note; an embed is the same situation one level in. */
.pkmd-note .pkmd-embed > :first-child { margin-block-start: 0; }
/* The five failure modes — unresolved, missing, cycle, too-deep, unsupported —
   all carry `.pkmd-embed-notice` (render.rs:1177). A diagnostic, not prose. */
.pkmd-note .pkmd-embed-notice {
  font-family: var(--pkmd-font-mono);
  font-size: var(--pkmd-fs-ui-xs);
  color: var(--pkmd-warning-text);
}
.pkmd-note :is(.pkmd-embed-unresolved, .pkmd-embed-missing) {
  border-inline-start-color: var(--pkmd-warning-border);
}
/* No math library ships, so the element's own text IS the TeX: this styles
   source, not glyphs, and when MathML Core lands in `render.rs` only the box's
   contents change. */
.pkmd-note :is(.pkmd-math, .pkmd-math-block) {
  font-family: var(--pkmd-font-mono);
  font-size: var(--pkmd-fs-code-em);
  color: var(--pkmd-text-2);
  background: var(--pkmd-surface-2);
  border-radius: var(--pkmd-radius-2);
  padding-inline: var(--pkmd-space-4);
}
.pkmd-note div.pkmd-math-block {
  margin-block: var(--pkmd-prose-space-block);
  padding: var(--pkmd-rhythm-half) 1.125rem;
  text-align: center;
  font-size: var(--pkmd-fs-code-block);
  overflow-x: auto;
}

/* ── small type ─────────────────────────────────────────────────────────────
   text-2 throughout, which clears AA at any size in both themes. No body
   text is in text-3, and text-disabled appears nowhere in this layer. */
.pkmd-caption {
  font-size: var(--pkmd-fs-caption);
  line-height: var(--pkmd-lh-caption);
  letter-spacing: var(--pkmd-tracking-caption);
  color: var(--pkmd-text-2);
}
.pkmd-label {
  font-size: var(--pkmd-fs-label);
  line-height: var(--pkmd-lh-label);
  letter-spacing: var(--pkmd-tracking-label);
  font-weight: var(--pkmd-weight-medium);
  color: var(--pkmd-text-2);
}
.pkmd-label--caps {
  text-transform: uppercase;
  letter-spacing: var(--pkmd-tracking-caps);
  font-feature-settings: "case" 1;
}

/* SF Pro ss06 = measured 57-substitution set (0 4 6 9 I J l disambiguation).
   No-op on Segoe UI Variable / DejaVu — ignored, never a fallback.

   Four app-chrome selectors used to share this rule — `.pkmd-prop-value`,
   `.pkmd-path`, `.pkmd-tree-row` and `.cm-lineNumbers`. None of them can
   appear on a published page or in `pkmd render` output, and this file is the
   CONTENT layer that both of those load. They now live in
   `apps/desktop/src/static/components.css`, where the app's own chrome is. */
.pkmd-tnum { font-variant-numeric: tabular-nums; }

/* ═══════════════════════════════════════════════════════════════════════════
   1b. REPAIRS TO SECTION 1
   ═══════════════════════════════════════════════════════════════════════════

   Rules that belong to the renderer contract but could not be written into the
   verbatim block above without making it diverge from the copy it was
   extracted from. They are here, after it, so section 1 stays byte-identical
   and a `diff` against the bundle sheet still comes back clean.

   `.pkmd-note li[data-task="x"]` (section 1, from bundle components.css:1182)
   is DEAD: `data-task` is emitted by nothing in the product. `render.rs:641`
   writes `class="pkmd-task"` and the checkbox's own `checked` attribute, and
   that is all there is. So a completed task never dimmed, in the app or
   anywhere else. Selecting on what is actually emitted fixes it. Keep the dead
   rule until the bundle copy is deleted; deleting it early would make the two
   copies differ for no gain. */
.pkmd-note li:has(> input[type="checkbox"]:checked) {
  color: var(--pkmd-text-2);
}

/* THE PAGE CANVAS. `.pkmd-note` styles the column and nothing styles what is
   behind it. In the app that is `layout.css`, which a vault page and an export
   never load — so a standalone page painted the UA canvas: literal `#ffffff`
   in light and Chromium's own near-black in dark, measured, against a system
   whose first rule about neutrals is that they are always tinted.
   `--pkmd-surface-page` is warm paper at H65 and cool at H265; neither is what
   the UA picks.

   Guarded by `:has(> .pkmd-note)` so this only fires when the body IS a pkmd
   page. Dropping these stylesheets into a host document that merely embeds a
   note fragment must not repaint that host's background. A background on
   `<body>` propagates to the canvas on its own when `<html>` has none, so one
   declaration covers the whole viewport, including overscroll. */
body:has(> .pkmd-note) {
  margin: 0;                            /* the UA's 8px, which layout.css also drops */
  background: var(--pkmd-surface-page);
}

/* AN UNRESOLVED WIKILINK, RENDERED. `render.rs:1113` emits
   `<a class="pkmd-link pkmd-unresolved" data-target="…">` and `.pkmd-unresolved`
   had no rule anywhere in the product, so a broken link was indistinguishable
   from a working one in reading mode, in an export and on a published page.

   Live preview was covered — `.cm-editor .pkmd-link-unresolved`, bundle
   components.css:1588 — which made this the same edit-versus-read split as the
   callout kinds: the dashed red underline appeared while you typed the link
   and vanished when you stopped. Identical declarations to that rule, so the
   two states match exactly. `[[does-not-exist]]` still reads as a link because
   it is one the moment the note is created; the dashed underline says the file
   is not there yet. */
.pkmd-note a.pkmd-unresolved {
  color: var(--pkmd-editor-unresolved);
  text-decoration-line: underline;
  text-decoration-style: dashed;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

/* THE MEASURE, and the reason this rule is not somewhere tidier.
   `.pkmd-note` sets `max-inline-size: 720px` and `padding-inline: 40px`, which
   is a 640px measure — 75.8 characters at 18px — but only under
   `box-sizing: border-box`. In the app that comes from the universal reset at
   `layout.css:8`. A vault page over `file://` and an export from
   `pkmd render` never load layout.css, so the same article measured 800px
   wide with a 720px measure: 85 characters, 12.5% over the target, and
   nothing in the markup to suggest why.

   Scoped to the article rather than declared as `*`, so dropping these two
   stylesheets into a page that has its own reset cannot fight it. In the app
   it is a no-op. */
.pkmd-note,
.pkmd-note *,
.pkmd-note *::before,
.pkmd-note *::after {
  box-sizing: border-box;
}

/* The renderer disables its checkboxes (`<input type="checkbox" disabled>`) so
   a reader cannot toggle a value that is not written anywhere. The UA's
   disabled styling greys them to the point of vanishing, which reads as
   "broken" rather than "not editable" — restore full opacity and say
   not-allowed on hover instead. */
.pkmd-note li > input[type="checkbox"][disabled] {
  opacity: 1;
  cursor: not-allowed;
}


/* ═══════════════════════════════════════════════════════════════════════════
   2. CALLOUT KINDS
   ═══════════════════════════════════════════════════════════════════════════

   `render.rs:546-554` emits the kind as an ATTRIBUTE — `<aside
   class="pkmd-callout" data-kind="danger" data-fold="open">` — and there were
   no `[data-kind]` rules anywhere in the product, so a `[!danger]` and a
   `[!note]` rendered as the same grey box in reading mode, in `pkmd render`
   and on a published page.

   Live preview did not have that problem: the editor colours callout source
   lines by kind (`.cm-line.pkmd-callout-danger`, bundle components.css
   1625-1644). So a callout was coloured while you typed it and grey the
   instant you stopped — the same edit-versus-read divergence one renderer is
   supposed to make impossible.

   The five families and their tokens are taken from those editor rules
   unchanged, so a callout is now the same colour in both states. Thirteen
   canonical kinds (`callout_kind`, render.rs:1535) map onto five families;
   `note`, `abstract`, `todo`, `example` and `quote` keep the neutral base.
   An unrecognised kind now keeps its own name in `data-kind`, sanitised for
   an attribute value, so a vault can style `[!goal]` from this file. The
   neutral base below is the fallback for every kind with no rule of its own,
   which is why there is no unstyled state to guard against. */
.pkmd-note .pkmd-callout[data-kind="info"],
.pkmd-note .pkmd-callout[data-kind="tip"] {
  background: var(--pkmd-info-subtle);
  box-shadow: inset 2px 0 0 var(--pkmd-info-border);
}
.pkmd-note .pkmd-callout[data-kind="success"] {
  background: var(--pkmd-success-subtle);
  box-shadow: inset 2px 0 0 var(--pkmd-success-border);
}
.pkmd-note .pkmd-callout[data-kind="question"],
.pkmd-note .pkmd-callout[data-kind="warning"] {
  background: var(--pkmd-warning-subtle);
  box-shadow: inset 2px 0 0 var(--pkmd-warning-border);
}
.pkmd-note .pkmd-callout[data-kind="failure"],
.pkmd-note .pkmd-callout[data-kind="danger"],
.pkmd-note .pkmd-callout[data-kind="bug"] {
  background: var(--pkmd-danger-subtle);
  box-shadow: inset 2px 0 0 var(--pkmd-danger-border);
}
/* The neutral kinds get the same 2px edge, so every callout reads as one
   family of object and colour is the only variable. */
.pkmd-note .pkmd-callout {
  box-shadow: inset 2px 0 0 var(--pkmd-border-subtle);
}
/* `data-fold="closed"` is written by the author as `[!note]-`. With no
   script, a closed callout shows its title and nothing else — which is what
   "collapsed" means, and it costs 0 KB to honour. */
.pkmd-note .pkmd-callout[data-fold="closed"] > :not(.pkmd-callout-title) {
  display: none;
}
.pkmd-note .pkmd-callout[data-fold="closed"] > .pkmd-callout-title {
  margin-block-end: 0;
}


/* ═══════════════════════════════════════════════════════════════════════════
   3. AUTHORING COMPONENTS
   ═══════════════════════════════════════════════════════════════════════════

   Nothing in this section is emitted by the renderer. These are the classes a
   human or an agent writes by hand into an `.html` page, or inline into a
   markdown note. Every one of them is a plain element with a class: no custom
   element, no script, no build step, so the page reads identically with
   JavaScript disabled.

   `.pkmd-card`, `.pkmd-badge` and `.pkmd-chip` below are the app's own chrome
   components, copied verbatim from bundle components.css lines 570-648 rather
   than reinterpreted, so a card in a page and a card in the app are the same
   object. Same intermediate state as section 1: two copies until integration
   collapses them to this one. */

/* ---------------------------------------------------------------------------
   CARD — 16px padding, radius 12, one hairline, never nested
------------------------------------------------------------------------------*/
.pkmd-card {
  padding: var(--pkmd-pad-card);
  background: var(--pkmd-surface-1);
  border: var(--pkmd-divider) solid var(--pkmd-border-default);
  border-radius: var(--pkmd-radius-4);
  corner-shape: var(--pkmd-squircle);
  box-shadow: var(--pkmd-shadow-1);
}
.pkmd-card.mod-quiet { background: var(--pkmd-surface-2); box-shadow: none; }
.pkmd-card.mod-interactive { cursor: default; transition: box-shadow var(--pkmd-dur-2) var(--pkmd-ease-out),
                                                          border-color var(--pkmd-dur-2) var(--pkmd-ease-out); }
.pkmd-card.mod-interactive:hover { border-color: var(--pkmd-border-strong); box-shadow: var(--pkmd-shadow-2); }
.pkmd-card.mod-interactive:active { box-shadow: var(--pkmd-shadow-1); }
.pkmd-card.mod-interactive:focus-visible { box-shadow: var(--pkmd-focus-ring); }
.pkmd-card.is-selected { border-color: var(--pkmd-accent-solid); box-shadow: 0 0 0 1px var(--pkmd-accent-solid); }
.pkmd-card[aria-disabled="true"] { opacity: 0.55; pointer-events: none; }
.pkmd-card > .pkmd-card { border: 0; box-shadow: none; padding: 0; background: none; } /* no nested cards */

/* ---------------------------------------------------------------------------
   BADGE / CHIP — 20px, pill; chip is the removable, interactive form
------------------------------------------------------------------------------*/
.pkmd-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--pkmd-space-4);
  height: 20px;
  padding-inline: var(--pkmd-space-8);
  border-radius: var(--pkmd-radius-pill);
  background: var(--pkmd-state-hover);
  color: var(--pkmd-text-2);
  font-family: var(--pkmd-font-ui);
  font-size: var(--pkmd-fs-ui-xs);
  font-weight: var(--pkmd-weight-ui-medium);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pkmd-badge.mod-accent  { background: var(--pkmd-accent-subtle);  color: var(--pkmd-accent-text); }
.pkmd-badge.mod-danger  { background: var(--pkmd-danger-subtle);  color: var(--pkmd-danger-text); }
.pkmd-badge.mod-warning { background: var(--pkmd-warning-subtle); color: var(--pkmd-warning-text); }
.pkmd-badge.mod-success { background: var(--pkmd-success-subtle); color: var(--pkmd-success-text); }
.pkmd-badge.mod-count { min-width: 20px; justify-content: center; padding-inline: var(--pkmd-space-6); }
/* A badge that is a button. The status bar's update notice is the one badge you
   can click, and a <button> arrives with a UA border, background, padding and
   font that would otherwise break the pill — the rule above sets font and
   padding-inline, so only the rest needs resetting. Accent-tinted rather than
   neutral because it is the only badge that is an invitation. */
.pkmd-badge.mod-action {
  appearance: none;
  border: 0;
  padding-block: 0;
  cursor: pointer;
  background: var(--pkmd-accent-subtle);
  color: var(--pkmd-accent-text);
}
.pkmd-badge.mod-action:hover { background: var(--pkmd-state-selected); }
.pkmd-badge.mod-action:focus-visible {
  outline: 2px solid var(--pkmd-state-ring);
  outline-offset: 1px;
}

.pkmd-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--pkmd-space-4);
  /* A FLOOR, not a height: a hierarchical tag (`project/2026/migration-plan`)
     in a 276px sidebar rail wraps, and with a fixed height the wrapped line
     escaped the pill. `max-inline-size` keeps the pill inside its container
     and `overflow-wrap` gives a slash-separated token somewhere to break, so
     one long chip can no longer overflow the panel it sits in. */
  min-height: 22px;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
  padding: 0 var(--pkmd-space-4) 0 var(--pkmd-space-8);
  border: var(--pkmd-divider) solid transparent;
  border-radius: var(--pkmd-radius-pill);
  background: var(--pkmd-state-hover);
  color: var(--pkmd-text-1);
  font-family: var(--pkmd-font-ui);
  font-size: var(--pkmd-fs-ui-sm);
  cursor: default;
  transition: background-color var(--pkmd-dur-1) var(--pkmd-ease-out);
}
.pkmd-chip.mod-plain { padding-inline: var(--pkmd-space-8); }
.pkmd-chip:hover { background: var(--pkmd-state-active); }
.pkmd-chip:active { background: var(--pkmd-state-active); }
.pkmd-chip.is-selected { background: var(--pkmd-state-selected); border-color: var(--pkmd-accent-border); }
.pkmd-chip:focus-visible { box-shadow: var(--pkmd-focus-ring); }
.pkmd-chip[aria-disabled="true"] { color: var(--pkmd-text-3); pointer-events: none; }
.pkmd-chip.is-invalid { background: transparent; border-color: var(--pkmd-danger-solid); color: var(--pkmd-danger-text); }
.pkmd-chip-remove {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--pkmd-text-3);
}
.pkmd-chip-remove:hover { background: var(--pkmd-surface-1); color: var(--pkmd-text-1); }


/* ---------------------------------------------------------------------------
   KBD — a key, not a code span
------------------------------------------------------------------------------
   `.pkmd-kbd` was referenced by the command menu (bundle components.css:738)
   and defined nowhere, so every keyboard hint in the product rendered as
   unstyled inline text. Defined here because a page documenting a shortcut
   needs it just as much as a menu does.

   Height is not fixed: a key sits in running prose and must ride the line box
   it lands in, so the box is em-derived and inherits prose zoom. */
.pkmd-kbd {
  display: inline-block;
  min-inline-size: 1.6em;
  padding: 0.1em 0.4em;
  border: var(--pkmd-divider) solid var(--pkmd-border-default);
  border-block-end-width: 2px;
  border-radius: var(--pkmd-radius-2);
  background: var(--pkmd-surface-1);
  color: var(--pkmd-text-2);
  font-family: var(--pkmd-font-ui);
  font-size: 0.85em;
  font-weight: var(--pkmd-weight-ui-medium);
  font-variant-ligatures: none;
  line-height: 1.4;
  text-align: center;
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   GRID — the one multi-column primitive
------------------------------------------------------------------------------
   `auto-fill` with a minimum, never a fixed column count: a prose column is
   640px and a full-width page is not, and the same markup has to survive both
   without the author choosing. `--pkmd-grid-min` is the only knob, set inline
   when a page needs wider or narrower cells.

   Deliberately not a `.pkmd-cols-2` / `-3` family. A fixed count is a
   breakpoint by another name, and it is what turns a page into the identical
   three-card grid every generated site has. */
.pkmd-grid {
  /* Declared on the component, not on :root. An author knob is not a design
     token — it has no value until a component needs one — but every
     `var(--pkmd-*)` in a shipped file must still resolve, and a fallback
     inside `var()` does not satisfy that check. Declaring it here does, and
     an inline `style="--pkmd-grid-min: 180px"` still overrides it. */
  --pkmd-grid-min: 220px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--pkmd-grid-min), 1fr));
  gap: var(--pkmd-space-12);
  margin-block: var(--pkmd-prose-space-block);
}

/* ---------------------------------------------------------------------------
   STACK — vertical rhythm without touching margins
------------------------------------------------------------------------------
   The prose layer sets `margin-block-end` on every block, which is right for
   prose and wrong inside a card, where the last child's margin escapes the
   padding box. `.pkmd-stack` owns the gap instead and zeroes the children. */
.pkmd-stack {
  --pkmd-gap: var(--pkmd-space-8);      /* author knob; see .pkmd-grid above */
  display: flex;
  flex-direction: column;
  gap: var(--pkmd-gap);
}
.pkmd-stack > * { margin-block: 0; }

/* ---------------------------------------------------------------------------
   ROW — horizontal, wrapping, baseline-agnostic
------------------------------------------------------------------------------
   For a line of badges, chips or keys. Wraps by default: a row of tags that
   overflows its column is the most common way a generated page breaks on a
   narrow window. */
.pkmd-row {
  --pkmd-gap: var(--pkmd-space-6);      /* author knob; see .pkmd-grid above */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--pkmd-gap);
}

/* ---------------------------------------------------------------------------
   LEDE — the one paragraph allowed to be larger than body
------------------------------------------------------------------------------
   There is no `body-lg` step in the scale and that is not an omission: across
   1998 real notes h5 and h6 measured ZERO uses, so the scale decelerates
   upward from body and has nothing between body (18px) and h3 (21px). A lede
   therefore borrows the h3 step deliberately, and takes the BODY line-height
   rather than h3's 1.25 — 1.25 is a heading's leading and unreadable over
   three lines of prose.

   text-2 rather than text-1, normal weight. Not bold, not centred, not
   accent-coloured: a lede is a paragraph read first, not a banner. */
.pkmd-lede {
  font-size: var(--pkmd-fs-h3-em);
  line-height: var(--pkmd-lh-body);
  color: var(--pkmd-text-2);
  text-wrap: pretty;
}

/* ---------------------------------------------------------------------------
   FIGURE — an image or table with its caption bound to it
------------------------------------------------------------------------------
   `.pkmd-caption` already exists in the prose layer above; this is the box
   that puts it under something and keeps the pair together. */
.pkmd-figure {
  margin-block: var(--pkmd-prose-space-block);
  margin-inline: 0;
}
.pkmd-figure > :is(img, svg, video) {
  display: block;
  max-inline-size: 100%;
  block-size: auto;
  border-radius: var(--pkmd-radius-2);
}
.pkmd-figure > figcaption {
  margin-block-start: var(--pkmd-space-6);
  font-size: var(--pkmd-fs-caption);
  line-height: var(--pkmd-lh-caption);
  letter-spacing: var(--pkmd-tracking-caption);
  color: var(--pkmd-text-2);
}

/* ---------------------------------------------------------------------------
   META — the dateline under a page title
------------------------------------------------------------------------------
   Separators are `::before` on the sibling rather than characters in the
   markup, so an author can add or drop an item without repairing punctuation
   and a screen reader never announces a middot. */
.pkmd-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--pkmd-space-8);
  font-size: var(--pkmd-fs-caption);
  line-height: var(--pkmd-lh-caption);
  color: var(--pkmd-text-2);
}
.pkmd-meta > * + *::before {
  content: "";
  display: inline-block;
  inline-size: 3px;
  block-size: 3px;
  margin-inline-end: var(--pkmd-space-8);
  border-radius: 50%;
  background: var(--pkmd-text-3);
  vertical-align: middle;
}

/* ---------------------------------------------------------------------------
   ICON — sizing for an inline SVG
------------------------------------------------------------------------------
   Optical weight is held at 1.5px on the 24 grid at every size, which is the
   single thing that separates this icon set from the same Lucide set rendered
   badly: stroke-width must scale INVERSELY with the box or the counters in
   `square-check` and `calendar-clock` fill in below 16px.

   `<use href="#id">` must point at a sprite in the SAME document. An external
   `<use href="icons.svg#id">` resolves to zero width over `file://` with no
   console error at all — the element exists, has a computed width, and paints
   nothing. Paste the sprite into the page. */
.pkmd-icon {
  display: inline-block;
  vertical-align: text-bottom;
  inline-size: var(--pkmd-icon-md);
  block-size: var(--pkmd-icon-md);
  stroke-width: var(--pkmd-icon-md-stroke);
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* `<use>` inherits paint from the REFERENCING svg, not the symbol. Without
     the two declarations above an icon renders as a solid blob. */
}
.pkmd-icon.mod-xs { inline-size: var(--pkmd-icon-xs); block-size: var(--pkmd-icon-xs); stroke-width: var(--pkmd-icon-xs-stroke); }
.pkmd-icon.mod-sm { inline-size: var(--pkmd-icon-sm); block-size: var(--pkmd-icon-sm); stroke-width: var(--pkmd-icon-sm-stroke); }
.pkmd-icon.mod-lg { inline-size: var(--pkmd-icon-lg); block-size: var(--pkmd-icon-lg); stroke-width: var(--pkmd-icon-lg-stroke); }
/* Inside prose the box is derived from the text it sits in, not from the UI
   ladder, or an icon in a 21px lede is the same size as one in a caption. */
.pkmd-icon.mod-prose { inline-size: var(--pkmd-icon-prose); block-size: var(--pkmd-icon-prose); stroke-width: var(--pkmd-icon-prose-stroke); }

/* The sprite host itself. Not `display:none`, which in some engines has
   stopped `<use>` resolving; a zero box that still participates in layout
   is the portable form. */
.pkmd-sprite {
  position: absolute;
  inline-size: 0;
  block-size: 0;
  overflow: hidden;
}

/* A custom callout kind, and the proof that one can be styled at all.

   `> [!goal] Q3 · target 40` is the reference corpus's own invented type —
   semantically a property wearing presentation, 17 occurrences. `render.rs`
   used to coerce every unrecognised kind to `data-kind="note"`, so this rule
   was unwritable. It is here rather than in section 2 because section 2 holds
   the thirteen kinds Rust canonicalises and this is a vault's own addition:
   copy it, rename the kind, pick a different accent. */
.pkmd-note .pkmd-callout[data-kind="goal"] {
  background: var(--pkmd-accent-subtle);
  box-shadow: inset 2px 0 0 var(--pkmd-accent-border);
}


/* ═══════════════════════════════════════════════════════════════════════════
   CUSTOM ELEMENTS — owner: LayoutChrome
   ───────────────────────────────────────────────────────────────────────────
   The `<pkmd-*>` tags. These rules exist for a reason that is easy to miss and
   expensive to rediscover: **an unknown element's default `display` is
   `inline`**. So `<pkmd-grid>` with no rule here is not "a grid with no
   styling", it is an inline box that stacks its children as text and ignores
   every grid property set on it. The matching `.pkmd-grid` classes above do
   not help, because the element carries no class.

   Everything here therefore does one of exactly two jobs:

     1. Give an element a `display` and inherit the behaviour its class
        already defines, so `<pkmd-grid>` and `<div class="pkmd-grid">` are
        the same box. The declarations are duplicated rather than shared
        through `:is()` because a selector list of an unknown element name and
        a class is still valid CSS in every engine that matters, but the
        duplication is three lines and the indirection is a puzzle.

     2. Supply a label that JavaScript cannot. An attribute on an *undefined*
        element is invisible to a reader — `<pkmd-tab label="Bash">` renders
        its children and drops the label entirely — so the no-JavaScript
        reading of a tab strip has no headings unless CSS puts them there with
        `content: attr(label)`. `pkmd-components.js` sets `data-pkmd-ready` on
        the host once it upgrades, so these rules apply *only* before or
        without script, and the upgraded component draws its own tab strip.

   `--pkmd-grid-min` and `--pkmd-gap` are declared on the component and never
   on `:root`, which is the existing convention above and the reason an author
   can set them per instance.
   ═══════════════════════════════════════════════════════════════════════════ */

pkmd-grid {
  display: grid;
  --pkmd-grid-min: 220px;
  --pkmd-gap: var(--pkmd-space-16);
  gap: var(--pkmd-gap);
  grid-template-columns: repeat(auto-fill, minmax(var(--pkmd-grid-min), 1fr));
}

pkmd-stack {
  display: flex;
  flex-direction: column;
  --pkmd-gap: var(--pkmd-space-8);
  gap: var(--pkmd-gap);
}
pkmd-stack > * { margin-block: 0; }

pkmd-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  --pkmd-gap: var(--pkmd-space-8);
  gap: var(--pkmd-gap);
}

pkmd-card {
  display: block;
  padding: var(--pkmd-pad-card);
  background: var(--pkmd-surface-1);
  border: var(--pkmd-divider) solid var(--pkmd-border-default);
  border-radius: var(--pkmd-radius-4);
  corner-shape: var(--pkmd-squircle);
  box-shadow: var(--pkmd-shadow-1);
}

/* Layout primitives are containers, so a bare one with nothing in it is a gap
   in the page rather than an element. Collapsing it is what lets a template
   place `<pkmd-grid>{{projects}}</pkmd-grid>` and have the region disappear on
   a site with no projects, without a conditional. */
pkmd-grid:empty,
pkmd-stack:empty,
pkmd-row:empty { display: none; }

/* --- the no-JavaScript reading of a composite component ------------------ */

/* A tab strip degrades to every panel, stacked, each under its own heading.
   The heading can only come from `attr(label)`, and only while the element is
   un-upgraded — after that `pkmd-components.js` owns the strip. */
pkmd-tabs:not([data-pkmd-ready]) { display: block; }
pkmd-tabs:not([data-pkmd-ready]) > pkmd-tab {
  display: block;
  margin-block-end: var(--pkmd-space-16);
}
pkmd-tabs:not([data-pkmd-ready]) > pkmd-tab[label]::before {
  content: attr(label);
  display: block;
  margin-block-end: var(--pkmd-space-2);
  font-weight: var(--pkmd-weight-h4);
  color: var(--pkmd-text-1);
}

/* Same argument for a disclosure. The upgraded form is a real button plus an
   animated panel; the un-upgraded form is the summary text followed by the
   content, which is exactly what a native `<details open>` looks like. */
pkmd-details:not([data-pkmd-ready]) { display: block; }
pkmd-details:not([data-pkmd-ready])[summary]::before {
  content: attr(summary);
  display: block;
  font-weight: var(--pkmd-weight-h5);
  color: var(--pkmd-text-1);
}

/* A theme toggle is the one component whose fallback is *nothing*: the OS
   preference already decides, so a dead control would be worse than an absent
   one. It appears only once script has upgraded it. */
pkmd-theme-toggle:not([data-pkmd-ready]) { display: none; }

/* A transient state a component sets on itself while it waits on the network.
   Opacity and a cursor only — no layout property, per the motion rules in
   85-motion.css. */
[data-pkmd-state="busy"] {
  opacity: 0.6;
  cursor: progress;
  transition: opacity var(--pkmd-dur-2) var(--pkmd-ease-out);
}
@media (prefers-reduced-motion: reduce) {
  [data-pkmd-state="busy"] { transition: none; }
}
