/* ==========================================================================
   PlansFlow — homepage mockup stylesheet (v3)
   HTML + CSS only. No JavaScript on this page.

   Ported from the live app so it renders without React/Tailwind:
     src/pages/Landing.tsx · src/components/Public/*.tsx
     src/styles/plansflow-public.css · src/styles/base.css · tailwind.config.ts

   v3 composition follows Fillout: one centered column, and the tab bar plus
   the top of the panel land inside the first viewport. §7 documents the
   vertical budget that makes that hold.

   Deliberately untouched: the header (§6) and the page background (§3).

   ── TWEAK HERE ────────────────────────────────────────────────────────────
   Everything visual is driven by the tokens in §1. §14 at the bottom is a
   scratch area for experiments so the code above stays clean.
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

/* ── HOW THEMING WORKS ──────────────────────────────────────────────────
   `:root` below is the LIGHT theme and the default. Two blocks after it
   carry the dark palette:

     :root[data-theme="dark"]                  explicit choice (the header
                                               control writes this attribute)
     @media (prefers-color-scheme: dark)       system follow, for visitors
       :root:not([data-theme="light"])         whose JS never runs

   The second block is a deliberate copy of the first. It exists so the
   system-follow path works with zero JavaScript, which is how the rest of
   this site is built. KEEP THE TWO DARK BLOCKS IN SYNC — if you change a
   value in one, change it in the other.

   Everything below the token layer is written against tokens only, so no
   rule anywhere needs to know which theme is on. Where a literal survived
   it is a MASK (`#000` inside mask-image) — those are luminance, not
   colour, and must stay hardcoded in both themes.
   ───────────────────────────────────────────────────────────────────── */

:root {
  color-scheme: light;

  /* Surfaces — pulled directly from the real app's light-theme tokens,
     src/styles/base.css :root (2026-08 cream pass): --card (#EEECE7),
     --secondary (#E6E3DD). Same roles, light instead of dark. */
  --surface:        hsl(43 17% 92%);   /* = --card, cream panels/sidebars */
  --surface-hover:  hsl(40 15% 88%);   /* = --secondary, elevated surfaces */
  --border-soft:    rgba(0, 0, 0, 0.08);
  --border-focus:   rgba(0, 0, 0, 0.18);

  /* Page base — src/styles/base.css :root --background (matte winter-light,
     warm, no harsh whites), the cream the owner asked for. */
  --bg-base:        hsl(45 16% 95%);   /* #F4F3F0 */
  --bg-deep:        hsl(43 17% 92%);   /* #EEECE7, = --surface */
  --background:     hsl(45 16% 95%);
  /* = the real app's --foreground (warm dark gray, deliberately not pure
     black — see base.css comment) rather than an invented value. */
  --text-base:      hsl(0 0% 16%);

  /* Brand — the real app's light-theme --accent (base.css :root, 18 100%
     62%), not the dark-theme --flow hex. Soft/strong are lightness steps
     off the same hue, matching the existing soft-lighter/strong-darker
     relationship. */
  --flow:           hsl(18 100% 62%);
  --flow-soft:      hsl(18 100% 72%);
  --flow-strong:    hsl(18 90% 50%);
  --flow-14:        hsla(18, 100%, 62%, 0.14);
  --flow-24:        hsla(18, 100%, 62%, 0.24);
  --landing-accent: hsl(18 100% 62%);

  /* Zinc scale — inverted for the light pass (2026-08): 100 was
     near-white/most-prominent, now near-black/most-prominent; 500/600
     stay the quiet tier, just light instead of dark. 200 is anchored to
     the real app's --foreground, 400 to its --muted-foreground, so body
     copy matches the platform exactly rather than an invented ramp. */
  --zinc-100: hsl(0 0% 9%);
  --zinc-200: hsl(0 0% 16%);
  --zinc-300: hsl(30 6% 28%);
  --zinc-400: hsl(0 0% 32%);
  --zinc-500: hsl(40 8% 46%);
  --zinc-600: hsl(40 8% 58%);
  --zinc-700: hsl(40 10% 72%);
  --zinc-800: hsl(40 12% 82%);
  --zinc-900: hsl(43 17% 92%);

  /* Semantic aliases so no rule hardcodes a literal: --ink is every
     heading/near-black, --card-solid every opaque card fill. Re-declaring
     these two on an ancestor re-themes the page wholesale. */
  --ink:         #17140f;
  --card-solid:  #F7F5F0;

  /* ── SURFACE PRIMITIVES ────────────────────────────────────────────────
     The five knobs that used to be literals scattered through the file.
     They are what makes the dark pass a token swap instead of a rewrite.

       --paper      the opaque "sheet" fill: plan cards, auth card, active
                    tour tab, doc cards. White on cream; graphite on black.
       --on-ink     text that sits ON an --ink-filled button. Follows --ink
                    to its opposite, so the CTA never goes white-on-white.
       --tint-rgb   the hover/press wash. Black over a light page, white
                    over a dark one — every `rgb(var(--tint-rgb) / .05)` in
                    the file flips direction from this one line.
       --sheen-rgb  the top-edge highlight on raised surfaces. Always white;
                    only the alpha differs per theme.
       --shadow-rgb the shadow ink. Warm near-black on cream (it reads as
                    part of the paper), true black on dark. */
  --paper:       #ffffff;
  --paper-soft:  #F7F5F0;
  --on-ink:      #ffffff;
  --tint-rgb:    0 0 0;
  --sheen-rgb:   255 255 255;
  --shadow-rgb:  23 20 15;

  /* Page field — .pf-public-bg's two gradient stops and the hero plate.
     The plate is the lighter field behind the first ~1.5 screens; in dark
     it stays a step ABOVE the page base so the hero still lifts. */
  --page-a:      #F4F3F0;
  --page-b:      #EEECE7;
  /* The dark closing plane on the homepage ("Make room for thought."). A
     plane in light; in dark it is the page itself, so no section sits on a
     differently tinted black (2026-09-17). */
  --plane:       #17140F;
  --plane-sheen: rgba(255, 255, 255, 0.06);
  --page-vignette: rgb(var(--tint-rgb) / 0.02);
  /* Was pure #ffffff. Mixed off the existing paper tokens so the hero field
     reads as a warm canvas surface rather than a bare white sheet; it still
     sits ~8 steps above --page-a, so the hero keeps its lift. Dark themes
     redefine --plate themselves and are unaffected. */
  --plate:       color-mix(in srgb, var(--paper) 62%, var(--paper-soft));
  /* Canvas-field dot weight (§3). Dark dots on a light ground carry less at
     equal alpha than light dots on dark, so light runs the higher number.
     1px points read far softer than a continuous hairline, so 0.10 still
     sits under --border-soft (0.08 lines) perceptually. */
  --pf-lattice-alpha: 0.10;

  /* Chrome that floats over the page and needs its own fill, not a tint:
     the nav bar and the two tour glass surfaces. */
  --nav-fill:     rgba(255, 255, 255, 0.5);
  --glass-fill:   rgba(255, 255, 255, 0.72);
  --glass-fill-2: rgba(255, 255, 255, 0.35);

  --selection-bg: rgba(24, 24, 26, 0.16);
  --selection-fg: #0d0d0f;

  /* The checkbox tick. It is painted ON the --ink fill, so its colour is
     --on-ink — but it lives inside a data URI, which cannot read a custom
     property, so the whole URL is the token instead of just the stroke. */
  --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.3 2.3 4.7-5' fill='none' stroke='%23fff' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  /* Shadows — tailwind.config.ts boxShadow */
  /* Written against --sheen-rgb / --shadow-rgb so the same five tokens
     serve both themes: the top-edge sheen stays white and the drop stays
     the theme's shadow ink. */
  --shadow-hairline: inset 0 1px 0 rgb(var(--sheen-rgb) / 0.05);
  --shadow-glass:    inset 0 1px 0 rgb(var(--sheen-rgb) / 0.05), 0 8px 32px -4px rgb(var(--shadow-rgb) / 0.3);
  --shadow-premium:  0 24px 48px -12px rgb(var(--shadow-rgb) / 0.4);
  --shadow-cockpit:  0 20px 70px rgb(var(--shadow-rgb) / 0.32);
  --shadow-input:    inset 0 1px 2px rgb(var(--shadow-rgb) / 0.2);

  /* Radii — --radius: 0.5rem */
  --radius-lg:  6px;
  --radius-xl:  10px;
  --radius-2xl: 14px;
  /* The hero prompt is the one soft object on the page. Nothing else goes
     above 16px, which is what keeps it reading as a single focal object. */
  --radius-prompt: 20px;

  /* ── FROSTED GLASS ─────────────────────────────────────────────────────
     Glass budget = the hero prompt only (the nav uses its own lighter blur,
     not these tokens). The editorial pass (2026-08) flattened the tour menu
     and tour panel to tonal graphite — treat these as prompt-only knobs.
     Light pass: a cream tint plus a white sheen, instead of a dark tint. */
  /* --well is the RECESSED field: the mat around the screenshot slot. It is
     the one surface that must not flip direction — a well reads as a well by
     going darker than what it sits in, in BOTH themes. Mirroring it as a
     white tint made it the brightest object on the dark page. */
  --well:        rgba(0, 0, 0, 0.18);

  /* The prompt's focus fill. A token per theme rather than a re-pointed
     --glass-tint, for the reason in the .pf-prompt:focus-within note. */
  --glass-tint-focus: rgba(238, 236, 231, 0.72);

  --glass-tint:   rgba(238, 236, 231, 0.55);
  --glass-sheen:  linear-gradient(180deg, rgba(255,255,255,0.5), rgba(255,255,255,0.15));
  --glass-blur:   blur(16px) saturate(1.6);
  --glass-border: rgba(0, 0, 0, 0.08);
  --glass-glaze:  inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -1px 0 rgba(0,0,0,0.08);
  --glass-lift:   0 18px 44px -18px rgba(0, 0, 0, 0.18);

  /* Type — three voices, each with one job.
       sans    Inter        reading: body, nav, panel copy
       mono    Roboto Mono  system: micro-labels, indices, captions
       mark    Clepto       the wordmark, nothing else
       display Bricolage    the hero statement, nothing else */
  --font-sans:    Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono:    "Roboto Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  --font-mark:    "Clepto", var(--font-sans);
  --font-display: "Bricolage Grotesque", var(--font-sans);

  /* Motion — two easings, two durations. Everything interactive uses these. */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --dur-fast: 160ms;
  --dur-med: 240ms;
  --shell-max: 72rem;   /* max-w-6xl */
}


/* ==========================================================================
   1b. DARK THEME
   --------------------------------------------------------------------------
   THE APP'S OWN CANVAS (2026-09-17). The page is one flat #101214 — the
   platform's dark canvas exactly (src/styles/base.css .dark --background
   and canvas.css --canvas-base: hsl(220 8% 7%)) — with panels at the
   app's --card #16181B, elevated surfaces at its --secondary #1A1D21 and
   the deeper #0D0E10 for wells. Graphite, matte, no gradient anywhere. The
   owner's rule: dark on the site must be identical to the canvas in the
   product. Same orange in both themes.

   Three rules held while picking these:

     1. NEAR-BLACK, NEVER #000, for large fields. A hair of value is what
        reads as matte and deliberate; pure black reads as a hole.
     2. OFF-WHITE, NEVER #FFF, for text at size. #ECECEE on #0D0D0F is
        ~15.6:1 — plenty — without the glare of full white on black.
     3. DEPTH IS TONE + HAIRLINE, not shadow. A drop shadow on near-black
        is invisible; the lift comes from --surface stepping up off
        --background and a 6% white border catching the edge.

   ⚠ The @media block below is a copy of this one. KEEP THEM IN SYNC.
   ========================================================================== */

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

  --surface:        #16181B;
  --surface-hover:  #1A1D21;
  --border-soft:    rgba(255, 255, 255, 0.07);
  --border-focus:   rgba(255, 255, 255, 0.16);

  --bg-base:        #101214;
  --bg-deep:        #0D0E10;
  --background:     #101214;
  --text-base:      #ECECEE;

  /* Same orange, both themes — the accent is the brand and does not shift.
     Only the tint alphas lift a little, because a 14% wash over black
     carries less than the same wash over cream. */
  --flow:           #FF7A2F;
  --flow-soft:      #FF9A62;
  --flow-strong:    #F2670F;
  --flow-14:        rgba(255, 122, 47, 0.16);
  --flow-24:        rgba(255, 122, 47, 0.28);
  --landing-accent: #FF7A2F;

  /* The zinc ramp runs the other way: 100 stays "most prominent", which in
     dark means near-white. Every rule using it keeps working unchanged. */
  --zinc-100: #FAFAFA;
  --zinc-200: #ECECEE;
  --zinc-300: #D4D4D8;
  --zinc-400: #A1A1AA;
  --zinc-500: #8B8B94;
  --zinc-600: #71717A;
  --zinc-700: #52525B;
  --zinc-800: #3F3F46;
  --zinc-900: #27272A;

  /* --ink flips, and the whole ORNAMENT set (§ORNAMENTS) re-themes with it
     for free — every mark there is color-mix'd off --ink by design. */
  --ink:         #ECECEE;
  --card-solid:  #16181B;

  --paper:       #16181B;
  --paper-soft:  #0D0E10;
  --on-ink:      #101214;
  --tint-rgb:    255 255 255;
  --sheen-rgb:   255 255 255;
  --shadow-rgb:  0 0 0;

  --page-a:      #101214;
  --page-b:      #101214;
  --plane:       #101214;
  --plane-sheen: transparent;
  /* The one warm moment in the field: a faint flow-tinted bloom at the top
     of the page, which is what the original dark landing had. Under 5% — it
     should be felt, not seen, and it does not count against the orange
     budget because you cannot point at it. */
  --page-vignette: transparent;
  --plate:       #101214;
  --pf-lattice-alpha: 0.075;

  --nav-fill:     rgba(16, 18, 20, 0.72);
  --glass-fill:   rgba(22, 24, 27, 0.8);
  --glass-fill-2: rgba(255, 255, 255, 0.04);

  --selection-bg: rgba(255, 122, 47, 0.3);
  --selection-fg: #ffffff;
  --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.3 2.3 4.7-5' fill='none' stroke='%23101214' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  --well:        rgba(0, 0, 0, 0.5);
  --glass-tint-focus: rgba(22, 24, 27, 0.74);
  --glass-tint:   rgba(16, 18, 20, 0.58);
  --glass-sheen:  linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015));
  --glass-border: rgba(255, 255, 255, 0.09);
  --glass-glaze:  inset 0 1px 0 rgba(255,255,255,0.07), inset 0 -1px 0 rgba(0,0,0,0.45);
  --glass-lift:   0 18px 44px -18px rgba(0, 0, 0, 0.72);
}

/* System follow, no JavaScript required. Applies whenever the visitor has
   NOT explicitly chosen light — the header control writes data-theme, and
   an explicit "light" wins over the OS here.
   ⚠ Mirror of the block above. KEEP IN SYNC. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --surface:        #16181B;
    --surface-hover:  #1A1D21;
    --border-soft:    rgba(255, 255, 255, 0.07);
    --border-focus:   rgba(255, 255, 255, 0.16);

    --bg-base:        #101214;
    --bg-deep:        #0D0E10;
    --background:     #101214;
    --text-base:      #ECECEE;

    --flow:           #FF7A2F;
    --flow-soft:      #FF9A62;
    --flow-strong:    #F2670F;
    --flow-14:        rgba(255, 122, 47, 0.16);
    --flow-24:        rgba(255, 122, 47, 0.28);
    --landing-accent: #FF7A2F;

    --zinc-100: #FAFAFA;
    --zinc-200: #ECECEE;
    --zinc-300: #D4D4D8;
    --zinc-400: #A1A1AA;
    --zinc-500: #8B8B94;
    --zinc-600: #71717A;
    --zinc-700: #52525B;
    --zinc-800: #3F3F46;
    --zinc-900: #27272A;

    --ink:         #ECECEE;
    --card-solid:  #16181B;

    --paper:       #16181B;
    --paper-soft:  #0D0E10;
    --on-ink:      #101214;
    --tint-rgb:    255 255 255;
    --sheen-rgb:   255 255 255;
    --shadow-rgb:  0 0 0;

    --page-a:      #101214;
    --page-b:      #101214;
  --plane:       #101214;
  --plane-sheen: transparent;
    --page-vignette: transparent;
    --plate:       #101214;
    --pf-lattice-alpha: 0.075;

    --nav-fill:     rgba(16, 18, 20, 0.72);
    --glass-fill:   rgba(22, 24, 27, 0.8);
    --glass-fill-2: rgba(255, 255, 255, 0.04);

    --selection-bg: rgba(255, 122, 47, 0.3);
    --selection-fg: #ffffff;
    --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2l2.3 2.3 4.7-5' fill='none' stroke='%23101214' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

    --well:        rgba(0, 0, 0, 0.5);
    --glass-tint-focus: rgba(22, 24, 27, 0.74);
    --glass-tint:   rgba(16, 18, 20, 0.58);
    --glass-sheen:  linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015));
    --glass-border: rgba(255, 255, 255, 0.09);
    --glass-glaze:  inset 0 1px 0 rgba(255,255,255,0.07), inset 0 -1px 0 rgba(0,0,0,0.45);
    --glass-lift:   0 18px 44px -18px rgba(0, 0, 0, 0.72);
  }
}

/* Theme changes are instant on purpose — no cross-fade. A 200ms tween on
   every colour in the document is a whole-page repaint that stutters, and
   the swap is more convincing when it lands in one frame. */

/* Clepto — self-hosted display face by @gadotak, used for the wordmark only.
   Free for personal and commercial use; see assets/fonts/Clepto-LICENSE.txt.
   Ships a single 400 cut, so weight has nothing to interpolate. */
@font-face {
  font-family: "Clepto";
  src: url("assets/fonts/Clepto-Regular.otf") format("opentype"),
       url("assets/fonts/Clepto-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}


/* ==========================================================================
   2. RESET + PAGE SHELL
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--background);
  color: var(--text-base);
  overflow-x: hidden;
  max-width: 100vw;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, textarea { font: inherit; }
h1, h2, h3, p, figure, figcaption, ul { margin: 0; }
ul { padding: 0; list-style: none; }

/* .pf-public-bg — light pass (2026-08): cream base, matching the real
   app's light-theme --background/--card (src/styles/base.css). */
.pf-public-bg {
  /* One flat, matte field per theme (2026-09-17): no vignette, no ramp. The
     canvas lattice in .pf-bg (§3) is the only thing drawn on it. */
  background-color: var(--page-a);
  color: var(--text-base);
  font-family: var(--font-sans);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}
.pf-public-bg ::selection { background: var(--selection-bg); color: var(--selection-fg); }

.pf-root {
  position: relative;
  /* REQUIRED, not cosmetic. `position: relative` alone leaves z-index auto,
     which does NOT open a stacking context — so this element's own opaque
     background paints in the same pass as positioned siblings, i.e. ABOVE its
     own negative-z children. The background plate, the grain, and the glow all
     live at negative z, so without this they are painted over and never seen.
     z-index: 0 opens the context and puts them where they belong: above the
     base gradient, below every piece of content. */
  z-index: 0;
  min-height: 100vh;
  width: 100%;
  overflow-x: hidden;
  scroll-behavior: smooth;
}

.pf-container {
  margin-inline: auto;
  width: 100%;
  max-width: var(--shell-max);
}


/* ==========================================================================
   3. PAGE BACKGROUND — the canvas field (2026-09-17)
   --------------------------------------------------------------------------
   One flat matte field per theme (§2, .pf-public-bg) and, fixed over it, the
   canvas lattice: the same 20px dot grid the composer is a window onto, an
   order of magnitude quieter, running under every page from top to bottom.
   No plate, no photo, no gradient, no grain. Layer order, bottom to top:
     .pf-public-bg   the flat field colour                          (§2)
     .pf-bg          fixed lattice + the attention pass             z -30
     content

   THE ATTENTION PASS. ::after is a second copy of the lattice, twice the
   weight, visible only through a large feathered window that follows the
   pointer — light moving across a physical surface, not a cursor spotlight.
   canvas-field.js drives --pf-mx / --pf-my / --pf-reveal with a small lerp
   that settles in ~100ms; with no script the layer never appears. Hidden
   outright for touch, coarse pointers and reduced motion. The window is the
   one radial gradient left on the page, and it is a mask, not a colour.
   ========================================================================== */

.pf-bg {
  position: fixed;
  inset: 0;
  z-index: -30;
  pointer-events: none;
}
.pf-bg::before,
.pf-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background-size: 20px 20px;
  background-position: calc(50% + 10px) 12px;
}
.pf-bg::before {
  background-image: radial-gradient(circle at 1px 1px,
    rgb(var(--tint-rgb) / var(--pf-lattice-alpha, 0.08)) 1px, transparent 0);
}
.pf-bg::after {
  background-image: radial-gradient(circle at 1px 1px,
    rgb(var(--tint-rgb) / calc(var(--pf-lattice-alpha, 0.08) * 2.2)) 1px,
    transparent 0);
  opacity: var(--pf-reveal, 0);
  -webkit-mask-image: radial-gradient(circle 430px
    at var(--pf-mx, 50%) var(--pf-my, -600px),
    rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.38) 42%,
    rgba(0, 0, 0, 0.16) 68%, transparent 88%);
  mask-image: radial-gradient(circle 430px
    at var(--pf-mx, 50%) var(--pf-my, -600px),
    rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.38) 42%,
    rgba(0, 0, 0, 0.16) 68%, transparent 88%);
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .pf-bg::after { display: none; }
}

/* ── HERO GRADIENT — retired for the light pass (2026-08) ──────────────
   Dark blooms over black don't translate to a flat cream field — the
   light theme's own philosophy (base.css: "warm, calm, no harsh whites")
   is a quiet flat surface, not a decorative gradient. The element stays in
   the markup as an empty hook; the retired dark-gradient rules were removed
   in the handoff cleanup. */
.pf-hero-gradient { display: none; }
@media (max-width: 720px) {
  .pf-hero-gradient { height: 760px; }
}

/* Film grain — retired 2026-09-17 with the flat field: the page is smooth by
   decision, and the lattice is its only texture. Markup was removed from the
   pages; the rule stays so a stray copy renders as nothing. */
