/* ═══════════════════════════════════════════════════════════════════════════
   pkmd — DESIGN TOKENS.  The product's contract.
   ───────────────────────────────────────────────────────────────────────────
   These exact bytes are (a) copied into the app bundle by
   apps/desktop/build.mjs, (b) seeded into every new vault's design/ folder,
   and (c) linked by published pages. App chrome, a vault opened in a bare
   browser over file://, and a published page therefore read ONE file. The
   rules that keeps that true, and that nothing here may violate:

     1. NO TOKEN DEPENDS ON A RUNTIME VALUE. Accents are literal oklch() with
        a variable hue channel; the app never injects colour channels.
     2. 1rem = 16px. `html` carries `font-size: 100%` and nothing else. A rem
        authored against a 13px or 14px root is wrong: it renders ~14% larger
        on a file:// page (browser default 16px) than in the app, silently.
     3. Dark mode is `@media (prefers-color-scheme: dark)` scoped to
        `:root:not([data-theme="light"])`, plus a `:root[data-theme="dark"]`
        block after it. `color-scheme` is declared in every theme block —
        that, not CSS source order, is what prevents the dark-mode white
        flash on first paint.
     4. LIGHT IS THE UNCONDITIONAL DEFAULT, so a browser with no media-query
        support still gets a complete, valid theme.
     5. Interaction states are explicit `oklch(L C H / α)`, never
        `color-mix()` with a `var()` operand: a hand-edited vault token file
        that misspells a referenced token invalidates the whole declaration
        and drops the state with no error.

   Sections, in load order, each owned by exactly one author:
     0. BUNDLED FACES ................ TypeSystem
     1. FONTS AND TYPE SCALE ......... TypeSystem
     2. GEOMETRY, DENSITY, CHROME .... LayoutChrome
     3. MOTION AND ELEVATION ......... MotionDepth
     4. COLOUR ....................... ColorSystem  (verified against
                                        rendered pixels; values untouched)
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════════════════
   0. BUNDLED FACES — owner: TypeSystem
   ───────────────────────────────────────────────────────────────────────────
   Three families, all OFL-1.1, all variable, all in `design/fonts/` beside
   this file. `url()` is RELATIVE, which is the whole trick: it resolves to
   `app://pkmd.local/fonts/…` from the bundled `dist/tokens.css`, to
   `<vault>/design/fonts/…` from a vault copy, and to a note-relative path in
   a `--document` export. There is no per-consumer list to keep in step.

   `font-display: block`, not `swap`: these are local files that load in
   milliseconds, and `swap` would flash a system face on every launch.

   Latin subsets. A vault needing latin-ext, Greek or Cyrillic swaps the six
   files for the same subset from the same upstream packages; this block is
   the only edit.
   ═══════════════════════════════════════════════════════════════════════════ */
@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: block;
  src: url("fonts/InterVariable.woff2") format("woff2");
}
@font-face {
  font-family: "Inter Variable";
  font-style: italic;
  font-weight: 100 900;
  font-display: block;
  src: url("fonts/InterVariable-Italic.woff2") format("woff2");
}
/* Two axes, `opsz` and `wght` — which is what `font-optical-sizing: auto` on
   `.pkmd-note` spends, across a prose scale that spans 15px to 34px. */