.pf-noise-layer, .pf-noise { display: none; }
/* Retired for the light pass (2026-08) — same reasoning as .pf-hero-gradient
   above: a warm dark-mode ambient bloom reads as a stain on flat cream.
   display:none only, so reverting to dark is a one-line change. */
.pf-glow { display: none; }


/* ==========================================================================
   4. ANIMATIONS  (tailwind.config.ts keyframes)
   ========================================================================== */

@keyframes fade-up {
  0%   { opacity: 0; transform: translateY(10px); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes rise-soft {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes line-in {
  0%   { opacity: 0; transform: scaleX(0); }
  100% { opacity: 1; transform: scaleX(1); }
}

.animate-fade-up         { animation: fade-up 640ms var(--ease-out-expo) both; }
.animate-fade-up-delayed { animation: fade-up 640ms var(--ease-out-expo) 120ms both; }
.animate-fade-up-late    { animation: fade-up 640ms var(--ease-out-expo) 240ms both; }
.animate-line-in         { animation: line-in 600ms var(--ease-out-expo) both; }

/* The prompt is deliberately exempt from the cascade: `fade-up` animates
   opacity, and an element with opacity < 1 becomes a backdrop root — its own
   backdrop-filter would have nothing to sample, so the glass would render
   flat for the length of the fade and then snap in. */

@media (prefers-reduced-motion: reduce) {
  .animate-fade-up,
  .animate-fade-up-delayed,
  .animate-fade-up-late,
  .animate-line-in { animation: none; }
  .pf-tour-glider { transition: none; }
  .pf-theme-opt { transition: none; }
  .pf-root { scroll-behavior: auto; }
}


/* ==========================================================================
   5. SHARED PRIMITIVES
   ========================================================================== */

.icon, .icon-12, .icon-14, .icon-16, .icon-18, .icon-20 { flex: none; }
.icon-4  { width: 1rem;    height: 1rem; }
.icon-12 { width: 12px;    height: 12px; }
.icon-16 { width: 16px;    height: 16px; }
.icon-5  { width: 1.25rem; height: 1.25rem; }
.icon-14 { width: 14px;    height: 14px; }
.icon-18 { width: 18px;    height: 18px; }
.icon-20 { width: 20px;    height: 20px; }

/* Visually hidden, still announced. Used by the hero composer's field label. */
.pf-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* .pf-pill — demoted from a glass chip to a bare mono label (editorial pass):
   fewer floating objects above the statement, archive voice instead. Type
   spec joins the shared micro-label rule below; only layout stays here. */
.pf-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--zinc-500);
}

/* BrandWordmark — .pf-accent (orange) is the base brand style, but the
   header logo is a single clean-white wordmark (editorial pass, 2026-08):
   "Flow" inherits the wordmark's own white rather than taking the accent,
   fixed regardless of the hero's Black/White text-mode toggle. The footer
   echo stays grey so the page's one orange moment remains the Access CTA. */
.pf-accent { color: var(--landing-accent); }
.pf-wordmark--footer .pf-accent { color: var(--zinc-300); }
.pf-wordmark--nav .pf-accent { color: inherit; }

/* Clepto in the header, matching the accent word in the hero. It is a display
   cut, so at nav size it needs a touch more size and tracking than the text
   faces around it to stay crisp; the trailing letter-space is pulled back so
   the mark still sits flush against the nav's left edge. */
.pf-wordmark--nav {
  font-family: var(--font-mark);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.045em;
  margin-right: -0.045em;
  color: var(--ink);
  line-height: 1;
}
.pf-wordmark--footer {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--zinc-300);
  line-height: 1;
}

/* The one accent gradient, on a single run of the hero statement. */
/* The accent word is the one place Clepto appears in the headline. It runs
   inline inside a Bricolage line, so it needs its own metrics: Clepto sits
   smaller on the em and carries no negative tracking of its own.
   The trailing letter-spacing is pulled back on the right — otherwise the
   space after the last glyph pushes the following text away and the word
   reads off-centre in its own line. */
.pf-accent-gradient {
  font-style: normal;
  font-family: var(--font-mark);
  font-weight: 400;
  font-size: 1.06em;
  letter-spacing: 0.04em;
  margin-right: -0.04em;
  background: linear-gradient(122deg, var(--flow-soft) 8%, var(--flow) 62%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Hero statement: the accent word keeps the full Clepto treatment from the
   rule above (face, 400 cut, gradient, tracking) — only the size bump is
   cancelled. 1.06em was tuned to match the old 91px statement optically;
   at 64px it made the word out-shout the line. At 1em Clepto sits a touch
   under the Bricolage caps, which is the integrated reading we want. */
.pf-statement .pf-accent-gradient {
  font-size: 1em;
}

/* Mono micro-labels — ONE system voice for every archive label on the page.
   Color stays per-selector; only the type spec is shared. */
.pf-mono-label, .pf-eyebrow, .pf-index-num, .pf-track-key, .pf-flowchain-key,
.pf-shot-empty, .pf-shot-cap, .pf-launch-date, .pf-card-num, .pf-footer-status,
.pf-pill {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
/* Pill's type reads from the hero dev-tool vars (repurposed from the
   retired PlansFlow mark group above) — same knobs, new target. Must come
   after the shared mono-label rule to win the cascade at equal specificity. */
.pf-pill {
  font-family: var(--hero-pill-font);
  font-size: var(--hero-pill-size);
  font-weight: var(--hero-pill-weight);
  letter-spacing: var(--hero-pill-track);
}
.pf-mono-label { color: var(--zinc-500); }
.pf-eyebrow { color: var(--zinc-600); }
.pf-hairline { flex: 1; height: 1px; background: var(--border-soft); }

.pf-h2 {
  margin-top: 0.75rem;
  max-width: 28rem;
  font-size: 1.875rem;
  line-height: 2.25rem;
  font-weight: 500;
  letter-spacing: -0.025em;
  color: var(--ink);
}
@media (min-width: 640px) { .pf-h2 { font-size: 2.25rem; line-height: 2.5rem; } }

.pf-section { padding: 4.5rem 1rem; }
@media (min-width: 640px) { .pf-section { padding-inline: 1.5rem; } }
@media (min-width: 768px) { .pf-section { padding-block: 6rem; } }
.pf-section--bordered-t { border-top: 1px solid var(--border-soft); }

.pf-split-head { display: grid; gap: 2rem; }
@media (min-width: 768px) {
  .pf-split-head { grid-template-columns: .85fr 1.15fr; align-items: end; }
  .pf-split-lede { justify-self: end; }
}
.pf-split-lede {
  max-width: 44ch;
  font-size: 0.875rem;
  line-height: 1.625;
  color: var(--zinc-400);
}

.pf-divider-line {
  margin-top: 3rem;
  height: 1px;
  transform-origin: left;
  background-image: linear-gradient(to right, transparent, rgb(var(--tint-rgb) / 0.12), transparent);
}

.pf-cards-3 { margin-top: 3rem; display: grid; gap: 1.5rem; }
@media (min-width: 768px) { .pf-cards-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }


/* ==========================================================================
   6. HEADER  (PublicHeader.tsx) — unchanged
   ========================================================================== */

.pf-header {
  position: absolute;
  inset-inline: 0;
  top: 0;
  z-index: 20;
  padding: 1.5rem 1rem;
}
@media (min-width: 640px) { .pf-header { padding-inline: 2rem; } }

.pf-nav {
  margin-inline: auto;
  display: grid;
  height: 3.5rem;
  max-width: var(--shell-max);
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 1rem;
  border-radius: var(--radius-2xl);
  border: 1px solid var(--border-soft);
  background: var(--nav-fill);
  padding-inline: 1rem;
  box-shadow: var(--shadow-hairline);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
@media (min-width: 640px) {
  .pf-nav { grid-template-columns: 1fr auto 1fr; padding-inline: 1.5rem; }
}

.pf-nav-brand {
  display: inline-flex;
  min-width: 0;
  align-items: center;
  gap: 0.5rem;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.pf-nav-brand:hover { opacity: 0.8; }

.pf-nav-links { display: none; align-items: center; gap: 0.375rem; font-size: 14px; color: var(--zinc-400); }
@media (min-width: 640px) { .pf-nav-links { display: flex; } }

.pf-nav-link {
  border-radius: var(--radius-lg);
  padding: 0.5rem 0.75rem;
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.pf-nav-link:hover { background: rgb(var(--tint-rgb) / 0.05); color: var(--zinc-100); }

.pf-nav-signin {
  justify-self: end;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-soft);
  background: rgb(var(--tint-rgb) / 0.04);
  padding: 0.5rem 1rem;
  font-size: 13px;
  font-weight: 500;
  color: var(--zinc-200);
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.pf-nav-signin:hover {
  border-color: var(--border-focus);
  background: rgb(var(--tint-rgb) / 0.08);
  color: var(--zinc-100);
}

/* The nav's right-hand cluster. `justify-self: end` moved off .pf-nav-signin
   and onto this wrapper when the theme control joined it — the grid's third
   column now holds two things, and they align as one unit. */
.pf-nav-end {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}


/* ==========================================================================
   6b. THEME CONTROL  (Light / Dark)
   --------------------------------------------------------------------------
   Two states, two words (2026-09-17). The control shows the RESOLVED theme:
   with no stored choice it follows the OS and paints whichever side is on;
   a click stores an explicit choice. Mono labels in the nav's own family
   (hairline ring, the nav radius), the active side filled with ink. No
   icons, no glider. Hidden until <html> gets `js`, so it is never a dead
   control.
   ========================================================================== */

.pf-theme { display: none; }

html.js .pf-theme {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-xl);
  border: 1px solid var(--border-soft);
  background: rgb(var(--tint-rgb) / 0.04);
}

.pf-theme-opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0 11px;
  border-radius: calc(var(--radius-xl) - 3px);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zinc-500);
  transition: color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
.pf-theme-opt:hover { color: var(--zinc-200); }
.pf-theme-opt[aria-pressed="true"] { background: var(--ink); color: var(--on-ink); }
:root[data-theme="dark"] .pf-theme-opt[data-set-theme="system"][aria-pressed="true"] { background: var(--flow); color: #fff; }
.pf-theme-opt:focus-visible {
  outline: 2px solid var(--flow);
  outline-offset: 1px;
}

/* auth.html has no nav to live in — it is a single centred card with just a
   wordmark above it. The control floats in the corner the nav would have
   occupied, so its position still reads as "page chrome". */
html.js .pf-theme--float {
  position: fixed;
  z-index: 30;
  top: 1.5rem;
  right: 1.5rem;
  background: var(--nav-fill);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
@media (max-width: 640px) {
  html.js .pf-theme--float { top: 1rem; right: 1rem; }
}

/* On a phone the nav is brand + this cluster and nothing else, and the two
   have to share 375px with room to breathe. */
@media (max-width: 420px) {
  .pf-theme-opt { height: 26px; padding: 0 8px; font-size: 9px; }
  .pf-nav-end { gap: 0.375rem; }
}

/* 320–360: the two words are wider than the three icons were, so the whole
   row gives up a few pixels on each side rather than letting the control
   ride over the wordmark. Measured: 11px of clearance at 320. */
@media (max-width: 360px) {
  .pf-nav { padding-inline: 0.75rem; }
  .pf-wordmark--nav { font-size: 15px; }
  .pf-theme-opt { padding: 0 6px; }
  .pf-nav-signin { padding-inline: 0.75rem; }
}


/* ==========================================================================
   7. HERO — one centered column
   --------------------------------------------------------------------------
   THE VERTICAL BUDGET. The tab bar and the top of the panel have to clear a
   800px-tall viewport, so every value below is spent deliberately:

      96  hero padding-top (clears the 80px absolute header, plus air)
      30  pill
      20  gap
      60  wordmark
      46  statement
      31  discipline row + gap
     180  prompt + gap
      44  starters + gap
      32  hero padding-bottom
      50  tab bar
      20  gap
     ---
     609  → ~190px of the panel is visible on load.

   The prompt is the expensive line and it is meant to be: it is the hero
   object. Everything around it was trimmed to pay for its height.

   Change any of these and re-check at 1280x800 before shipping.
   ========================================================================== */

/* ── HERO TUNING VARS ────────────────────────────────────────────────────
   Every size and gap in the hero reads from one of these, so the dev tool
   can drive the whole block and Copy code pastes straight back here.
   Sizes stay inside min() so they still shrink on narrow screens. */
.pf-hero {
  --hero-pad-top: 106px;      /* top of the plate to the pill                */
  --hero-gap-pill: 20px;     /* pill        → wordmark                      */
  --hero-gap-mark: 0px;      /* wordmark    → statement                     */
  --hero-gap-stmt: 18px;     /* unused since the supporting line retired    */
  --hero-gap-sub: 44px;      /* statement   → prompt (line removed, so the
                                gap carries the full separation itself)     */
  --hero-gap-prompt: 18px;   /* prompt      → starters                      */

  --hero-mark-font: var(--font-mono);
  --hero-mark-size: 21px;
  --hero-mark-weight: 900;
  --hero-mark-track: 0.16em;

  /* Repurposed 2026-08 from the retired PlansFlow mark group — same dev-tool
     slot, now drives the "AI personal workspace" pill instead. */
  --hero-pill-font: var(--font-mono);
  --hero-pill-size: 11px;
  --hero-pill-weight: 400;
  --hero-pill-track: 0.14em;

  /* 91px → 64px on the hero refinement pass: at 91 the phrase read as a
     slogan and out-shouted the composer. 64 keeps the display jump against
     the 11px mono labels and sits just inside the prompt's 768px width. */
  --hero-stmt-size: 64px;
  --hero-stmt-lh: 0.95;

  --hero-sub-size: 15px;
  --hero-sub-word-gap: 37px;

  --hero-col-w: 1200px;       /* the column everything sits in — caps the prompt */
  --hero-prompt-w: 768px;
  --hero-prompt-h: 108px;
  --hero-prompt-size: 17.5px;
  --hero-prompt-radius: 21px;
  --hero-chip-size: 12.5px;

  position: relative;
  padding: var(--hero-pad-top) 1rem 1rem;
}
@media (min-width: 640px) { .pf-hero { padding-inline: 2rem; } }

.pf-hero-inner {
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
  max-width: var(--hero-col-w);
}

/* ── The headline: one voice, two sizes ─────────────────────────────────
   Wordmark and statement share Bricolage Grotesque 800; hierarchy reads
   through scale alone. Clepto is reserved for the accent word — see
   .pf-accent-gradient below. */
.pf-hero-title {
  margin-top: var(--hero-gap-pill);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* NOT `gap` — flex gap rejects negative lengths, so a negative value made
     the whole declaration invalid and silently fell back to 0. The seam is a
     margin on the statement instead, which can go negative for real. */
  gap: 0;
}

.pf-mark {
  font-family: var(--hero-mark-font);
  font-optical-sizing: auto;
  font-size: min(var(--hero-mark-size), 12vw);
  font-weight: var(--hero-mark-weight);
  line-height: 1;
  letter-spacing: var(--hero-mark-track);
  color: var(--ink);
}

/* Bricolage Grotesque 800 — a display grotesque, not a UI face scaled up.
   `font-optical-sizing: auto` drives its opsz axis, so at 40px it renders the
   display cut: tighter apertures, more contrast in the stems. Same family,
   weight, and tracking direction as .pf-mark above it. */
.pf-statement {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: min(var(--hero-stmt-size), 10vw);
  line-height: var(--hero-stmt-lh);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
  margin-top: var(--hero-gap-mark);
}

/* ── The supporting line — RETIRED (hero simplification pass) ───────────
   The sentence under the statement was removed from the markup entirely:
   the eyebrow names the category, the statement carries the point of view,
   the composer demonstrates. These rules stay as the re-entry point if a
   line is ever wanted back. */
.pf-hero-sub {
  margin-top: var(--hero-gap-stmt);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--hero-sub-word-gap);
  line-height: 1.2;
}
.pf-sub-item {
  max-width: 48em;
  font-size: var(--hero-sub-size);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0;
  color: var(--zinc-400);
  text-wrap: balance;
}
.pf-sub-dot {
  width: 3px;
  height: 3px;
  flex: none;
  border-radius: 9999px;
  background: var(--zinc-600);
}

/* ── Prompt starters — three quiet examples under the composer ──────────
   Demoted from pill chips on the editorial pass: no containers, no fills,
   no borders. A 10px mono archive label, then three text actions divided
   by 12px hairlines — the page's own scaffolding voice. Deliberately a
   full step quieter than every composer control, so the reading order
   stays statement → line → composer → examples. */
.pf-starters {
  margin-top: var(--hero-gap-prompt);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
/* (.pf-starters-label retired with the "Examples" heading — the row of
   three explains itself; one less layer between statement and composer.) */
.pf-starters-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px 32px;
}
.pf-starter {
  position: relative;
  padding: 2px 0;
  font-size: 13px;
  letter-spacing: 0.01em;
  color: var(--zinc-500);
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-starter:hover { color: var(--ink); }
.pf-starter:focus-visible {
  outline: 2px solid var(--flow);
  outline-offset: 4px;
  border-radius: 2px;
}
/* Hairline dividers, centred in the 32px column gap. They only make sense
   on one row, so the stacked mobile list drops them. */
.pf-starter + .pf-starter::before {
  content: '';
  position: absolute;
  left: -16px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 12px;
  background: var(--border-soft);
}
@media (max-width: 720px) {
  .pf-starters-row { flex-direction: column; gap: 10px; }
  .pf-starter + .pf-starter::before { display: none; }
}


/* ==========================================================================
   8. HERO PROMPT — the one soft object on the page
   --------------------------------------------------------------------------
   A working composer, not a sign-in gate. A visitor can type, turn Search on,
   and pick an agent count; only committed actions (an attachment source,
   Improve prompt, dictate, send) ask them to sign in.

   Design source: PlansFlow 1.1.0 / public/prompt-bar-mockup — hierarchy,
   selection treatment, send shape, canvas lattice and motion are that design
   verbatim. Everything here is expressed in THIS page's tokens (--glass-*,
   --zinc-*, --tint-rgb, --flow, --hero-prompt-*), so light, dark and system
   all follow with no per-theme rules and nothing new to keep in sync.

   Layout is three zones, top to bottom:
     the field, full width, nothing beside it
     the rail — context and modes left, act-on-prompt and commit right
   ========================================================================== */

.pf-prompt {
  position: relative;
  margin: var(--hero-gap-sub) auto 0;
  width: 100%;
  max-width: var(--hero-prompt-w);
  text-align: left;

  background-image: var(--glass-sheen);
  background-color: var(--glass-tint);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--hero-prompt-radius);
  box-shadow: var(--glass-glaze), var(--glass-lift);
  /* was hidden — the popovers have to escape the surface */
  overflow: visible;
  cursor: text;
  transition: background-color var(--dur-med) var(--ease-standard),
              border-color var(--dur-med) var(--ease-standard);
}

/* Gains a little body on focus so typing never fights the background.
   Declared concretely rather than by re-pointing --glass-tint: a transitioned
   property whose value arrives through a custom property freezes at its
   pre-change value, and the effect silently never fires. */
.pf-prompt:focus-within {
  background-color: var(--glass-tint-focus);
  border-color: rgb(var(--tint-rgb) / 0.16);
}

/* The single accent hairline, drawn from the centre on focus. */
.pf-prompt-seam {
  position: absolute;
  left: 50%;
  bottom: 0;
  height: 1.5px;
  width: 72%;
  transform: translateX(-50%) scaleX(0);
  transform-origin: center;
  background: linear-gradient(90deg,
    transparent, var(--flow) 22%, var(--flow) 78%, transparent);
  opacity: 0;
  transition: transform 420ms var(--ease-out-soft, cubic-bezier(0.16, 1, 0.3, 1)),
              opacity var(--dur-med) var(--ease-standard);
  pointer-events: none;
  z-index: 3;
}
.pf-prompt:focus-within .pf-prompt-seam {
  transform: translateX(-50%) scaleX(1);
  opacity: 0.5;
}

/* Popover anchor — a positioning context and nothing else. */
.pf-pa { position: relative; }

/* ── FIELD ───────────────────────────────────────────────────────────────── */

.pf-prompt-input {
  position: relative;
  display: block;
  padding: 1rem 1rem 0.25rem;
}

.pf-prompt-field {
  display: block;
  width: 100%;
  min-height: 54px;
  max-height: 210px;
  overflow-y: auto;
  resize: none;
  border: 0;
  background: transparent;
  outline: none;
  padding: 0 2.125rem 0 0;
  /* Sans, not the page's mono: this is where a paragraph gets written, and
     the composer was designed around long prompts. Flip this one line back to
     var(--font-mono) if the mono voice matters more than the reading. */
  font-family: var(--font-sans);
  font-size: var(--hero-prompt-size);
  line-height: 1.6;
  color: var(--ink);
  caret-color: var(--flow);
  cursor: text;
}
.pf-prompt-field::placeholder {
  color: rgb(var(--tint-rgb) / 0.4);
  transition: opacity var(--dur-med) var(--ease-standard);
}
.pf-prompt:focus-within .pf-prompt-field::placeholder { opacity: 0.6; }

/* Overflow signal — a fade at the top edge once the field has scrolled. */
.pf-prompt-fade {
  position: absolute;
  left: 1px; right: 1px; top: 0;
  height: 26px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(var(--glass-tint-focus), transparent);
  border-radius: var(--hero-prompt-radius) var(--hero-prompt-radius) 0 0;
  transition: opacity var(--dur-med) var(--ease-standard);
}
.pf-prompt[data-scrolled="true"] .pf-prompt-fade { opacity: 1; }

/* Edit text — appears only once the prompt is genuinely long. */
.pf-prompt-expand {
  position: absolute;
  top: 0.75rem; right: 0.75rem;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 0;
  border-radius: var(--radius-lg);
  background: rgb(var(--tint-rgb) / 0.05);
  box-shadow: inset 0 0 0 1px var(--border-soft);
  color: var(--zinc-400);
  cursor: pointer;
  opacity: 0;
  transform: scale(0.86);
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-standard),
              transform var(--dur-med) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard);
}
.pf-prompt-expand:hover { color: var(--ink); background: rgb(var(--tint-rgb) / 0.09); }
.pf-prompt[data-long="true"] .pf-prompt-expand {
  opacity: 1; transform: scale(1); pointer-events: auto;
}

/* ── RAIL ────────────────────────────────────────────────────────────────── */

.pf-prompt-quick {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 0.75rem 0.75rem;
  cursor: default;
}
.pf-prompt-quick-l { display: flex; align-items: center; gap: 0.25rem; min-width: 0; }
.pf-prompt-quick-r {
  display: flex; align-items: center; gap: 0.25rem;
  margin-left: auto; flex: none;
}
/* Dictate and send are one pair: 4px apart, a clear 10px break from the
   prompt-editing controls to their left. */
.pf-prompt-quick-r .pf-pa + .pf-pa { margin-left: 10px; }

.pf-prompt-sep {
  width: 1px; height: 18px;
  background: var(--border-soft);
  margin: 0 0.1875rem;
  flex: none;
}

/* icon button */
.pf-prompt-ico {
  position: relative;
  width: 30px; height: 30px;
  flex: none;
  display: grid; place-items: center;
  border: 0;
  border-radius: var(--radius-lg);
  background: transparent;
  color: var(--zinc-400);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.pf-prompt-ico svg { transition: transform var(--dur-med) var(--ease-standard); }
.pf-prompt-ico:hover { background: rgb(var(--tint-rgb) / 0.05); color: var(--ink); }
.pf-prompt-ico:active { transform: scale(0.94); }
.pf-prompt-ico[aria-expanded="true"] { background: rgb(var(--tint-rgb) / 0.08); color: var(--ink); }
.pf-prompt-ico[data-attach][aria-expanded="true"] svg { transform: rotate(45deg); }

/* mode chip — the page's existing chip look, now a real toggle */
.pf-prompt-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  height: 30px;
  padding: 0 0.625rem;
  border: 0;
  border-radius: var(--radius-lg);
  background: transparent;
  font-family: var(--font-mono);
  font-size: var(--hero-chip-size);
  font-weight: 500;
  line-height: 16px;
  white-space: nowrap;
  color: var(--zinc-400);
  cursor: pointer;
  overflow: hidden;
  transition: color var(--dur-med) var(--ease-standard);
}
.pf-prompt-chip svg { flex: none; z-index: 1; opacity: 0.85; }
.pf-prompt-chip > span { z-index: 1; }
/* the wash arrives from the left rather than popping */
.pf-prompt-chip::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgb(var(--tint-rgb) / 0.05);
  opacity: 0;
  transform: scaleX(0.7);
  transform-origin: left center;
  transition: opacity var(--dur-med) var(--ease-standard),
              transform var(--dur-med) var(--ease-standard);
}
.pf-prompt-chip:hover { color: var(--ink); }
.pf-prompt-chip:hover::before { opacity: 1; transform: scaleX(1); }

/* Selected = a filled, hairlined chip against transparent ones. No hue, no
   badge, and identical padding to the unselected chip, so turning a mode on
   never resizes or shifts the control or its neighbours. Built on --tint-rgb,
   so it is dark-on-cream in light and light-on-graphite in dark. */
.pf-prompt-chip[aria-pressed="true"] { color: var(--ink); }
.pf-prompt-chip[aria-pressed="true"]::before {
  opacity: 1;
  transform: scaleX(1);
  background: rgb(var(--tint-rgb) / 0.10);
  box-shadow: inset 0 0 0 1px rgb(var(--tint-rgb) / 0.16);
}
.pf-prompt-chip[aria-pressed="true"] svg { opacity: 1; }
.pf-prompt-chip[aria-pressed="true"]:hover::before { background: rgb(var(--tint-rgb) / 0.13); }

/* A fixed-width slot for the agent count — always in the layout, empty or
   not, so the chip measures the same selected and unselected. */
.pf-prompt-slot {
  z-index: 1;
  width: 10px;
  flex: none;
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--zinc-400);
}
.pf-prompt-chip[aria-pressed="true"] .pf-prompt-slot { color: var(--ink); }
.pf-prompt-caret { opacity: 0.55; transition: transform var(--dur-med) var(--ease-standard); }
.pf-prompt-chip[aria-expanded="true"] .pf-prompt-caret { transform: rotate(180deg); }

/* named action — Improve prompt says what it does rather than being a glyph */
.pf-prompt-action {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  height: 30px;
  flex: none;
  border: 0;
  border-radius: var(--radius-lg);
  background: transparent;
  font-family: var(--font-mono);
  font-size: var(--hero-chip-size);
  font-weight: 500;
  white-space: nowrap;
  color: var(--zinc-400);
  cursor: pointer;
  max-width: 0;
  padding: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: max-width var(--dur-med) var(--ease-standard),
              opacity var(--dur-med) var(--ease-standard),
              padding var(--dur-med) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.pf-prompt-action svg { flex: none; transition: transform var(--dur-med) var(--ease-standard); }
.pf-prompt[data-armed="true"] .pf-prompt-action {
  max-width: 190px;
  padding: 0 0.625rem;
  opacity: 1;
  pointer-events: auto;
}
.pf-prompt-action:hover { background: rgb(var(--tint-rgb) / 0.05); color: var(--ink); }
.pf-prompt-action:hover svg { transform: rotate(15deg); }

.pf-prompt-count {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--zinc-500);
  font-variant-numeric: tabular-nums;
  flex: none;
  margin-right: 2px;
  opacity: 0;
  transition: opacity var(--dur-med) var(--ease-standard);
}
.pf-prompt[data-long="true"] .pf-prompt-count { opacity: 1; }

/* send — the one filled object in the composer. A wide rounded rect rather
   than the default chat circle: it reads as a button, a destination. */
.pf-prompt-send {
  width: 42px; height: 32px;
  flex: none;
  display: grid; place-items: center;
  border: 0;
  border-radius: 10px;
  background: rgb(var(--tint-rgb) / 0.05);
  box-shadow: inset 0 0 0 1px var(--border-soft);
  color: var(--zinc-400);
  cursor: pointer;
  transition: background var(--dur-med) var(--ease-standard),
              color var(--dur-med) var(--ease-standard),
              box-shadow var(--dur-med) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.pf-prompt-send svg { transition: transform var(--dur-med) var(--ease-standard); }
.pf-prompt[data-armed="true"] .pf-prompt-send,
.pf-sheet[data-armed="true"] .pf-sheet-foot .pf-prompt-send {
  background: var(--flow);
  color: #1A0E06;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--flow) 40%, transparent),
    0 0 0 4px color-mix(in srgb, var(--flow) 13%, transparent),
    0 3px 12px color-mix(in srgb, var(--flow) 26%, transparent);
}
.pf-prompt[data-armed="true"] .pf-prompt-send:hover {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--flow) 46%, transparent),
    0 0 0 6px color-mix(in srgb, var(--flow) 15%, transparent),
    0 4px 16px color-mix(in srgb, var(--flow) 30%, transparent);
}
.pf-prompt[data-armed="true"] .pf-prompt-send:hover svg { transform: translateY(-1.5px); }
.pf-prompt-send:active { transform: scale(0.94); }
.pf-prompt-send.is-launching svg { animation: pf-launch 340ms cubic-bezier(0.16, 1, 0.3, 1) both; }

/* ── POPOVERS ────────────────────────────────────────────────────────────── */

.pf-pop {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  z-index: 20;
  min-width: 258px;
  padding: 5px;
  border-radius: 12px;
  background: var(--paper);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-lift);
  transform-origin: bottom left;
  animation: pf-pop-in 220ms cubic-bezier(0.16, 1, 0.3, 1) both;
  cursor: default;
}
.pf-pop[hidden] { display: none; }
.pf-pop-r { left: auto; right: 0; transform-origin: bottom right; }

.pf-pop-label {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--zinc-500);
  padding: 7px 9px 5px;
}
.pf-pop-item {
  display: flex;
  align-items: center;
  gap: 0.5625rem;
  width: 100%;
  height: 33px;
  padding: 0 9px;
  border: 0;
  border-radius: var(--radius-lg);
  background: transparent;
  font-family: var(--font-sans);
  font-size: 13px;
  text-align: left;
  white-space: nowrap;
  color: var(--zinc-300);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.pf-pop-item svg { flex: none; opacity: 0.75; }
.pf-pop-item:hover { background: rgb(var(--tint-rgb) / 0.05); color: var(--ink); }
.pf-pop-sep { height: 1px; margin: 5px 4px; background: var(--border-soft); }

/* agent stepper */
.pf-pop-steps { display: flex; gap: 4px; padding: 4px 5px 6px; }
.pf-pop-step {
  flex: 1 1 0; min-width: 0; height: 32px;
  border: 0;
  border-radius: var(--radius-lg);
  background: rgb(var(--tint-rgb) / 0.05);
  box-shadow: inset 0 0 0 1px var(--border-soft);
  font-family: var(--font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--zinc-400);
  cursor: pointer;
  display: grid; place-items: center;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.pf-pop-step:hover { color: var(--ink); transform: translateY(-1px); }
/* same selection language as the chips, one step stronger — these cells
   already sit on a well */
.pf-pop-step[aria-pressed="true"] {
  background: rgb(var(--tint-rgb) / 0.14);
  color: var(--ink);
  font-weight: 500;
  box-shadow: inset 0 0 0 1.5px rgb(var(--tint-rgb) / 0.2);
}
.pf-pop-step-locked { color: var(--zinc-500); opacity: 0.6; }
.pf-pop-foot {
  padding: 7px 9px 6px;
  margin-top: 2px;
  border-top: 1px solid var(--border-soft);
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--zinc-500);
}

/* ── EDIT TEXT SHEET ─────────────────────────────────────────────────────── */

.pf-sheet {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgb(var(--shadow-rgb) / 0.62);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: pf-fade-in 200ms var(--ease-standard) both;
}
.pf-sheet[hidden] { display: none; }
.pf-sheet-panel {
  width: min(760px, 100%);
  max-height: min(640px, 86vh);
  display: flex;
  flex-direction: column;
  border-radius: 16px;
  background: var(--paper);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-lift);
  overflow: hidden;
  animation: pf-sheet-in 300ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.pf-sheet-head {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 13px 14px;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--zinc-500);
}
.pf-sheet-head strong { color: var(--ink); font-weight: 500; }
.pf-sheet-body {
  padding: 16px 18px;
  flex: 1;
  min-height: 240px;
  display: flex;
  position: relative;
  isolation: isolate;
}
.pf-sheet-body textarea {
  flex: 1;
  border: 0; outline: 0; resize: none;
  background: transparent;
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.65;
  color: var(--ink);
  caret-color: var(--flow);
}
.pf-sheet-foot {
  display: flex; align-items: center; gap: 0.375rem;
  padding: 10px 12px;
  border-top: 1px solid var(--border-soft);
}
.pf-sheet-kbd {
  display: inline-flex; align-items: center;
  height: 20px; padding: 0 6px;
  border-radius: 5px;
  background: rgb(var(--tint-rgb) / 0.05);
  box-shadow: inset 0 0 0 1px var(--border-soft);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--zinc-500);
  flex: none;
}

/* ── CANVAS LATTICE ──────────────────────────────────────────────────────── *
   A dot grid on the same 20px pitch as the app's canvas, masked so it dissolves
   before it reaches an edge, and fading as the field fills — the prompt reads
   as a window onto the board it is about to become. --tint-rgb makes it dark
   dots on cream and light dots on graphite with one declaration. */

.pf-prompt::before,
.pf-sheet-body::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background-image: radial-gradient(circle at 1px 1px,
    rgb(var(--tint-rgb) / 0.14) 1px, transparent 0);
  background-size: 20px 20px;
  background-position: 12px 10px;
  -webkit-mask-image: radial-gradient(125% 105% at 10% 2%,
    #000 0%, rgba(0, 0, 0, 0.55) 44%, transparent 84%);
  mask-image: radial-gradient(125% 105% at 10% 2%,
    #000 0%, rgba(0, 0, 0, 0.55) 44%, transparent 84%);
  opacity: 1;
  transition: opacity 360ms var(--ease-standard);
}
.pf-prompt:focus-within::before { opacity: 0.5; }
.pf-prompt[data-armed="true"]::before { opacity: 0.22; }

/* the sheet inverts the dissolve: the lattice lives in the empty board BELOW
   the writing and fades out through the lines themselves */
.pf-sheet-body::before {
  -webkit-mask-image: radial-gradient(115% 115% at 50% 108%,
    #000 0%, rgba(0, 0, 0, 0.5) 42%, transparent 82%);
  mask-image: radial-gradient(115% 115% at 50% 108%,
    #000 0%, rgba(0, 0, 0, 0.5) 42%, transparent 82%);
  opacity: 0.6;
}
.pf-sheet[data-armed="true"] .pf-sheet-body::before { opacity: 0.34; }

/* ── STARTERS ────────────────────────────────────────────────────────────── */
/* They fill the prompt now instead of navigating away — clicking one must not
   interrupt the exploration the composer exists to invite. (`font: inherit`
   was dropped here on the editorial pass: the global button reset already
   provides it, and this later copy was overriding the starters' own 13px.) */
.pf-starter {
  text-decoration: none;
  cursor: pointer;
}

@keyframes pf-pop-in {
  from { opacity: 0; transform: translateY(6px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes pf-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pf-sheet-in {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
@keyframes pf-launch {
  0%   { transform: translateY(0);     opacity: 1; }
  45%  { transform: translateY(-14px); opacity: 0; }
  46%  { transform: translateY(10px);  opacity: 0; }
  100% { transform: translateY(0);     opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .pf-prompt *, .pf-prompt *::before, .pf-prompt::before,
  .pf-sheet *, .pf-sheet *::before {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media (max-width: 640px) {
  .pf-prompt[data-armed="true"] .pf-prompt-action { max-width: 30px; padding: 0 7px; }
  .pf-prompt-action span { display: none; }
}


/* ==========================================================================
   9. LOGO LOOP — CSS-only infinite marquee
   --------------------------------------------------------------------------
   Structure follows the React Bits component: a track holding the set twice,
   sliding exactly -50% (one full set) so the seam never lands on screen.

   Two deliberate departures from the reference CSS:

   · Edge softening is a `mask-image`, not ::before/::after colour gradients.
     A colour fade has to know the page background to stay invisible, and this
     page's background is a vertical gradient — the match would drift as the
     section moves. A mask fades to real transparency, so it is correct here
     and stays correct over whatever background lands behind it later.

   · Items are monochrome via `currentColor`. It reads as one system rather
     than fifteen brand palettes competing under the hero, and a neutral
     rendering is the safest way to present a third-party mark.

   Spacing uses `margin-right` on the item rather than a flex `gap` — the
   trailing margin on the last item of set one is what keeps the rhythm even
   across the seam into set two.
   ========================================================================== */

.logoloop-section {
  padding: 1.25rem 0 1.5rem;
}

.logoloop {
  position: relative;
  overflow: hidden;
  /* room for the 1px hover lift — the track is clipped horizontally, so
     without this the raised item loses a pixel off its top edge */
  padding-block: 5px;

  --logoloop-gap: 3.25rem;
  --logoloop-logoHeight: 22px;
  --logoloop-duration: 72s;
  --logoloop-fade: clamp(72px, 16%, 260px);
}

/* the fade — real transparency, so nothing has to match the background.
   `isolation` gives the mask its own stacking context, so it composites
   against a stable backdrop instead of re-resolving one every frame. */
.logoloop--fade {
  isolation: isolate;
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0,
    #000 var(--logoloop-fade),
    #000 calc(100% - var(--logoloop-fade)),
    transparent 100%);
  mask-image: linear-gradient(90deg,
    transparent 0,
    #000 var(--logoloop-fade),
    #000 calc(100% - var(--logoloop-fade)),
    transparent 100%);
}

.logoloop__track {
  display: flex;
  width: max-content;
  user-select: none;

  /* ── Why translate3d and not translateX ──────────────────────────────
     The wrap is geometrically exact — both sets measure the same to the
     fractional pixel, so -50% lands the second set precisely where the
     first began, and frame timing across the boundary is clean.

     What was left was paint. With a 2D transform under a masked ancestor
     the track can be re-rasterised through the mask, and the 1854px jump
     at the wrap exposes a region that may miss its raster deadline — one
     blank frame, which is the flicker.

     Forcing a 3D-composited layer rasterises the track once into a GPU
     texture, so the wrap becomes a pure compositor offset with no repaint.
     `backface-visibility` keeps that layer from being torn down and
     rebuilt, and the explicit `from` means the transform is never resolved
     from the underlying `none` at the iteration boundary. */
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
  will-change: transform;
  animation: logoloop-scroll var(--logoloop-duration) linear infinite;
}
/* -50% is exactly one set: both lists are identical, so the reset is invisible */
@keyframes logoloop-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.logoloop__list {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}

.logoloop__item {
  flex: 0 0 auto;
  margin-right: var(--logoloop-gap);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  line-height: 1;
  white-space: nowrap;

  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  /* var(--ink) — black in light mode, warm-white in dark mode (2026-08).
     Every mark in the strip is drawn with currentColor — Google included
     — so this one declaration carries the whole set. Was hardcoded #fff,
     a leftover from the old dark-only page that read as washed-out on
     the cream background. */
  color: var(--ink);
  opacity: 1;
  transition: color 240ms var(--ease-standard),
              opacity 240ms var(--ease-standard),
              transform 240ms var(--ease-out-expo);
}

/* the mark, whether inline <svg> or a dropped-in <img> */
.logoloop__mark {
  height: var(--logoloop-logoHeight);
  width: auto;
  flex: none;
  display: block;
  object-fit: contain;
}
.logoloop__item img { height: var(--logoloop-logoHeight); width: auto; display: block; object-fit: contain; }

/* wordmark-only items sit a touch larger so they hold the same optical weight
   as an item carrying a mark */
.logoloop__item--word { font-size: 0.9375rem; }

/* ---- hover: quiet, and only on the thing under the cursor ---- */
.logoloop:hover .logoloop__track { animation-play-state: paused; }
.logoloop__item:hover {
  color: var(--flow);
  opacity: 1;
  transform: translateY(-1px);
}

.logoloop-note {
  margin: 1rem auto 0;
  max-width: 44rem;
  padding-inline: 1.5rem;
  text-align: center;
  font-size: 10px;
  line-height: 1.5;
  color: var(--zinc-600);
}

@media (prefers-reduced-motion: reduce) {
  /* stop dead and show the first set from the start, rather than freezing
     mid-slide on a half-cut logo */
  .logoloop__track {
    animation: none;
    transform: translate3d(0, 0, 0);
    will-change: auto;
  }
}


/* ==========================================================================
   10. PRODUCT TOUR — CSS-only tabs
   Five radios drive both the menu state and which panel is shown. No JS,
   and fully keyboard-operable (arrow keys move between radios natively).

   Nothing sits between the hero and the tab bar on purpose — the bar is the
   section heading, and dropping the heading is what lets the panel reach
   the first viewport.
   ========================================================================== */

.pf-tour-section { padding: 1.25rem 1rem 4.5rem; }
@media (min-width: 640px) { .pf-tour-section { padding-inline: 1.5rem; } }
@media (min-width: 768px) { .pf-tour-section { padding-bottom: 6rem; } }

.pf-tab-input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px;
  height: 1px;
}

/* Two elements on purpose: the BAR scrolls, the MENU sizes to max-content.
   That keeps repeat(5, 1fr) resolving to five EQUAL columns at every
   viewport, which is what makes translateX(N * 100%) land exactly. */
.pf-tour-menubar {
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  overflow-x: auto;
  scrollbar-width: none;
}
.pf-tour-menubar::-webkit-scrollbar { display: none; }

.pf-tour-menu {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: center;
  width: max-content;
  padding: 5px;

  /* tonal cream — the glass budget is spent on the prompt and the nav */
  background-color: var(--glass-fill);
  border: 1px solid rgb(var(--tint-rgb) / 0.08);
  border-radius: 9999px;
  box-shadow: none;
}

/* the moving highlight — sits in column 1 and slides one column per step.
   Solid white + a soft shadow (not just an opacity step) so the "selected"
   pill still reads clearly against the already-bright menu bar. */
.pf-tour-glider {
  grid-row: 1;
  grid-column: 1;
  z-index: 0;
  pointer-events: none;
  width: 100%;
  height: 38px;
  border-radius: 9999px;
  background: var(--paper);
  box-shadow: 0 1px 3px rgb(var(--shadow-rgb) / 0.10), 0 1px 2px rgb(var(--shadow-rgb) / 0.06);
  transition: transform 460ms var(--ease-out-expo);
}
#area-2:checked ~ .pf-tour-menubar .pf-tour-glider { transform: translateX(100%); }
#area-3:checked ~ .pf-tour-menubar .pf-tour-glider { transform: translateX(200%); }
#area-4:checked ~ .pf-tour-menubar .pf-tour-glider { transform: translateX(300%); }
#area-5:checked ~ .pf-tour-menubar .pf-tour-glider { transform: translateX(400%); }

.pf-tour-menu label {
  grid-row: 1;
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 38px;
  padding: 0 1.125rem;
  white-space: nowrap;
  border-radius: 9999px;
  color: var(--zinc-500);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.008em;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-tour-menu label:nth-of-type(1) { grid-column: 1; }
.pf-tour-menu label:nth-of-type(2) { grid-column: 2; }
.pf-tour-menu label:nth-of-type(3) { grid-column: 3; }
.pf-tour-menu label:nth-of-type(4) { grid-column: 4; }
.pf-tour-menu label:nth-of-type(5) { grid-column: 5; }
.pf-tour-menu label:hover { color: var(--zinc-300); }

/* Tab icons retired (editorial pass) — the spans stay in the HTML so the
   radio/glider/equal-column mechanics are untouched; type carries the bar. */
.pf-tour-ico { display: none; }

/* active tab — the glider supplies the surface, the label supplies the colour */
#area-1:checked ~ .pf-tour-menubar label[for="area-1"],
#area-2:checked ~ .pf-tour-menubar label[for="area-2"],
#area-3:checked ~ .pf-tour-menubar label[for="area-3"],
#area-4:checked ~ .pf-tour-menubar label[for="area-4"],
#area-5:checked ~ .pf-tour-menubar label[for="area-5"] { color: var(--zinc-100); }


/* keyboard focus ring on the label of the focused radio */
#area-1:focus-visible ~ .pf-tour-menubar label[for="area-1"],
#area-2:focus-visible ~ .pf-tour-menubar label[for="area-2"],
#area-3:focus-visible ~ .pf-tour-menubar label[for="area-3"],
#area-4:focus-visible ~ .pf-tour-menubar label[for="area-4"],
#area-5:focus-visible ~ .pf-tour-menubar label[for="area-5"] { box-shadow: 0 0 0 3px var(--flow-24); }

/* ---- panels ---- */
.pf-panels { margin-top: 1.25rem; }
.pf-panel { display: none; }
#area-1:checked ~ .pf-panels .pf-panel-1,
#area-2:checked ~ .pf-panels .pf-panel-2,
#area-3:checked ~ .pf-panels .pf-panel-3,
#area-4:checked ~ .pf-panels .pf-panel-4,
#area-5:checked ~ .pf-panels .pf-panel-5 { display: grid; }

/* The panel is tonal cream (var(--surface) + 1px border), not glass — the
   editorial pass (2026-08) spent the glass budget on the hero prompt and
   nav only. Children tint on top of this flat surface with plain
   background-color/opacity, no backdrop-filter of their own. */
.pf-panel {
  grid-template-columns: minmax(0, 1fr);
  background-color: var(--surface);
  border: 1px solid rgb(var(--tint-rgb) / 0.07);
  border-radius: var(--radius-2xl);
  box-shadow: none;
  overflow: hidden;
}
@media (min-width: 900px) {
  .pf-panel { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); }
}

.pf-panel-copy {
  display: flex;
  flex-direction: column;
  padding: 1.5rem 1.75rem;
  min-width: 0;
  background: var(--glass-fill-2);
  border-bottom: 1px solid var(--border-soft);
}
@media (min-width: 900px) {
  .pf-panel-copy { border-bottom: 0; border-right: 1px solid var(--border-soft); padding: 2rem 1.75rem 2.25rem; }
}

.pf-index { display: flex; align-items: center; gap: 0.625rem; margin-bottom: 1.125rem; }
.pf-index-num { color: var(--zinc-400); }
.pf-index-rule { flex: 1; height: 1px; background: var(--border-soft); }

.pf-panel-copy h2 {
  font-size: 1.5rem;
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 500;
  max-width: 18ch;
  color: var(--ink);
}

/* .pf-notes retired (editorial pass): all five panels now use the label-led
   .pf-track / .pf-flowchain patterns — one archive voice, no icon tiles. */

/* ---- 01 · Dashboard: tracking readout ----
   Each tab card gets its own hierarchy. The dashboard's is an instrument
   table — mono keys, hairline rows — because the dashboard's job IS
   tracking. Icons are dropped: the label column carries the structure.
   Orange appears only as a transient tick on hover (live-element rule).
   Rows stagger in on tab entry; display:none → grid restarts the
   animation on every switch, so the readout "boots" each visit. */
.pf-panel-lede {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.6;
  max-width: 34ch;
  color: var(--zinc-400);
}
.pf-track {
  margin-top: 1.125rem;
  display: flex;
  flex-direction: column;
}
.pf-track li {
  position: relative;
  display: grid;
  grid-template-columns: 4.75rem minmax(0, 1fr);
  gap: 0.75rem;
  align-items: baseline;
  padding: 0.5625rem 0.625rem;
  margin-inline: -0.625rem;
  border-radius: 6px;
  transition: background-color var(--dur-fast) var(--ease-standard);
  animation: rise-soft 360ms var(--ease-out-expo) both;
}
.pf-track li + li { border-top: 1px solid var(--border-soft); }
.pf-track li:nth-child(1) { animation-delay: 30ms; }
.pf-track li:nth-child(2) { animation-delay: 60ms; }
.pf-track li:nth-child(3) { animation-delay: 90ms; }
.pf-track li:nth-child(4) { animation-delay: 120ms; }
.pf-track li:nth-child(5) { animation-delay: 150ms; }
.pf-track li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  width: 2px;
  height: 0;
  border-radius: 1px;
  background: var(--flow);
  transition: height 200ms var(--ease-out-expo);
}
.pf-track-key {
  color: var(--zinc-500);
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-track-val {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--zinc-400);
}
.pf-track li:hover { background: rgb(var(--tint-rgb) / 0.035); }
.pf-track li:hover::before { height: 55%; }
.pf-track li:hover .pf-track-key { color: var(--zinc-200); }
@media (max-width: 480px) {
  .pf-track li { grid-template-columns: 4.25rem minmax(0, 1fr); gap: 0.625rem; }
}
@media (prefers-reduced-motion: reduce) {
  .pf-track li { animation: none; }
}

/* ---- 02 · Workflow: growth chain ----
   The canvas is a graph, so this card reads as one: hollow node dots on a
   hairline spine, one stage feeding the next — capture → research →
   connect → create. Same mono/Inter voice as the dashboard readout, but a
   chain instead of a table: each tab keeps its own hierarchy. On hover a
   node fills with flow — the live-element rule, transient only. */
.pf-flowchain {
  margin-top: 1.125rem;
  display: flex;
  flex-direction: column;
}
.pf-flowchain li {
  position: relative;
  padding: 0.5rem 0 0.5rem 1.75rem;
  animation: rise-soft 360ms var(--ease-out-expo) both;
}
.pf-flowchain li:nth-child(1) { animation-delay: 30ms; }
.pf-flowchain li:nth-child(2) { animation-delay: 70ms; }
.pf-flowchain li:nth-child(3) { animation-delay: 110ms; }
.pf-flowchain li:nth-child(4) { animation-delay: 150ms; }
/* node */
.pf-flowchain li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 0.6875rem;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--zinc-600);
  background: transparent;
  z-index: 1;
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
/* spine segment down to the next node */
.pf-flowchain li::after {
  content: "";
  position: absolute;
  left: 8px;
  top: calc(0.6875rem + 11px);
  bottom: -0.6875rem;
  width: 1px;
  background: var(--border-soft);
}
.pf-flowchain li:last-child::after { display: none; }
.pf-flowchain-key {
  display: block;
  margin-bottom: 0.125rem;
  color: var(--zinc-500);
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-flowchain-val {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--zinc-400);
}
.pf-flowchain li:hover::before { border-color: var(--flow); background: var(--flow-14); }
.pf-flowchain li:hover .pf-flowchain-key { color: var(--zinc-200); }
@media (prefers-reduced-motion: reduce) {
  .pf-flowchain li { animation: none; }
}

/* ---- screenshot slot ----
   The image is a background on .pf-shot-media driven by --shot, so a capture
   drops in with one attribute on the figure and nothing else moves. With
   --shot unset the layer paints nothing and the empty state shows through.

   The shot is locked to one aspect ratio across all five tabs: the source
   captures are 1.44 and 1.97, and without this the panel would jump height
   on every switch — the most obvious tell of a fake tab set. */
.pf-shot-frame {
  display: flex;
  flex-direction: column;
  padding: 0.75rem;
  background: var(--well);
  min-width: 0;
}
/* the stage is unclipped so the corner marks can sit outside the image */
.pf-shot-stage { position: relative; min-width: 0; }

.pf-shot-media {
  position: relative;
  aspect-ratio: 1.85;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-soft);
  background-color: rgb(var(--tint-rgb) / 0.02);
  background-image: radial-gradient(rgb(var(--tint-rgb) / 0.07) 1px, transparent 1px);
  background-size: 22px 22px;
  box-shadow: 0 12px 32px -12px rgb(var(--shadow-rgb) / 0.35);
}
.pf-shot-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--shot, none);
  background-size: cover;
  background-position: center top;
}

.pf-shot-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.875rem;
  color: var(--zinc-600);
}
.pf-shot-box {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-lg);
  border: 1px dashed rgb(var(--tint-rgb) / 0.15);
}

.pf-shot-cap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 0.25rem 0.125rem;
  color: var(--zinc-600);
}