@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 200 900;
  font-display: block;
  src: url("fonts/Literata.woff2") format("woff2");
}
@font-face {
  font-family: "Literata";
  font-style: italic;
  font-weight: 200 900;
  font-display: block;
  src: url("fonts/Literata-Italic.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: block;
  src: url("fonts/JetBrainsMono.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: italic;
  font-weight: 100 800;
  font-display: block;
  src: url("fonts/JetBrainsMono-Italic.woff2") format("woff2");
}


/* ═══════════════════════════════════════════════════════════════════════════
   1. FONTS AND TYPE SCALE — owner: TypeSystem
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* ── families ────────────────────────────────────────────────────────────
     Generics LEAD, deliberately. Apple's system faces are dot-prefixed
     hidden families — SFNS.ttf is `.SF NS`, SFNSMono.ttf `.SF NS Mono`,
     NewYork.ttf `.New York` (read from nameID 1) — so "SF Pro Text",
     "SF Mono" and "New York" CANNOT match the system copies. Only the
     generics reach them.

     `system-ui` before `-apple-system`: measured, `-apple-system` and
     `ui-sans-serif` can match NOTHING (byte-identical metrics to a
     deliberately nonexistent family, i.e. they fell through to the engine's
     Times-metric last resort) while `system-ui` resolved genuine SF Pro at
     cap 1443/2048. Once nothing matches, no later entry runs — so every
     stack needs at least one guaranteed-match entry per platform. The
     shipped app.css previously led with `-apple-system`, which is why this
     is called out rather than assumed. */

  --pkmd-font-ui:
      "Segoe UI Variable Text",  /* Win 11 only; absent elsewhere, safe first */
      system-ui,                 /* standard generic; real SF Pro on macOS    */
      -apple-system,             /* WebKit spelling, for file:// in Safari    */
      BlinkMacSystemFont,        /* legacy Blink alias                        */
      "Segoe UI",                /* Win 10                                    */
      "Noto Sans", "DejaVu Sans", sans-serif,
      "Apple Color Emoji", "Segoe UI Emoji";

  /* ── the three prose faces ───────────────────────────────────────────────
     Exactly three, shared by the vault default (`proseFamily`) and by a
     page's own `data-prose`. Each leads with the bundled face and keeps a
     system tail, so a published page that never fetched the woff2 degrades
     to SF/Segoe/Georgia rather than breaking.

     `--pkmd-font-ui` is deliberately NOT one of them: the chrome keeps the
     system face, and only prose gets a bundled family. */
  --pkmd-font-prose-sans:
      "Inter Variable",
      "Segoe UI Variable Text", system-ui, -apple-system, BlinkMacSystemFont,
      "Segoe UI", "Noto Sans", "DejaVu Sans", sans-serif;

  /* Charter + Iowan Old Style carry ordinary (name-reachable) families and
     are what actually catch a ui-serif fallback on macOS. "New York" is kept
     only for users who installed Apple's standalone download. */
  --pkmd-font-prose-serif:
      "Literata",
      ui-serif, "New York", Charter, "Iowan Old Style",
      Georgia, "Noto Serif", "DejaVu Serif", serif;

  /* An alias, so all three prose names exist and `shared/appearance.ts` can
     write `var(--pkmd-font-prose-${family})` without a special case. */
  --pkmd-font-prose-mono: var(--pkmd-font-mono);

  /* The default reading face, with prose size/tracking. */
  --pkmd-font-prose: var(--pkmd-font-prose-sans);

  /* JetBrains Mono leads, bundled. `calt` is off in `components.css`, so the
     face's ligatures never fire. "Cascadia Mono" not Cascadia Code: enforces
     no-ligatures at the font level. SF Mono has no `liga`/`calt` at all, so
     macOS has none either. Courier / Courier New are NEVER named: measured
     x-heights 0.4512 and 0.4229 against SF Mono's 0.5259 would render inline
     code at 75.8% of the prose x-height. Liberation Mono + Noto Sans Mono
     guard the bare generic on minimal Linux installs, which can resolve to
     Nimbus Mono or Courier. */
  --pkmd-font-mono:
      "JetBrains Mono",
      ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", "Roboto Mono",
      Menlo, Consolas, "Liberation Mono", "Noto Sans Mono", "DejaVu Sans Mono",
      monospace;

  /* ── size scale, rem (root 16px) ──────────────────────────────────────────
     Decelerating, deliberately NOT a strict modular scale. Successive heading
     ratios 1.308 / 1.238 / 1.167 / 1.125 / 1.067. Measured heading usage
     across 1998 real vault files: h1 1502, h2 9809, h3 3618, h4 80, h5 0,
     h6 0 — h2 alone is 65% of all headings and h5/h6 are never used, so size
     carries h1-h3 and weight/tracking/case carry h4-h6. */
  --pkmd-fs-h1:         2.1250rem;   /* 34px */
  --pkmd-fs-h2:         1.6250rem;   /* 26px */
  --pkmd-fs-h3:         1.3125rem;   /* 21px */
  --pkmd-fs-h4:         1.1250rem;   /* 18px */
  --pkmd-fs-h5:         1.0000rem;   /* 16px */
  --pkmd-fs-h6:         0.9375rem;   /* 15px */
  --pkmd-fs-body:       1.1250rem;   /* 18px — prose base */
  --pkmd-fs-body-sm:    1.0000rem;   /* 16px */
  --pkmd-fs-caption:    0.8125rem;   /* 13px */
  --pkmd-fs-label:      0.7500rem;   /* 12px */
  --pkmd-fs-code:       1.0625rem;   /* 17px — inline; SF Mono x-height 0.5259
                                        vs SF Pro Text 0.5264 is a 0.1% match
                                        at equal size, so only a small
                                        reduction is affordable */
  --pkmd-fs-code-block: 1.0000rem;   /* 16px — buys 72.8 cols at the 720px
                                        bleed, where 17px gives only 68.5 */
  --pkmd-fs-marker:     0.6875rem;   /* 11px — live-preview source markers.
                                        rem, NOT em: markers are chrome
                                        affordances in fixed geometry owned by
                                        LayoutChrome, so they must not scale
                                        with prose zoom. At 11px the widest
                                        real marker '#####' is 34.0px against
                                        a 35px usable rail; em-based it would
                                        be 42.5px at 1.25x and 51.0px at 1.5x
                                        and overflow. Holding it in rem also
                                        removes every dependency between
                                        --pkmd-prose-zoom and
                                        --pkmd-gutter-marker. */

  /* chrome ladder: 14/13/12. --pkmd-fs-caption and --pkmd-fs-label coincide
     by value with -ui-sm / -ui-xs today and stay separate by role:
     caption/label are content tiers that ride --pkmd-prose-zoom, the -ui-*
     tiers ride --pkmd-ui-zoom. Same number now, different owner later. */
  --pkmd-fs-ui-lg:      1.0000rem;   /* 16px — palette input, modal title */
  --pkmd-fs-ui:         0.8750rem;   /* 14px — the chrome base */
  --pkmd-fs-ui-sm:      0.8125rem;   /* 13px */
  --pkmd-fs-ui-xs:      0.7500rem;   /* 12px */
  --pkmd-fs-mono:       0.8125rem;   /* 13px — chrome monospace: terminal
                                        body, vault paths, diagnostics. Rides
                                        --pkmd-ui-zoom, not prose zoom. */

  /* ── size scale, em — mirrors the rem family so --pkmd-prose-zoom
        propagates through the whole prose block. CSS calc() cannot divide by
        a length, so these are explicit rather than derived. ─────────────── */
  --pkmd-fs-h1-em:      1.8889em;    /* 34/18 */
  --pkmd-fs-h2-em:      1.4444em;    /* 26/18 */
  --pkmd-fs-h3-em:      1.1667em;    /* 21/18 */
  --pkmd-fs-h4-em:      1.0000em;    /* 18/18 */
  --pkmd-fs-h5-em:      0.8889em;    /* 16/18 */
  --pkmd-fs-h6-em:      0.8333em;    /* 15/18 */
  --pkmd-fs-code-em:    0.9444em;    /* 17/18 */
  --pkmd-fs-caption-em: 0.7222em;    /* 13/18 */

  /* ── zoom multipliers. NEVER implement a text-size preference as root
        font-size; it breaks the rem invariant in the file header. Two
        independent controls, neither touching `html`:
          body       { font-size: calc(var(--pkmd-fs-ui)   * var(--pkmd-ui-zoom)) }
          .pkmd-note { font-size: calc(var(--pkmd-fs-body) * var(--pkmd-prose-zoom)) }
     ───────────────────────────────────────────────────────────────────── */
  --pkmd-ui-zoom:    1;              /* chrome only */
  --pkmd-prose-zoom: 1;              /* the note only */

  /* ── line heights. Unitless throughout, so switching prose family never
        changes the line box. ────────────────────────────────────────────── */
  --pkmd-lh-h1:      1.15;           /* 39.10px at 34px */
  --pkmd-lh-h2:      1.20;           /* 31.20px at 26px */
  --pkmd-lh-h3:      1.25;           /* 26.25px at 21px */
  --pkmd-lh-h4:      1.35;           /* 24.30px at 18px */
  --pkmd-lh-h5:      1.40;           /* 22.40px at 16px */
  --pkmd-lh-h6:      1.40;           /* 21.00px at 15px */
  --pkmd-lh-body:    1.6667;         /* 30.00px at 18px — THE rhythm unit */
  --pkmd-lh-body-sm: 1.625;          /* 26.00px at 16px */
  --pkmd-lh-caption: 1.5385;         /* 20.00px at 13px */
  --pkmd-lh-label:   1.25;           /* 15.00px at 12px */
  --pkmd-lh-code:    1.625;          /* 26.00px at 16px */
  --pkmd-lh-table:   1.40;           /* 22.40px at 16px */
  --pkmd-lh-ui:      1.4285714;      /* 20.00px at 14px. An integer chrome
                                        line box on purpose: LayoutChrome
                                        measured 13px x 1.45 = 18.85px, which
                                        rendered a 36.5px list row — half a
                                        pixel off the density ladder and a
                                        visible seam against the 30px tree
                                        rows beside it. */

  /* ── tracking ─────────────────────────────────────────────────────────── */
  --pkmd-tracking-h1:      -0.02em;
  --pkmd-tracking-h2:      -0.015em;
  --pkmd-tracking-h3:      -0.01em;
  --pkmd-tracking-h4:      -0.005em;
  --pkmd-tracking-h5:       0em;
  --pkmd-tracking-h6:       0.06em;  /* uppercase */
  --pkmd-tracking-body:     0em;
  --pkmd-tracking-caption:  0.005em;
  --pkmd-tracking-label:    0.01em;
  --pkmd-tracking-caps:     0.06em;
  --pkmd-tracking-code:     0em;     /* never track a monospace grid */

  /* ── weights ──────────────────────────────────────────────────────────────
     Two ladders. The prose ladder (regular/medium/strong/bold + h1-h6) is
     TypeSystem's and is re-derived in dark mode below. The -ui- ladder is the
     chrome's: SF Pro is variable, and 560/590/620 are the weights that read
     as "slightly emphasised / label / title" at 12-16px without jumping to a
     visible semibold. Static fallbacks snap these to 500/600, harmlessly. */
  --pkmd-weight-regular:   400;
  --pkmd-weight-medium:    500;
  --pkmd-weight-strong:    600;
  --pkmd-weight-bold:      700;
  --pkmd-weight-h1: 700;
  --pkmd-weight-h2: 600;
  --pkmd-weight-h3: 600;
  --pkmd-weight-h4: 600;
  --pkmd-weight-h5: 600;
  --pkmd-weight-h6: 600;
  --pkmd-weight-ui-medium: 560;      /* selected row, active tab, crumb */
  --pkmd-weight-ui-strong: 590;      /* panel head, toast title, uppercase */
  --pkmd-weight-ui-bold:   620;      /* modal title, empty-state title */
  --pkmd-weight-display:   680;      /* the note title, and only that */

  /* ── rhythm. 30px unit = the body line box; everything is a 15px multiple.
        No strict baseline grid: images, code and tables have content-
        determined heights, so enforcing one only yields arbitrary gaps. ─── */
  --pkmd-rhythm:             1.8750rem;   /* 30px */
  --pkmd-rhythm-half:        0.9375rem;   /* 15px */
  /* The prose rhythm is 15px and the chrome ladder is 4px, so these five
     values are NOT --pkmd-space-*: that ladder is a closed enumerated set
     where every member is named for its own px value (--pkmd-space-2 IS 2px),
     and 30 and 45 are not on it. Putting two incompatible rhythms in one
     namespace is what the rename avoids. */
  --pkmd-prose-space-para:   1.8750rem;   /* 30px — EQUALS a blank editor
                                             line, which is what makes edit
                                             and reading mode pixel-identical */
  --pkmd-prose-space-h-up:   2.8125rem;   /* 45px — h1/h2. Collapses against
                                             the paragraph's 30px to 45px;
                                             the editor reaches the same 45px
                                             as 30px blank line + 15px
                                             padding-block-start */
  --pkmd-prose-space-h-down: 0.9375rem;   /* 15px — space belongs below */
  --pkmd-prose-space-block:  1.8750rem;   /* 30px — quote/callout/table/code */
  --pkmd-prose-space-rule:   2.8125rem;   /* 45px — hr */
  --pkmd-list-indent:        1.5000rem;   /* 24px per level */
  --pkmd-list-gap:           0.3750rem;   /* 6px — list items are lines, not
                                             blocks, so they get a tighter
                                             sub-scale than the 15px rhythm */
  --pkmd-marker-gap:         0.3125rem;   /* 5px — rail to text edge */

  /* Derived text measure, for published pages that lack the app's box model.
     720px column − 2 × 40px marker gutter = 640px = 75.8 characters at 18px.
     NOT in `ch`: SF Pro's '0' is 34% wider than its average character, so the
     same 640px is 56.4ch but 75.8 actual characters. */
  --pkmd-measure: 640px;

  /* Manual hanging punctuation. `hanging-punctuation` is unsupported in EVERY
     Chromium version (Safari only), so it is not used. pkmd-core::render
     knows the first byte of each block and emits data-pkmd-hang; these are
     the measured advances in SF Pro Text at opsz 17. */
  --pkmd-hang-dquote: 0.4775em;   /* " U+0022 */
  --pkmd-hang-cquote: 0.4590em;   /* “ U+201C */
  --pkmd-hang-squote: 0.2969em;   /* ‘ U+2018 */
}

/* Graduated heading weights only where the font can actually interpolate.
   On static fallbacks these snap to 600, which is why the SIZE steps carry
   the hierarchy rather than the weights. */
@supports (font-variation-settings: normal) {
  :root {
    --pkmd-weight-h2: 660;
    --pkmd-weight-h3: 620;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   2. GEOMETRY, DENSITY, CHROME — owner: LayoutChrome
   Every value is numeric and verified by rendering in the target engine,
   Electron 44.1.1 / Chromium 152.0.7977.65, macOS 25.6, dppx 2, across ten
   states (1440/1040/860/560 px, light/dark, comfortable/compact,
   left-collapsed, fullscreen, Windows, window-inactive).
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── window chrome ───────────────────────────────────────────────────────
     Measured, macOS 25.6 via AppKit (xcrun swift,
     NSWindow.standardWindowButton): buttons are 14x14pt, origins x=9/32/55
     (23pt pitch), y=9, in a 32pt band. With Electron
     trafficLightPosition {x:19, y:15} the group spans x 19->79pt and
     y 15->29pt, i.e. exactly centred in a 44px band ((44-14)/2 = 15).
     `zoom.ts` carries that 44 as `BAND_H` and `windows.ts` imports it: main
     cannot read this file, so the two values are kept in step by hand.

     44 rather than the 40 this shipped with: a 28px control in a 40px band
     left 6px of air and every chrome row read as crammed against the island's
     edge. 48 was tried first and was too loose - 8px above and below a 28px
     control is more air than the row is worth.
     px, never rem: this is device geometry pinned to the OS window, and a rem
     would let a stray root font-size move the traffic lights off centre. */
  --pkmd-titlebar-h: 44px;
  --pkmd-traffic-reserve: 84px;          /* 79pt group + 5pt clearance */

  /* ── shell style ──────────────────────────────────────────────────────────
     0px is the flush, bordered grid this app has always drawn: panes meet on
     a divider and the grid fills the window. 8px is the floating style, where
     every pane becomes a card inset from the window edge and the gap is where
     the background layer below shows through. `--pkmd-shell-gap` is the ONE
     value the two styles differ by; everything else derives from it.

     The card radius is concentric with the window's own: two rounded corners
     only stay parallel if their radii differ by the gap between them, or the
     gap visibly fattens through the arc. Three refinements over the textbook
     `outer - gap`, all taken from Zen's shipped implementation: a 5px floor so
     a large gap cannot square the corner, HALF the gap subtracted (softer, and
     it holds up when the gap grows), and the squircle factor applied last
     because a superellipse of the same nominal radius reads visually smaller.
     1.33 is --pkmd-squircle's own exponent. */
  --pkmd-shell-gap: 0px;
  --pkmd-window-radius: 10px;            /* macOS. layout.css overrides win/linux to 8px. */
  --pkmd-card-radius: max(5px, calc((var(--pkmd-window-radius) - var(--pkmd-shell-gap) / 2) * 1.33));

  /* ── shell geometry ───────────────────────────────────────────────────────
     264 = 12 left pad + 16 chevron + 4 gap + 174 label + 12 scrollbar + 46 of
     depth-4 indent at 12px/level; 174px holds ~26 characters at 13px.
     300px is the narrowest right sidebar that fits a two-column properties
     row without wrapping.
     Right min 240 is where the properties grid still fits a 132px key plus a
     96px value before the container query stacks it. */
  --pkmd-sidebar-l-w: 264px;
  --pkmd-sidebar-l-min: 180px;
  --pkmd-sidebar-l-max: 480px;
  --pkmd-sidebar-r-w: 300px;
  --pkmd-sidebar-r-min: 240px;
  --pkmd-sidebar-r-max: 480px;
  --pkmd-editor-min-w: 400px;
  /* The narrowest the note column may be squeezed to before the sidebars
     start giving way, and the pivot the shell grid's shrink order turns on:
     the editor track gives up space down to this, then the right sidebar,
     then the left. Distinct from `--pkmd-editor-min-w` above, which is the
     comfortable measure a pane asks for and the terminal's own flex basis.

     Using THAT as the grid's track floor is what made a pushing layout
     impossible, and the failure is worth the line. Measured in Electron
     44.1.1 at the app's own 640px window minimum, with the previous template
     `264px / minmax(400px, 1fr) / 300px`: the tracks resolved to 264 + 400 +
     300, the inspector's box sat at x 664->964 — entirely outside a 640px
     viewport — `documentElement.scrollWidth - clientWidth` was 0, and
     `scrollLeft = 300` left `scrollLeft` at 0. `html` and `body` are
     `overflow: clip`, so an overflowing grid creates no scrollport: the
     column is not off to the side, it is unreachable. That is why the
     sidebars used to leave the grid and float over the note instead.

     240 is `--pkmd-sidebar-r-min`, the narrowest column this design already
     commits to being readable. Measured at a 600px window with both panels
     open, it holds a 176px note column: 240 less the 2 x 20px `--pkmd-gutter`
     a <=600px window uses and the scroller's 2 x 12px stable gutter. */
  --pkmd-editor-floor: 240px;
  /* Space between two panes, and the radius each one carries. Both are 0 in
     the FLUSH shell style, where panes meet on a divider and the window reads
     as one surface; `layout.css` raises both under
     `:root[data-shell="floating"]`, where a pane becomes a card and the gap is
     what lets the background layer show between them. Declared here — at 0 —
     so a `design/` page opened over `file://` resolves them like every other
     token instead of inheriting nothing. */
  --pkmd-pane-gap: 0px;
  --pkmd-pane-radius: 0px;
  /* How narrow a divider drag may leave a pane. The grid tracks themselves
     have a floor of 0, so a window resize always fits every open pane; this
     is the clamp on the drag alone. 360 holds the 720px measure at half its
     width plus both gutters; 180 is two heading rows and a paragraph. The
     width is overridden per vault from the `paneMinWidth` preference. */
  --pkmd-pane-min-w: 360px;
  --pkmd-pane-min-h: 180px;
  --pkmd-terminal-h: 320px;
  --pkmd-terminal-min-h: 120px;
  --pkmd-terminal-max-h: 70vh;
  --pkmd-statusbar-h: 26px;
  --pkmd-vault-bar-h: 44px;              /* the sidebar's top band: the 28px
                                            --pkmd-hit-min plus 8px above and
                                            below, so the workspace selector
                                            and the gear both get a full-size
                                            target in a band with real air
                                            around it rather than a hairline
                                            of clearance */

  --pkmd-divider: 1px;                   /* -> 0.5px at 192dpi, below */
  --pkmd-handle-hit: 10px;               /* a 3px hit target is the common
                                            shape, and exactly why such
                                            dividers are fiddly to grab */
  --pkmd-handle-visible: 1px;
  --pkmd-handle-visible-active: 3px;

  /* ── note frame ────────────────────────────────────────────────────────── */
  --pkmd-reading-width: 720px;           /* the COLUMN, not the measure */
  --pkmd-reading-width-full: 100%;       /* 100%, not `none`, so .pkmd-bleed's
                                            centring arithmetic resolves */
  /* Bleed width for tables, .table views, code blocks and wide images inside
     reading mode. 960px = 113 characters at TypeSystem's 18px body, which is
     why prose never uses it. */
  --pkmd-reading-width-wide: 960px;
  /* The live-preview marker rail, reserved IDENTICALLY in edit and reading
     mode so switching modes shifts nothing horizontally. 720 − 2 x 40 = 640px
     of text = 75.8 characters at 18px (SF Pro Text average advance 0.4692em,
     measured with fontTools). 720px alone would be 85.3 characters, past the
     60-75 legibility range — so if this rail is ever removed, the 720px
     column becomes wrong and must drop to ~680px. */
  --pkmd-gutter-marker: 2.5rem;          /* 40px at the 16px root basis */
  /* Properties key column. Fixed: no resize handle is rendered anywhere, and
     a rail narrow enough for the track to hurt stacks instead of shrinking
     (`@container props` in layout.css). */
  --pkmd-prop-key-w: 132px;
  /* CONTAINER units, not viewport units. Measured: at a 1440px window with
     both sidebars open the editor column is 875px, and a 5vw gutter eats 72px
     a side, capping the note at 708px so the 720px measure was UNREACHABLE.
     5cqw of .pkmd-editor takes 43.8px a side and the note lands on 720px
     exactly. Resolves against .pkmd-editor (container-name: editor). */
  --pkmd-gutter: clamp(20px, 5cqw, 56px);

  /* ── spacing: strict 4px ladder + two half-steps ──────────────────────────
     A CLOSED enumerated ladder: every member is named for its own px value,
     so --pkmd-space-2 IS 2px. The shipped app.css previously declared
     --pkmd-space-2: 0.5rem (8px) under the same name, which is the collision
     this resolves. Prose spacing is a 15px rhythm and lives in
     --pkmd-prose-space-* (TypeSystem); 30 and 45 are deliberately not here. */
  --pkmd-space-2: 2px;   --pkmd-space-4: 4px;   --pkmd-space-6: 6px;
  --pkmd-space-8: 8px;   --pkmd-space-10: 10px; --pkmd-space-12: 12px;
  --pkmd-space-16: 16px; --pkmd-space-20: 20px; --pkmd-space-24: 24px;
  --pkmd-space-32: 32px; --pkmd-space-40: 40px; --pkmd-space-48: 48px;
  --pkmd-space-64: 64px; --pkmd-space-80: 80px;

  /* ── radii + squircles (corner-shape verified true in Chromium 152) ────── */
  --pkmd-radius-1: 4px;   --pkmd-radius-2: 6px;   --pkmd-radius-3: 8px;
  --pkmd-radius-4: 12px;  --pkmd-radius-5: 16px;  --pkmd-radius-6: 22px;
  --pkmd-radius-pill: 999px;
  --pkmd-squircle: superellipse(1.33);

  /* ── density: comfortable (default) ──────────────────────────────────────
     The usual tree row is ~28px (13px text + 4px + 4px pad); ours is 30px so
     a 20px chevron/icon and a 2px focus rail both fit without the row
     growing. */
  --pkmd-row-tree: 30px;
  --pkmd-row-list: 36px;                 /* 44px in the two-line variant */
  --pkmd-row-menu: 30px;
  --pkmd-row-palette: 40px;
  --pkmd-row-prop: 32px;
  --pkmd-row-table: 34px;
  --pkmd-sheet-gutter-w: 52px;           /* row numbers: five digits plus the
                                            padding, so a 10,000-row sheet
                                            never reflows the gutter mid-scroll */
  --pkmd-sheet-col-w: 128px;             /* a default column: wide enough for a
                                            date or a two-decimal number
                                            without wrapping */
  --pkmd-tab-h: 36px;                    /* in the 44px band: 4px shows above
                                            and below, so a tab reads as a
                                            chip inside the band */
  --pkmd-hit-min: 28px;
  --pkmd-ctl-h-sm: 24px;
  --pkmd-ctl-h-md: 32px;
  --pkmd-ctl-h-lg: 40px;
  --pkmd-indent: 12px;

  --pkmd-pad-panel-x: 12px;
  --pkmd-pad-panel-y: 8px;
  --pkmd-pad-card: 16px;
  --pkmd-pad-input-x: 10px;
  --pkmd-pad-input-y: 6px;
  --pkmd-pad-btn-sm-x: 8px;
  --pkmd-pad-btn-md-x: 12px;
  --pkmd-pad-btn-lg-x: 18px;
  --pkmd-pad-row-x: 8px;

  /* ── icons (values supplied by IconVoice, owned here) ────────────────────
     MUST stay px, never rem. IconVoice measured that --pkmd-icon-sm: 1rem
     under a 13px root yields a 13px box, and stroke-width 1.5 on a 24 viewBox
     then renders 13/24 x 1.5 = 0.813px — below the ~0.875px floor where a
     hairline stops landing on a device pixel and antialiases to a grey smear.
     These are optical constants tied to device pixels, not to type. */
  --pkmd-icon-xs: 14px;  --pkmd-icon-xs-stroke: 1.75px;
  --pkmd-icon-sm: 16px;  --pkmd-icon-sm-stroke: 1.5px;
  --pkmd-icon-md: 18px;  --pkmd-icon-md-stroke: 1.5px;
  --pkmd-icon-lg: 20px;  --pkmd-icon-lg-stroke: 1.5px;
  --pkmd-icon-xl: 24px;  --pkmd-icon-xl-stroke: 1.5px;
  --pkmd-icon-2xl: 32px; --pkmd-icon-2xl-stroke: 1.25px;
  --pkmd-icon-empty: 40px; --pkmd-icon-empty-stroke: 1.25px;
  /* The one em-based icon size: icons inline in note PROSE must track prose
     zoom, chrome icons must not. em, not rem, so it follows the local prose
     size. Bounds measured by IconVoice: below a 16px box the rendered stroke
     falls under the ~0.875px hairline floor (1em at prose zoom 0.75 = 13.5px
     box = 0.844px stroke) and above 26px it exceeds the display weight.
     Confined to body/body-sm/inline-code, where the clamp never binds; the
     caption and label tiers take the chrome family even inside a note. */
  --pkmd-icon-prose: clamp(16px, 1em, 26px);
  --pkmd-icon-prose-stroke: 1.5px;

  /* ── scrollbars ───────────────────────────────────────────────────────────
     A DESIGNED scrollbar needs the ::-webkit-scrollbar pseudos; those need
     `scrollbar-gutter`; and `scrollbar-width`/`scrollbar-color` must never be
     declared in the app, because any non-`auto` value makes Chromium discard
     every ::-webkit-scrollbar rule silently. Measured, same 300px container,
     clientWidth without -> with overflow:
       unstyled (macOS overlay)                300 -> 300   no jitter
       ::-webkit-scrollbar{width:10px}         300 -> 290   10px JUMP
       + scrollbar-gutter: stable              290 -> 290   none
       + stable both-edges                     280 -> 280   none, stays centred
       scrollbar-width:thin AND width:24px     300 -> 300   webkit IGNORED
     The thumb is transparent at rest and paints on container hover, so the
     reserved width is constant and nothing ever moves. Alphas are explicit
     oklch of ColorSystem's own text-1 L/C/H rather than color-mix(var(...)):
     a misspelled operand would invalidate the declaration and leave an
     invisible scrollbar. */
  --pkmd-scrollbar-w: 12px;
  --pkmd-scrollbar-inset: 3px;
  --pkmd-scrollbar-thumb: transparent;
  --pkmd-scrollbar-thumb-hover: oklch(0.268 0.0140 265 / 0.22);
  --pkmd-scrollbar-thumb-active: oklch(0.268 0.0140 265 / 0.38);

  /* ── z ladder ─────────────────────────────────────────────────────────── */
  --pkmd-z-content: 0;
  --pkmd-z-handle: 20;
  --pkmd-z-statusbar: 30;
  --pkmd-z-drawer: 40;
  --pkmd-z-popover: 50;
  --pkmd-z-menu: 60;
  --pkmd-z-modal: 70;
  --pkmd-z-toast: 80;
  --pkmd-z-tooltip: 90;
}

/* Retina hairline: 1px -> 0.5px at 192dpi, so a divider stays one device
   pixel instead of doubling on a retina display. */
@media (min-resolution: 192dpi) {
  :root { --pkmd-divider: 0.5px; }
}

/* ── density: compact. GEOMETRY ONLY — no font size is touched here, so
   TypeSystem's scale stays authoritative in both modes. Set by the app as
   data-density="compact" on <html>; a plain attribute selector, so a vault's
   design/tokens.css behaves identically over file://. ──────────────────── */
:root[data-density="compact"] {
  --pkmd-row-tree: 26px;
  --pkmd-row-list: 30px;
  --pkmd-row-menu: 26px;
  --pkmd-row-palette: 34px;
  --pkmd-row-prop: 28px;
  --pkmd-row-table: 28px;
  --pkmd-sheet-gutter-w: 44px;
  --pkmd-sheet-col-w: 112px;
  /* 32 in the same 44px band the traffic lights pin: compact shrinks rows,
     never the window band. */
  --pkmd-tab-h: 32px;
  --pkmd-pane-min-w: 320px;
  --pkmd-pane-min-h: 160px;
  --pkmd-vault-bar-h: 40px;
  --pkmd-ctl-h-sm: 22px;
  --pkmd-ctl-h-md: 28px;
  --pkmd-ctl-h-lg: 34px;
  --pkmd-indent: 10px;
  --pkmd-pad-panel-x: 8px;
  --pkmd-pad-panel-y: 6px;
  --pkmd-pad-card: 12px;
  --pkmd-pad-input-x: 8px;
  --pkmd-pad-input-y: 4px;
  --pkmd-pad-btn-md-x: 10px;
  --pkmd-pad-btn-lg-x: 14px;
  --pkmd-scrollbar-w: 10px;
}


/* ═══════════════════════════════════════════════════════════════════════════
   3. MOTION AND ELEVATION — owner: MotionDepth
   Measured on M1 Pro, dpr 2, 120 Hz (8.33 ms/frame), with a 15 400-node
   editor DOM (the 534 KB note) and one synthetic keystroke per frame:

     control, no animation                          8.30 ms median, 0/200 late
     animate sidebar `width` (editor resizes)      16.70 ms median, 63/200
     animate `grid-template-columns`               16.70 ms median, 59/200
     animate sidebar `transform`                    8.30 ms median, 0/200
     animate `width` + `contain: strict` on editor  8.30 ms median, 0/200
     `transition: all 140ms` on every token span    8.30 ms median, 0/200
     full-viewport `backdrop-filter: blur(40px)`    8.30 ms median, 0/200
     4-layer `box-shadow` on a modal                8.30 ms median, 0/200

   PAINT AND COMPOSITE ARE FREE; LAYOUT IS NOT. That is the single rule this
   section encodes, and it is why blur and four-layer shadows are permitted
   while no property that resizes the editor's containing block may be
   animated anywhere in the window.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── duration ────────────────────────────────────────────────────────────
     Anchors: Claude desktop --cds-dur-fast 60 / -snap 120 / -base 200 /
     -sheet 300ms; Material 3 short2 100 / short3 150 / short4 200 /
     medium2 300; macOS CATransaction.animationDuration() measured 0.25s. */
  --pkmd-dur-0:   0ms;   /* instant    — no animation; the honest default */
  --pkmd-dur-1:  70ms;   /* fast       — state change under the cursor */
  --pkmd-dur-2: 140ms;   /* normal     — entrance/exit of something local */
  --pkmd-dur-3: 220ms;   /* slow       — layout move, or a covering overlay */
  --pkmd-dur-4: 340ms;   /* deliberate — full-surface change to follow */
  /* Exit rule (M3): an exit is one step BELOW its entrance. Never author an
     exit duration directly; use the entrance token minus one. */

  /* ── easing. Every curve is a literal cubic-bezier: no spring, no
        multi-stop linear(), no keyword aliases. ─────────────────────────── */
  --pkmd-ease-state:  cubic-bezier(0.2, 0, 0, 1);        /* M3 standard */
  --pkmd-ease-enter:  cubic-bezier(0.05, 0.7, 0.1, 1);   /* M3 emph.-decel */
  --pkmd-ease-exit:   cubic-bezier(0.3, 0, 0.8, 0.15);   /* M3 emph.-accel */
  --pkmd-ease-layout: cubic-bezier(0.32, 0.72, 0, 1);    /* Claude ease-snap */
  --pkmd-ease-system: cubic-bezier(0.25, 0.1, 0.25, 1);  /* kCAMediaTimingFunctionDefault */
  --pkmd-ease-settle: cubic-bezier(0.34, 1.3, 0.64, 1);  /* +2.99% overshoot;
                                            drag-drop settle ONLY. A curve
                                            peaking at +9.27% is the bounce
                                            this forbids */
  --pkmd-ease-linear: cubic-bezier(0, 0, 1, 1);          /* progress bars only */

  /* ── semantic aliases. The numbered tokens are canonical because they
        encode the ladder; these exist because peers reference motion by
        intent, not by index (TypeSystem's marker reveal cites
        --pkmd-dur-fast / --pkmd-ease-out, which did not exist when written
        and would have silently resolved to NO transition). They are pure
        indirection: an alias never carries its own literal. ────────────── */
  --pkmd-dur-instant:    var(--pkmd-dur-0);
  --pkmd-dur-fast:       var(--pkmd-dur-1);
  --pkmd-dur-normal:     var(--pkmd-dur-2);
  --pkmd-dur-slow:       var(--pkmd-dur-3);
  --pkmd-dur-deliberate: var(--pkmd-dur-4);
  --pkmd-ease-out:       var(--pkmd-ease-enter);   /* decelerating */
  --pkmd-ease-in:        var(--pkmd-ease-exit);    /* accelerating */
  --pkmd-ease-in-out:    var(--pkmd-ease-state);

  /* ── elevation ────────────────────────────────────────────────────────────
     Five levels, tuned in a closed loop against pixels actually composited by
     Chromium 152 (capturePage -> OKLab-L of the darkest row under the card's
     bottom edge), not by eye. Light steps +0.0276 / +0.0283 / +0.0263 /
     +0.0291; the loop converged in one iteration, max error 0.0018.

     Shadow ink is neither black nor a single hue: it follows the neutral ramp
     of its own mode, so a shadow reads as the same family as the borders
     beside it. Light neutrals are warm H65, dark neutrals cool H265.

     `oklch(from ... l c h / a)` is relative colour syntax; it lets ONE ink
     token carry hue and lightness while each layer sets its own alpha, so
     light -> dark is a single declaration instead of eight rewritten shadows.
     Verified beyond CSS.supports: rendered against the literal form and
     pixel-compared at 1/3/6/12/24px below the card edge for levels 1 and 4 —
     byte-identical at every sample.

     Level N pairs with ColorSystem's surface at the same rung, plus a border
     tier at the top two. The three are not independent choices:
       0  surface-page     none                    the page itself
       1  surface-panel    none                    inputs, resting cards
       2  surface-app      none                    menus, popups, tooltips
       3  surface-raised   1px border-subtle       palette, popovers, ghosts
       4  surface-overlay  1px border-default      modals, sheets, diff pane
     Rungs 3 and 4 carry a second channel because in LIGHT MODE raised and
     overlay are the SAME COLOUR (#fefdfc — there is no lightness headroom
     above white), so on lightness alone those rungs are identical. The border
     tier is orthogonal: adding it moves the shadow peak by zero counts, the
     step is 2.4x in edge contrast (3.38:1 vs 1.42:1 against the page), and a
     modal's edge at 3.38:1 clears SC 1.4.11 on its own. */
  --pkmd-shadow-ink: oklch(0.20 0.020 65);

  --pkmd-shadow-0: none;
  --pkmd-shadow-1:
    0 1px 2px  0    oklch(from var(--pkmd-shadow-ink) l c h / 0.062),
    0 0   1px  0    oklch(from var(--pkmd-shadow-ink) l c h / 0.047);
  --pkmd-shadow-2:
    0 1px 2px  0    oklch(from var(--pkmd-shadow-ink) l c h / 0.054),
    0 2px 4px  -1px oklch(from var(--pkmd-shadow-ink) l c h / 0.070),
    0 0   6px  -2px oklch(from var(--pkmd-shadow-ink) l c h / 0.070);
  --pkmd-shadow-3:
    0 1px 2px  0    oklch(from var(--pkmd-shadow-ink) l c h / 0.065),
    0 4px 8px  -2px oklch(from var(--pkmd-shadow-ink) l c h / 0.102),
    0 0   14px -4px oklch(from var(--pkmd-shadow-ink) l c h / 0.118);
  --pkmd-shadow-4:
    0 2px 4px  -1px oklch(from var(--pkmd-shadow-ink) l c h / 0.086),
    0 8px 16px -4px oklch(from var(--pkmd-shadow-ink) l c h / 0.123),
    0 0   28px -8px oklch(from var(--pkmd-shadow-ink) l c h / 0.161);

  /* Clipped contexts (inside overflow:hidden) cannot show an outer shadow.
     Verified by pixel sampling: an outer box-shadow on a child that reaches
     the clip edge is painted away entirely; the inset form survives. */
  --pkmd-shadow-hairline: inset 0 0 0 1px oklch(from var(--pkmd-shadow-ink) l c h / 0.075);

  /* ── focus ring ───────────────────────────────────────────────────────────
     ONE declaration site. Components never author their own `outline`; they
     apply box-shadow: var(--pkmd-focus-ring), or append it to an elevation
     with a comma. box-shadow takes NO layout space, so a ring never shifts a
     row and never needs reserved padding — which is why this is a shadow and
     not a border, and not an outline with outline-offset (that jitters by a
     device pixel at dpr 2 when animated).

     Ring colour is ColorSystem's --pkmd-state-ring, NOT --pkmd-accent: a
     desaturated mid-lightness derivative that clears SC 1.4.11 on its own
     against every surface. Using the accent would tie ring contrast to a hue
     whose L is capped by the on-accent text floor. Measured from the captured
     frame: ring vs the control 3.74:1 light / 3.96:1 dark; ring vs the page
     3.56:1 / 4.54:1. Both structural edges clear 3:1 in both modes.

     --pkmd-ring-spacer MUST be the LOCAL surface: every raised container
     re-points it in one line (.pkmd-modal { --pkmd-ring-spacer:
     var(--pkmd-surface-overlay) }), or the ring looks like it is floating
     over a seam. */
  --pkmd-ring-w:      2px;
  --pkmd-ring-gap:    1px;
  --pkmd-ring-halo:   40%;
  --pkmd-ring-color:  var(--pkmd-state-ring);
  --pkmd-ring-spacer: var(--pkmd-surface-page);

  --pkmd-focus-ring:
    0 0 0 var(--pkmd-ring-gap) var(--pkmd-ring-spacer),
    0 0 0 calc(var(--pkmd-ring-gap) + var(--pkmd-ring-w)) var(--pkmd-ring-color),
    0 0 6px calc(var(--pkmd-ring-gap) + var(--pkmd-ring-w))
      color-mix(in oklab, var(--pkmd-ring-color) var(--pkmd-ring-halo), transparent);

  /* For anything inside overflow:hidden / clip — tree rows, tabs, board
     cards. The outer form is painted away entirely there (pixel-sampled: no
     ring pixels at all); the inset form renders. */
  --pkmd-focus-ring-inset:
    inset 0 0 0 var(--pkmd-ring-gap) var(--pkmd-ring-spacer),
    inset 0 0 0 calc(var(--pkmd-ring-gap) + var(--pkmd-ring-w)) var(--pkmd-ring-color);

  /* For focusables sitting on arbitrary USER imagery: attachment widgets,
     image embeds, a drag ghost over a note, graph nodes. Mandatory, not
     optional: swept across 2001 backdrop luminances, the two-layer ring
     bottoms out at 2.18:1 light / 2.73:1 dark against a worst-case mid-grey,
     i.e. it FAILS 3:1 over a pasted screenshot. The theme-invariant flank
     pair has a swept floor of 4.21:1 against every backdrop that exists. */
  --pkmd-focus-ring-onmedia:
    0 0 0 1px var(--pkmd-ring-flank-hi),
    0 0 0 3px var(--pkmd-ring-color),
    0 0 0 4px var(--pkmd-ring-flank-lo);

  /* ── blur. Legal because it measured free (8.30 ms for a full-viewport
        40px backdrop-filter). NEVER decorative: only on a surface that
        genuinely overlaps content the user was reading, which is the one case
        where it carries information.

        --pkmd-blur-N are LENGTHS and --pkmd-veil-N are FILTERS. Keeping both
        matters: `backdrop-filter: var(--pkmd-blur-2)` is a bare length, which
        is invalid and drops the blur entirely with no error — a live defect
        in the draft component sheet. Always apply a veil. ──────────────── */
  --pkmd-blur-1:  8px;   /* raised chips over content */
  --pkmd-blur-2: 14px;   /* menus, dropdowns */
  --pkmd-blur-3: 22px;   /* command palette, popovers */
  --pkmd-blur-4: 32px;   /* modal scrim */
  --pkmd-blur-sat: 1.35; /* 1.5 over-saturates a neutral UI */
  --pkmd-veil-1: blur(var(--pkmd-blur-1)) saturate(var(--pkmd-blur-sat));
  --pkmd-veil-2: blur(var(--pkmd-blur-2)) saturate(var(--pkmd-blur-sat));
  --pkmd-veil-3: blur(var(--pkmd-blur-3)) saturate(var(--pkmd-blur-sat));
  --pkmd-veil-4: blur(var(--pkmd-blur-4)) saturate(var(--pkmd-blur-sat));

  /* ── background layer ─────────────────────────────────────────────────────
     The colour wash the app paints behind its chrome — flat in `tint` mode,
     a three-stop gradient in `gradient` mode, and free in `none` because the
     opacity is 0 and the stops are `transparent`.

     Three stop slots exist unconditionally so the gradient never has to
     branch on how many the user picked: one stop repeats to three, two repeat
     the last. The app writes resolved oklch() literals into these, which is
     not a runtime colour CHANNEL injection — rule 1 forbids a token whose
     value depends on the app being there, and all six of these resolve to a
     complete, valid, invisible layer on their own.

     The grain is a data URL rather than a file so it resolves over file://
     with no network, no build step and no second asset to ship. 120px tile,
     fractalNoise at 0.8 — fine enough to read as film grain and not as a
     pattern at any zoom on the ladder. */
  --pkmd-bg-stop-1: transparent;
  --pkmd-bg-stop-2: transparent;
  --pkmd-bg-stop-3: transparent;
  --pkmd-bg-angle: 180;
  --pkmd-bg-opacity: 0;
  --pkmd-bg-grain: 0;
  --pkmd-bg-grain-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}

*:focus-visible { outline: none; box-shadow: var(--pkmd-focus-ring); }


/* ═══════════════════════════════════════════════════════════════════════════
   4. COLOUR — owner: ColorSystem
   Verified in Chromium against rendered pixels.

   THE SURFACES ARE TINTED, NOT NEUTRAL. Every neutral plane — surfaces,
   borders, the two interaction washes, the scrim — carries up to 4x the
   chroma it did before, on a hue of 72 in light and 280 in dark: warm ivory
   over near-black in one theme, violet-inked in the other. Lightness is
   BYTE-IDENTICAL to the pre-retune palette on every one of those tokens,
   which is what keeps every contrast ratio where it was; the text ramp, the
   accent quartet, the focus and ring tokens, every *-solid / *-text /
   *-border semantic and the whole editor plane are untouched.

   The binding constraint is the sRGB gamut, not taste, and a declaration
   outside it is altered silently by the compositor. The two plausible
   models for that — per-channel clamp and CSS Color 4 chroma reduction —
   DISAGREE: on the pre-retune --pkmd-accent-subtle they land 6/255 apart in
   the red channel, one holding the hue and the other rotating it 14 degrees
   off the accent the token is named after. So nothing here is left outside
   the gamut, where both models are the identity and the question cannot
   arise. Every value was round-tripped oklch -> 8-bit sRGB -> oklch and
   accepted only inside the gamut with its chroma back within 0.002. Eleven
   of the twenty-eight retuned values had to stop short of the chroma this
   retune asked for, and each carries its measured ceiling beside it. The two
   accent-derived -subtle tokens are capped by the WORST hue on the wheel,
   because their hue channel is the user's and one declaration serves all 360.

   The three fixed-hue -subtle backgrounds and both -accent-subtle tokens are
   the only values whose lightness moved (by 0.010-0.028, to buy chroma the
   gamut does not offer higher up), so every *-text-on-*-subtle pair was
   re-measured; the worst is 4.96:1 against a 4.5 floor.

   Appended inside each theme block, and belonging to this section because
   they carry colour: the three glyph-asset tokens, plus the dark-mode
   non-colour overrides that must switch with the theme (type weights,
   elevation, scrollbar thumb) — kept here so there is exactly ONE block per
   theme selector and `color-scheme` is declared exactly once in each.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  color-scheme: light;

  --pkmd-accent-h: 252;
  --pkmd-neutral-h: 72;

  /* --- surfaces ------------------------------------------------
     Chroma is 4x the pre-retune neutral, so a surface reads as tinted ivory
     rather than as grey, capped where the sRGB gamut runs out. That ceiling
     closes as L approaches 1 — C 0.0165 at L 0.978, C 0.0037 at L 0.995 —
     which is why -1/-page take 0.0160 and the raised trio keeps 0.0020
     rather than the 4x the rest carry. Above the ceiling the compositor
     alters the colour and the section header's note applies: the models for
     how disagree, so no value is authored there. */
  --pkmd-surface-1: oklch(0.978 0.0160 72);                               /* #fff6ec */
  --pkmd-surface-2: oklch(0.962 0.0240 72);                               /* #fdf0e1 */
  --pkmd-surface-3: oklch(0.946 0.0280 72);                               /* #f9ebd9 */
  --pkmd-surface-page: oklch(0.978 0.0160 72);                            /* #fff6ec */
  --pkmd-surface-panel: oklch(0.962 0.0240 72);                           /* #fdf0e1 */
  --pkmd-surface-app: oklch(0.946 0.0280 72);                             /* #f9ebd9 */
  --pkmd-surface-raised: oklch(0.995 0.0020 72);                          /* #fefdfc */
  --pkmd-surface-input: oklch(0.995 0.0020 72);                           /* #fefdfc */
  --pkmd-surface-overlay: oklch(0.995 0.0020 72);                         /* #fefdfc */  /* == raised: no L headroom above white; shadow separates */
  --pkmd-surface-scrim: oklch(0.200 0.0400 72 / 0.420);                   /* #211301 @42% */

  /* --- text --------------------------------------------------- */
  --pkmd-text-1: oklch(0.268 0.0140 265);                                 /* #23262d */
  --pkmd-text-2: oklch(0.410 0.0160 265);                                 /* #464a53 */
  --pkmd-text-3: oklch(0.513 0.0170 265);                                 /* #626771 */
  --pkmd-text-disabled: oklch(0.646 0.0150 265);                          /* #898e97 */  /* sub-AA by design: WCAG 1.4.3 exempts disabled */
  --pkmd-text-inverse: oklch(0.955 0.0045 265);                           /* #eff0f3 */
  --pkmd-text-link: oklch(0.476 0.1300 var(--pkmd-accent-h));             /* #155ea3 */
  --pkmd-text-on-accent: oklch(0.995 0.0020 65);                          /* #fefdfc */

  /* --- borders ------------------------------------------------ */
  --pkmd-border-subtle: oklch(0.862 0.0240 72);                           /* #dccfc1 */
  --pkmd-border-default: oklch(0.621 0.0320 72);                          /* #938472 */
  --pkmd-border-strong: oklch(0.531 0.0400 72);                           /* #7b6953 */
  --pkmd-border-focus: oklch(0.608 0.1100 var(--pkmd-accent-h));          /* #4e86c2 */

  /* --- interaction states (explicit alpha, never color-mix) ---
     A wash replaces a border in this palette, so the alphas are up by a
     third to make one legible on a surface that is itself tinted. Chroma is
     2.1x, not the 4x the surfaces take: C 0.0642 is where the sRGB gamut
     ends at L 0.300 on this hue, so 0.1200 would have been outside it.
     --pkmd-state-selected keeps its chroma — it is accent-hued, and the
     accent plane is already at the gamut wall. */
  --pkmd-state-hover: oklch(0.300 0.0640 72 / 0.060);                     /* #412800 @6% */
  --pkmd-state-active: oklch(0.300 0.0640 72 / 0.090);                    /* #412800 @9% */
  --pkmd-state-selected: oklch(0.520 0.1500 var(--pkmd-accent-h) / 0.180);/* #0d6abb @18% */
  --pkmd-state-ring: oklch(0.608 0.1100 var(--pkmd-accent-h));            /* #4e86c2 */
  --pkmd-state-ring-offset: var(--pkmd-surface-page);
  --pkmd-ring-flank-hi: oklch(0.990 0.0030 65);                           /* #fdfbfa */  /* theme-invariant: ring over arbitrary imagery */
  --pkmd-ring-flank-lo: oklch(0.200 0.0100 265);                          /* #14161b */

  /* --- semantic status (FIXED hues, not themable) -------------
     The three -subtle backgrounds each carry as much chroma as the gamut
     holds at their own hue, which is why the numbers differ: at L 0.952 the
     ceiling is C 0.0796 at hue 150, 0.0439 at hue 80 and 0.0238 at hue 25.
     Their L is 0.010 below the pre-retune value to buy that chroma, so each
     -text/-subtle pair was re-measured: 5.12 / 5.01 / 4.96 against a 4.5
     floor. */
  --pkmd-success-solid: oklch(0.546 0.1512 150);                          /* #00873c */
  --pkmd-success-text: oklch(0.496 0.1350 150);                           /* #047635 */
  --pkmd-success-border: oklch(0.616 0.0900 150);                         /* #5c9468 */
  --pkmd-success-subtle: oklch(0.952 0.0700 150);                         /* #cffdd7 */
  --pkmd-warning-solid: oklch(0.566 0.1137 80);                           /* #996d0d */
  --pkmd-warning-text: oklch(0.513 0.1015 80);                            /* #855f0e */
  --pkmd-warning-border: oklch(0.628 0.0900 80);                          /* #a58245 */
  --pkmd-warning-subtle: oklch(0.952 0.0420 80);                          /* #feedd0 */
  --pkmd-danger-solid: oklch(0.581 0.1550 25);                            /* #c64d49 */
  --pkmd-danger-text: oklch(0.527 0.1350 25);                             /* #ab4541 */
  --pkmd-danger-border: oklch(0.637 0.0900 25);                           /* #bc756f */
  --pkmd-danger-subtle: oklch(0.952 0.0220 25);                           /* #feeae8 */
  --pkmd-info-solid: var(--pkmd-accent-solid);                            /* info aliases accent */
  --pkmd-info-text: var(--pkmd-accent-text);                              /* info aliases accent */
  --pkmd-info-border: var(--pkmd-accent-border);                          /* info aliases accent */
  --pkmd-info-subtle: var(--pkmd-accent-subtle);                          /* info aliases accent */

  /* --- editor (fills stay on this theme's side of L=0.5) ----- */
  --pkmd-editor-active-line: oklch(0.930 0.0100 65 / 0.218);              /* #ede7e1 @22% */
  --pkmd-editor-selection: oklch(0.640 0.1500 var(--pkmd-accent-h) / 0.207);/* #3d8fe4 @21% */
  --pkmd-editor-highlight: oklch(0.860 0.1500 75 / 0.378);                /* #ffc151 @38% */
  --pkmd-editor-match: oklch(0.820 0.1600 75 / 0.464);                    /* #ffb330 @46% */
  --pkmd-editor-match-active: oklch(0.760 0.1700 75 / 0.478);             /* #ef9e00 @48% */
  --pkmd-editor-diff-added: oklch(0.700 0.1400 150 / 0.107);              /* #54b66e @11% */
  --pkmd-editor-diff-removed: oklch(0.700 0.1500 25 / 0.112);             /* #ed756e @11% */
  --pkmd-editor-match-line: oklch(0.524 0.1500 75);                       /* #9b5900 */
  --pkmd-editor-match-active-ring: oklch(0.429 0.1400 75);                /* #7a3f00 */
  --pkmd-editor-unresolved: oklch(0.444 0.1500 25);                       /* #952325 */
  --pkmd-editor-tag-text: oklch(0.426 0.1300 252);                        /* #004f93 */
  --pkmd-editor-marker: oklch(0.513 0.0170 265);                          /* #626771 */
  --pkmd-editor-tag-bg: var(--pkmd-accent-subtle);
  --pkmd-editor-tag-border: var(--pkmd-accent-border);
  /* --- aliases the chrome needs, so no second colour value exists ---------
     Each is pure indirection and therefore re-resolves per theme on its own;
     they are declared once here rather than in every theme block.
     --pkmd-surface-4 was requested by the component sheet and DELETED: light
     has no lightness headroom below --pkmd-surface-app, so a fourth neutral
     step would have been a new colour. Its three uses are relative alpha
     states instead (--pkmd-state-hover / -active), which is what a "one step
     further" fill means in both directions. */
  --pkmd-surface-inverse: var(--pkmd-text-1);  /* tooltips. text-1 and
                                                  text-inverse are mirror
                                                  values, so the pair is
                                                  13.29:1 in BOTH themes by
                                                  construction. */
  --pkmd-mark: var(--pkmd-editor-match);       /* search hit in a backlink
                                                  context. Verified over every
                                                  host surface, not just the
                                                  editor page: worst case
                                                  text-1 9.16:1, text-2
                                                  6.60:1 (dark over raised).
                                                  It works because it is alpha
                                                  rather than opaque. */
  --pkmd-text-on-danger: var(--pkmd-text-on-accent);

  /* --- glyph assets: the only COLOUR-BEARING non-colour tokens ------------
     A data-URL SVG is a separate document, so `currentColor` does not resolve
     inside it and no custom property can reach its `stroke`. The two ways out
     were both measured and rejected: masking the <input> clips the accent
     fill along with the glyph, and Chromium renders no ::before on a replaced
     element, so the mask-on-a-pseudo trick is unavailable. These are
     therefore colour tokens, defined once per theme, with the stroke
     authored as the correct SEMANTIC colour.
       tick / dash  sit INSIDE a filled --pkmd-accent-solid box, so they are
                    --pkmd-text-on-accent #fefdfc (theme-invariant).
       chevron      is a muted affordance on a form control, so it is
                    --pkmd-text-3: #626771 light, #a0a5ae dark.
     Geometry is fixed by the component sheet: 12x12 centred tick, 10x2 dash,
     14x14 chevron inset 8px from the trailing edge. */
  --pkmd-tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fefdfc" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>');
  --pkmd-dash: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 4"><rect width="24" height="4" rx="2" fill="%23fefdfc"/></svg>');
  --pkmd-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23626771" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');
}
:root, [data-pkmd-accent] {
  --pkmd-accent-solid: oklch(0.520 0.1500 var(--pkmd-accent-h));          /* #0d6abb */
  --pkmd-accent-solid-hover: oklch(0.484 0.1520 var(--pkmd-accent-h));    /* #005fb1 */
  --pkmd-accent-solid-active: oklch(0.452 0.1500 var(--pkmd-accent-h));   /* #0055a5 */
  --pkmd-accent-text: oklch(0.476 0.1300 var(--pkmd-accent-h));           /* #155ea3 */
  --pkmd-accent-border: oklch(0.612 0.0900 var(--pkmd-accent-h));         /* #5b87b8 */
  /* The hue channel is the user's, so -subtle's chroma has to survive EVERY
     hue, and at this lightness the gamut is tightest in the blues: the
     ceiling is C 0.0236 at hue 270, against 0.0717 at 180. 0.0220 is
     therefore the whole-wheel maximum, and L drops 0.012 to buy even that.
     The pre-retune 0.0300 was outside that ceiling and shipped as the one
     value in this section the compositor had to alter: it rendered #e4f4ff,
     C 0.0225 with the hue 14 degrees off the accent the token is named
     after. Avoiding that, not the dullness it looks like, is the point. */
  --pkmd-accent-subtle: oklch(0.950 0.0220 var(--pkmd-accent-h));         /* #e4f0fd */
}