/* registration marks — texture, not noise */
.pf-corner {
  position: absolute;
  z-index: 1;
  width: 10px;
  height: 10px;
  border: 1px solid rgb(var(--tint-rgb) / 0.16);
  pointer-events: none;
}
.pf-corner.tl { top: -5px;    left: -5px;  border-right: 0; border-bottom: 0; }
.pf-corner.tr { top: -5px;    right: -5px; border-left: 0;  border-bottom: 0; }
.pf-corner.bl { bottom: -5px; left: -5px;  border-right: 0; border-top: 0; }
.pf-corner.br { bottom: -5px; right: -5px; border-left: 0;  border-top: 0; }


/* ==========================================================================
   11. LAUNCH STRIP
   ========================================================================== */

.pf-launch {
  border-top: 1px solid var(--border-soft);
  border-bottom: 1px solid var(--border-soft);
  padding: 1.125rem 1rem;
}
@media (min-width: 640px) { .pf-launch { padding-inline: 1.5rem; } }

.pf-launch-row { display: flex; align-items: center; gap: 1.25rem; }
.pf-launch-date { color: var(--zinc-300); }


/* ==========================================================================
   12. SYSTEM CARDS
   ========================================================================== */

.pf-card {
  border-radius: var(--radius-2xl);
  border: 1px solid var(--border-soft);
  background: var(--card-solid);
  padding: 2rem;
  transition: background-color var(--dur-med) var(--ease-standard),
              border-color var(--dur-med) var(--ease-standard);
}
.pf-card:hover { background: var(--surface); border-color: rgb(var(--tint-rgb) / 0.12); }
.pf-card-top { margin-bottom: 3rem; display: flex; align-items: center; justify-content: space-between; }
.pf-card-icon {
  display: flex;
  height: 2.5rem;
  width: 2.5rem;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-xl);
  border: 1px solid var(--border-soft);
  background: rgb(var(--tint-rgb) / 0.03);
  color: var(--zinc-400);
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-card:hover .pf-card-icon { color: var(--zinc-100); }
.pf-card-num { color: var(--zinc-600); }
.pf-card-title { font-size: 1.125rem; font-weight: 500; color: var(--zinc-100); }
.pf-card-body { margin-top: 0.75rem; font-size: 0.875rem; line-height: 1.625; color: var(--zinc-400); }


/* ==========================================================================
   13. ACCESS + FOOTER
   ========================================================================== */

.pf-access-section { padding: 4.5rem 1rem 3rem; }
@media (min-width: 640px) { .pf-access-section { padding-inline: 1.5rem; } }
@media (min-width: 768px) { .pf-access-section { padding-block: 6rem 3.5rem; } }

.pf-access-card {
  margin-inline: auto;
  display: flex;
  max-width: var(--shell-max);
  flex-direction: column;
  gap: 1.5rem;
  border-radius: var(--radius-2xl);
  border: 1px solid var(--border-soft);
  background: var(--card-solid);
  padding: 2rem;
}
@media (min-width: 640px) {
  .pf-access-card { flex-direction: row; align-items: center; justify-content: space-between; padding: 2rem 2.5rem; }
}
.pf-access-title {
  margin-top: 0.5rem;
  font-size: 1.75rem;
  line-height: 1.2;
  font-weight: 500;
  letter-spacing: -0.025em;
  color: var(--ink);
}
.pf-access-body { margin-top: 0.5rem; font-size: 0.875rem; line-height: 1.6; max-width: 40ch; color: var(--zinc-400); }
/* The primary action. White on the cream card, so it reads as a raised
   surface rather than a coloured chip — the orange is spent elsewhere on the
   page and a solid orange button was competing with it. A hairline gives it
   an edge against the near-white card; the border darkens on hover rather
   than the fill changing, which keeps the button calm. */
.pf-access-cta {
  display: inline-flex;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-xl);
  border: 1px solid var(--border-focus);
  background: var(--paper);
  padding-inline: 1.25rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  box-shadow: 0 1px 2px rgb(var(--shadow-rgb) / 0.04);
  transition: border-color var(--dur-med) var(--ease-standard),
              box-shadow var(--dur-med) var(--ease-standard);
}
.pf-access-cta:hover {
  border-color: var(--ink);
  box-shadow: 0 4px 14px -6px rgb(var(--shadow-rgb) / 0.22);
}

/* ── FOOTER ───────────────────────────────────────────────────────────────
   Brand block on the left, three link columns on the right, a hairline, then
   a quiet base row. Restraint is the point: mono micro-labels head the
   columns, links stay at the quiet tier and only brighten on hover, and the
   one accent left in the whole footer is the status dot. */
.pf-footer {
  margin: 4.5rem auto 0;
  max-width: var(--shell-max);
  font-size: 13px;
  color: var(--zinc-500);
}

.pf-footer-top {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
  padding-bottom: 2.25rem;
}
@media (min-width: 860px) {
  .pf-footer-top { flex-direction: row; justify-content: space-between; gap: 4rem; }
}

.pf-footer-brand {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: 21rem;
  color: var(--zinc-300);
}
.pf-footer-blurb {
  margin: 0;
  font-size: 12.5px;
  line-height: 19px;
  color: var(--zinc-500);
}

/* Explicit track counts, NOT auto-fit. This grid is a shrink-to-fit flex item,
   so it has no definite width for auto-fit to divide — it collapsed to a
   single stacked column. Two tracks on small screens, three once there's room. */
.pf-footer-cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(112px, auto));
  gap: 2rem 3rem;
}
@media (min-width: 640px) {
  .pf-footer-cols { grid-template-columns: repeat(3, minmax(112px, auto)); gap: 2rem 3.25rem; }
}
.pf-footer-col { display: flex; flex-direction: column; gap: 0.55rem; }

.pf-footer-head {
  margin: 0 0 0.25rem;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 14px;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zinc-600);
}

.pf-footer-link {
  width: fit-content;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--zinc-400);
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-footer-link:hover { color: var(--ink); }

.pf-footer-base {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border-soft);
}
@media (min-width: 640px) {
  .pf-footer-base { flex-direction: row; align-items: center; justify-content: space-between; }
}
.pf-footer-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-footer-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--flow);
}


/* ==========================================================================
   14. SCRATCH AREA — put experiments below this line
   --------------------------------------------------------------------------
   Nothing here by default. Overrides written here win over everything above,
   so the code above stays a clean reference and a bad idea is one delete away.

   The knobs most worth turning:
     • --glass-tint / --glass-blur   the hero prompt's frosted material —
                                     the only place these tokens apply
     • --radius-prompt               how soft the one focal object is
     • --flow / --landing-accent     the single accent; the wordmark,
                                     focus rings, CTA, and the glow follow
     • §7's vertical budget          what keeps the tab bar above the fold
   ========================================================================== */



/* ══════════════════════════════════════════════════════════════════════════
   ORNAMENTS — decorative technical scaffolding
   ──────────────────────────────────────────────────────────────────────────
   A small, deliberately closed set of marks: hairlines, grids, corner
   brackets, crosshairs, indicators, micro-labels. The visual language is
   PlansFlow's "signature texture" — blueprint / lab-sheet / HUD — kept at
   low contrast so it reads as TEXTURE, NOT NOISE.

   Three rules hold the whole system together:

   1. INK BY DEFAULT, ORANGE ON REQUEST. Every ornament renders in near-black
      hairline. Orange is not a variant of the set — it is the `.is-live`
      modifier, and it means one thing: this element is active/running. If
      more than one ornament in a view is orange, none of them mean anything.

   2. DECORATION IS INERT, CONTENT IS LIVE. `.pf-o` is pointer-events:none, so
      an ornament can be dropped over anything without stealing a click. Its
      CHILDREN get pointer-events back — which is what lets the framing
      ornaments (--corners, --bounds) graduate from decoration to real UI
      later without a rewrite.

   3. EVERYTHING IS A CUSTOM PROPERTY. Size, gap, length, colour, and position
      are all vars, so one class covers every use and nothing needs a variant
      class per size.

   PLACEMENT — two modes:
      inline   <span class="pf-o pf-o--rule"></span>          (normal flow)
      free     <span class="pf-o pf-o--cross pf-o--free" style="--x:70%;--y:24%"></span>
   Free mode is absolute; put `.pf-o-anchor` on the nearest container.

   Pure CSS — no SVG files, no images, no JS. Every mark is a gradient or a
   border, so the whole set costs one stylesheet block and zero requests.
   ========================================================================== */

:root {
  /* Two weights of line: --o-line draws marks you should notice, --o-line-soft
     draws field texture you shouldn't. Both are ink-derived, so re-declaring
     --ink on an ancestor re-themes every ornament with it. */
  --o-w:         1px;    /* stroke weight — the whole set is hairline    */
  --o-gap:       22px;   /* grid pitch, matches the canvas dot grid      */
  --o-size:      64px;   /* default footprint for the square marks       */
}

.pf-o {
  pointer-events: none;
  flex: none;

  /* ── THE COLOUR CONTRACT ────────────────────────────────────────────────
     Four inks, all derived from one place, so a single --o-c recolours ANY
     component in the set — no per-component colour rules anywhere.

       unset   → the defaults below, mixed off --ink, so the whole set
                 re-themes for free when --ink flips (light ⇄ dark).
       --o-c   → takes over at FULL strength. That's deliberate: a hairline
                 wants to be quiet at 26% ink, but if you've explicitly
                 chosen a colour you want to SEE it, not a 26% wash of it.

     --o-accent is the orange-by-nature slot (banner fill, HUD frame, meter
     fill, live dot). It follows --o-c too, so a recoloured component stays
     internally consistent instead of going half-orange. */
  --o-line:      var(--o-c,      color-mix(in srgb, var(--ink) 26%, transparent));
  --o-line-soft: var(--o-c-soft, color-mix(in srgb, var(--ink) 11%, transparent));
  --o-solid:     var(--o-c,      var(--ink));
  --o-accent:    var(--o-c,      var(--flow));

  /* Rotation AND scale ride one transform. Any ornament needing an intrinsic
     angle sets --o-rot rather than declaring its own transform, so nothing
     ever fights over this property. */
  transform: rotate(var(--o-rot, 0deg)) scale(var(--o-s, var(--o-scale, 1)));
}
/* Content placed inside a framing ornament is real UI again. */
.pf-o > * { pointer-events: auto; }

.pf-o-anchor { position: relative; }
.pf-o--free {
  position: absolute;
  left: var(--x, 0);
  top:  var(--y, 0);
  z-index: 0;
}

/* The one sanctioned accent state. Orange = live/active/running. */
.pf-o.is-live { --o-c: var(--flow); --o-c-soft: var(--flow-24); }


/* ── RULES ─────────────────────────────────────────────────────────────── */

/* Plain hairline. Width comes from the container. */
.pf-o--rule {
  display: block;
  width: var(--o-w-box, 100%);
  height: var(--o-w);
  background: var(--o-line-soft);
}

/* Hairline that dissolves at both ends — for a rule that shouldn't collide
   with whatever sits beside it. */
.pf-o--rule-fade {
  display: block;
  width: var(--o-w-box, 100%);
  height: var(--o-w);
  background: linear-gradient(90deg, transparent, var(--o-line) 22%, var(--o-line) 78%, transparent);
}

/* Registration rule: a baseline with measuring ticks. --o-gap sets the pitch,
   --o-tick the tick height. Reads as a scale/timeline edge. */
.pf-o--rule-tick {
  display: block;
  width: var(--o-w-box, 100%);
  --o-tick: 6px;
  height: var(--o-tick);
  background-image:
    linear-gradient(var(--o-line-soft) 0 0),
    repeating-linear-gradient(90deg, var(--o-line) 0 var(--o-w), transparent var(--o-w) var(--o-gap));
  background-size: 100% var(--o-w), 100% var(--o-tick);
  background-position: left top, left top;
  background-repeat: no-repeat, repeat-x;
}


/* ── FIELDS ────────────────────────────────────────────────────────────── */

/* Dot grid — the canvas's own texture, borrowed. Says "infinite surface".
   Masked to fade at the edges so it never ends on a hard rectangle. */
.pf-o--dots,
.pf-o--grid {
  display: block;
  width:  var(--o-w-box, var(--o-size));
  height: var(--o-h-box, var(--o-size));
  -webkit-mask-image: radial-gradient(ellipse at center, #000 35%, transparent 78%);
          mask-image: radial-gradient(ellipse at center, #000 35%, transparent 78%);
}
.pf-o--dots {
  background-image: radial-gradient(circle, var(--o-line) var(--o-w), transparent var(--o-w));
  background-size: var(--o-gap) var(--o-gap);
}
/* Blueprint grid — squarer, more architectural than the dot field. */
.pf-o--grid {
  background-image:
    linear-gradient(90deg, var(--o-line-soft) var(--o-w), transparent var(--o-w)),
    linear-gradient(  0deg, var(--o-line-soft) var(--o-w), transparent var(--o-w));
  background-size: var(--o-gap) var(--o-gap);
}


/* ── MARKS ─────────────────────────────────────────────────────────────── */

/* Crosshair / registration mark. Two hairlines through a point, with a gap at
   the centre so it reads as a target rather than a plus sign. */
.pf-o--cross {
  display: block;
  --o-arm: 9px;
  --o-eye: 3px;              /* the void at the centre */
  width:  calc(var(--o-arm) * 2);
  height: calc(var(--o-arm) * 2);
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size:
    calc(var(--o-arm) - var(--o-eye)) var(--o-w),
    calc(var(--o-arm) - var(--o-eye)) var(--o-w),
    var(--o-w) calc(var(--o-arm) - var(--o-eye)),
    var(--o-w) calc(var(--o-arm) - var(--o-eye));
  background-position: left center, right center, center top, center bottom;
  background-repeat: no-repeat;
}

/* Node glyph — a small outlined primitive. The three shapes are the canvas's
   own vocabulary (block, junction, terminal), not decoration for its own sake.
   Add .is-filled to make it solid. */
.pf-o--node {
  display: block;
  --o-glyph: 9px;
  width: var(--o-glyph);
  height: var(--o-glyph);
  border: var(--o-w) solid var(--o-line);
}
.pf-o--node.is-round   { border-radius: 50%; }
.pf-o--node.is-diamond { --o-rot: 45deg; }
.pf-o--node.is-filled  { background: var(--o-line); }

/* Status dot. Default is a quiet ink point; .is-live turns it orange and
   gives it the one ambient loop this system allows — a processing pulse,
   because background work is a first-class PlansFlow concept. */
.pf-o--dot {
  display: block;
  --o-glyph: 5px;
  width: var(--o-glyph);
  height: var(--o-glyph);
  border-radius: 50%;
  background: var(--o-line);
}
.pf-o--dot.is-live {
  background: var(--o-accent);
  animation: pf-o-pulse 2s var(--ease-standard) infinite;
}
@keyframes pf-o-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--flow-24); }
  50%      { box-shadow: 0 0 0 4px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .pf-o--dot.is-live { animation: none; }
}


/* ── LABELS ────────────────────────────────────────────────────────────── */

/* Index micro-label. The mono voice at its smallest: N: 042, v2, /04, ID:.
   Meant to carry REAL metadata — an index that indexes nothing is cosplay. */
.pf-o--index {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--zinc-600);
}
.pf-o--index.is-live { color: var(--o-accent); }

/* Leader annotation — a hairline running out to a label, the way a spec
   drawing calls out a part. The line is the ::before so the text stays
   selectable and the whole thing is still one element. */
.pf-o--leader {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  --o-lead: 28px;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-o--leader::before {
  content: "";
  width: var(--o-lead);
  height: var(--o-w);
  background: var(--o-line);
  flex: none;
}
.pf-o--leader.is-live { color: var(--o-accent); }


/* ── FRAMES — these accept content ─────────────────────────────────────── */

/* Corner brackets: a viewfinder around whatever is inside. Eight gradient
   layers rather than pseudo-elements, so ::before/::after stay free for the
   content and the same class works empty (pure decoration) or wrapped around
   a real panel later. --o-len is the arm length. */
.pf-o--corners {
  display: block;
  --o-len: 13px;
  padding: 10px;
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size:
    var(--o-len) var(--o-w), var(--o-w) var(--o-len),
    var(--o-len) var(--o-w), var(--o-w) var(--o-len),
    var(--o-len) var(--o-w), var(--o-w) var(--o-len),
    var(--o-len) var(--o-w), var(--o-w) var(--o-len);
  background-position:
    left top,     left top,
    right top,    right top,
    left bottom,  left bottom,
    right bottom, right bottom;
  background-repeat: no-repeat;
}
/* Empty/decorative use — give it a footprint without needing content. */
.pf-o--corners.is-empty {
  width:  var(--o-w-box, var(--o-size));
  height: var(--o-h-box, var(--o-size));
  padding: 0;
}

/* Bounding box — the full hairline rectangle, with tick marks biting in at
   the midpoint of each edge. The annotated-specimen look. */
.pf-o--bounds {
  display: block;
  --o-tick: 5px;
  padding: 12px;
  border: var(--o-w) solid var(--o-line-soft);
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size:
    var(--o-w) var(--o-tick), var(--o-w) var(--o-tick),
    var(--o-tick) var(--o-w), var(--o-tick) var(--o-w);
  background-position: center top, center bottom, left center, right center;
  background-repeat: no-repeat;
}
.pf-o--bounds.is-empty {
  width:  var(--o-w-box, var(--o-size));
  height: var(--o-h-box, var(--o-size));
  padding: 0;
}


/* ══════════════════════════════════════════════════════════════════════════
   ORNAMENTS II — expanded set, drawn from assets/uico/
   ──────────────────────────────────────────────────────────────────────────
   Vocabulary lifted from the four reference sheets:
     1.jpg  sliced heavy bars, aligned data columns, dot matrices,
            registration pluses, offset filled squares, diagonal leaders
     2.jpg  solid ORANGE banner bars, HUD corner frames with thick accent
            segments, pluses on a faint grid, inverted clearance chips
     3.jpg  prefixed data lines (// >> = *), chamfered/notched marks
     4.jpg  plus-at-every-intersection field

   Same three rules as §ORNAMENTS: ink by default, decoration inert, every
   dimension a custom property. The two ornaments that ARE orange by nature
   (--banner, --frame-hud) are the exception that proves the rule: they're
   the "one orange moment", so a page should carry at most one of them.
   ========================================================================== */

/* ── BARS — the heavy mass ─────────────────────────────────────────────── */

/* Solid bar. The reference's heaviest element; use it as a rule that shouts. */
.pf-o--bar {
  display: block;
  width: var(--o-w-box, 180px);
  height: var(--o-bar, 9px);
  background: var(--o-solid);
}

/* Sliced bar — a solid bar with a diagonal cut through it. The single most
   recognisable mark on sheet 1: it reads as a bar that has been machined. */
.pf-o--bar-slice {
  display: block;
  width: var(--o-w-box, 180px);
  height: var(--o-bar, 9px);
  background: linear-gradient(74deg,
    var(--o-solid) 0 var(--o-cut, 34%),
    transparent    var(--o-cut, 34%) calc(var(--o-cut, 34%) + 3.5%),
    var(--o-solid) calc(var(--o-cut, 34%) + 3.5%) 100%);
}

/* Segmented bar — dashes at a fixed pitch. Reads as a scale or a data track. */
.pf-o--bar-seg {
  display: block;
  width: var(--o-w-box, 180px);
  height: var(--o-bar, 9px);
  background-image: repeating-linear-gradient(90deg,
    var(--o-solid) 0 var(--o-seg, 13px),
    transparent    var(--o-seg, 13px) calc(var(--o-seg, 13px) + 6px));
}

/* The same track stood on end — the stacked tabs down sheet 1's right edge. */
.pf-o--ladder {
  display: block;
  width: var(--o-bar, 9px);
  height: var(--o-h-box, 74px);
  background-image: repeating-linear-gradient(180deg,
    var(--o-solid) 0 var(--o-seg, 9px),
    transparent    var(--o-seg, 9px) calc(var(--o-seg, 9px) + 5px));
}

/* THE orange moment. A solid accent bar carrying dark text, exactly as the
   spec sheet's header and footer. One per page — it is the loudest object
   in the whole system and stops meaning anything if repeated. */
.pf-o--banner {
  display: inline-block;
  padding: 7px 20px;
  background: var(--o-accent);
  color: var(--o-on, #17140f);
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 800;
  font-size: var(--o-banner, 19px);
  line-height: 1.2;
  letter-spacing: -0.015em;
}


/* ── FIELDS ────────────────────────────────────────────────────────────── */

/* Crisp bounded dot matrix — unlike --dots, no edge mask. Sheet 1 uses it as
   a hard rectangle of dots, which reads as sampled data rather than texture. */
.pf-o--dotmatrix {
  display: block;
  width:  var(--o-w-box, 120px);
  height: var(--o-h-box, 84px);
  background-image: radial-gradient(circle, var(--o-line) var(--o-w), transparent var(--o-w));
  background-size: var(--o-gap) var(--o-gap);
}

/* A single column of dots — sheet 1's right-edge tick column. */
.pf-o--dotcol {
  display: block;
  width: calc(var(--o-w) * 2);
  height: var(--o-h-box, 64px);
  background-image: radial-gradient(circle, var(--o-line) var(--o-w), transparent var(--o-w));
  background-size: var(--o-gap) var(--o-gap);
}

/* Plus-at-every-intersection field (sheet 4). Masked rather than painted so
   the colour stays a token — an inline SVG can't read a custom property, but
   a mask can carry the SHAPE while background-color carries the INK. No
   network request: the mask is a data URI. Stack --grid behind it if you
   want the faint rules underneath too. */
.pf-o--crossfield {
  display: block;
  width:  var(--o-w-box, 160px);
  height: var(--o-h-box, 120px);
  background-color: var(--o-line);
  --o-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M12 7.5v9M7.5 12h9' stroke='%23000' stroke-width='1.2'/%3E%3C/svg%3E");
  -webkit-mask-image: var(--o-plus);  mask-image: var(--o-plus);
  -webkit-mask-size: var(--o-gap) var(--o-gap);  mask-size: var(--o-gap) var(--o-gap);
  -webkit-mask-repeat: repeat;  mask-repeat: repeat;
}


/* ── MARKS ─────────────────────────────────────────────────────────────── */

/* Registration plus — no centre void, unlike --cross. Sheet 2 sets these at
   grid intersections as alignment marks. */
.pf-o--plus {
  display: block;
  --o-arm: 11px;
  width: var(--o-arm);
  height: var(--o-arm);
  background-image: linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size: 100% var(--o-w), var(--o-w) 100%;
  background-position: center, center;
  background-repeat: no-repeat;
}

/* One chevron. Place three in a row for sheet 1's >>> run. */
.pf-o--chev {
  display: block;
  --o-glyph: 8px;
  width: var(--o-glyph);
  height: var(--o-glyph);
  border-top: var(--o-w) solid var(--o-line);
  border-right: var(--o-w) solid var(--o-line);
  --o-rot: 45deg;
}

/* Free diagonal — sheet 1's long leader running from the dot matrix to the
   box. Set length with --o-len and angle with --o-rot. */
.pf-o--diag {
  display: block;
  width: var(--o-len, 90px);
  height: var(--o-w);
  background: var(--o-line);
  transform-origin: left center;
  --o-rot: -38deg;
}


/* ── FRAMES ────────────────────────────────────────────────────────────── */

/* A single corner bracket. Four corner variants off one class. */
.pf-o--bracket {
  display: block;
  width:  var(--o-w-box, 26px);
  height: var(--o-h-box, 26px);
  border-top:  var(--o-w) solid var(--o-line);
  border-left: var(--o-w) solid var(--o-line);
}
.pf-o--bracket.is-tr { border-left: 0; border-right: var(--o-w) solid var(--o-line); }
.pf-o--bracket.is-bl { border-top: 0;  border-bottom: var(--o-w) solid var(--o-line); }
.pf-o--bracket.is-br { border: 0; border-bottom: var(--o-w) solid var(--o-line); border-right: var(--o-w) solid var(--o-line); }

/* HUD frame (sheet 2) — corner brackets in the accent, each arm carrying a
   thick block partway along. Twelve gradient layers: per corner, a thin
   horizontal arm, a thin vertical arm, and the heavy accent block. Accepts
   content, so this is the natural upgrade path to a real featured panel. */
.pf-o--frame-hud {
  display: block;
  --o-len: 42px;
  --o-blk: 15px;
  --o-hud: var(--o-accent);
  padding: 22px;
  background-image:
    linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0),
    linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0),
    linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0),
    linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0), linear-gradient(var(--o-hud) 0 0);
  background-size:
    var(--o-len) var(--o-w), var(--o-w) var(--o-len), var(--o-blk) 5px,
    var(--o-len) var(--o-w), var(--o-w) var(--o-len), var(--o-blk) 5px,
    var(--o-len) var(--o-w), var(--o-w) var(--o-len), var(--o-blk) 5px,
    var(--o-len) var(--o-w), var(--o-w) var(--o-len), var(--o-blk) 5px;
  background-position:
    left top,     left top,     left 26px top -2px,
    right top,    right top,    right 26px top -2px,
    left bottom,  left bottom,  left 26px bottom -2px,
    right bottom, right bottom, right 26px bottom -2px;
  background-repeat: no-repeat;
}
.pf-o--frame-hud.is-empty { width: var(--o-w-box, 150px); height: var(--o-h-box, 92px); padding: 0; }

/* Outlined box with a filled square pushed off its corner — sheet 1's
   overlapping-squares motif, which is what gives that sheet its depth. */
.pf-o--boxfill {
  position: relative;
  display: block;
  width:  var(--o-w-box, 54px);
  height: var(--o-h-box, 54px);
  border: var(--o-w) solid var(--o-line);
}
.pf-o--boxfill::after {
  content: "";
  position: absolute;
  right: calc(var(--o-off, 14px) * -1);
  bottom: calc(var(--o-off, 14px) * -1);
  width: 46%;
  height: 46%;
  background: var(--o-solid);
}

/* Box with a diagonal through it — the empty-slot / no-media mark. */
.pf-o--slot {
  display: block;
  width:  var(--o-w-box, 46px);
  height: var(--o-h-box, 30px);
  border: var(--o-w) solid var(--o-line);
  background: linear-gradient(to top right,
    transparent calc(50% - 0.5px), var(--o-line) calc(50% - 0.5px),
    var(--o-line) calc(50% + 0.5px), transparent calc(50% + 0.5px));
}

/* Chamfered block — sheet 3's notched mark. Filled, because that sheet's
   logo is a solid shape; the cut corner is what makes it read as machined. */
.pf-o--notch {
  display: block;
  width:  var(--o-w-box, 28px);
  height: var(--o-h-box, 28px);
  background: var(--o-solid);
  clip-path: polygon(0 0, calc(100% - var(--o-chamfer, 10px)) 0, 100% var(--o-chamfer, 10px), 100% 100%, 0 100%);
}


/* ── LABELS ────────────────────────────────────────────────────────────── */

/* Label sitting on its own rule — sheet 1's "SCREEN - FF" over a long line. */
.pf-o--tag {
  display: block;
  width: var(--o-w-box, 170px);
  padding-bottom: 5px;
  border-bottom: var(--o-w) solid var(--o-line);
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zinc-600);
}

/* Inverted chip — sheet 2's "Clearance Level 4". Solid ink, page-coloured
   text. The quiet counterpart to --banner. */
.pf-o--chip-inv {
  display: inline-block;
  padding: 4px 10px;
  background: var(--o-solid);
  color: var(--o-on, var(--bg-base));
  font-family: var(--font-mono);
  font-size: 9px;
  line-height: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Prefixed data line — sheet 3's `// QUANTUM FLUX`, `>> FLUXBOOST`, `= SYNAPSE`.
   The prefix is the accent and comes from a property, so one class covers
   every operator:  style="--o-pre:'>>'" */
.pf-o--prefix {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 16px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zinc-500);
}
.pf-o--prefix::before {
  content: var(--o-pre, "//");
  margin-right: 8px;
  color: var(--o-accent);
}


/* ── DATA ──────────────────────────────────────────────────────────────── */

/* Display code — sheet 1's "A3-D", sheet 2's "PRG 01". The one large object
   in the set; everything else is micro by comparison, and that jump IS the
   hierarchy. */
.pf-o--readout {
  display: block;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: 800;
  font-size: var(--o-readout, 38px);
  line-height: 0.92;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* Spec stack — a few dense mono lines. Newlines in the text render as
   breaks, so it stays one element with no markup inside. */
.pf-o--spec {
  display: block;
  white-space: pre-line;
  font-family: var(--font-mono);
  font-size: 8.5px;
  line-height: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--zinc-500);
}

/* Aligned data columns — sheet 1's `/ TR-C   AK   80` block. Three columns,
   tabular figures, so the numbers line up the way a readout should. */
.pf-o--datacol {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 2px 16px;
  font-family: var(--font-mono);
  font-size: 8.5px;
  line-height: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--zinc-500);
}
.pf-o--datacol > :nth-child(3n) { text-align: right; color: var(--zinc-500); }

/* Justified micro paragraph — sheet 2's body block. Deliberately too small to
   read comfortably: it is texture that happens to be words. */
.pf-o--micro {
  display: block;
  max-width: var(--o-w-box, 30ch);
  font-family: var(--font-sans);
  font-size: 9px;
  line-height: 13px;
  text-align: justify;
  hyphens: auto;
  color: var(--zinc-500);
}


/* ══════════════════════════════════════════════════════════════════════════
   ORNAMENTS III — meters, signals, HUD details, clusters, connectors
   ──────────────────────────────────────────────────────────────────────────
   The premium tier. Every one of these obeys the colour contract in §ORNAMENTS
   (--o-c recolours it, --o-scale resizes it, --o-rot turns it), and every one
   is a single element built from gradients, borders, or clip-path — no SVG
   files, no images, no per-component JS.

   Where a component has a "value" (fill level, count, angle) it reads a custom
   property, so the same class covers every state:  style="--o-fill:64%"
   ========================================================================== */

/* ── METERS — quantity made visible ────────────────────────────────────── */

/* Continuous progress. Track is the faint tier, fill is the accent. */
.pf-o--meter {
  display: block;
  width: var(--o-w-box, 150px);
  height: var(--o-bar, 4px);
  background: var(--o-line-soft);
  background-image: linear-gradient(90deg, var(--o-accent) 0 var(--o-fill, 62%), transparent var(--o-fill, 62%));
}

/* Segmented progress — the same value, read as discrete cells. Two layers:
   the accent fill underneath, the notches punched over it. */
.pf-o--meter-seg {
  display: block;
  width: var(--o-w-box, 150px);
  height: var(--o-bar, 8px);
  background-color: var(--o-line-soft);
  background-image:
    repeating-linear-gradient(90deg, transparent 0 var(--o-seg, 11px), var(--bg-base) var(--o-seg, 11px) calc(var(--o-seg, 11px) + 4px)),
    linear-gradient(90deg, var(--o-accent) 0 var(--o-fill, 62%), transparent var(--o-fill, 62%));
}

/* Arc gauge. A conic sweep clipped to a ring by a radial mask — the cheapest
   way to draw a dial with zero markup. */