/* The separator a page draws its `<hr>` with.

   Two defaults, on `:root` alone: `components.css`'s
   `.pkmd-note[data-pkmd-rule="…"]` rules set both channels themselves, so a
   page that names a separator needs nothing declared per element and a page
   that names none inherits the vault's divider. */
:root {
  --pkmd-page-rule-style: solid;
  --pkmd-page-rule-size: var(--pkmd-divider);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  color-scheme: dark;

  /* `--pkmd-accent-h` is NOT re-declared here, and must not be: it is
     theme-invariant, the base `:root` above always matches, and this
     selector's `:not()` gives it specificity (0,2,0) — which outranks the
     `:root` rule the app writes the user's hue into. Measured: with the
     declaration present, picking accent 262 left every accent token resolving
     252 in system-dark and forced-dark, and only in those. */
  --pkmd-neutral-h: 280;

  /* --- surfaces ------------------------------------------------
     Chroma is 4x the pre-retune neutral on every rung and the hue moves
     265 -> 280, so the ink reads as tinted violet rather than as grey. Dark
     has room light does not: the gamut ceiling runs from C 0.1119 at L 0.185
     to 0.1815 at L 0.300, so 4x is nowhere near it and every rung is the
     stated multiple. */
  --pkmd-surface-1: oklch(0.185 0.0340 280);                              /* #101121 */
  --pkmd-surface-2: oklch(0.215 0.0380 280);                              /* #16172b */
  --pkmd-surface-3: oklch(0.245 0.0420 280);                              /* #1d1e34 */
  --pkmd-surface-page: oklch(0.185 0.0340 280);                           /* #101121 */
  --pkmd-surface-panel: oklch(0.215 0.0380 280);                          /* #16172b */
  --pkmd-surface-app: oklch(0.245 0.0420 280);                            /* #1d1e34 */
  --pkmd-surface-raised: oklch(0.268 0.0440 280);                         /* #22233b */
  --pkmd-surface-input: oklch(0.150 0.0300 280);                          /* #090917 */
  --pkmd-surface-overlay: oklch(0.300 0.0460 280);                        /* #292b45 */
  --pkmd-surface-scrim: oklch(0.080 0.0400 280 / 0.620);                  /* #01010b @62% */

  /* --- text --------------------------------------------------- */
  --pkmd-text-1: oklch(0.955 0.0045 265);                                 /* #eff0f3 */
  --pkmd-text-2: oklch(0.850 0.0130 265);                                 /* #caced7 */
  --pkmd-text-3: oklch(0.720 0.0150 265);                                 /* #a0a5ae */
  --pkmd-text-disabled: oklch(0.580 0.0140 265);                          /* #767a83 */  /* sub-AA by design: WCAG 1.4.3 exempts disabled */
  --pkmd-text-inverse: oklch(0.268 0.0140 265);                           /* #23262d */
  --pkmd-text-link: oklch(0.728 0.1050 var(--pkmd-accent-h));             /* #75abe7 */
  --pkmd-text-on-accent: oklch(0.995 0.0020 65);                          /* #fefdfc */

  /* --- borders ------------------------------------------------ */
  --pkmd-border-subtle: oklch(0.369 0.0440 280);                          /* #3b3d57 */
  --pkmd-border-default: oklch(0.566 0.0520 280);                         /* #707395 */
  --pkmd-border-strong: oklch(0.667 0.0600 280);                          /* #8d91b9 */
  --pkmd-border-focus: oklch(0.588 0.1100 var(--pkmd-accent-h));          /* #4880bc */

  /* --- interaction states (explicit alpha, never color-mix) ---
     Alpha carries the retune here, not chroma: these are near-white washes
     at L 0.980, where the gamut ends at C 0.0095 on this hue. The pre-retune
     0.0100 sat just outside that ceiling; 0.0080 is the first
     0.002 step inside it. --pkmd-state-selected is accent-hued and keeps
     its chroma. */
  --pkmd-state-hover: oklch(0.980 0.0080 280 / 0.075);                    /* #f7f8fe @8% */
  --pkmd-state-active: oklch(0.980 0.0080 280 / 0.120);                   /* #f7f8fe @12% */
  --pkmd-state-selected: oklch(0.520 0.1500 var(--pkmd-accent-h) / 0.280);/* #0d6abb @28% */
  --pkmd-state-ring: oklch(0.588 0.1100 var(--pkmd-accent-h));            /* #4880bc */
  --pkmd-state-ring-offset: var(--pkmd-surface-page);
  --pkmd-ring-flank-hi: oklch(0.990 0.0030 65);                           /* #fdfbfa */  /* theme-invariant: ring over arbitrary imagery */
  --pkmd-ring-flank-lo: oklch(0.200 0.0100 265);                          /* #14161b */

  /* --- semantic status (FIXED hues, not themable) -------------
     Each -subtle carries as much chroma as the gamut holds at its own hue
     and lightness, which is why the three numbers differ: the ceiling at
     L 0.302 is C 0.0832 at hue 150, 0.0626 at hue 80 and 0.1224 at hue 25.
     -text/-subtle re-measured at 5.14 / 5.37 / 5.62 against a 4.5 floor. */
  --pkmd-success-solid: oklch(0.549 0.1210 150);                          /* #328449 */
  --pkmd-success-text: oklch(0.699 0.1050 150);                           /* #6cb17b */
  --pkmd-success-border: oklch(0.558 0.0900 150);                         /* #4a8357 */
  --pkmd-success-subtle: oklch(0.302 0.0830 150);                         /* #003916 */
  --pkmd-warning-solid: oklch(0.567 0.1178 80);                           /* #9a6d00 */
  --pkmd-warning-text: oklch(0.715 0.1050 80);                            /* #c59c51 */
  --pkmd-warning-border: oklch(0.572 0.0900 80);                          /* #947234 */
  --pkmd-warning-subtle: oklch(0.302 0.0610 80);                          /* #3e2a02 */
  --pkmd-danger-solid: oklch(0.576 0.1210 25);                            /* #b65954 */
  --pkmd-danger-text: oklch(0.725 0.1050 25);                             /* #e18c85 */
  --pkmd-danger-border: oklch(0.578 0.0900 25);                           /* #a9645e */
  --pkmd-danger-subtle: oklch(0.302 0.1210 25);                           /* #5d010a */
  --pkmd-info-solid: var(--pkmd-accent-solid);                            /* info aliases accent */
  --pkmd-info-text: var(--pkmd-accent-text);                              /* info aliases accent */
  --pkmd-info-border: var(--pkmd-accent-border);                          /* info aliases accent */
  --pkmd-info-subtle: var(--pkmd-accent-subtle);                          /* info aliases accent */

  /* --- editor (fills stay on this theme's side of L=0.5) ----- */
  --pkmd-editor-active-line: oklch(0.500 0.0100 265 / 0.072);             /* #606369 @7% */
  --pkmd-editor-selection: oklch(0.520 0.1400 var(--pkmd-accent-h) / 0.363);/* #1b6ab6 @36% */
  --pkmd-editor-highlight: oklch(0.500 0.1400 75 / 0.328);                /* #905300 @33% */
  --pkmd-editor-match: oklch(0.520 0.1500 75 / 0.419);                    /* #995700 @42% */
  --pkmd-editor-match-active: oklch(0.560 0.1600 75 / 0.466);             /* #a96200 @47% */
  --pkmd-editor-diff-added: oklch(0.480 0.1300 150 / 0.242);              /* #067132 @24% */
  --pkmd-editor-diff-removed: oklch(0.480 0.1400 25 / 0.247);             /* #9d3533 @25% */
  --pkmd-editor-match-line: oklch(0.701 0.1500 75);                       /* #d48f00 */
  --pkmd-editor-match-active-ring: oklch(0.814 0.1400 75);                /* #f7b44d */
  --pkmd-editor-unresolved: oklch(0.869 0.1500 25);                       /* #ffaba1 */
  --pkmd-editor-tag-text: oklch(0.815 0.1300 252);                        /* #82c7ff */
  --pkmd-editor-marker: oklch(0.720 0.0150 265);                          /* #a0a5ae */
  --pkmd-editor-tag-bg: var(--pkmd-accent-subtle);
  --pkmd-editor-tag-border: var(--pkmd-accent-border);
  /* --- glyph assets, dark. Only the chevron changes: tick and dash sit on a
     filled accent box and --pkmd-text-on-accent is theme-invariant, but they
     are restated so a reader never has to check whether a theme block is
     complete. chevron stroke = dark --pkmd-text-3 #a0a5ae. */
  --pkmd-tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fefdfc" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>');
  --pkmd-dash: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 4"><rect width="24" height="4" rx="2" fill="%23fefdfc"/></svg>');
  --pkmd-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23a0a5ae" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');

  /* --- dark type (TypeSystem) -------------------------------------------
     Typography's dark change is WEIGHT and TRACKING, not colour: light-on-
     dark haloes, so glyphs read heavier. No @supports gate needed — 380 snaps
     to 400 on a static font, harmlessly. The -ui- ladder moves by the same
     -20 for the same reason. */
  --pkmd-weight-regular:   380;
  --pkmd-weight-medium:    480;
  --pkmd-weight-strong:    580;
  --pkmd-weight-ui-medium: 540;
  --pkmd-weight-ui-strong: 570;
  --pkmd-weight-ui-bold:   600;
  --pkmd-weight-display:   660;
  --pkmd-tracking-body:    0.003em;

  /* --- dark elevation (MotionDepth) -------------------------------------
     ELEVATION IS CARRIED BY SURFACE LIGHTNESS HERE, NOT BY SHADOW. Measured:
     compositing black over a dark surface is 5.3x weaker at equal alpha than
     over a light one (alpha 0.30 gives dL +0.1104 light vs +0.0207 dark), and
     matching light level 4 by darkening alone would need alpha 1.00 —
     literally opaque black. Tripling the dark alphas
     (0.028/0.042/0.070 -> 0.121/0.179/0.300) still buys only dL ~0.03, which
     is the approach this rejects. So level N is ColorSystem's surface at rung
     N and MINTS NOTHING; the shadow degrades to a contact shadow plus a top
     hairline, and the ink switches to the cool neutral hue.

     Dark surface steps +0.0316 / +0.0291 / +0.0240 / +0.0326 against light
     shadow steps +0.0276 / +0.0283 / +0.0263 / +0.0291: the totals agree to
     within 0.008 at every level, so the two modes read as the same four
     levels while neither is an inversion of the other. In dark the surface
     step carries 3.7x/4.6x/6.1x/6.6x more perceptual signal than the shadow.

     Hairline alpha 0.045 renders dL +0.0426 (L1) / +0.0405 (L2) and 0.060
     renders +0.0525 (L3) / +0.0507 (L4). An alpha of 0.16 renders +0.1419 — a
     whole elevation level's worth of signal in a 0.5px line, rejected as too
     hot for a reading surface. */
  --pkmd-shadow-ink: oklch(0.10 0.010 265);
  --pkmd-shadow-1:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.045),
    0 1px 2px 0 oklch(from var(--pkmd-shadow-ink) l c h / 0.20);
  --pkmd-shadow-2:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.045),
    0 2px 4px -1px oklch(from var(--pkmd-shadow-ink) l c h / 0.24),
    0 0   6px -2px oklch(from var(--pkmd-shadow-ink) l c h / 0.20);
  --pkmd-shadow-3:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.060),
    0 4px 8px  -2px oklch(from var(--pkmd-shadow-ink) l c h / 0.28),
    0 0   14px -4px oklch(from var(--pkmd-shadow-ink) l c h / 0.22);
  --pkmd-shadow-4:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.060),
    0 8px 16px -4px oklch(from var(--pkmd-shadow-ink) l c h / 0.32),
    0 0   28px -8px oklch(from var(--pkmd-shadow-ink) l c h / 0.26);
  --pkmd-shadow-hairline: inset 0 0 0 1px oklch(1 0 0 / 0.075);

  /* --- dark scrollbar thumb (LayoutChrome). Explicit oklch of dark text-1's
     own L/C/H, for the same reason as the light values. */
  --pkmd-scrollbar-thumb-hover: oklch(0.955 0.0045 265 / 0.22);
  --pkmd-scrollbar-thumb-active: oklch(0.955 0.0045 265 / 0.38);
  }
  :root:not([data-theme="light"]), :root:not([data-theme="light"]) [data-pkmd-accent] {
  --pkmd-accent-solid: oklch(0.520 0.1500 var(--pkmd-accent-h));          /* #0d6abb */
  --pkmd-accent-solid-hover: oklch(0.484 0.1520 var(--pkmd-accent-h));    /* #005fb1 */
  --pkmd-accent-solid-active: oklch(0.452 0.1500 var(--pkmd-accent-h));   /* #0055a5 */
  --pkmd-accent-text: oklch(0.728 0.1050 var(--pkmd-accent-h));           /* #75abe7 */
  --pkmd-accent-border: oklch(0.584 0.0770 var(--pkmd-accent-h));         /* #597ea8 */
  /* The hue channel is the user's, so this chroma has to survive EVERY hue,
     and dark's tightest is the cyan-green side: the ceiling is C 0.0599 at
     hue 180 against 0.2163 at 270. 0.0580 is the whole-wheel maximum, and L
     rises 0.028 to buy it. Past the ceiling the compositor alters the value
     and the tint stops agreeing with the accent it is named after. */
  --pkmd-accent-subtle: oklch(0.330 0.0580 var(--pkmd-accent-h));         /* #1e3752 */
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  /* Not re-declared, for the reason stated in the media block above: an
     attribute selector outranks the `:root` rule carrying the user's hue. */
  --pkmd-neutral-h: 280;

  /* --- surfaces ------------------------------------------------
     Chroma is 4x the pre-retune neutral on every rung and the hue moves
     265 -> 280, so the ink reads as tinted violet rather than as grey. Dark
     has room light does not: the gamut ceiling runs from C 0.1119 at L 0.185
     to 0.1815 at L 0.300, so 4x is nowhere near it and every rung is the
     stated multiple. */
  --pkmd-surface-1: oklch(0.185 0.0340 280);                              /* #101121 */
  --pkmd-surface-2: oklch(0.215 0.0380 280);                              /* #16172b */
  --pkmd-surface-3: oklch(0.245 0.0420 280);                              /* #1d1e34 */
  --pkmd-surface-page: oklch(0.185 0.0340 280);                           /* #101121 */
  --pkmd-surface-panel: oklch(0.215 0.0380 280);                          /* #16172b */
  --pkmd-surface-app: oklch(0.245 0.0420 280);                            /* #1d1e34 */
  --pkmd-surface-raised: oklch(0.268 0.0440 280);                         /* #22233b */
  --pkmd-surface-input: oklch(0.150 0.0300 280);                          /* #090917 */
  --pkmd-surface-overlay: oklch(0.300 0.0460 280);                        /* #292b45 */
  --pkmd-surface-scrim: oklch(0.080 0.0400 280 / 0.620);                  /* #01010b @62% */

  /* --- text --------------------------------------------------- */
  --pkmd-text-1: oklch(0.955 0.0045 265);                                 /* #eff0f3 */
  --pkmd-text-2: oklch(0.850 0.0130 265);                                 /* #caced7 */
  --pkmd-text-3: oklch(0.720 0.0150 265);                                 /* #a0a5ae */
  --pkmd-text-disabled: oklch(0.580 0.0140 265);                          /* #767a83 */  /* sub-AA by design: WCAG 1.4.3 exempts disabled */
  --pkmd-text-inverse: oklch(0.268 0.0140 265);                           /* #23262d */
  --pkmd-text-link: oklch(0.728 0.1050 var(--pkmd-accent-h));             /* #75abe7 */
  --pkmd-text-on-accent: oklch(0.995 0.0020 65);                          /* #fefdfc */

  /* --- borders ------------------------------------------------ */
  --pkmd-border-subtle: oklch(0.369 0.0440 280);                          /* #3b3d57 */
  --pkmd-border-default: oklch(0.566 0.0520 280);                         /* #707395 */
  --pkmd-border-strong: oklch(0.667 0.0600 280);                          /* #8d91b9 */
  --pkmd-border-focus: oklch(0.588 0.1100 var(--pkmd-accent-h));          /* #4880bc */

  /* --- interaction states (explicit alpha, never color-mix) ---
     Alpha carries the retune here, not chroma: these are near-white washes
     at L 0.980, where the gamut ends at C 0.0095 on this hue. The pre-retune
     0.0100 sat just outside that ceiling; 0.0080 is the first
     0.002 step inside it. --pkmd-state-selected is accent-hued and keeps
     its chroma. */
  --pkmd-state-hover: oklch(0.980 0.0080 280 / 0.075);                    /* #f7f8fe @8% */
  --pkmd-state-active: oklch(0.980 0.0080 280 / 0.120);                   /* #f7f8fe @12% */
  --pkmd-state-selected: oklch(0.520 0.1500 var(--pkmd-accent-h) / 0.280);/* #0d6abb @28% */
  --pkmd-state-ring: oklch(0.588 0.1100 var(--pkmd-accent-h));            /* #4880bc */
  --pkmd-state-ring-offset: var(--pkmd-surface-page);
  --pkmd-ring-flank-hi: oklch(0.990 0.0030 65);                           /* #fdfbfa */  /* theme-invariant: ring over arbitrary imagery */
  --pkmd-ring-flank-lo: oklch(0.200 0.0100 265);                          /* #14161b */

  /* --- semantic status (FIXED hues, not themable) -------------
     Each -subtle carries as much chroma as the gamut holds at its own hue
     and lightness, which is why the three numbers differ: the ceiling at
     L 0.302 is C 0.0832 at hue 150, 0.0626 at hue 80 and 0.1224 at hue 25.
     -text/-subtle re-measured at 5.14 / 5.37 / 5.62 against a 4.5 floor. */
  --pkmd-success-solid: oklch(0.549 0.1210 150);                          /* #328449 */
  --pkmd-success-text: oklch(0.699 0.1050 150);                           /* #6cb17b */
  --pkmd-success-border: oklch(0.558 0.0900 150);                         /* #4a8357 */
  --pkmd-success-subtle: oklch(0.302 0.0830 150);                         /* #003916 */
  --pkmd-warning-solid: oklch(0.567 0.1178 80);                           /* #9a6d00 */
  --pkmd-warning-text: oklch(0.715 0.1050 80);                            /* #c59c51 */
  --pkmd-warning-border: oklch(0.572 0.0900 80);                          /* #947234 */
  --pkmd-warning-subtle: oklch(0.302 0.0610 80);                          /* #3e2a02 */
  --pkmd-danger-solid: oklch(0.576 0.1210 25);                            /* #b65954 */
  --pkmd-danger-text: oklch(0.725 0.1050 25);                             /* #e18c85 */
  --pkmd-danger-border: oklch(0.578 0.0900 25);                           /* #a9645e */
  --pkmd-danger-subtle: oklch(0.302 0.1210 25);                           /* #5d010a */
  --pkmd-info-solid: var(--pkmd-accent-solid);                            /* info aliases accent */
  --pkmd-info-text: var(--pkmd-accent-text);                              /* info aliases accent */
  --pkmd-info-border: var(--pkmd-accent-border);                          /* info aliases accent */
  --pkmd-info-subtle: var(--pkmd-accent-subtle);                          /* info aliases accent */

  /* --- editor (fills stay on this theme's side of L=0.5) ----- */
  --pkmd-editor-active-line: oklch(0.500 0.0100 265 / 0.072);             /* #606369 @7% */
  --pkmd-editor-selection: oklch(0.520 0.1400 var(--pkmd-accent-h) / 0.363);/* #1b6ab6 @36% */
  --pkmd-editor-highlight: oklch(0.500 0.1400 75 / 0.328);                /* #905300 @33% */
  --pkmd-editor-match: oklch(0.520 0.1500 75 / 0.419);                    /* #995700 @42% */
  --pkmd-editor-match-active: oklch(0.560 0.1600 75 / 0.466);             /* #a96200 @47% */
  --pkmd-editor-diff-added: oklch(0.480 0.1300 150 / 0.242);              /* #067132 @24% */
  --pkmd-editor-diff-removed: oklch(0.480 0.1400 25 / 0.247);             /* #9d3533 @25% */
  --pkmd-editor-match-line: oklch(0.701 0.1500 75);                       /* #d48f00 */
  --pkmd-editor-match-active-ring: oklch(0.814 0.1400 75);                /* #f7b44d */
  --pkmd-editor-unresolved: oklch(0.869 0.1500 25);                       /* #ffaba1 */
  --pkmd-editor-tag-text: oklch(0.815 0.1300 252);                        /* #82c7ff */
  --pkmd-editor-marker: oklch(0.720 0.0150 265);                          /* #a0a5ae */
  --pkmd-editor-tag-bg: var(--pkmd-accent-subtle);
  /* --- glyph assets, dark. Only the chevron changes: tick and dash sit on a
     filled accent box and --pkmd-text-on-accent is theme-invariant, but they
     are restated so a reader never has to check whether a theme block is
     complete. chevron stroke = dark --pkmd-text-3 #a0a5ae. */
  --pkmd-tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23fefdfc" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>');
  --pkmd-dash: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 4"><rect width="24" height="4" rx="2" fill="%23fefdfc"/></svg>');
  --pkmd-chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23a0a5ae" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');

  /* --- dark type (TypeSystem) -------------------------------------------
     Typography's dark change is WEIGHT and TRACKING, not colour: light-on-
     dark haloes, so glyphs read heavier. No @supports gate needed — 380 snaps
     to 400 on a static font, harmlessly. The -ui- ladder moves by the same
     -20 for the same reason. */
  --pkmd-weight-regular:   380;
  --pkmd-weight-medium:    480;
  --pkmd-weight-strong:    580;
  --pkmd-weight-ui-medium: 540;
  --pkmd-weight-ui-strong: 570;
  --pkmd-weight-ui-bold:   600;
  --pkmd-weight-display:   660;
  --pkmd-tracking-body:    0.003em;

  /* --- dark elevation (MotionDepth) -------------------------------------
     ELEVATION IS CARRIED BY SURFACE LIGHTNESS HERE, NOT BY SHADOW. Measured:
     compositing black over a dark surface is 5.3x weaker at equal alpha than
     over a light one (alpha 0.30 gives dL +0.1104 light vs +0.0207 dark), and
     matching light level 4 by darkening alone would need alpha 1.00 —
     literally opaque black. Tripling the dark alphas
     (0.028/0.042/0.070 -> 0.121/0.179/0.300) still buys only dL ~0.03, which
     is the approach this rejects. So level N is ColorSystem's surface at rung
     N and MINTS NOTHING; the shadow degrades to a contact shadow plus a top
     hairline, and the ink switches to the cool neutral hue.

     Dark surface steps +0.0316 / +0.0291 / +0.0240 / +0.0326 against light
     shadow steps +0.0276 / +0.0283 / +0.0263 / +0.0291: the totals agree to
     within 0.008 at every level, so the two modes read as the same four
     levels while neither is an inversion of the other. In dark the surface
     step carries 3.7x/4.6x/6.1x/6.6x more perceptual signal than the shadow.

     Hairline alpha 0.045 renders dL +0.0426 (L1) / +0.0405 (L2) and 0.060
     renders +0.0525 (L3) / +0.0507 (L4). An alpha of 0.16 renders +0.1419 — a
     whole elevation level's worth of signal in a 0.5px line, rejected as too
     hot for a reading surface. */
  --pkmd-shadow-ink: oklch(0.10 0.010 265);
  --pkmd-shadow-1:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.045),
    0 1px 2px 0 oklch(from var(--pkmd-shadow-ink) l c h / 0.20);
  --pkmd-shadow-2:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.045),
    0 2px 4px -1px oklch(from var(--pkmd-shadow-ink) l c h / 0.24),
    0 0   6px -2px oklch(from var(--pkmd-shadow-ink) l c h / 0.20);
  --pkmd-shadow-3:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.060),
    0 4px 8px  -2px oklch(from var(--pkmd-shadow-ink) l c h / 0.28),
    0 0   14px -4px oklch(from var(--pkmd-shadow-ink) l c h / 0.22);
  --pkmd-shadow-4:
    inset 0 0.5px 0 0 oklch(1 0 0 / 0.060),
    0 8px 16px -4px oklch(from var(--pkmd-shadow-ink) l c h / 0.32),
    0 0   28px -8px oklch(from var(--pkmd-shadow-ink) l c h / 0.26);
  --pkmd-shadow-hairline: inset 0 0 0 1px oklch(1 0 0 / 0.075);

  /* --- dark scrollbar thumb (LayoutChrome). Explicit oklch of dark text-1's
     own L/C/H, for the same reason as the light values. */
  --pkmd-scrollbar-thumb-hover: oklch(0.955 0.0045 265 / 0.22);
  --pkmd-scrollbar-thumb-active: oklch(0.955 0.0045 265 / 0.38);
  --pkmd-editor-tag-border: var(--pkmd-accent-border);
}
:root[data-theme="dark"], :root[data-theme="dark"] [data-pkmd-accent] {
  --pkmd-accent-solid: oklch(0.520 0.1500 var(--pkmd-accent-h));          /* #0d6abb */
  --pkmd-accent-solid-hover: oklch(0.484 0.1520 var(--pkmd-accent-h));    /* #005fb1 */
  --pkmd-accent-solid-active: oklch(0.452 0.1500 var(--pkmd-accent-h));   /* #0055a5 */
  --pkmd-accent-text: oklch(0.728 0.1050 var(--pkmd-accent-h));           /* #75abe7 */
  --pkmd-accent-border: oklch(0.584 0.0770 var(--pkmd-accent-h));         /* #597ea8 */
  /* The hue channel is the user's, so this chroma has to survive EVERY hue,
     and dark's tightest is the cyan-green side: the ceiling is C 0.0599 at
     hue 180 against 0.2163 at 270. 0.0580 is the whole-wheel maximum, and L
     rises 0.028 to buy it. Past the ceiling the compositor alters the value
     and the tint stops agreeing with the accent it is named after. */
  --pkmd-accent-subtle: oklch(0.330 0.0580 var(--pkmd-accent-h));         /* #1e3752 */
}