.pf-o--gauge {
  display: block;
  --o-dia: 54px;
  width: var(--o-dia);
  height: var(--o-dia);
  border-radius: 50%;
  background: conic-gradient(var(--o-accent) 0 var(--o-fill, 62%), var(--o-line-soft) var(--o-fill, 62%) 100%);
  -webkit-mask-image: radial-gradient(circle, transparent 58%, #000 59%);
          mask-image: radial-gradient(circle, transparent 58%, #000 59%);
}

/* Histogram / equaliser. Six columns at fixed heights — a gradient can't vary
   per-column, so each column is its own layer, anchored to the baseline. */
.pf-o--bars-eq {
  display: block;
  width: var(--o-w-box, 62px);
  height: var(--o-h-box, 34px);
  background-image:
    linear-gradient(var(--o-solid) 0 0), linear-gradient(var(--o-solid) 0 0),
    linear-gradient(var(--o-accent) 0 0), linear-gradient(var(--o-solid) 0 0),
    linear-gradient(var(--o-solid) 0 0), linear-gradient(var(--o-solid) 0 0);
  background-size: 5px 40%, 5px 68%, 5px 100%, 5px 54%, 5px 82%, 5px 30%;
  background-position: 0 100%, 11px 100%, 22px 100%, 33px 100%, 44px 100%, 55px 100%;
  background-repeat: no-repeat;
}

/* Measuring scale — long ticks every fifth, short ticks between. Reads as a
   ruler edge running down a section. */
.pf-o--scale-v {
  display: block;
  width: var(--o-w-box, 13px);
  height: var(--o-h-box, 92px);
  background-image:
    repeating-linear-gradient(180deg, var(--o-line) 0 var(--o-w), transparent var(--o-w) var(--o-gap)),
    repeating-linear-gradient(180deg, var(--o-line) 0 var(--o-w), transparent var(--o-w) calc(var(--o-gap) * 5));
  background-size: 6px 100%, 100% 100%;
  background-position: left top, left top;
  background-repeat: no-repeat;
}


/* ── SIGNALS — radiating marks ─────────────────────────────────────────── */

/* Concentric rings. --o-rings sets the pitch; the mask fades the outer edge
   so it reads as emanating rather than as a bullseye. */
.pf-o--pulse-ring {
  display: block;
  --o-dia: 52px;
  width: var(--o-dia);
  height: var(--o-dia);
  background-image: repeating-radial-gradient(circle,
    var(--o-line) 0 var(--o-w), transparent var(--o-w) var(--o-rings, 7px));
  -webkit-mask-image: radial-gradient(circle, #000 30%, transparent 72%);
          mask-image: radial-gradient(circle, #000 30%, transparent 72%);
}

/* Signal arcs — the same rings, cut to a quadrant. Two masks compose: the
   rings' fade, and a conic wedge. */
.pf-o--signal {
  display: block;
  --o-dia: 34px;
  width: var(--o-dia);
  height: var(--o-dia);
  background-image: repeating-radial-gradient(circle at 0% 100%,
    transparent 0 5px, var(--o-line) 5px calc(5px + var(--o-w)), transparent calc(5px + var(--o-w)) 11px);
  -webkit-mask-image: conic-gradient(from 270deg at 0% 100%, #000 0 90deg, transparent 90deg);
          mask-image: conic-gradient(from 270deg at 0% 100%, #000 0 90deg, transparent 90deg);
}

/* Targeting reticle — rings plus a full crosshair through the centre. */
.pf-o--target {
  display: block;
  --o-dia: 42px;
  width: var(--o-dia);
  height: var(--o-dia);
  border: var(--o-w) solid var(--o-line);
  border-radius: 50%;
  background-image:
    radial-gradient(circle, transparent 30%, var(--o-line) 30%, var(--o-line) calc(30% + var(--o-w)), transparent calc(30% + var(--o-w))),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size: 100% 100%, 100% var(--o-w), var(--o-w) 100%;
  background-position: center, center, center;
  background-repeat: no-repeat;
}

/* Radar — a reticle with a conic sweep wedge in the accent. */
.pf-o--radar {
  display: block;
  --o-dia: 52px;
  width: var(--o-dia);
  height: var(--o-dia);
  border: var(--o-w) solid var(--o-line);
  border-radius: 50%;
  background-image:
    conic-gradient(from var(--o-sweep, 20deg), var(--o-accent) 0 34deg, transparent 34deg 360deg),
    linear-gradient(var(--o-line-soft) 0 0), linear-gradient(var(--o-line-soft) 0 0);
  background-size: 100% 100%, 100% var(--o-w), var(--o-w) 100%;
  background-position: center, center, center;
  background-repeat: no-repeat;
}

/* Waveform — a symmetric column set mirrored about the midline. */
.pf-o--waveform {
  display: block;
  width: var(--o-w-box, 76px);
  height: var(--o-h-box, 26px);
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-accent) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0);
  background-size: 3px 34%, 3px 62%, 3px 100%, 3px 78%, 3px 46%, 3px 88%, 3px 28%;
  background-position: 0 50%, 12px 50%, 24px 50%, 36px 50%, 48px 50%, 60px 50%, 72px 50%;
  background-repeat: no-repeat;
}

/* Barcode — irregular vertical rules. Sheet-1 texture; good as a section edge. */
.pf-o--barcode {
  display: block;
  width: var(--o-w-box, 84px);
  height: var(--o-h-box, 26px);
  background-image: repeating-linear-gradient(90deg,
    var(--o-solid) 0 1px, transparent 1px 3px,
    var(--o-solid) 3px 5px, transparent 5px 6px,
    var(--o-solid) 6px 7px, transparent 7px 11px);
}

/* Scanlines — fine horizontal repeat. Pure texture; keep it very low contrast. */
.pf-o--scanline {
  display: block;
  width:  var(--o-w-box, 120px);
  height: var(--o-h-box, 60px);
  background-image: repeating-linear-gradient(180deg,
    var(--o-line-soft) 0 var(--o-w), transparent var(--o-w) 4px);
}


/* ── HUD DETAILS ───────────────────────────────────────────────────────── */

/* Corner L with a filled block sitting in its elbow. More resolved than the
   plain --bracket; good for anchoring the corners of a real section. */
.pf-o--hud-corner {
  display: block;
  width:  var(--o-w-box, 30px);
  height: var(--o-h-box, 30px);
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-accent) 0 0);
  background-size: 100% var(--o-w), var(--o-w) 100%, 6px 6px;
  background-position: left top, left top, left 5px top 5px;
  background-repeat: no-repeat;
}

/* Rail — a spine with tick marks off one side. Runs beside a column of copy. */
.pf-o--hud-rail {
  display: block;
  width: var(--o-w-box, 15px);
  height: var(--o-h-box, 100px);
  background-image:
    linear-gradient(var(--o-line) 0 0),
    repeating-linear-gradient(180deg, var(--o-line) 0 var(--o-w), transparent var(--o-w) var(--o-gap));
  background-size: var(--o-w) 100%, 100% 100%;
  background-position: left top, left top;
  background-repeat: no-repeat;
}

/* Focus reticle — four corner Ls tight around nothing, like a camera's AF box.
   Unlike --corners this is fixed-size and decorative; it doesn't hold content. */
.pf-o--reticle {
  display: block;
  --o-len: 8px;
  width:  var(--o-w-box, 34px);
  height: var(--o-h-box, 34px);
  background-image:
    linear-gradient(var(--o-accent) 0 0), linear-gradient(var(--o-accent) 0 0),
    linear-gradient(var(--o-accent) 0 0), linear-gradient(var(--o-accent) 0 0),
    linear-gradient(var(--o-accent) 0 0), linear-gradient(var(--o-accent) 0 0),
    linear-gradient(var(--o-accent) 0 0), linear-gradient(var(--o-accent) 0 0);
  background-size:
    var(--o-len) var(--o-w), var(--o-w) var(--o-len),
    var(--o-len) var(--o-w), var(--o-w) var(--o-len),
    var(--o-len) var(--o-w), var(--o-w) var(--o-len),
    var(--o-len) var(--o-w), var(--o-w) var(--o-len);
  background-position:
    left top, left top, right top, right top,
    left bottom, left bottom, right bottom, right bottom;
  background-repeat: no-repeat;
}

/* Panel with a header strip — the smallest thing that reads as a real window. */
.pf-o--panel-head {
  display: block;
  width:  var(--o-w-box, 90px);
  height: var(--o-h-box, 56px);
  border: var(--o-w) solid var(--o-line);
  background-image: linear-gradient(var(--o-solid) 0 0);
  background-size: 100% 9px;
  background-position: left top;
  background-repeat: no-repeat;
}

/* Cut-corner frame. The filled shape is clipped, then a same-shape inset is
   punched out of it by the mask — which is how you get a hairline outline
   with mitred corner cuts and still only one element. */
.pf-o--frame-tech {
  display: block;
  --o-cut: 12px;
  width:  var(--o-w-box, 110px);
  height: var(--o-h-box, 68px);
  background: var(--o-line);
  clip-path: polygon(var(--o-cut) 0, 100% 0, 100% calc(100% - var(--o-cut)), calc(100% - var(--o-cut)) 100%, 0 100%, 0 var(--o-cut));
  -webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
          mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  -webkit-mask-size: 100% 100%, calc(100% - 2px) calc(100% - 2px);
          mask-size: 100% 100%, calc(100% - 2px) calc(100% - 2px);
  -webkit-mask-position: center, center;
          mask-position: center, center;
  -webkit-mask-repeat: no-repeat;  mask-repeat: no-repeat;
  -webkit-mask-composite: xor;     mask-composite: exclude;
}

/* Dashed frame — accepts content, so it doubles as a placeholder well. */
.pf-o--frame-dash {
  display: block;
  padding: 12px;
  border: var(--o-w) dashed var(--o-line);
}
.pf-o--frame-dash.is-empty { width: var(--o-w-box, 96px); height: var(--o-h-box, 58px); padding: 0; }


/* ── CLUSTERS & CONNECTORS ─────────────────────────────────────────────── */

/* Node cluster — dots wired together. The canvas's own diagram, in miniature:
   three nodes, two links, one of them live. */
.pf-o--cluster {
  display: block;
  width:  var(--o-w-box, 78px);
  height: var(--o-h-box, 54px);
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    radial-gradient(circle, var(--o-solid) 2.5px, transparent 2.5px),
    radial-gradient(circle, var(--o-solid) 2.5px, transparent 2.5px),
    radial-gradient(circle, var(--o-accent) 2.5px, transparent 2.5px);
  background-size: 34px var(--o-w), 30px var(--o-w), 7px 7px, 7px 7px, 7px 7px;
  background-position: 6px 9px, 40px 44px, 3px 6px, 37px 6px, 67px 41px;
  background-repeat: no-repeat;
  transform: rotate(var(--o-rot, 0deg)) scale(var(--o-s, var(--o-scale, 1)));
}

/* Constellation — scattered points, no wiring. Reads as sampled data. */
.pf-o--constellation {
  display: block;
  width:  var(--o-w-box, 80px);
  height: var(--o-h-box, 56px);
  background-image:
    radial-gradient(circle, var(--o-line) 1.5px, transparent 1.5px),
    radial-gradient(circle, var(--o-line) 1.5px, transparent 1.5px),
    radial-gradient(circle, var(--o-accent) 2px, transparent 2px),
    radial-gradient(circle, var(--o-line) 1.5px, transparent 1.5px),
    radial-gradient(circle, var(--o-line) 1.5px, transparent 1.5px);
  background-size: 5px 5px;
  background-position: 4px 8px, 30px 2px, 52px 26px, 18px 40px, 72px 48px;
  background-repeat: no-repeat;
}

/* Right-angle connector — the elbow that wires two things together. */
.pf-o--elbow {
  display: block;
  width:  var(--o-w-box, 44px);
  height: var(--o-h-box, 28px);
  background-image: linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size: 100% var(--o-w), var(--o-w) 100%;
  background-position: left top, right top;
  background-repeat: no-repeat;
}

/* Arrow — a hairline with a head. Head is a rotated corner on ::after. */
.pf-o--arrow {
  position: relative;
  display: block;
  width: var(--o-len, 62px);
  height: var(--o-w);
  background: var(--o-line);
}
.pf-o--arrow::after {
  content: "";
  position: absolute;
  right: 0;
  top: 50%;
  width: 7px;
  height: 7px;
  border-top: var(--o-w) solid var(--o-line);
  border-right: var(--o-w) solid var(--o-line);
  transform: translate(0, -50%) rotate(45deg);
}

/* Bracket pair — [ content ] as pure decoration around a gap. */
.pf-o--bracket-pair {
  display: block;
  --o-len: 9px;
  width:  var(--o-w-box, 46px);
  height: var(--o-h-box, 26px);
  background-image:
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0),
    linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0), linear-gradient(var(--o-line) 0 0);
  background-size:
    var(--o-w) 100%, var(--o-len) var(--o-w), var(--o-len) var(--o-w),
    var(--o-w) 100%, var(--o-len) var(--o-w), var(--o-len) var(--o-w);
  background-position:
    left top, left top, left bottom,
    right top, right top, right bottom;
  background-repeat: no-repeat;
}


/* ── READOUTS ──────────────────────────────────────────────────────────── */

/* Coordinate pair — tabular, so the digits sit on a column even as they change. */
.pf-o--coord {
  display: inline-flex;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--zinc-600);
}

/* Boxed index — a number in a hairline square. Sequence markers. */
.pf-o--badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border: var(--o-w) solid var(--o-line);
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 1;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--o-solid);
}
.pf-o--badge.is-round { border-radius: 50%; padding: 0; }

/* Status row — dot, label, value. The smallest complete readout in the set,
   and the most obvious candidate to become real bound UI later. */
.pf-o--status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 14px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-o--status::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--o-accent);
  flex: none;
}


/* ══════════════════════════════════════════════════════════════════════════
   ORNAMENTS — RESPONSIVE TIERS
   ──────────────────────────────────────────────────────────────────────────
   Decoration is designed at WIDE DESKTOP and degrades from there. Wide is the
   source of truth: --x / --y / --o-scale are the authored values and are never
   overwritten. Each narrower tier is an OVERRIDE LAYER that only exists if you
   actually authored something for it.

     ≥1200  wide    exactly as placed — position, scale, rotation
     720…1199  md   same spot, scaled down a notch; optional alternate
                    position via --x-md / --y-md
     <720   sm      hidden BY DEFAULT — a decorative layer is the first thing
                    that should go when the column gets narrow. Marks worth
                    keeping opt back in with .is-sm, and shrink further still.

   The cascade is expressed purely through var() fallbacks:
       --x-sm  →  --x-md  →  --x
   so a mark authored only at wide needs no extra properties at all, and one
   nudged at tablet carries exactly one extra pair.

   Only .pf-o--free (placed stickers) is affected. Ornaments used inline as
   real page furniture keep their normal flow behaviour at every width.
   ========================================================================== */

@media (max-width: 1199px) {
  .pf-o--free {
    left: var(--x-md, var(--x));
    top:  var(--y-md, var(--y));
    /* One notch down so marks stop crowding a narrower text column. Override
       per mark with --o-md-shrink, or pin it exactly with --o-scale-md. */
    --o-s: var(--o-scale-md, calc(var(--o-scale, 1) * var(--o-md-shrink, 0.82)));
  }
}

/* GUTTER-PINNED. A percentage x is the wrong model for a mark that belongs in
   the margin: the gutter is (100% - shell)/2, so it shrinks about 3x faster
   than any percentage of the section does. A rail authored to sit just outside
   the text column at 1710 is INSIDE it by 1600. This tracks the real gutter,
   so the mark keeps the same relationship to the content column at every
   width — which is what "stays where I put it" actually means here. */
.pf-o--free.gutter-left {
  left: calc((100% - var(--shell-max)) / 2 - var(--gutter-off, 24px));
}
.pf-o--free.gutter-right {
  left: auto;
  right: calc((100% - var(--shell-max)) / 2 - var(--gutter-off, 24px));
}

/* Opt-out for marks that only make sense with a wide gutter. Below 1200 the
   .pf-container fills the width (the left gutter drops from ~16% to ~2%), so a
   gutter ornament has nowhere legitimate to stand. */
@media (max-width: 1199px) {
  .pf-o--free.md-off { display: none; }
}

/* 860 is where the page's two-column blocks collapse into stacks: the footer
   brand/columns split, and #system's head/lede stop sharing a row. Marks that
   lived in the space those columns freed have nowhere to stand afterwards. */
@media (max-width: 859px) {
  .pf-o--free.sm-footer-low { top: var(--y-low, 86%); }
  .pf-o--free.narrow-off { display: none; }
}

@media (max-width: 719px) {
  /* :not(.is-sm) rather than display:none + display:block — restoring display
     would flatten inline-flex marks (--status, --coord, --badge, --leader)
     into blocks. This leaves every kept mark's own display intact. */
  .pf-o--free:not(.is-sm) { display: none; }

  .pf-o--free.is-sm {
    left: var(--x-sm, var(--x-md, var(--x)));
    top:  var(--y-sm, var(--y-md, var(--y)));
    --o-s: var(--o-scale-sm, calc(var(--o-scale, 1) * var(--o-sm-shrink, 0.7)));
  }
}


/* ══════════════════════════════════════════════════════════════════════════
   PROMPT GATE + PAGE CHROME (production pass)
   ========================================================================== */

/* The prompt is a working composer now, not a gate — see §8. */

/* ── ABOUT ─────────────────────────────────────────────────────────────────
   Editorial rather than demonstrative. It borrows the landing page's whole
   vocabulary — .pf-section, .pf-split-head, .pf-cards-3, .pf-track,
   .pf-shot-frame — and adds only what an article genuinely needs: a hero, a
   prose measure, a two-column split, and a definition list. */
.pf-ab-hero { padding: 7rem 1rem 3.5rem; }
@media (min-width: 640px) { .pf-ab-hero { padding: 8.5rem 2rem 4rem; } }

.pf-ab-title {
  margin: 0.85rem 0 0;
  max-width: 18ch;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(2.25rem, 5.2vw, 4rem);
  line-height: 1.02;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--ink);
  text-wrap: balance;
}
.pf-ab-lede {
  margin: 1.35rem 0 0;
  /* ~68 characters. Long enough to argue, short enough to stay readable. */
  max-width: 46ch;
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--zinc-400);
}

/* Body prose sits on the same measure as the lede so the page has one column
   of reading, not several competing ones. */
.pf-ab-prose { margin-top: 2.25rem; max-width: 62ch; }
.pf-ab-prose p {
  margin: 0 0 1.1rem;
  font-size: 0.9375rem;
  line-height: 1.72;
  color: var(--zinc-400);
}
.pf-ab-prose p:last-child { margin-bottom: 0; }

/* List beside a figure. Single column until there is genuinely room for two. */
.pf-ab-split { display: grid; gap: 2.5rem; margin-top: 2.25rem; align-items: start; }
@media (min-width: 900px) {
  .pf-ab-split { grid-template-columns: minmax(0, 27rem) minmax(0, 1fr); gap: 3.5rem; }
}
.pf-ab-figure-wide { margin-top: 2.5rem; }

/* Use cases: label over description, on a grid that reflows by available room. */
.pf-ab-uses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.75rem 2.5rem;
  margin: 2.25rem 0 0;
}
.pf-ab-uses div { display: flex; flex-direction: column; gap: 0.4rem; }
.pf-ab-uses dt {
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-ab-uses dd {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--zinc-400);
}

/* Current page in the nav — a weight change, not a colour change. */
.pf-nav-link.is-current { color: var(--ink); font-weight: 600; }

/* ── ABOUT · REFINEMENT PASS ───────────────────────────────────────────────
   Accents only. The type scale, colour, and hierarchy are unchanged; what is
   added is a small amount of orange and a few technical marks, placed where
   they help the eye find structure rather than where they'd merely decorate.

   Orange budget on this page: the hero accent word, the section numerals,
   the flow rail, and one plus mark. Roughly one per screenful, which is the
   most the accent can carry before it stops meaning anything. */

/* The hero's accent word — Clepto, same device as the landing page's "chat."
   One word, and only in the hero. */
.pf-ab-title .pf-accent-gradient { font-size: 0.94em; }

/* Section numerals go orange, the label stays quiet. Structure becomes
   scannable without adding a single new element. */
.pf-eyebrow { color: var(--zinc-600); }
.pf-eyebrow::first-line { color: inherit; }
.pf-section .pf-eyebrow,
.pf-ab-hero .pf-eyebrow { position: relative; }
.pf-ab-num { color: var(--flow); }

/* Clepto, used once per heading at most, on a single short word. */
.pf-ab-mark {
  font-style: normal;
  font-family: var(--font-mark);
  font-weight: 400;
  font-size: 1.02em;
  letter-spacing: 0.03em;
  margin-right: -0.03em;
  color: var(--flow);
}

/* The promise line under the hero. A tick rule leads into it so it reads as a
   caption on the statement above rather than a second lede. */
.pf-ab-promise {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  margin: 2rem 0 0;
  max-width: 70ch;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 19px;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--zinc-500);
}
.pf-ab-promise .pf-o { position: relative; top: -3px; flex: none; }

/* ── The four movements. The rail down the left IS the shared context: one
   continuous line touching all four, which is the whole argument drawn. */
.pf-ab-flow {
  position: relative;
  margin: 2.5rem 0 0;
  padding: 0 0 0 3.25rem;
  list-style: none;
  display: grid;
  gap: 2.25rem;
}
.pf-ab-flow::before {
  content: "";
  position: absolute;
  left: 0.72rem;
  top: 0.4rem;
  bottom: 0.4rem;
  width: 1px;
  /* Solid at the top where research begins, fading out at the end — the
     context carries through rather than stopping at a boundary. */
  background: linear-gradient(180deg, var(--flow) 0%, var(--flow-24) 55%, transparent 100%);
}
.pf-ab-flow li { position: relative; display: grid; gap: 0.5rem; }
.pf-ab-flow-num {
  position: absolute;
  left: -3.25rem;
  top: 0.1rem;
  width: 1.45rem;
  height: 1.45rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--bg-base);
  border: 1px solid var(--flow-24);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--flow);
}
.pf-ab-flow h3 {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.pf-ab-flow p {
  margin: 0;
  max-width: 62ch;
  font-size: 0.9375rem;
  line-height: 1.68;
  color: var(--zinc-400);
}

/* Closing aside — a leader line runs out to it, the way a drawing annotates. */
.pf-ab-note {
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  margin: 2.5rem 0 0;
  max-width: 60ch;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--zinc-500);
}
.pf-ab-note .pf-o--leader { position: relative; top: -4px; flex: none; --o-lead: 34px; }

/* A single registration mark beside the principles lede. */
.pf-ab-plus { margin-top: 0.9rem; }

@media (max-width: 640px) {
  .pf-ab-flow { padding-left: 2.5rem; }
  .pf-ab-flow::before { left: 0.6rem; }
  .pf-ab-flow-num { left: -2.5rem; width: 1.25rem; height: 1.25rem; font-size: 9px; }
  .pf-ab-promise { flex-direction: column; gap: 0.6rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PRICING
   ──────────────────────────────────────────────────────────────────────────
   The money page. Restraint here is not a style choice — a page that asks for
   a card should look like a statement, not a campaign. So: no gradients on
   the cards, no glow on the recommended tier, no motion beyond the hover
   states the rest of the site already uses. Hierarchy is carried by weight,
   a hairline, and one accent.
   ========================================================================== */

.pf-pr-hero { padding: 7rem 1rem 2.5rem; text-align: center; }
@media (min-width: 640px) { .pf-pr-hero { padding: 8.5rem 2rem 3rem; } }
.pf-pr-hero .pf-eyebrow { text-align: center; }

.pf-pr-title {
  margin: 0.85rem 0 0;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(2.25rem, 5vw, 3.75rem);
  line-height: 1.03;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--ink);
}
.pf-pr-lede {
  margin: 1.15rem auto 0;
  max-width: 46ch;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--zinc-400);
}

/* ── Billing toggle. Radios + :checked, no script. ─────────────────────── */
.pf-bill-input { position: absolute; opacity: 0; pointer-events: none; }

.pf-bill { margin-top: 2.25rem; display: flex; flex-direction: column; align-items: center; gap: 0.9rem; }
.pf-bill-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
}
.pf-bill-switch label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: 8.5rem;
  height: 2.375rem;
  padding-inline: 1rem;
  border-radius: var(--radius-lg);
  font-size: 13px;
  font-weight: 600;
  color: var(--zinc-500);
  cursor: pointer;
  /* Colour only. A sliding indicator would be the one animated thing on a
     page whose job is to feel steady. */
  transition: color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
.pf-bill-switch label:hover { color: var(--ink); }
#bill-monthly:checked ~ main .pf-bill-switch label[for="bill-monthly"],
#bill-yearly:checked  ~ main .pf-bill-switch label[for="bill-yearly"] {
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 1px 2px rgb(var(--shadow-rgb) / 0.05);
}
.pf-bill-save {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--flow);
}

.pf-bill-note {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 12.5px;
  color: var(--zinc-500);
}
.pf-bill-note svg { color: var(--zinc-600); flex: none; }
.pf-bill-note strong { font-weight: 600; color: var(--zinc-300); }

/* Only one figure at a time. Both are in the markup so the page needs no
   script and the number is never a layout shift away. */
[data-bill] { display: none; }
#bill-monthly:checked ~ main [data-bill="monthly"],
#bill-yearly:checked  ~ main [data-bill="yearly"] { display: inline; }

/* ── Plan cards ────────────────────────────────────────────────────────── */
.pf-section--tight { padding-top: 1.5rem; }

.pf-plans { display: grid; gap: 1.25rem; align-items: start; }
@media (min-width: 820px) {
  .pf-plans { grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: stretch; }
  /* Free carries less content, so its feature list takes the slack and both
     cards end on the same line. Only above 820 — stacked, a stretched card
     would leave a strange gap under the shorter plan. */
  .pf-plan { height: 100%; }
  .pf-plan .pf-plan-list { flex: 1; align-content: start; }
}

.pf-plan {
  display: flex;
  flex-direction: column;
  padding: 1.75rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--card-solid);
}
@media (min-width: 640px) { .pf-plan { padding: 2rem; } }
/* The recommended tier is marked by a firmer edge and a white field, not by
   colour or a glow. It reads as the more solid object of the two. */
.pf-plan--featured { background: var(--paper); border-color: var(--border-focus); }

.pf-plan-head { margin-bottom: 1.5rem; }
.pf-plan-name { display: flex; align-items: center; gap: 0.75rem; }
.pf-plan-name h2 {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.pf-plan-badge {
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--flow-24);
  border-radius: var(--radius-lg);
  background: var(--flow-14);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--flow-strong);
}
.pf-plan-tag { margin: 0.4rem 0 0; font-size: 13.5px; color: var(--zinc-500); }

.pf-plan-price { display: flex; align-items: baseline; gap: 0.5rem; }
.pf-plan-amount {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: 2.75rem;
  line-height: 1;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.pf-plan-per { font-size: 13px; color: var(--zinc-500); }
.pf-plan-billed {
  margin: 0.6rem 0 0;
  min-height: 1rem;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zinc-600);
}

.pf-plan-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.75rem;
  margin-top: 1.5rem;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-xl);
  background: var(--paper);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
  box-shadow: 0 1px 2px rgb(var(--shadow-rgb) / 0.04);
  transition: border-color var(--dur-med) var(--ease-standard),
              box-shadow var(--dur-med) var(--ease-standard);
}
.pf-plan-cta:hover { border-color: var(--ink); box-shadow: 0 4px 14px -6px rgb(var(--shadow-rgb) / 0.22); }
/* The paid action is emphasised by WEIGHT, not by force. A solid black button
   on a page this quiet reads as a demand; a warm tinted fill with a firmer
   edge sits one step above the plain white "Start free" without shouting at
   anyone. The ink stays in the text where it is legible. */
.pf-plan-cta--primary {
  background: var(--surface-hover);
  border-color: rgb(var(--tint-rgb) / 0.24);
  color: var(--ink);
  box-shadow: 0 1px 2px rgb(var(--shadow-rgb) / 0.06);
}
.pf-plan-cta--primary:hover {
  background: color-mix(in srgb, var(--surface-hover) 88%, var(--ink));
  border-color: var(--ink);
  box-shadow: 0 4px 14px -6px rgb(var(--shadow-rgb) / 0.24);
}

.pf-plan-fine { margin: 0.85rem 0 0; font-size: 12.5px; line-height: 1.55; color: var(--zinc-500); }
.pf-plan-rule { height: 1px; margin: 1.5rem 0; background: var(--border-soft); }
.pf-plan-inherit {
  margin: 0 0 0.85rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}

.pf-plan-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.7rem; }
.pf-plan-list li {
  position: relative;
  padding-left: 1.4rem;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--zinc-400);
}
/* A tick drawn from two borders — no icon font, no inline SVG per row. */
.pf-plan-list li::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 0.34em;
  width: 0.3rem;
  height: 0.55rem;
  border-right: 1.5px solid var(--flow);
  border-bottom: 1.5px solid var(--flow);
  transform: rotate(45deg);
}
.pf-plan-list strong { font-weight: 600; color: var(--ink); }

.pf-pr-tax {
  margin: 1.75rem 0 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zinc-600);
}

/* ── Top-ups ───────────────────────────────────────────────────────────── */
.pf-topups { display: grid; gap: 1rem; margin-top: 2.25rem; }
@media (min-width: 720px) { .pf-topups { grid-template-columns: repeat(3, 1fr); } }

.pf-topup {
  position: relative;
  display: grid;
  gap: 0.25rem;
  padding: 1.5rem;
  padding-right: 3.25rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--card-solid);
  transition: border-color var(--dur-med) var(--ease-standard),
              background-color var(--dur-med) var(--ease-standard);
}
.pf-topup:hover { border-color: var(--border-focus); background: var(--paper); }

/* ── The go-arrow. ::before is the shaft, ::after the head; both share one
   transition so they travel as a single object. 3px is the whole movement —
   enough to answer the hover, not enough to be a performance. */
.pf-topup::before,
.pf-topup::after {
  content: "";
  position: absolute;
  right: 1.5rem;
  bottom: 1.6rem;
  color: var(--zinc-600);
  transition: transform var(--dur-med) var(--ease-out-expo),
              color var(--dur-med) var(--ease-standard);
}
.pf-topup::before {          /* shaft */
  width: 15px;
  height: 1.5px;
  background: currentColor;
}
.pf-topup::after {           /* head */
  width: 7px;
  height: 7px;
  bottom: 1.42rem;
  border-top: 1.5px solid currentColor;
  border-right: 1.5px solid currentColor;
  transform: rotate(45deg);
}
.pf-topup:hover::before { color: var(--flow); transform: translateX(3px); }
.pf-topup:hover::after  { color: var(--flow); transform: translateX(3px) rotate(45deg); }

@media (prefers-reduced-motion: reduce) {
  .pf-topup::before, .pf-topup::after { transition: color var(--dur-med) var(--ease-standard); }
  .pf-topup:hover::before { transform: none; }
  .pf-topup:hover::after  { transform: rotate(45deg); }
}
.pf-topup-credits {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: 1.875rem;
  line-height: 1;
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.pf-topup-unit {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-topup-price { margin-top: 0.75rem; font-size: 14px; font-weight: 600; color: var(--ink); }

/* ── Trust ─────────────────────────────────────────────────────────────── */
.pf-trust {
  display: grid;
  gap: 2rem;
  padding: 2rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--card-solid);
}
@media (min-width: 900px) { .pf-trust { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 3.5rem; padding: 2.5rem; } }
.pf-trust-lead p {
  margin: 1rem 0 0;
  max-width: 52ch;
  font-size: 14px;
  line-height: 1.65;
  color: var(--zinc-400);
}
.pf-trust-lead strong { font-weight: 600; color: var(--ink); }

.pf-trust-points { margin: 0; padding: 0; list-style: none; display: grid; gap: 1rem; align-content: center; }
.pf-trust-points li {
  display: grid;
  grid-template-columns: 2.25rem 1fr;
  gap: 0.75rem;
  align-items: baseline;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--zinc-400);
}

/* ── FAQ — native <details>, no script ─────────────────────────────────── */
.pf-faq { margin-top: 2rem; border-top: 1px solid var(--border-soft); }
.pf-faq details { border-bottom: 1px solid var(--border-soft); }
.pf-faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem 0;
  cursor: pointer;
  list-style: none;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}
.pf-faq summary::-webkit-details-marker { display: none; }
/* A plus that becomes a minus. Two spans would need markup; one rotated
   pseudo-element does it with none. */
.pf-faq summary::after {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  background:
    linear-gradient(var(--zinc-500) 0 0) center / 100% 1.5px no-repeat,
    linear-gradient(var(--zinc-500) 0 0) center / 1.5px 100% no-repeat;
  transition: transform var(--dur-fast) var(--ease-standard);
}
.pf-faq details[open] summary::after { transform: rotate(90deg); background-size: 100% 1.5px, 0 0; }
.pf-faq summary:hover { color: var(--flow-strong); }
.pf-faq p {
  margin: 0 0 1.35rem;
  max-width: 68ch;
  font-size: 14px;
  line-height: 1.65;
  color: var(--zinc-400);
}

/* ══════════════════════════════════════════════════════════════════════════
   AUTHENTICATION
   ──────────────────────────────────────────────────────────────────────────
   A standalone surface: no header, no footer, no navigation except the
   wordmark. One card, centred, on the page's own cream field. The restraint
   is functional — after someone has decided to sign in, every additional
   link is an exit.

   The whole page carries exactly two accents: the active tab's underline and
   the focus ring. Everything else is ink and hairline.
   ========================================================================== */

.pf-au-input { position: absolute; opacity: 0; pointer-events: none; }

/* min-height on the ROOT, not the body — .pf-root is the positioned element
   the background layers hang off, so it has to be the thing that fills the
   viewport or the cream field stops short of the fold. */
.pf-authpage .pf-root { min-height: 100vh; display: flex; flex-direction: column; }

.pf-au {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  padding: 3rem 1rem 3.5rem;
}
@media (min-width: 640px) { .pf-au { padding: 4rem 2rem; } }

.pf-au-brand { display: inline-flex; }

.pf-au-card {
  width: 100%;
  max-width: 25.5rem;
  padding: 1.75rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--paper);
  box-shadow: 0 1px 2px rgb(var(--shadow-rgb) / 0.03),
              0 12px 40px -22px rgb(var(--shadow-rgb) / 0.18);
}
@media (min-width: 480px) { .pf-au-card { padding: 2rem; } }

.pf-au-title {
  margin: 0;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: 1.5rem;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -0.018em;
  color: var(--ink);
}
.pf-au-sub { margin: 0.5rem 0 0; font-size: 13.5px; line-height: 1.5; color: var(--zinc-500); }

/* ── Mode tabs. Underline, not a pill — a segmented control would echo the
   pricing toggle, and these two are different kinds of choice. ─────────── */
.pf-au-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin: 1.5rem 0 1.25rem;
  border-bottom: 1px solid var(--border-soft);
}
.pf-au-tabs label {
  position: relative;
  padding: 0.6rem 0 0.7rem;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--zinc-500);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-au-tabs label:hover { color: var(--ink); }
.pf-au-tabs label::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1.5px;
  background: var(--flow);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
#mode-signin:checked   ~ .pf-au .pf-au-tabs label[for="mode-signin"],
#mode-register:checked ~ .pf-au .pf-au-tabs label[for="mode-register"] { color: var(--ink); }
#mode-signin:checked   ~ .pf-au .pf-au-tabs label[for="mode-signin"]::after,
#mode-register:checked ~ .pf-au .pf-au-tabs label[for="mode-register"]::after { opacity: 1; }

/* One mode visible at a time. Both forms ship; the radio picks one.
   Specificity matters here: `.pf-au [data-mode]` (0,2,0) has to outrank
   `.pf-au-form { display: grid }` (0,1,0), or the form's own display wins on
   source order and BOTH forms stay on screen. And the reveal cannot simply say
   `display: block` — that would flatten the form's grid and strand every
   field. So each element type is restored to the display it actually needs. */
.pf-au [data-mode] { display: none; }
#mode-signin:checked   ~ .pf-au form[data-mode="signin"],
#mode-register:checked ~ .pf-au form[data-mode="register"] { display: grid; }
#mode-signin:checked   ~ .pf-au span[data-mode="signin"],
#mode-register:checked ~ .pf-au span[data-mode="register"] { display: inline; }

/* ── Providers ────────────────────────────────────────────────────────── */
.pf-au-providers { display: grid; gap: 0.55rem; }
.pf-au-provider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  height: 2.75rem;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-xl);
  background: var(--paper);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.pf-au-provider:hover { background: var(--bg-base); border-color: var(--ink); }
.pf-au-provider svg { flex: none; }

/* Rule with the word sitting in a gap punched out of it. */
.pf-au-or {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-au-or::before, .pf-au-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border-soft);
}

/* ── Fields ───────────────────────────────────────────────────────────── */
.pf-au-form { display: grid; gap: 1rem; }
.pf-au-field { display: grid; gap: 0.4rem; }
.pf-au-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.pf-au-field label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--zinc-300);
}
.pf-au-field input {
  height: 2.75rem;
  padding-inline: 0.85rem;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-xl);
  background: var(--bg-base);
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--ink);
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.pf-au-field input::placeholder { color: var(--zinc-600); }
.pf-au-field input:hover { border-color: var(--zinc-500); }
.pf-au-field input:focus {
  outline: none;
  background: var(--paper);
  border-color: var(--flow);
  box-shadow: 0 0 0 3px var(--flow-14);
}
/* The browser's own invalid styling fires before anyone has typed; :not(:focus)
   plus :not(:placeholder-shown) waits until there is something to be wrong. */
.pf-au-field input:not(:focus):not(:placeholder-shown):invalid { border-color: var(--danger, #F0533F); }

.pf-au-forgot { font-size: 12px; font-weight: 500; color: var(--zinc-500); }
.pf-au-forgot:hover { color: var(--flow-strong); }
.pf-au-hint { margin: 0.15rem 0 0; font-size: 11.5px; color: var(--zinc-600); }

.pf-au-submit {
  height: 2.75rem;
  margin-top: 0.25rem;
  border: 1px solid var(--ink);
  border-radius: var(--radius-xl);
  background: var(--ink);
  font-family: var(--font-sans);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--on-ink);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard);
}
.pf-au-submit:hover { background: var(--zinc-100); }
.pf-au-submit:focus-visible { outline: 2px solid var(--flow); outline-offset: 2px; }

.pf-au-terms { margin: 0.25rem 0 0; font-size: 11.5px; line-height: 1.55; color: var(--zinc-600); }
.pf-au-terms a { color: var(--zinc-500); text-decoration: underline; text-underline-offset: 2px; }
.pf-au-terms a:hover { color: var(--ink); }

.pf-au-foot {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  max-width: 25.5rem;
  text-align: center;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--zinc-600);
}
.pf-au-foot svg { flex: none; color: var(--zinc-600); }

/* ── Consent ───────────────────────────────────────────────────────────────
   Required by law, so it cannot be hidden; not the point of the page, so it
   should not compete with it. The whole line sits one step quieter than the
   field labels above it, and the box only gains weight once it is ticked.

   `required` on the input is what actually blocks submission — native
   constraint validation, no script. The dimmed button below is only a signal;
   the browser does the enforcing and points at the box if you try anyway. */
.pf-au-consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.6rem;
  align-items: start;
  margin-top: 0.25rem;
}

.pf-au-consent input[type="checkbox"] {
  /* appearance:none keeps the real control — focus, space bar, :required,
     and the validation bubble all still work. Only the paint is ours. */
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 15px;
  height: 15px;
  margin: 1px 0 0;
  border: 1px solid var(--border-focus);
  border-radius: 4px;
  background: var(--bg-base);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.pf-au-consent input[type="checkbox"]:hover { border-color: var(--zinc-500); }
.pf-au-consent input[type="checkbox"]:checked {
  border-color: var(--ink);
  /* Tick as a data-URI background rather than ::after — pseudo-elements on
     form controls are inconsistent, a background is not. */
  background: var(--ink) var(--tick) center / 11px no-repeat;
}
.pf-au-consent input[type="checkbox"]:focus-visible {
  outline: none;
  border-color: var(--flow);
  box-shadow: 0 0 0 3px var(--flow-14);
}

.pf-au-consent label {
  font-size: 12px;
  line-height: 1.5;
  font-weight: 400;
  color: var(--zinc-500);
  cursor: pointer;
}
/* A link inside a label does NOT toggle the control — per spec, label
   activation is skipped when the event target is interactive content. So the
   link can live in the sentence where it reads naturally. */
.pf-au-consent label a {
  color: var(--zinc-300);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-focus);
}
.pf-au-consent label a:hover { color: var(--ink); text-decoration-color: currentColor; }

/* Until consent is given the action reads as not-yet-available. Deliberately
   still clickable: clicking surfaces the browser's own validation message
   pointing at the checkbox, which explains far more than a dead button. */
.pf-au-form:has(.pf-au-consent input:not(:checked)) .pf-au-submit {
  background: var(--zinc-600);
  border-color: var(--zinc-600);
}
.pf-au-form:has(.pf-au-consent input:not(:checked)) .pf-au-submit:hover {
  background: var(--zinc-500);
  border-color: var(--zinc-500);
}

/* ══════════════════════════════════════════════════════════════════════════
   BLOG
   ──────────────────────────────────────────────────────────────────────────
   A grid built to be filled. `auto-fill` + `minmax` means post four and post
   forty need no layout change — add another <article class="pf-post"> and it
   flows into place. Nothing here assumes three.
   ========================================================================== */

.pf-bl-hero { padding: 7rem 1rem 2.5rem; }
@media (min-width: 640px) { .pf-bl-hero { padding: 8.5rem 2rem 3rem; } }

.pf-bl-title {
  margin: 0.85rem 0 0;
  max-width: 16ch;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(2.25rem, 5vw, 3.75rem);
  line-height: 1.03;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--ink);
}
.pf-bl-lede {
  margin: 1.15rem 0 0;
  max-width: 48ch;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--zinc-400);
}

.pf-bl-head { margin-bottom: 1.5rem; }

.pf-posts {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  align-items: stretch;
}

.pf-post { display: flex; }
.pf-post-link {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 1.5rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--card-solid);
  transition: border-color var(--dur-med) var(--ease-standard),
              background-color var(--dur-med) var(--ease-standard),
              box-shadow var(--dur-med) var(--ease-standard);
}
.pf-post-link:hover {
  border-color: var(--border-focus);
  background: var(--paper);
  box-shadow: 0 8px 26px -18px rgb(var(--shadow-rgb) / 0.28);
}

/* The icon sits in its own well so the drawing has a frame of its own and the
   cards stay aligned regardless of how tall each illustration is. */
.pf-post-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 6.5rem;
  margin-bottom: 1.25rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--bg-base);
  color: var(--ink);
  transition: color var(--dur-med) var(--ease-standard),
              border-color var(--dur-med) var(--ease-standard);
}
.pf-post-icon svg { width: 84px; height: 60px; }
.pf-post-link:hover .pf-post-icon { color: var(--flow-strong); border-color: var(--flow-24); }

.pf-post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.6rem;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
/* Separators drawn, not typed — one less character to keep in sync. */
.pf-post-meta > * + *::before { content: "·"; margin-right: 0.5rem; }
.pf-post-cat { color: var(--flow-strong); }

.pf-post-title {
  margin: 0 0 0.6rem;
  font-size: 1.1875rem;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--ink);
}

/* flex:1 pushes the read affordance to the bottom edge, so every card's
   footer line sits level no matter how long the excerpt runs. */
.pf-post-excerpt {
  flex: 1;
  margin: 0 0 1.25rem;
  font-size: 13.5px;
  line-height: 1.62;
  color: var(--zinc-400);
}

.pf-post-more {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-500);
  transition: color var(--dur-med) var(--ease-standard);
}
.pf-post-link:hover .pf-post-more { color: var(--flow-strong); }

/* Same two-part arrow as the pricing top-ups, so "go" reads identically
   wherever it appears on the site. */
.pf-post-arrow {
  position: relative;
  display: inline-block;
  width: 15px;
  height: 8px;
}
.pf-post-arrow::before,
.pf-post-arrow::after {
  content: "";
  position: absolute;
  right: 0;
  transition: transform var(--dur-med) var(--ease-out-expo);
}
.pf-post-arrow::before { top: 3px; width: 15px; height: 1.5px; background: currentColor; }
.pf-post-arrow::after {
  top: 0.5px;
  width: 6.5px;
  height: 6.5px;
  border-top: 1.5px solid currentColor;
  border-right: 1.5px solid currentColor;
  transform: rotate(45deg);
}
.pf-post-link:hover .pf-post-arrow::before { transform: translateX(3px); }
.pf-post-link:hover .pf-post-arrow::after  { transform: translateX(3px) rotate(45deg); }

@media (prefers-reduced-motion: reduce) {
  .pf-post-arrow::before, .pf-post-arrow::after { transition: none; }
  .pf-post-link:hover .pf-post-arrow::before { transform: none; }
  .pf-post-link:hover .pf-post-arrow::after  { transform: rotate(45deg); }
}

.pf-bl-more {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin: 2.5rem 0 0;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-bl-more .pf-o--dot { --o-c: var(--flow); flex: none; }

/* ── Per-icon hover ────────────────────────────────────────────────────────
   Each of the three later icons animates the ONE part of itself that carries
   its idea, so the movement explains the drawing rather than decorating it:
   the piece rotates, the result advances, the pinch travels. Everything else
   in each drawing holds still — including the ghost, which is the point of
   comparison and would say nothing if it moved too.

   transform-box: view-box makes transform-origin resolve against the SVG's
   own coordinate system, so the origins below are in viewBox units and stay
   correct at any rendered size. */
.pf-ic-spin,
.pf-ic-push,
.pf-ic-slide {
  transform-box: view-box;
  transition: transform 420ms var(--ease-out-expo);
}

/* 04 · the piece completes its rotation, about its own centre */
.pf-ic-spin { transform-origin: 39.5px 18.5px; }
.pf-post-link:hover .pf-ic-spin { transform: rotate(90deg); }

/* 05 · the result moves up to meet the examples that produced it */
.pf-ic-push { transform-origin: 44px 25px; }
.pf-post-link:hover .pf-ic-push { transform: translateX(-3.5px); }

/* 06 · the constraint slides further along the channel */
.pf-ic-slide { transform-origin: 44px 20px; }
.pf-post-link:hover .pf-ic-slide { transform: translateX(4px); }

@media (prefers-reduced-motion: reduce) {
  .pf-ic-spin, .pf-ic-push, .pf-ic-slide { transition: none; }
  .pf-post-link:hover .pf-ic-spin,
  .pf-post-link:hover .pf-ic-push,
  .pf-post-link:hover .pf-ic-slide { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   LEGAL  (terms.html · privacy.html)
   ──────────────────────────────────────────────────────────────────────────
   The text in these two pages is verbatim from the application's own source
   and must stay that way. Everything here is presentation: it styles the
   document SEMANTICALLY, by element, so the markup carries no classes and a
   re-extraction can drop straight in without touching a single selector.

   A legal document is read differently from a marketing page — people scan
   for a clause, then read closely. So: one narrow measure, generous space
   between sections, numbered headings that stand out when skimming, and no
   ornament anywhere. Nothing here should be interesting.
   ========================================================================== */

.pf-legal-hero { padding: 7rem 1rem 0; }
@media (min-width: 640px) { .pf-legal-hero { padding: 8.5rem 2rem 0; } }

.pf-legal-title {
  margin: 0.85rem 0 0;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(2rem, 4.2vw, 3rem);
  line-height: 1.05;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* Dates are the first thing a reader checks for currency, so they sit
   immediately under the title in the mono voice rather than buried. */
.pf-legal-dates {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  margin: 1.15rem 0 0;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-legal-dates strong { font-weight: 400; color: var(--zinc-500); }

.pf-legal-body { padding: 2.5rem 1rem 1rem; }
@media (min-width: 640px) { .pf-legal-body { padding: 3rem 2rem 1rem; } }

/* ~78 characters. Wider than the marketing measure because legal prose is
   long-sentenced and a narrow column makes clause-heavy text harder, not
   easier, to follow. */
.pf-legal { max-width: 47rem; }

.pf-legal section { margin-bottom: 3rem; }
.pf-legal section:last-of-type { margin-bottom: 1.5rem; }

.pf-legal h2 {
  margin: 0 0 1.15rem;
  padding-top: 0.5rem;
  font-size: 1.375rem;
  line-height: 1.25;
  font-weight: 700;
  letter-spacing: -0.012em;
  color: var(--ink);
  scroll-margin-top: 6rem;
}
.pf-legal h3 {
  margin: 2rem 0 0.75rem;
  font-size: 1rem;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.pf-legal h3:first-of-type { margin-top: 1.5rem; }

.pf-legal p {
  margin: 0 0 1.1rem;
  font-size: 0.9375rem;
  line-height: 1.72;
  color: var(--zinc-400);
}
.pf-legal p:last-child { margin-bottom: 0; }

.pf-legal ul { margin: 0 0 1.25rem; padding-left: 1.35rem; list-style: none; }
.pf-legal li {
  position: relative;
  margin-bottom: 0.55rem;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--zinc-400);
}
/* A hairline dash rather than a bullet — quieter, and it echoes the mono
   rules used everywhere else on the site. */
.pf-legal li::before {
  content: "";
  position: absolute;
  left: -1.35rem;
  top: 0.82em;
  width: 7px;
  height: 1px;
  background: var(--zinc-600);
}

/* Emphasis in a contract is load-bearing — the all-caps acceptance clauses,
   the carve-outs. It gets full ink weight, not a colour. */
.pf-legal strong { font-weight: 600; color: var(--ink); }

.pf-legal a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-focus);
}
.pf-legal a:hover { text-decoration-color: currentColor; }

/* Indented contact / address blocks. */
.pf-legal-block {
  margin: 0 0 1.25rem;
  padding-left: 1.35rem;
  border-left: 1px solid var(--border-soft);
  font-size: 0.9375rem;
  line-height: 1.72;
  color: var(--zinc-400);
}
.pf-legal-block p { margin-bottom: 0.35rem; }

/* Closing block after the final section. */
.pf-legal-end {
  margin-top: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border-soft);
}
.pf-legal-end p { font-size: 0.875rem; color: var(--zinc-500); }

/* ── NAV · MORE DROPDOWN ───────────────────────────────────────────────────
   Opens on hover and on :focus-within, so a pointer and the Tab key both
   reach it with no script. The trade-off is honest and worth stating: there
   is no click-to-latch and no Escape-to-close, because neither exists without
   JS. On touch, tapping the button focuses it — which is what opens the menu —
   and tapping elsewhere blurs it shut. Good enough here; when this becomes a
   component it should get real open state.

   aria-expanded is deliberately absent rather than hardcoded: CSS drives the
   visibility, so any fixed value would be a lie half the time. */
.pf-nav-more { position: relative; display: inline-flex; }

.pf-nav-more-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}
.pf-nav-chev {
  width: 12px;
  height: 12px;
  margin-top: 1px;
  opacity: .55;
  transition: transform var(--dur-fast) var(--ease-standard);
}
.pf-nav-more:hover .pf-nav-chev,
.pf-nav-more:focus-within .pf-nav-chev { transform: rotate(180deg); }

.pf-nav-menu {
  position: absolute;
  top: calc(100% + 0.85rem);
  left: 50%;
  z-index: 40;
  display: grid;
  min-width: 11rem;
  padding: 0.35rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--paper);
  box-shadow: 0 1px 2px rgb(var(--shadow-rgb) / .04), 0 16px 40px -20px rgb(var(--shadow-rgb) / .28);
  opacity: 0;
  visibility: hidden;
  transform: translateX(-50%) translateY(-4px);
  transition: opacity var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard),
              visibility 0s linear var(--dur-fast);
}
/* Bridges the gap between button and panel — without it the menu closes the
   moment the pointer crosses the space between them. */
.pf-nav-menu::before {
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: -0.85rem;
  height: 0.85rem;
}
.pf-nav-more:hover .pf-nav-menu,
.pf-nav-more:focus-within .pf-nav-menu {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
  transition-delay: 0s;
}

.pf-nav-menu-link {
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-lg);
  font-size: 13px;
  font-weight: 500;
  color: var(--zinc-400);
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
.pf-nav-menu-link:hover { color: var(--ink); background: var(--bg-base); }
.pf-nav-menu-link:focus-visible { outline: 2px solid var(--flow); outline-offset: -2px; }

@media (prefers-reduced-motion: reduce) {
  .pf-nav-chev, .pf-nav-menu { transition: opacity var(--dur-fast) linear, visibility 0s; }
  .pf-nav-more:hover .pf-nav-chev,
  .pf-nav-more:focus-within .pf-nav-chev { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   CAREERS
   ──────────────────────────────────────────────────────────────────────────
   One centred column, because the page is mostly prose and prose reads best
   on a single measure. The hierarchy departs from convention in exactly one
   place — the roles register, which runs wider than the reading measure and
   indexes itself in the gutter. Departing once is a decision; departing
   everywhere is just noise.
   ========================================================================== */

.pf-ca { --ca-measure: 38rem; }

.pf-ca-hero {
  max-width: var(--ca-measure);
  margin-inline: auto;
  padding: 7rem 1rem 0;
  text-align: center;
}
@media (min-width: 640px) { .pf-ca-hero { padding: 8.5rem 2rem 0; } }
.pf-ca-hero .pf-eyebrow { text-align: center; }

.pf-ca-title {
  margin: 0.85rem 0 0;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(2.125rem, 4.8vw, 3.25rem);
  line-height: 1.05;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--ink);
  text-wrap: balance;
}
.pf-ca-lede {
  margin: 1.25rem auto 0;
  max-width: 34rem;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--zinc-400);
}

.pf-ca-section {
  max-width: var(--ca-measure);
  margin: 4.5rem auto 0;
  padding-inline: 1rem;
}
@media (min-width: 640px) { .pf-ca-section { padding-inline: 2rem; } }

/* The tick rule under the hero is the page's one ornament. It sits on the
   centre line and does nothing else. */
.pf-ca-rule { display: block; margin: 0 auto 2rem; }

.pf-ca-prose p {
  margin: 0 0 1.15rem;
  font-size: 1rem;
  line-height: 1.75;
  color: var(--zinc-400);
}
.pf-ca-prose p:last-child { margin-bottom: 0; }

.pf-ca-h2 {
  margin: 0 0 1.5rem;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: 1.5rem;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -0.018em;
  color: var(--ink);
}

/* ── The register. Wider than the measure, indexed in its own gutter. ──── */
.pf-ca-roles {
  margin: 0;
  padding: 0;
  list-style: none;
  /* the one break from the centre line */
  width: calc(100% + 3rem);
  margin-left: -1.5rem;
}
@media (max-width: 560px) { .pf-ca-roles { width: 100%; margin-left: 0; } }

.pf-ca-roles li {
  display: grid;
  grid-template-columns: 3.25rem 1fr;
  gap: 1rem;
  align-items: baseline;
  padding: 0.95rem 1.5rem;
  border-top: 1px solid var(--border-soft);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--zinc-300);
}
.pf-ca-roles li:last-child { border-bottom: 1px solid var(--border-soft); }

.pf-ca-num {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  font-variant-numeric: tabular-nums;
  color: var(--zinc-600);
}

.pf-ca-contact {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  margin: 2rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--zinc-500);
}
.pf-ca-contact .pf-o--leader { position: relative; top: -4px; flex: none; --o-lead: 28px; }
.pf-ca-contact a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-focus);
}
.pf-ca-contact a:hover { text-decoration-color: var(--flow); }

/* ── Application ───────────────────────────────────────────────────────── */
.pf-ca-apply {
  padding: 1.75rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--card-solid);
}
@media (min-width: 640px) { .pf-ca-apply { padding: 2.25rem; } }
.pf-ca-apply-head { margin-bottom: 1.75rem; }
.pf-ca-apply-head .pf-ca-h2 { margin: 0.6rem 0 0; }
.pf-ca-apply-sub {
  margin: 0.65rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--zinc-500);
}

.pf-ca-form { display: grid; gap: 1.1rem; }
.pf-ca-row { display: grid; gap: 1.1rem; }
@media (min-width: 560px) { .pf-ca-row { grid-template-columns: 1fr 1fr; } }

.pf-ca-field { display: grid; gap: 0.4rem; }
.pf-ca-field label {
  font-size: 12px;
  font-weight: 600;
  color: var(--zinc-300);
}
.pf-ca-opt {
  margin-left: 0.4rem;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zinc-600);
}

.pf-ca-field input,
.pf-ca-field select,
.pf-ca-field textarea {
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-xl);
  background: var(--paper);
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--ink);
  transition: border-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.pf-ca-field textarea { resize: vertical; min-height: 6rem; line-height: 1.6; }
.pf-ca-field input::placeholder,
.pf-ca-field textarea::placeholder { color: var(--zinc-600); }
.pf-ca-field select { appearance: none; -webkit-appearance: none; cursor: pointer;
  /* chevron drawn as a background so no wrapper element is needed */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--zinc-500) 50%),
    linear-gradient(135deg, var(--zinc-500) 50%, transparent 50%);
  background-position: right 1.05rem center, right 0.8rem center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 2.25rem;
}
.pf-ca-field :is(input, select, textarea):hover { border-color: var(--zinc-500); }
.pf-ca-field :is(input, select, textarea):focus {
  outline: none;
  border-color: var(--flow);
  box-shadow: 0 0 0 3px var(--flow-14);
}

/* Styling ::file-selector-button keeps the NATIVE control — which means the
   browser still shows the chosen filename, and no script is needed to echo
   it back. A custom label over a hidden input would have lost that. */
.pf-ca-field input[type="file"] {
  padding: 0.5rem;
  font-size: 13px;
  color: var(--zinc-500);
  cursor: pointer;
}
.pf-ca-field input[type="file"]::file-selector-button {
  margin-right: 0.85rem;
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-lg);
  background: var(--bg-base);
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.pf-ca-field input[type="file"]::file-selector-button:hover {
  background: var(--surface-hover);
  border-color: var(--ink);
}

.pf-ca-consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.6rem;
  align-items: start;
  margin-top: 0.25rem;
}
.pf-ca-consent input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  margin: 1px 0 0;
  border: 1px solid var(--border-focus);
  border-radius: 4px;
  background: var(--paper);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
}
.pf-ca-consent input[type="checkbox"]:hover { border-color: var(--zinc-500); }
.pf-ca-consent input[type="checkbox"]:checked {
  border-color: var(--ink);
  background: var(--ink) var(--tick) center / 11px no-repeat;
}
.pf-ca-consent input[type="checkbox"]:focus-visible {
  outline: none;
  border-color: var(--flow);
  box-shadow: 0 0 0 3px var(--flow-14);
}
.pf-ca-consent label { font-size: 12px; line-height: 1.5; color: var(--zinc-500); cursor: pointer; }
.pf-ca-consent label a {
  color: var(--zinc-300);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-focus);
}
.pf-ca-consent label a:hover { color: var(--ink); }

.pf-ca-submit {
  height: 2.75rem;
  margin-top: 0.4rem;
  border: 1px solid var(--ink);
  border-radius: var(--radius-xl);
  background: var(--ink);
  font-family: var(--font-sans);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--on-ink);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard);
}
.pf-ca-submit:hover { background: var(--zinc-100); }
.pf-ca-submit:focus-visible { outline: 2px solid var(--flow); outline-offset: 2px; }
.pf-ca-form:has(.pf-ca-consent input:not(:checked)) .pf-ca-submit {
  background: var(--zinc-600);
  border-color: var(--zinc-600);
}

.pf-ca-note {
  margin: 0.25rem 0 0;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--zinc-600);
}
.pf-ca-note a { color: var(--zinc-500); text-decoration: underline; text-underline-offset: 2px; }
.pf-ca-note a:hover { color: var(--ink); }

/* The footer sits on the page's own shell, not the careers measure. */
.pf-ca .pf-access-section { margin-top: 5rem; }

/* ══════════════════════════════════════════════════════════════════════════
   DOCUMENTATION
   ──────────────────────────────────────────────────────────────────────────
   Neutral by intention. Documentation is read, not admired, so the ornament
   budget here is close to zero: orange appears on the current sidebar item,
   the focused search field, and nothing else. The PlansFlow voice survives in
   the type — display face on the page title, mono for labels and code.

   The grid is the whole layout:
     >=1200   14rem sidebar · content · 13rem contents
     960-1199 sidebar · content        (contents folds inline, above the body)
     <960     content only, sidebar behind a labelled toggle
   ========================================================================== */

.pf-docpage .pf-root { min-height: 100vh; }

.pf-doc {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0 3rem;
  max-width: 84rem;
  margin-inline: auto;
  /* 7rem clears the 104px absolute header, matching the hero padding every
     other page uses. Without it the sidebar and title run underneath. */
  padding: 7rem 1rem 5rem;
}
@media (min-width: 640px) { .pf-doc { padding-inline: 2rem; } }
@media (min-width: 960px)  { .pf-doc { grid-template-columns: 14rem minmax(0, 1fr); padding-top: 7.5rem; } }
@media (min-width: 1200px) { .pf-doc { grid-template-columns: 14rem minmax(0, 1fr) 13rem; } }

/* ── Sidebar ───────────────────────────────────────────────────────────── */
.pf-doc-side { position: relative; }
@media (min-width: 960px) {
  .pf-doc-side {
    position: sticky;
    top: 2rem;
    align-self: start;
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    /* the scrollbar only appears when the nav actually outgrows the viewport */
    scrollbar-width: thin;
  }
}

.pf-doc-search {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  height: 2.375rem;
  padding: 0 0.6rem 0 0.75rem;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-xl);
  background: var(--paper);
  transition: border-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.pf-doc-search:focus-within { border-color: var(--flow); box-shadow: 0 0 0 3px var(--flow-14); }
.pf-doc-search svg { flex: none; color: var(--zinc-600); }
.pf-doc-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--ink);
}
.pf-doc-search input:focus { outline: none; }
.pf-doc-search input::placeholder { color: var(--zinc-600); }
.pf-doc-search input::-webkit-search-cancel-button { -webkit-appearance: none; }
.pf-doc-search kbd {
  flex: none;
  padding: 0.1rem 0.35rem;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  background: var(--bg-base);
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--zinc-600);
}

/* Mobile disclosure. A checkbox rather than <details> because <details>
   cannot be forced open by a media query — it would need different markup
   per breakpoint. Above 960 the label is hidden and the nav is simply shown,
   so the checkbox state stops mattering entirely. */
.pf-doc-navtoggle { position: absolute; opacity: 0; pointer-events: none; }

.pf-doc-navbtn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.6rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--zinc-500);
  cursor: pointer;
}
.pf-doc-navchev { width: 14px; height: 14px; transition: transform var(--dur-fast) var(--ease-standard); }
#doc-nav:checked ~ .pf-doc .pf-doc-navchev { transform: rotate(180deg); }

.pf-doc-nav { display: none; margin-top: 1.25rem; }
#doc-nav:checked ~ .pf-doc .pf-doc-nav { display: block; }
@media (min-width: 960px) {
  .pf-doc-navbtn { display: none; }
  .pf-doc-nav { display: block; }
}

.pf-doc-navgroup {
  margin: 1.5rem 0 0.5rem;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-navgroup:first-child { margin-top: 0; }

.pf-doc-navlist { margin: 0; padding: 0; list-style: none; }
.pf-doc-navlist a {
  display: block;
  padding: 0.3rem 0.7rem;
  margin-left: -0.7rem;
  border-radius: var(--radius-lg);
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--zinc-400);
  transition: color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
.pf-doc-navlist a:hover { color: var(--ink); background: var(--card-solid); }
/* The only orange in the sidebar, and it marks exactly one thing. */
.pf-doc-navlist a.is-current {
  color: var(--flow-strong);
  font-weight: 600;
  background: var(--flow-14);
}

/* ── Main column ───────────────────────────────────────────────────────── */
.pf-doc-main { min-width: 0; padding-top: 1.75rem; }
@media (min-width: 960px) { .pf-doc-main { padding-top: 0; } }

.pf-doc-crumbs {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.9rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-crumbs a { color: var(--zinc-500); }
.pf-doc-crumbs a:hover { color: var(--ink); }

.pf-doc-title {
  margin: 0;
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-size: clamp(1.875rem, 3.4vw, 2.5rem);
  line-height: 1.08;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.pf-doc-lede {
  margin: 0.9rem 0 0;
  max-width: 62ch;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--zinc-400);
}

.pf-doc-body { margin-top: 2.5rem; max-width: 68ch; }

.pf-doc-body h2 {
  margin: 2.75rem 0 0.9rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border-soft);
  font-size: 1.25rem;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: -0.012em;
  color: var(--ink);
  scroll-margin-top: 2rem;
}
.pf-doc-body h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.pf-doc-body h3 {
  margin: 1.75rem 0 0.6rem;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--ink);
}
.pf-doc-body p { margin: 0 0 1rem; font-size: 0.9375rem; line-height: 1.72; color: var(--zinc-400); }
.pf-doc-body ul { margin: 0 0 1.15rem; padding-left: 1.25rem; list-style: none; }
.pf-doc-body li {
  position: relative;
  margin-bottom: 0.55rem;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--zinc-400);
}
.pf-doc-body li::before {
  content: "";
  position: absolute;
  left: -1.25rem;
  top: 0.8em;
  width: 6px;
  height: 1px;
  background: var(--zinc-600);
}
.pf-doc-body strong { font-weight: 600; color: var(--ink); }
.pf-doc-body a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--border-focus);
}
.pf-doc-body a:hover { text-decoration-color: var(--flow); }

/* Callout. One accent edge, no icon, no colour wash — it is an aside, not
   a warning klaxon. */
.pf-doc-note {
  margin: 0 0 1.25rem;
  padding: 0.9rem 1.1rem;
  border-left: 2px solid var(--flow-24);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  background: var(--card-solid);
}
.pf-doc-note p { margin: 0; font-size: 0.875rem; line-height: 1.65; color: var(--zinc-400); }

/* Example block. Mono, on a sunken field, with a label so it is obvious the
   content is a specimen rather than instructions. */
.pf-doc-example {
  margin: 0 0 1.25rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
  overflow: hidden;
}
.pf-doc-example-label {
  margin: 0;
  padding: 0.55rem 1rem;
  border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-example pre {
  margin: 0;
  padding: 1rem;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--zinc-300);
  white-space: pre;
}

.pf-doc-table { margin: 0 0 1.25rem; overflow-x: auto; }
.pf-doc-table table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.pf-doc-table th {
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid var(--border-focus);
  text-align: left;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-table td {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border-soft);
  color: var(--zinc-400);
}
.pf-doc-table tr td:last-child { color: var(--zinc-300); white-space: nowrap; }

/* ── Related ───────────────────────────────────────────────────────────── */
.pf-doc-related { margin-top: 3rem; padding-top: 1.75rem; border-top: 1px solid var(--border-soft); }
.pf-doc-related-head {
  margin: 0 0 1rem;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-related-grid { display: grid; gap: 0.75rem; }
@media (min-width: 560px) { .pf-doc-related-grid { grid-template-columns: 1fr 1fr; } }
.pf-doc-card {
  display: grid;
  gap: 0.25rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
  transition: border-color var(--dur-fast) var(--ease-standard),
              background-color var(--dur-fast) var(--ease-standard);
}
.pf-doc-card:hover { border-color: var(--border-focus); background: var(--paper); }
.pf-doc-card-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.pf-doc-card-desc { font-size: 12.5px; line-height: 1.5; color: var(--zinc-500); }

/* ── Pager ─────────────────────────────────────────────────────────────── */
.pf-doc-pager {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border-soft);
}
.pf-doc-pager-next {
  display: grid;
  gap: 0.15rem;
  padding: 0.7rem 1rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  text-align: right;
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.pf-doc-pager-next:hover { border-color: var(--border-focus); }
.pf-doc-pager-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-pager-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }

.pf-doc-feedback { margin: 2rem 0 0; font-size: 12.5px; color: var(--zinc-600); }
.pf-doc-feedback a { color: var(--zinc-500); text-decoration: underline; text-underline-offset: 2px; }
.pf-doc-feedback a:hover { color: var(--ink); }

/* ── On this page ──────────────────────────────────────────────────────── */
/* Ordering, per breakpoint:
     <960     side (search + toggle) → contents → article.  The sidebar is
              collapsed here, so an on-page contents list is the main way to
              navigate and belongs above the body, not below it.
     960-1199 hidden. The full sidebar is present and the reading column is
              already narrow; a second nav rail would be redundant.
     >=1200   its own sticky third column.
   `order: -1` alone put it above the search field in the single-column
   layout, which read as the page starting with a list of its own headings. */
.pf-doc-side { order: 1; }
.pf-doc-toc  { order: 2; }
.pf-doc-main { order: 3; }

@media (min-width: 960px) and (max-width: 1199px) {
  .pf-doc-toc { display: none; }
}

.pf-doc-toc {
  margin-bottom: 2rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--card-solid);
}
@media (min-width: 1200px) {
  .pf-doc-toc {
    order: 3;
    position: sticky;
    top: 2rem;
    align-self: start;
    margin-bottom: 0;
    padding: 0;
    border: 0;
    background: none;
  }
}
.pf-doc-toc-head {
  margin: 0 0 0.6rem;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-doc-toc ul { margin: 0; padding: 0; list-style: none; }
.pf-doc-toc a {
  display: block;
  padding: 0.25rem 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--zinc-500);
  transition: color var(--dur-fast) var(--ease-standard);
}
.pf-doc-toc a:hover { color: var(--ink); }

/* Previous link in the docs pager. The pair is justify-between, so a page
   with only one neighbour still anchors it to the correct side. */
.pf-doc-pager-prev {
  display: grid;
  gap: 0.15rem;
  padding: 0.7rem 1rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  transition: border-color var(--dur-fast) var(--ease-standard);
}
.pf-doc-pager-prev:hover { border-color: var(--border-focus); }
.pf-doc-pager-prev .pf-doc-pager-label,
.pf-doc-pager-prev .pf-doc-pager-title { text-align: left; }

/* ── CONTACT ───────────────────────────────────────────────────────────── */
.pf-ct-routes { display: grid; gap: 1rem; }
@media (min-width: 720px) { .pf-ct-routes { grid-template-columns: repeat(3, 1fr); } }

.pf-ct-route {
  display: grid;
  align-content: start;
  gap: 0.4rem;
  padding: 1.25rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-2xl);
  background: var(--card-solid);
}
.pf-ct-route-label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-ct-route-desc { margin: 0; font-size: 13px; line-height: 1.55; color: var(--zinc-400); }
.pf-ct-route-desc a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.pf-ct-route-link {
  margin-top: 0.35rem;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--border-focus);
  word-break: break-word;
}
.pf-ct-route-link:hover { text-decoration-color: var(--flow); }

/* ── CHANGELOG ─────────────────────────────────────────────────────────────
   A dated list, newest first. The date rail sits in its own column on wide
   screens and stacks above the entry on narrow ones — the entry is the thing
   being read, so it keeps the full measure either way. */
.pf-cl { margin: 0; padding: 0; list-style: none; }

.pf-cl-entry {
  display: grid;
  gap: 0.5rem 2rem;
  padding: 1.75rem 0;
  border-top: 1px solid var(--border-soft);
}
.pf-cl-entry:last-child { border-bottom: 1px solid var(--border-soft); }
@media (min-width: 720px) { .pf-cl-entry { grid-template-columns: 9.5rem minmax(0, 1fr); } }

.pf-cl-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 0.75rem; }
@media (min-width: 720px) { .pf-cl-meta { display: grid; align-content: start; gap: 0.45rem; } }
.pf-cl-meta time {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--zinc-600);
}
.pf-cl-tag {
  justify-self: start;
  padding: 0.15rem 0.45rem;
  border: 1px solid var(--flow-24);
  border-radius: var(--radius-lg);
  background: var(--flow-14);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--flow-strong);
}

.pf-cl-body h2 {
  margin: 0 0 0.5rem;
  font-size: 1.0625rem;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -0.008em;
  color: var(--ink);
}
.pf-cl-body p { margin: 0; font-size: 0.9375rem; line-height: 1.7; color: var(--zinc-400); }
.pf-cl-body a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
